引用百度百科:
MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。
消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。
排队指的是应用程序通过 队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。其中较为成熟的MQ产品有IBM WEBSPHERE MQ。
MQ是消费-生产者模型的一个典型的代表,一端往消息队列中不断写入消息,而另一端则可以读取或者订阅队列中的消息。MQ和JMS类似,但不同的是JMS是SUN JAVA消息中间件服务的一个标准和API定义,而MQ则是遵循了AMQP协议的具体实现和产品。
在项目中,将一些无需即时返回且耗时的操作提取出来,进行了异步处理,而这种异步处理的方式大大的节省了服务器的请求响应时间,从而提高了系统的吞吐量。
RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统。他遵循Mozilla Public License开源协议。
现在公司项目需要,要安装RabbitMQ,在安装之前,要确定依赖的环境要有:erlang、python、simplejson,下面将我安装过程过记录如下。
一、安装erlang
首先下载otp_src_R16B03.tar.gz。
依次执行如下命令:
tar -zxf otp_src_R16B.tar.gz #具体版本 cd otp_src_R16B ./configure --prefix=/opt/ make make install
在安装Erlang过程中可能会出现如下问题:
checking for kstat_open in -lkstat... no checking for tgetent in -lncurses... no checking for tgetent in -lcurses... no checking for tgetent in -ltermcap... no checking for tgetent in -ltermlib... no configure: error: No curses library functions found configure: error: /bin/sh '/home/niewf/software/erlang_R13B01/erts/configure' failed for erts
在网上找了一下,发现该问题在安装Mysql的时候也可能发生。
具体原因为:缺少ncurses安装包。因此要先安装ncurses,安装过程如下:
a)、如果你的系统是RedHat系列:
yum list|grep ncurses yum -y install ncurses-devel yum install ncurses-devel
b)、如果你的系统是Ubuntu或Debian:
apt-cache search ncurses apt-get install libncurses5-dev
安装之后,验证是否安装成功,执行以下命令并显示结果:
[root@sckf otp_src_R16B]# erl Erlang R16B (erts-5.10.1) [source] [64-bit] [smp:24:24] [async-threads:10] [hipe] [kernel-poll:false] Eshell V5.10.1 (abort with ^G)
表示erlang已经安装成功。
二、安装python
在操作系统安装时要选择上python安装,CRM5.7的OS是6.2,所以python不需升级。
如果机器的python版本过低,编译simplejson时会出错,需安装python较新版本,我这里使用的是Python-3.4.1.tgz。
tar -zxf Python-3.4.1.tgz cd Python-3.4.1 ./configure make make install mv/usr/bin/python /usr/bin/python-old ln -s /usr/local/bin/python /usr/bin/python
安装完成后验证python版本
[root@sckf ~]# python -V Python 3.4.1 [root@sckf ~]# which python /usr/bin/python [root@sckf~]#
三、安装simplejson
一般都未安装simplejson,如果机器未安装,在安装过程中会出现出现如下提示:
You don't appear to have simplejson.py installed
这时需先安装simplejson,这里安装最新的simplejson:simplejson-3.3.1.tar.gz。
然后执行以下命令:
tar xvzf simplejson-2.6.1.tar.gz cd simplejson-2.6.1 python setup.py install
四、安装rabbitmq
在http://www.rabbitmq.com/download.html下载相应安装包,请使用当前最新的稳定版本。
我这里使用的版本是:rabbitmq-server-generic-unix-3.2.2.tar.gz
(注意:请不要在内核是pae版本的os上安装,因为rabbitmq的可用内存会因为pae而大大减小。)
1. 直接使用generic版本(推荐的方式)
[root@localhost rabbitmq]# tar -zxfrabbitmq-server-generic-unix-3.2.2.tar.gz [root@localhost rabbitmq]# ll 总计 3804 drwxr-xr-x 8 root root 4096 11-07 18:54 rabbitmq_server-3.2.2 -rw-r--r-- 1 root root 3886276 11-20 11:23rabbitmq-server-generic-unix-3.2.2.tar.gz [root@localhost rabbitmq]# cd rabbitmq -bash: cd: rabbitmq: 没有那个文件或目录 [root@localhostrabbitmq]# cd rabbitmq_server-3.2.2/
2. 启动rabbitmqserver
./rabbitmq-server -detached
(可能会因为没有日志文件夹而启用失败,只需要创建相应文件夹后重新运行该命令即可)
执行一下命令:
make TARGET_DIR=/opt/rabbitmq_server-3.2.2 SBIN_DIR=/opt/rabbitmq_server-3.2.2l/sbin MAN_DIR=/opt/rabbitmq_server-3.2.2/man make install
3. 启用web管理界面
$rabbimq_home$/sbin/ ./rabbitmq-plugins enable rabbitmq_management
启用web管理插件时会由于在/etc下无rabbitmq目录而失败,请建立/etc/rabbitmq目录;
之后我们就可以通过http://localhsot:15672/来访问web管理界面了
交易日志中间件需要启用stomp插件(看应用是否需要再启用)
$rabbimq_home$/sbin/ ./rabbitmq-plugins enable rabbitmq_stomp
五、集群配置(单节点部署不需要这部分)
假设有两个节点10.109.1.149,10.109.1.158
(1)修改机器的hostname,例:
10.109.1.149 : export HOSTNAME=”server149” 10.109.1.158 : export HOSTNAME=”server158”
注意:
这里只是会话级修改,所以必须修改/etc/sysconfig/network文件才行。
(2)修改/etc/hosts文件,使得DNS可解析HOSTNAME,例:
10.109.1.149 server149 10.109.1.158 server158
(3)保证两台机器的.erlang.cookie文件相同,以便他们之间能互相通信
将141的文件(/root/.erlang.cookie)scp至143,然后执行如下命令:
cat erlang.cookie.141 >>.erlang.cookie
再将.erlang.cookie拷贝至其他机器即可,其目的是要将集群里的所有节点的.erlang.cookie文件cat到一个中,然后再拷贝至其他所有的节点,这样所有节点的.erlang.cookie文件一致,他们才能够互信。
(4)假设158作为磁盘节点,149作为内存节点
启动158的rabbitmqserver
$rabbimq_home$/sbin/ ./rabbitmq-server -detached
(5)启动149的rabbitmqserver并以内存节点的形式加入集群
$rabbimq_home$/sbin/ ./rabbitmq-server -detached $rabbimq_home$/sbin/ ./rabbitmqctl stop_app $rabbimq_home$/sbin/ ./rabbitmqctl reset $rabbimq_home$/sbin/ ./rabbitmqctl join_cluster --ram rabbit@server158 $rabbimq_home$/sbin/ ./rabbitmqctl start_app
至此集群环境搭建成功,可以使用rabbitmqctl cluster_status来查看集群状态。
六、测试实例
ReceiveTest:
package com.asiainfo.mq.rabbitmq.rabbitmqtest; import java.util.Date; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.Connection; import com.rabbitmq.client.Channel; import com.rabbitmq.client.QueueingConsumer; public class ReceiveTest { private final static String QUEUE_NAME = "hello"; public static void main(String[] argv) throws java.io.IOException, java.lang.InterruptedException { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("10.5.1.11"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); QueueingConsumer consumer = new QueueingConsumer(channel); channel.basicConsume(QUEUE_NAME, true, consumer); Date nowTime = new Date(); while (true) { QueueingConsumer.Delivery delivery = consumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println("RecieveTime: " + nowTime); System.out.println(" [x] Received '" + message + "'"); } } }
SendTest:
package com.asiainfo.mq.rabbitmq.rabbitmqtest; import java.util.Date; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.Connection; import com.rabbitmq.client.Channel; public class SendTest { private final static String QUEUE_NAME = "hello"; public static void main(String[] argv) throws java.io.IOException { try { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("10.5.1.11"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); Date nowTime = new Date(); String message = "Hello World! I'm RabbitMQ!!" + " SendTime: " + nowTime; channel.basicPublish("", QUEUE_NAME, null, message.getBytes()); System.out.println(" [x] Sent '" + message + "'"); channel.close(); connection.close(); System.out.println("Over Send."); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } }