1. 消息队列理论
1)消息队列产品介绍:
redis:数据小于10k的时候,性能特别强悍,一旦大于10k入队速度慢到无法忍受
memcacheQ:并发性能强,兼容memcache完美
MSMQ:最大消息4Mb(这是微软产品唯一被认为有价值的东西),只能发送和接收
zeroMQ:轻量级的,号称最快的消息列队,专门用于高吞吐量/低延迟场景(金融机构)
kafka:高吞吐量,高达10万/秒,支持快速持久化,高吞吐,普通pc可达到10w/s吞吐率,支持大数据Hadoop
ActiveMQ:apache开源出来的
java世界中的中间力量
跨平台使用
RabbitMQ:Erlang语言
最老牌
最稳定
支持的协议最多
2)关于rabbitmq
AMQP:高级消息列队协议,语言使用的是erlang
支持python/ruby/.net/java/php/c/xmpp/stomp。
扩展性好,可用性强
解决问题:
- web高并发
- 高并发链接问题
mysql:大量请求包括insert,update。—行锁、表锁
提示:error :too many connextions的时候 - 程序间的消息发送
这里要求主机必须开RPC(rpc.statd可以从系统核心中获取系统性能统计的相关信息,将结果返回给调用程序)
3)原理部分
a. 相关概念
- Broker:它提供一种传输服务,它的角色就是维护一条从生产者到消费者的路线,保证数据能按照指定的方式进行传输,
- Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
- Queue:消息的载体,每个消息都会被投到一个或多个队列。
- Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来.
- Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
- vhost:虚拟主机,一个broker里可以有多个vhost,用作不同用户的权限分离。
- Producer:消息生产者,就是投递消息的程序.
- Consumer:消息消费者,就是接受消息的程序.
- Channel:消息通道,在客户端的每个连接里,可建立多个channel.
b. 流程思路
左边的Client向右边的Client发送消息,流程:
1) 获取Conection (producer与server建立连接)
2)获取Channel (建立连接后,建立消息通道)
3)producer定义Exchange,Queue ()
4)producer在传递消息的时候还会传递一个routing key,它使用RoutingKey将Queue Binding到一个Exchange上
5)接收方在接收时也是获取connection,接着获取channel,然后指定一个Queue直接到它关心的Queue上取消息,它对Exchange,RoutingKey及如何binding都不关心,到对应的Queue上去取消息就OK了
c.通信过程
假设P1和C1注册了相同的Broker,Exchange和Queue。P1发送的消息最终会被C1消费。基本的通信流程大概如下所示:
1)P1生产消息,发送给服务器端的Exchange
2)Exchange收到消息,根据ROUTINKEY,将消息转发给匹配的Queue1
3)Queue1收到消息,将消息发送给订阅者C1
4)C1收到消息,发送ACK给队列确认收到消息
5)Queue1收到ACK,删除队列中缓存的此条消息
d. 注意要点
1)consumer消费消息后要发送ack给broker
2)如果consumer接收了消息,并发送了ack,那么队列中就会删除这条消息
3)RabbitMQ它没有用到超时机制.RabbitMQ仅仅通过Consumer的连接中断来确认该Message并没有正确处理,也就是说RabbitMQ给了Consumer足够长的时间做数据处理。
4)如果Consumer退出了但是没有发送ack,那么RabbitMQ就会把这个Message发送到下一个Consumer,这样就保证在Consumer异常退出情况下数据也不会丢失;如果忘记ack,那么当Consumer退出时,Mesage会重新分发,然后RabbitMQ会占用越来越多的内存
5)rabbitmq2.0.0和之后的版本支持consumer reject某条(类)消息,如果拒绝,那么rabbitmq将会把消息发送给下一个注册的consumer
6)一个client与一个server之间有一个连接;一个连接上可以建立多个channel,可以理解为逻辑上的连接。一般应用的情况下,有一个channel就够用了,不需要创建更多的channel
7)exchange的类型:
- direct exchange :完全根据key进行投递,routing key=exchange key
- fanout exchange: 不需要key的叫做fanout交换机,采用广播模式
- topic exchange: 采用正则表达式的方式进行投递
- headers: 按照头部消息进行投递(量太大,区分不明显)
8)dead-letter选项说明
dead-letter=requeue-false 直接抛弃异常数据,而不是重新进入队列。重新进入队列可能会造成大量消息积压在队列中,压力较大。
9)关于vhost
一个RabbitMQ的实体上可以有多个vhosts,用户与权限设置就是依附于vhosts。
在rabbitmq server上可以创建多个虚拟的message broker,又叫做virtual hosts (vhosts)。每一个vhost本质上是一个mini-rabbitmq server,分别管理各自的exchange,和bindings。vhost相当于物理的server,可以为不同app提供边界隔离,使得应用安全的运行在不同的vhost实例上,相互之间不会干扰。producer和consumer连接rabbit server需要指定一个vhost。
2. 操作部分
2.1 rabbitmq单节点、打模块
rabbitMQ的集群:
- 普通模式(默认):消息只有一份(节省内存空间)
- 镜像模式:消息存在多个节点上,消息会主动在节点之间同步
缺点:如果消息过多,则会损耗通讯信道;会降低系统性能
Pattern: queue的匹配模式(正则表达式)
Definition:镜像定义,包括三个部分ha-mode, ha-params, ha-sync-mode
ha-mode:指明镜像队列的模式,有效值为 all/exactly/nodes
all:表示在集群中所有的节点上进行镜像
exactly:表示在指定个数的节点上进行镜像,节点的个数由ha-params指定
nodes:表示在指定的节点上进行镜像,节点名称通过ha-params指定
ha-params:ha-mode模式需要用到的参数
ha-sync-mode:进行队列中消息的同步方式,有效值为automatic和manual
priority:可选参数,policy的优先级
集群节点类型:
- 内存节点:只保存状态到内存
- 磁盘节点:保存状态到内存和磁盘上
生产中,内存节点不会写入硬盘,但是它执行比磁盘节点好,集群中,一般有一个磁盘节点来持久化就足够了,其他的使用内存节点。如果集群中只有内存节点,那么不能停止它们,否则所有状态、消息都会丢失。
集群可以共享 user vhost queue exchange policy
安装rabbitmq
681 cd
682 cp /mnt/hgfs/soft/ra/* .
683 ls
684 rpm -qa | grep erlang
685 yum -y localinstall erlang-solutions-1.0-1.noarch.rpm
686 yum -y localinstall erlang-18.1-1.el6.x86_64.rpm
687 yum -y localinstall socat-1.7.2.3-1.el6.x86_64.rpm
688 yum -y localinstall rabbitmq-server-3.6.6-1.el6.noarch.rpm
启动rabbitmq,并加入开机自启
689 /etc/init.d/rabbitmq-server start
690 chkconfig rabbitmq-server on
691 chkconfig rabbitmq-server --list
为rabbitmq添加一个admin用户,密码是redhat,设置用户角色为administrator,Tag可以为 administrator,monitoring, management
692 rabbitmqctl add_user admin redhat
693 rabbitmqctl set_user_tags admin administrator
开启 rabbitmq web管理插件
694 rabbitmq-plugins enable rabbitmq_management
rabbitMQ打模块(yum装mysql的LNMP)
(1)安装LNMP
639 mount /dev/cdrom /mount
640 nginx
641 killall nginx
642 yum -y install mysql mysql-server mysql-devel
734 service mysqld restart
737 mysqladmin -u root password 123456
738 mysql -uroot -p
739 ln -s /var/lib/mysql/mysql.sock /tmp/mysql.sock
740 ln -s /usr/lib64/mysql/libmysqlclient.so.16.0.0 /usr/lib/libmysqlclient.so
643 tar -zxvf /mnt/hgfs/soft/php-5.3.28.tar.gz -C /usr/src
644 cd /usr/src/php-5.3.28/
645 yum -y install gd libxml2-devel libjpeg-devel libpng-devel
655 ./configure --prefix=/usr/local/php --with-config-file-path=/usr/local/php --with-zlib --with-gd --enable-mbstring --with-mysql=/usr/share/mysql/ --enable-fpm --with-jpeg-dir=/usr/lib
658 make
659 make install
668 cp sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm
668 chmod +x /etc/init.d/php-fpm
660 cp php.ini-development /usr/local/php/php.ini
661 cd /usr/local/php/etc/
661 cp php-fpm.conf.default php-fpm.conf
661 vim php-fpm.conf
pid = run/php-fpm.pid 取消注释
user = php
group = php
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
662 cd ..
663 vim php.ini
short_open_tag = On
default_charset = "utf-8"
664 useradd -M -u 40 -s /sbin/nologin php
667 ln -s /usr/local/php/bin/* /usr/local/bin/
668 ln -s /usr/local/php/sbin/* /usr/local/sbin/
669 vim /usr/local/nginx/conf/nginx.conf
index index.php index.html index.htm; location里增加index.php
将下边的PHP的location取消注释,并把fastcgi改为fastcgi.conf
669 cd /usr/local/nginx/html/
669 vim index.php
<?php
phpinfo();
?>
669 vim index1.php
<?php
$link=mysql_connect('localhost','root','123456');
if ($link) echo "connection is ok";
mysql_close();
?>
670 /etc/init.d/php-fpm start
671 nginx
672 firefox 127.0.0.1&
672 firefox 127.0.0.1/index1.php&
打模块 amqp:advanced message queuing protocol
695 tar -zxvf rabbitmq-c-0.7.1.tar.gz
696 cd rabbitmq-c-0.7.1
697 ./configure --prefix=/usr/local/rabbitmq-c
698 make
699 make install
700 cd
701 gunzip amqp-1.6.1.tgz
702 tar -xvf amqp-1.6.1.tar
703 cd amqp-1.6.1
704 yum -y install autoconf
704 phpize
705 ./configure --with-php-config=/usr/local/php/bin/php-config --with-librabbitmq-dir=/usr/local/rabbitmq-c/
706 make
707 make install
708 ls /usr/local/php/lib/php/extensions/no-debug-non-zts-20090626/
709 vim /usr/local/php/php.ini
710 /etc/init.d/php-fpm restart
711 firefox 127.0.0.1&
2.2 rabbit集群
主机1 2 3如下操作
[root@localhost ~]# yum -y localinstall erlang-solutions-1.0-1.noarch.rpm
[root@localhost ~]# yum -y localinstall erlang-18.1-1.el6.x86_64.rpm
[root@localhost ~]# yum -y localinstall socat-1.7.2.3-1.el6.x86_64.rpm
[root@localhost ~]# yum -y locallinstall rabbitmq-server-3.6.6-1.el6.noarch.rpm
[root@localhost ~]# yum -y localinstall rabbitmq-server-3.6.6-1.el6.noarch.rpm
[root@localhost ~]# chkconfig rabbitmq-server on
[root@localhost ~]# service rabbitmq-server start
[root@localhost ~]# vim /etc/hosts
添加内容:
192.168.1.17 rabbitmq1
192.168.1.19 rabbitmq2
192.168.1.22 rabbitmq3
ping其他两台主机的主机名 确保可以ping通
主机1
[root@localhost ~]# cat /var/lib/rabbitmq/.erlang.cookie
FIIUZZNUWRTXICRSMVDG[root@localhost ~]#
主机2 3
[root@localhost ~]#echo "FIIUZZNUWRTXICRSMVDG" > /var/lib/rabbitmq/.erlang.cookie
按按钮,重启 三台主机都重启 重启之后hostname变成rabbitmq* 再往下操作
三台主机启动rabbitmq-server
主机1
[root@rabbitmq1 ~]# rabbitmqctl stop_app
Stopping node rabbit@rabbitmq1 ...
[root@rabbitmq1 ~]# rabbitmqctl reset
Resetting node rabbit@rabbitmq1 ...
[root@rabbitmq1 ~]# rabbitmqctl start_app
Starting node rabbit@rabbitmq1 ...
主机2 3 操作相同
[root@rabbitmq2 ~]# rabbitmqctl stop_app
Stopping node rabbit@rabbitmq2 ...
[root@rabbitmq2 ~]# rabbitmqctl reset
Resetting node rabbit@rabbitmq2 ...
[root@rabbitmq2 ~]# rabbitmqctl join_cluster --ram rabbit@rabbitmq1
Clustering node rabbit@rabbitmq2 with rabbit@rabbitmq1 ...
[root@rabbitmq2 ~]# rabbitmqctl start_app
Starting node rabbit@rabbitmq2 ...
主机1
[root@rabbitmq1 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbitmq1 ...
[{nodes,[{disc,[rabbit@rabbitmq1]},{ram,[rabbit@rabbitmq3,rabbit@rabbitmq2]}]},
{running_nodes,[rabbit@rabbitmq3,rabbit@rabbitmq2,rabbit@rabbitmq1]},
{cluster_name,<<"rabbit@rabbitmq1">>},
{partitions,[]},
{alarms,[{rabbit@rabbitmq3,[nodedown]},
{rabbit@rabbitmq2,[]},
{rabbit@rabbitmq1,[]}]}]
[root@rabbitmq1 ~]# rabbitmqctl add_user admin redhat
Creating user "admin" ...
[root@rabbitmq1 ~]# rabbitmqctl set_user_tags admin administrator
Setting tags for user "admin" to [administrator] ...
主机 1 2 3
[root@rabbitmq1 ~]# rabbitmq-plugins enable rabbitmq_management
主机1
为rabbitmq添加一个admin用户,密码是redhat,设置用户角色为administrator,Tag可以为 administrator,monitoring, management
692 rabbitmqctl add_user admin redhat
693 rabbitmqctl set_user_tags admin administrator
[root@rabbitmq1 ~]# firefox 127.0.0.1:15672& rabbitmq管理端口
先建立一个vhost
设置一下vhost的权限
建立policy:
创建列队:
创建消息:
查看列队中有几个消息: