RabbitMQ基础(二)——工作队列Work Queues

上一篇,我们编写了从一个指定的队列发送和接收消息的程序。在本文中,我们将创建一个工作队列,用于将耗时的任务分配给多个工作人员。 Work Queues,称为工作队列(也称Task Queues,任务队列),其主旨在于避免立即执行资源密集型任务,并且必须等待它完成。相反,我们把任务安排在后来执行。对此,我们将任务封装为消息并将其发送到队列中。在后台运行的工作进程会获取任务并最终执行任务。当你运行许多工作进程时,任务将在他们之间共享。 1. 轮询调度 使用任务队列的优点之一是能够轻松地并行工作。如果我们积累了大量的工作,我们就可以增加更多的任务消费者,这样就可以很容易地扩大规模。默认情况下,RabbitMQ将依次将每个消息发送给下一个使用者。平均每个消费者将得到相同数量的消息,这种分发消息的方式称为轮询。 2. 消息确认 完成一项任务可能需要几秒钟。你可能会想,如果其中一个消费者开始了一项很长的任务,并且只完成了部分任务,会发生什么。使用我们当前的代码,一旦RabbitMQ向客户传递消息,它立即标记为删除。在这种情况下,如果你关闭一个工作进程,我们将失去它正在处理的信息。我们也将丢失所有发送给这个特定工作进程并且还未处理消息。 通常,我们希望一个工作进程挂掉后,将其任务交给其他工作进程完成。为了保证消息不丢失,RabbitMQ支持消息确认机制:当消费者处理完消息后,其反馈给RabbitMQ,表明消息已经被接收和处理,RabbitMQ可以自由删除该消息。 如果一个消费者挂掉(其通道关闭,连接关闭,或者TCP连接丢失),而没有发送ack,RabbitMQ将会知道一条消息没有被完全处理,并且将重新排队。如果同时有其他的消费者在线,那么它将很快把消息重新交给另一个消费者处理,这样就保证不会丢失任何信息。 消息不会超时:当消费者进程挂掉时,RabbitMQ将重新传递消息,即使处理消息需要很长时间。 RabbitMQ默认是开启手动消息确认的,我们可以通过autoAck=true标记明确地关闭,即采用系统自动确认消息。如果需要手动确认消息,那么将autoAck设置为false,一旦我们完成了任务,需要向工作进程发出确认消息,代码如下: // 处理完成,手动接收消息时,需要在处理成功后进行反馈,保证消息不丢失 channel.basicAck(envelope.getDeliveryTag(), false); 示例的部分关键代码如下: NewTask.java /** * 发布5条消息,每条消息的一个“.”表示消息执行时间需要1秒。 * * @param args * @throws IOException * @throws TimeoutException */ public static void main(String[] args) throws IOException, TimeoutException { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection = factory.newConnection(); String[] msgs = new String[]{ "First Message.", // 1s "Second Message..", // 2s "Third Message...", // 3s "Fourth Message....", // 4s "Fifth Message....." // 5s }; Channel channel = connection.createChannel(); channel.queueDeclare(TASK_QUEUE_NAME, false, false, false, null); for (String msg : msgs) { // 发布消息 channel.basicPublish("", TASK_QUEUE_NAME, null, msg.getBytes("utf-8")); System.out.println("[x] Sent '" + msg + "'"); } channel.close(); connection.close(); } ...

2018-01-24 · 3 min · 431 words · 老墨

RabbitMQ基础(一)——基本概念和HelloWorld

1. 基本概念 RabbitMQ是一个消息代理,是一个erlang开发的AMQP(Advanced Message Queue )的开源实现。 RabbitMQ是轻量级的,易于部署在premises和云中。它支持多种消息传递协议。RabbitMQ可以部署在分布式和联合配置中,以满足高级别、高可用性需求。 其主要思想非常简单:它接受并转发消息。你可以把它想象成邮局:当你把邮件寄到邮箱时,你很确定邮差先生最终会把邮件寄给你的收件人。使用这个比喻,RabbitMQ是一个邮筒,一个邮局和一个邮差。 RabbitMQ与邮局的主要区别在于,它不处理纸张,而是接受、存储和转发二进制数据。 官网地址: http://www.rabbitmq.com 2. AMQP AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有 RabbitMQ等。 目标是实现一种在全行业广泛使用的标准消息中间件技术,以便降低企业和系统集成的开销,并且向大众提供工业级的集成服务。通过AMQP,让消息中间件的能力最终被网络本身所具有,并且通过消息中间件的广泛使用发展出一系列有用的应用程序。 Broker: 中间件。接收和分发消息的应用,RabbitMQ Server就是Message Broker。 Virtual host: 虚拟主机。出于多租户和安全因素设计的,把AMQP的基本组件划分到一个虚拟的分组中,类似于网络中的namespace概念。当多个不同的用户使用同一个RabbitMQ server提供的服务时,可以划分出多个vhost,每个用户在自己的vhost创建exchange/queue等。 Connection: 连接。publisher/consumer和broker之间的TCP连接。断开连接的操作只会在client端进行,Broker不会断开连接,除非出现网络故障或broker服务出现问题。 Channel: 渠道。如果每一次访问RabbitMQ都建立一个Connection,在消息量大的时候建立TCP Connection的开销将是巨大的,效率也较低。Channel是在connection内部建立的逻辑连接,如果应用程序支持多线程,通常每个thread创建单独的channel进行通讯,AMQP method包含了channel id帮助客户端和message broker识别channel,所以channel之间是完全隔离的。Channel作为轻量级的Connection极大减少了操作系统建立TCP connection的开销。 Exchange: 路由。message到达broker的第一站,根据分发规则,匹配查询表中的routing key,分发消息到queue中去。常用的类型有:direct (point-to-point), topic (publish-subscribe) and fanout (multicast)。 Queue: 队列。消息最终被送到这里等待consumer取走。一个message可以被同时拷贝到多个queue中。 Binding: 绑定。exchange和queue之间的虚拟连接,binding中可以包含routing key。Binding信息被保存到exchange中的查询表中,用于message的分发依据。 3. RabbitMQ术语 3.1. Producter 即生产者。Producing就是发送,发送消息的程序是生产者(Producter)。用P表示,如下图: 3.2. Exchange 交换器,RabbitMQ中,其实消息不会直接相队列发送,而是发送给交换器,然后交换器在按照一定的规则转发给不同的队列。交换器做的事情非常简单:一方面,它接收来自生产者的消息,另一边则将消息推送到队列中。交换必须知道如何处理它接收到的消息。是否应该附加到特定的队列?是否应该附加到许多队列?或者应该被抛弃。这些规则由交换类型(exchange type)定义。 3.3. Exchange Type 交换器类型,在创建交换器时指定,用于区分交换器的不同作用,实现不同的功能。RabbitMQ定义了四种交换器类型:direct、topic、headers、fanout,每种类型都有特定的应用场景(见后续文章的详细介绍)。 direct:bindingKey和routingKey进行精确匹配,适用于精确将消息发送给指定队列; topic:bindingKey和routingKey可以进行模糊匹配,通过使用通配符"*"和"#"分别来模糊匹配一个单词和多个单词;适用于将消息按照一定的规则发送到匹配的一个或多个队列; fanout:广播,这种交换器可以将消息广播给所有订阅的交换器; header:不常用,有兴趣的话可以自行了解。 3.4. Queue 即队列,队列是邮箱的名称,它处于RabbitMQ内部。尽管消息流通过RabbitMQ和您的应用程序,但它们只能存储在队列中。队列不受任何限制,它可以根据你的需要存储尽可能多的消息----它本质上是一个无限的缓冲区。许多生产者都可以发送消息到一个队列,许多消费者可以尝试从一个队列接收数据。队列上有它的名称,如下图表示: 3.5. Consumer 即消费者,Consuming跟receiving的含义类似。Consumer通常为等待接收消息的应用程序 。注意,生产者、消费者和消息代理不需要处于同一台主机上,事实上,在大多数应用场景都是如此。 ...

2018-01-18 · 2 min · 354 words · 老墨

Windows server 2012 R2评估版本激活

原来服务器安装了Windows server 2012 R2评估版本,只能试用180天,最近刚好到期了,系统激活前每隔一个小时会自动关机,所以必须进行激活。 要激活分为两步: 1、将评估版升级为标准版 2、使用激活工具激活 1. 将评估版升级为标准版 1.1. 查看系统当前版本 最好以管理员身份运行cmd,输入命令: DISM /online /Get-CurrentEdition 可以查询当前安装的版本是什么。 如果是评估版,例如Standard,把“ServerStandardEval”中的Eval这四个字母去掉,就是你的当前版本。 我的当前版本就是ServerStandard,如下图所示: 1.2. 升级为标准版 同样在cmd中输入如下命令: DISM /online /Set-Edition:ServerStandard /ProductKey:你的标准版key /AcceptEula ServerStandard为查出来的EDITION ID,ProductKey为标准版key,例如我使用如下命令成功升级为标准版: DISM /online /Set-Edition:ServerStandard /ProductKey:M98WF-NY2PP-73243-PC8R6-V6B4Y /AcceptEula 如果提示key无效或不可用,多找一些key试试。 升级完成后,重启系统,现在桌面的标准评估版本已经不再显示,右键点击我的电脑-属性,可以看到现在为standard版本,说明升级成功,但是仍然没有激活。 2. 使用激活工具激活 我尝试使用KMSTools激活工具激活,结果激活失败。 最终,在网上找到了小马激活工具,成功激活。 工具下载地址: https://pan.baidu.com/s/1qYwqI2w。 注意:博主亲测可以激活,但杀毒软件可能会报病毒,博主是直接绕过杀毒软件的,存在一定的风险,请谨慎考虑。 激活成功后,再次重启系统,可以看到已经成功激活了。 申明 本文章仅供个人学习参考使用,如需商业用途,建议大家支持正版系统。

2017-12-05 · 1 min · 45 words · 老墨

redis desktop manager桌面工具

链接 http://pan.baidu.com/s/1i53VLmX 密码 vmm6 比较好用的Redis可视化界面工具,支持Windows 10, Mac OS X 10.12, Ubuntu 16, LinuxMint | Fedora | CentOS | OpenSUSE等平台。 github地址: https://github.com/uglide/RedisDesktopManager/ 官网: http://redisdesktop.com 界面截图: 可支持控制台: 支持按key过滤查找功能:

2017-11-23 · 1 min · 26 words · 老墨

Astah professional 7.2版本破解文件

分享Astah professional 7.2下载和破解: 官方下载地址: http://astah.net/download 1、免费的community版本 链接: http://pan.baidu.com/s/1kVch3oj 密码:3o49 2、专业版 链接: http://pan.baidu.com/s/1slzBKip 密码:lwjn 专业版破解文件 链接: http://pan.baidu.com/s/1pLBlgDH 密码:u9x7 破解方法:解压下载的文件,将astah-pro.jar拷贝的软件安装根目录覆盖原文件即可。 上边的连接永久有效,博主自己测试可以正常破解使用。

2017-11-22 · 1 min · 19 words · 老墨

WEBP格式的图片导致ImageIO.read方法return null

1. 问题背景 最近开发一个图片服务,主要是维护项目图片,支持JPG、BMP、PNG、JPEG等常规格式。开发的时候没问题,但是上到生产的时候,客户在维护图片的时候,发现有的JPG格式的图片能上传,有的不能。 拿到正常上传和不能上传的图片,对比发现,不能上传的图片,在windows上根本无法打开,图片如下(用chrome打开可以看见,右键另存图片,或者 点击这里下载): 但是奇怪的是,该图片可以在chrome浏览器显示,也可以在安卓APP上显示,但是其他浏览器和iOS无法正常显示。 2. 问题分析 首先debug代码,发现图片都会使用ImageIO来读取,以便获取图片宽高从而进行等比例压缩,代码如下: BufferedImage bi = ImageIO.read(inputStream); Map rtnMap = new HashMap(); if (bi == null) { rtnMap.put("status", "1"); //上传不成功 rtnMap.put("msg", "该图片本身不是图片格式"); return rtnMap; } 非正常图片,上边的bi会返回null,而不会抛出任何异常信息。 首先怀疑图片是损坏的,因为windows上根本无法打开,显示如下: 但是该图片可以在chrome上正常显示,这表明图片不会是损坏了,应该是跟平台有关,那么会不会是图片格式根本不是JPG,仅仅后缀显示为JPG呢? 然后我用记事本打开正常的和非正常的图片文件进行比对,想获取一些有用的信息,结果发现: 非正常JPG图片 正常JPG图片 如上所示,正常JPG里边,显示格式为JFIF,而非正常图片显示为WEBPVP8,明显不同。看来,不能正常上传的图片是平台不支持的图片格式,到底WEBPVP8是什么格式? 3. WEBP格式 通过谷歌搜索,查询半天发现,这种格式名为WEBP,由谷歌开发,官方地址(记得翻墙): https://developers.google.com/speed/webp/?hl=zh-CN,也是图片格式的一种, 百度百科原文如下: WebP格式,谷歌(google)开发的一种旨在加快图片加载速度的图片格式。图片压缩体积大约只有JPEG的2/3,并能节省大量的服务器带宽资源和数据空间。Facebook Ebay等知名网站已经开始测试并使用WebP格式。 但WebP是一种有损压缩。相较编码JPEG文件,编码同样质量的WebP文件需要占用更多的计算资源。桌面版Chrome可打开WebP格式。 恍然大悟,原来是一种新型图片格式,很明显windows和iOS还不支持,但是谷歌旗下产品可以支持,这就解释了为什么chrome、安卓能够打开。 在JAVA中,还不支持这种格式,可以用如下代码检查当前支持的图片格式: String[] ss = ImageIO.getReaderFormatNames(); System.out.println(Arrays.asList(ss)); 返回结果:[JPG, jpg, bmp, BMP, gif, GIF, WBMP, png, PNG, jpeg, wbmp, JPEG] 在查找问题时,我还尝试使用twelvemonkeys扩展包来扩展所支持的图片类型: <dependency> <group>com.twelvemonkeys.imageio</group> <artifact>imageio-jpeg</artifact> <version>3.3.2</version> </dependency> <dependency> <group>com.twelvemonkeys.imageio</group> <artifact>imageio-tiff</artifact> <version>3.3.2</version> </dependency> <dependency> <group>com.twelvemonkeys.imageio</group> <artifact>imageio-pnm</artifact> <version>3.3.2</version> </dependency> ...

2017-11-03 · 2 min · 375 words · 老墨

ubuntu下ssh关闭密码登陆,采用公钥认证登陆

前段时间,公司内网的机器被黑客入侵,最后分析原因,在于我们希望通过外网访问公司的git仓库,然后开放了22端口,而此前git所在机器上被病毒感染过…… 由于git是单独的服务器,所以我们希望只有公钥认证的用户可以授权访问该服务器,否则拒绝访问。因此,我们决定采用以下方案: 禁止用户通过ssh的账号密码登陆,而是用公钥私钥认证登陆。具体做法如下: 1. 修改SSH配置文件sshd_config 注意是sshd_config,修改ssh_config无效 编辑sshd_config文件: $ vi /etc/ssh/sshd_config 禁用密码验证,默认是yes $ vi /etc/ssh/sshd_config 启用密钥验证 $ vi /etc/ssh/sshd_config 指定公钥数据库文件 $ vi /etc/ssh/sshd_config 2. 重启ssh服务 $ vi /etc/ssh/sshd_config 由于服务器有两个用户:root管理员用户和git用户,而所有访问代码的必须通过git用户访问,git本身已经通过公钥私钥登陆,所以对原来访问代码仓库的客户端没有影响。而目前root用户禁止了密码登陆,如果进行授权呢? 很简单,将授权以root用户登录服务器的客户端公钥加入到/root/.ssh/authorized_keys文件中,客户端登陆时,带上客户端的私钥信息,就可以完成认真并成功以root用户登录,我用的mobXterm工具,其他工具类似,链接选择私钥如下: 这样,就完成了只能公钥认证通过的用户才能登陆服务器的功能。 3. 注意事项 3.1. 保留会话窗口 在修改sshd_config文件并重启ssh之前,先保留一个链接到服务器的会话,否则如果ssh配置出现错误,将导致不能链接到服务器。 3.2. ssh配置文件 修改sshd_config而非ssh_config。 3.3. 为何不修改ssh默认的22端口 因为链接git仓库客户端较多,如果修改了22端口,每一个客户端都要重新设置代码仓库的remote地址,处理起来较为麻烦,如果如何处理请自行百度。当然为了更为安全,建议还是修改ssh默认的22端口。

2017-08-14 · 1 min · 41 words · 老墨

git从其他git服务器完整迁移到自建git服务器

1). 从原地址克隆一份裸版本库,原本托管于oschina。 git clone --bare git://github.com/username/project.git (1) 1 --bare 创建的克隆版本库都不包含工作区,直接就是版本库的内容,这样的版本库称为裸版本库。 2). 然后到新的 Git 服务器上创建一个新项目,比如commons。 mkdir commons.git cd commons.git git init --bare 上边的命令表示创建名为commons的版本库,并初始化为空版本库(注意--bare参数)。 3). 以镜像推送的方式上传代码到新的git服务器上。 git push --mirror git@<你的serverIp>:commons.git (1) 1 --mirror 克隆出来的裸版本对上游版本库进行了注册,这样可以在裸版本库中使用git fetch命令和上游版本库进行持续同步。 例如: $ git push --mirror git@192.168.0.106:/data/code/commons.git Counting objects: 100, done. Delta compression using up to 4 threads. Compressing objects: 100% (54/54), done. Writing objects: 100% (100/100), 44.88 KiB | 0 bytes/s, done. Total 100 (delta 13), reused 100 (delta 13) To 192.168.0.106:/data/code/commons.git * [new branch] master -> master ...

2017-06-08 · 1 min · 98 words · 老墨

Nginx学习——nginx的下载、安装和启动

Nginx作为一款轻量级WEB服务服务器,除了作为http代理和反向代理服务器,还更广泛的运用于负载均衡、高级http服务、邮件代理服务等。接下来,我们开始学习如何下载安装Nginx服务器,包括windows平台和linux平台。 1. Nginx版本 Nginx的官方网址: http://nginx.org Nginx下载地址: http://nginx.org/en/download.html 如上图所示,目前nginx官方分为三个版本: 主线开发版本(Mainline version):即功能较新的处于开发中的版本,可以用于学习,但不太稳定,不适合商用; 稳定版本(Stable version):功能稳定,适合商用; 历史遗留版本(Legacy versions):较早的历史版本。 其他链接 图1中的CHANGES的链接,是对于此版本的更新日志记录; 图1中的nginx-x.x.x的链接,对应的是nginx特定版本的源代码; 图1中的pgp链接,记录的是使用GPG加密软件计算后的签名信息,用于下载文件的验证,防止文件被篡改; 图1中的nginx/Windows-x.x.x对应的是nginx的windows版本的下载链接。 2. Windows 1、下载安装 下载图1中的nginx/Windows-1.12.0,得到window版本的nginx压缩包。 windows版本为绿色版本,解压即用,无须安装。解压下载的压缩包,得到如下的目录结构: 2、启动 双击nginx.exe启动 直接运行图2的nginx.exe即启动了nginx,同时可以在任务管理器中看到有两个nginx.exe的进程。 Windows命令行启动 运行cmd,进入nginx目录,运行命令 $ nginx.exe 这种方式会使命令行一直处于执行中,无法进行后续操作 或者 $ start nginx 推荐的方式。 如果启动未出现异常信息,表明启动成功,任务管理器中会出现两个nginx.exe的进程。 3、停止 杀进程 直接在任务管理器中kill掉nginx进程,不推荐。 命令行 运行cmd,进入nginx目录,输入命令 $ nginx.exe –s quit 推荐,这种方式是平缓停止,完整有序的停止nginx,并保存相关信息 或者 $ nginx.exe –s stop 快速停止nginx,不保存相关信息。 4、重新加载配置文件 运行cmd,进入nginx目录,输入命令 $ nginx –s reload 5、重新打开日志文件 运行cmd,进入nginx目录,输入命令 $ nginx –s reopen 6、Nginx版本查看 $ ./sbin/nginx –v 或者 $ ./sbin/nginx –V ...

2017-05-15 · 2 min · 269 words · 老墨

linux常见操作整理

Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。本文记录了Linux常用的一些命令,并不断完善中,以备查阅。 1. 基本操作 1、删除文件命令: rm -rf 目录循环删除目录 2、打开/关闭fpt命令: service sftpd stop/start 3、ftp开启命令: /etc/rc.d/init.d/xinetd stop /etc/rc.d/init.d/vsftpd start /etc/rc.d/init.d/xinetd start 4、svn开启命令: svnserve -d -r /usr/local/svn/ 5、jetty启动: root@ubuntu-server1:/usr/local/jetty-mvn/jetty9/bin# ./jetty.sh start Starting Jetty: . . . OK Tue Sep 10 12:30:45 CST 2013 6、解压文件到指定目录: tar xxx.gz -C /usr/local/ 7、查看权限命令 查看目录的相关权限可以采用命令ls -lD,或者直接用ls -la如: ls -l www.jb51.net 这里表示查看www.jb51.net目录 8、查看linux机器是32位还是64位的方法: file /sbin/init 或者 file /bin/ls 9、找不到网卡解决: vi /etc/udev/rules.d/70-persistent-net.rules 将最新的eth2网卡改为eth0,并拷贝其ATTR(即最新的mac地址)值,然后编辑eth0的配置文件,将HWADDR改为该值,重启网络服务,问题解决。 10、查看磁盘空间: df -hl 11、查看系统用户和组: groups查看当前登录用户的组内成员 groups gliethttp查看gliethttp用户所在的组,以及组内成员 whoami查看当前登录用户名 /etc/group文件包含所有组 /etc/shadow和/etc/passwd系统存在的所有用户名 ...

2017-04-05 · 4 min · 694 words · 老墨

高性能Javascript--脚本的无阻塞加载策略

Javascript在浏览器中的性能,可以说是前端开发者所要面对的最重要的可用性问题。 在Yahoo的Yslow23条规则当中,其中一条是将JS放在底部 <wbr>。原因是,事实上,大多数浏览器使用单进程处理UI和更新Javascript运行等多个任务,而同一时间只能有一个任务被执行。Javascript运行了多长时间,那么在浏览器空闲下来响应用户交互之前的等待时间就有多长。 从基本层面说,这意味着<script>标签的出现使整个页面因脚本解析、运行而出现等待。不论实际的 JavaScript 代码是内联的还是包含在一个不相干的外部文件中,页面下载和解析过程必须停下,等待脚本 完成这些处理,然后才能继续。这是页面生命周期必不可少的部分,因为脚本可能在运行过程中修改页面 内容。典型的例子是 document.write()函数,例如: <html> <head> <title>Script Example</title> </head> <body> <p> <script type="text/javascript"> document.write("The date is " + (new Date()).toDateString()); </script> </p> </body> </html> 当浏览器遇到一个<script>标签时,正如上面 HTML 页面中那样,无法预知 JavaScript 是否在标签中 添加内容。因此,浏览器停下来,运行此 JavaScript 代码,然后再继续解析、翻译页面。同样的事情发生 在使用 src 属性加载 JavaScript的过程中。浏览器必须首先下载外部文件的代码,这要占用一些时间,然后 解析并运行此代码。此过程中,页面解析和用户交互是被完全阻塞的。 <wbr> 因为脚本阻塞其他页面资源的下载过程,所以推荐的办法是:将所有<script>标签放在尽可能接近<body> <wbr>标签底部的位置,尽量减少对整个页面下载的影响。例如: <html> <head> <title>Script Example</title> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <p>Hello world!</p> <-- Example of recommended script positioning --> <script type="text/javascript" src="file1.js"></script> <script type="text/javascript" src="file2.js"></script> <script type="text/javascript" src="file3.js"></script> </body> </html> ...

2017-04-05 · 3 min · 440 words · 老墨

MySQL慢查询分析

最近开发微信红包活动,并发量大概在100左右,数据库存储数据几十万条。活动上线后,遇到一个问题,服务启动起来后,在几分钟之内,服务变得很慢,通过分析tcp状态(ss -s)发现,处于timewait状态的TCP达到一千多个,然后从应用前台、后台到数据库逐步分析,最后发现,由于某一张表的数据量达到几十万,而某一个逻辑需要连接该表进行数据查询,导致SQL执行非常缓慢。于是整理下SQL慢查询分析的相关方法,以便查阅。 1. explain语句 explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,explain可以用来查看 SQL 语句的执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好的优化语句。 Explain语法: explain select … from … [where ...] 例如:explain select * from news; 输出: ---- ------------- ------- ------- ------------------- --------- --------- ------- ------ ------- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | ---- ------------- ------- ------- ------------------- --------- --------- ------- ------ ------- 下面对各个属性进行了解: 1、id:这是SELECT的查询序列号 2、select_type:select_type就是select的类型,可以有以下几种: SIMPLE:简单SELECT(不使用UNION或子查询等) PRIMARY:最外面的SELECT UNION:UNION中的第二个或后面的SELECT语句 DEPENDENT UNION:UNION中的第二个或后面的SELECT语句,取决于外面的查询 UNION RESULT:UNION的结果。 SUBQUERY:子查询中的第一个SELECT DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询 DERIVED:导出表的SELECT(FROM子句的子查询) ...

2017-04-04 · 6 min · 1074 words · 老墨

JVM垃圾回收器工作原理及使用实例介绍

本文首先介绍了JVM各类垃圾回收器及其工作原理,接着通过实例演示它们的使用方式及需注意事项,最后总结了垃圾回收器的配置方式及参数意义。 1. 垃圾收集基础 Java语言的一大特点就是可以进行自动垃圾回收处理,而无需开发人员过于关注系统资源,例如内存资源的释放情况。自动垃圾收集虽然大大减轻了开发人员的工作量,但是也增加了软件系统的负担。 拥有垃圾收集器可以说是Java语言与C语言的一项显著区别。在 C语言中,程序员必须小心谨慎地处理每一项内存分配,且内存使用完后必须手工释放曾经占用的内存空间。当内存释放不够完全时,即存在分配但永不释放的内存块,就会引起内存泄漏,严重时甚至导致程序瘫痪。 以下列举了垃圾回收器常用的算法及实验原理: 1.1. 1、引用计数法 (Reference Counting) 引用计数器在微软的 COM 组件技术中、Adobe 的 ActionScript3 种都有使用。 引用计数器的实现很简单,对于一个对象 A,只要有任何一个对象引用了 A,则 A 的引用计数器就加 1,当引用失效时,引用计数器就减 1。只要对象 A 的引用计数器的值为 0,则对象 A 就不可能再被使用。 引用计数器的实现也非常简单,只需要为每个对象配置一个整形的计数器即可。但是引用计数器有一个严重的问题,即无法处理循环引用的情况。因此,在 Java 的垃圾回收器中没有使用这种算法。 一个简单的循环引用问题描述如下:有对象 A 和对象 B,对象 A 中含有对象 B 的引用,对象 B 中含有对象 A 的引用。此时,对象 A 和对象 B 的引用计数器都不为 0。但是在系统中却不存在任何第 3 个对象引用了 A 或 B。也就是说,A 和 B 是应该被回收的垃圾对象,但由于垃圾对象间相互引用,从而使垃圾回收器无法识别,引起内存泄漏。 1.2. 2、标记-清除算法 (Mark-Sweep) 标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。一种可行的实现是,在标记阶段首先通过根节点,标记所有从根节点开始的较大对象。因此,未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清除所有未被标记的对象。该算法最大的问题是存在大量的空间碎片,因为回收后的空间是不连续的。在对象的堆空间分配过程中,尤其是大对象的内存分配,不连续的内存空间的工作效率要低于连续的空间。 1.3. 3、复制算法 (Copying) 将现有的内存空间分为两快,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收。 如果系统中的垃圾对象很多,复制算法需要复制的存活对象数量并不会太大。因此在真正需要垃圾回收的时刻,复制算法的效率是很高的。又由于对象在垃圾回收过程中统一被复制到新的内存空间中,因此,可确保回收后的内存空间是没有碎片的。该算法的缺点是将系统内存折半。 Java 的新生代串行垃圾回收器中使用了复制算法的思想。新生代分为 eden 空间、from 空间、to 空间 3 个部分。其中 from 空间和 to 空间可以视为用于复制的两块大小相同、地位相等,且可进行角色互换的空间块。from 和 to 空间也称为 survivor 空间,即幸存者空间,用于存放未被回收的对象。 ...

2017-04-03 · 7 min · 1413 words · 老墨

maven定义profile无法替换property属性值

1. 场景 最近开发一个web项目,用的maven构建,建立多个profile,对应不同环境,分别包含不同的配置,在打包的时候发现,xml和properties配置文件没有被替换为profile下定义的property属性值。 2. 解决方案: WEB工程需要war插件,启用web资源目录的filter功能,而普通jar不需要。步骤如下: 1、定义profile和各个property属性值 2、定义maven-war插件,并确认webresource文件目录 3、开启filter功能 4、执行clean package -P(profile-id) 命令,可以正常替换web资源目录下的形如${}的变量 3. 示例 3.1. 定义profile 定义dev和uat两个profile,分别对应开发环境和uat环境: <profiles> <profile> <id>dev</id> <properties> <!-- 数据库相关配置--> <mysql.jdbc.url>192.168.1.224:3306/cd_pro</mysql.jdbc.url> <mysql.jdbc.username>root</mysql.jdbc.username> <mysql.jdbc.password>xxxxxx</mysql.jdbc.password> <!-- 环境配置 --> <application.context.ip>http://192.168.1.224/</application.context.ip> <site.id>510100</site.id> <!-- 支付相关配置--> <revisa.pay.service.id>123456</revisa.pay.service.id> <!--LOG4J日志级别--> <log4j.log.level>debug</log4j.log.level> <log4j.logfile.path>D:/logs/cd_pro.log</log4j.logfile.path> <memorycache.url>192.168.1.224:11211</memorycache.url> </properties> <activation> <activeByDefault>true</activeByDefault> </activation> </profile> <profile> <id>uat</id> <properties> <!-- 数据库相关配置--> <mysql.jdbc.url>10.150.39.21:3306/cd_pro</mysql.jdbc.url> <mysql.jdbc.username>root</mysql.jdbc.username> <mysql.jdbc.password>xxxxxx</mysql.jdbc.password> <!-- 环境配置 --> <application.context.ip>http://uat.zaichengdu.com/</application.context.ip> <revisa.pay.site.id>510100</revisa.pay.site.id> <!-- 支付相关配置--> <revisa.pay.service.id>123456</revisa.pay.service.id> <!--LOG4J日志级别--> <log4j.log.level>info</log4j.log.level> <log4j.logfile.path>/data/logs/cd_pro.log</log4j.logfile.path> <memorycache.url>10.150.38.106:11211</memorycache.url> </properties> </profile> </profiles> 3.2. war插件配置和web资源目录定义 <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <configuration> <webResources> <resource> <!-- this is relative to the pom.xml directory --> <directory>src/main/resources</directory> <targetPath>WEB-INF/classes/</targetPath> <filtering>true</filtering> </resource> </webResources> </configuration> </plugin> ...

2017-04-03 · 1 min · 113 words · 老墨

jQuery validator表单验证框架使用说明

jquery.validate.js是jquery旗下的一个验证框架,借助jquery的优势,我们可以迅速验证一些常见的输入,并且可以自己扩充自己的验证方法,并且对国际化也有很好的支持,本文介绍了该框架的基本使用及常见API。 官网地址: http://jqueryvalidation.org/ 1. 导入js库 <script src='../js/jquery.js' type='text/javascript'></script> <script src='../js/jquery.validate.js' type='text/javascript'></script> 2. 默认校验规则 required:true 必输字段 remote:”check.php” 使用ajax方法调用check.php验证输入值 email:true 必须输入正确格式的电子邮件 url:true 必须输入正确格式的网址 date:true 必须输入正确格式的日期 日期校验ie6出错,慎用 dateISO:true 必须输入正确格式的日期(ISO),例如:2009-06-23,1998/01/22 只验证格式,不验证有效性 number:true 必须输入合法的数字(负数,小数) digits:true 必须输入整数 creditcard: 必须输入合法的信用卡号 equalTo:”#field” 输入值必须和#field相同 accept: 输入拥有合法后缀名的字符串(上传文件的后缀) maxlength:5 输入长度最多是5的字符串(汉字算一个字符) minlength:10 输入长度最小是10的字符串(汉字算一个字符) rangelength:[5,10] 输入长度必须介于 5 和 10 之间的字符串”)(汉字算一个字符) range:[5,10] 输入值必须介于 5 和 10 之间 max:5 输入值不能大于5 min:10 输入值不能小于10 3. 默认的提示 messages: { required: "This field is required.", remote: "Please fix this field.", email: "Please enter a valid email address.", url: "Please enter a valid URL.", date: "Please enter a valid date.", dateISO: "Please enter a valid date (ISO).", dateDE: "Bitte geben Sie ein g眉ltiges Datum ein.", number: "Please enter a valid number.", numberDE: "Bitte geben Sie eine Nummer ein.", digits: "Please enter only digits", creditcard: "Please enter a valid credit card number.", equalTo: "Please enter the same value again.", accept: "Please enter a value with a valid extension.", maxlength: $.validator.format("Please enter no more than {0} characters."), minlength: $.validator.format("Please enter at least {0} characters."), rangelength: $.validator.format("Please enter a value between {0} and {1} characters long.") range: $.validator.format("Please enter a value between {0} and {1}."), max: $.validator.format("Please enter a value less than or equal to {0}."), min: $.validator.format("Please enter a value greater than or equal to {0}.") } ...

2017-04-03 · 6 min · 1138 words · 老墨