本文共 15681 字,大约阅读时间需要 52 分钟。
初识rabbitmq以及我们线上业务环境的mq服务方式:
交换器的4种类型:
direct 根据路由键投递消息fanout 广播方式,绑定到同一个exchange上的queue都能收到同样的msg。不需要路由键,如果接受到消息的Exchange没有与任何Queue绑定,则消息会被抛弃topic 根据queue定义的topic名称来接收相应的msgheader (很少用,直接忽略它)运维 09:18:31
faout就是广播,我们现在使用的就是faout运维 09:19:03faout没有routing key绑定确实简单运维 09:19:37但是我们的业务的调用连是一条接一条的为啥不用topic,运维 09:20:07这样srm队列获取wbms的队列消息不是更快么架构师 09:20:58架构师 09:21:16快不是我们的系统需要关注的架构师 09:23:04我们的系统每秒500的消息量顶天了,不要拿来跟互联网公司高峰期每秒几百万的量做对比,业务完全不同,没必要参考他们的做法架构师 09:24:13再说了如果当初把系统的高性能需求摆在第一位也不可能选型rabbitmq的架构师 09:26:11架构师 09:26:43要多分析业务而不是技术我们线上的消息很少,一秒也就几票数据,二十票每秒都算高的
我们线上业务的mq的queue之间,没先后顺序,相互间都有互传数据,数据库相互都独立的,为了冗余数据必定要做一些回传目前使用的是faout,一个功能一个echange,通常Echange 与queue的名字相同rabbitmq的事务机制和确认机制
消息确认机制:
RabbitMQ提供了transaction、confirm两种消息确认机制。transaction即事务机制,手动提交和回滚;confirm机制提供了Confirmlistener和waitForConfirms两种方式。confirm机制效率明显会高于transaction机制,但transaction的优势在于强一致性。如果没有特别的要求,建议使用conrim机制。Confirmlistener从代码或者抓包可以看待我们线上业务使用的是confirm
事务机制适用的场景极少的,要么涉及钱,要么有多机房的情况,或者网络质量很差才考虑事务确认1、从实验来看,消息的确认机制只是确认publisher发送消息到broker,由broker进行应答,不能确认消息是否有效消费。
2、而为了确认消息是否被发送给queue,应该在发送消息中启用参数mandatory=true,使用ReturnListener接收未被发送成功的消息。3、接下来就需要确认消息是否被有效消费。publisher端目前并没有提供监听事件,但提供了应答机制来保证消息被成功消费,应答方式:basicAck:成功消费,消息从队列中删除
basicNack:requeue=true,消息重新进入队列,false被删除
basicReject:等同于basicNack
basicRecover:消息重入队列,requeue=true,发送给新的consumer,false发送给相同的consumer
发送方确认机制:
客户端发送请求(消息)时,在消息的属性(Message Properties,在AMQP协议中定义了14种properties,这些属性会随着消息一起发送)中设置两个值replyTo(一个Queue名称,用于告诉服务器处理完成后将通知我的消息发送到这个Queue中)和correlationId(此次请求的标识号,服务器处理完成后需要将此属性返还,客户端将根据这个id了解哪条请求被成功执行了或执行失败)。服务器端收到消息处理完后,将生成一条应答消息到replyTo指定的Queue,同时带上correlationId属性。客户端之前已订阅replyTo指定的Queue,从中收到服务器的应答消息后,根据其中的correlationId属性分析哪条请求被执行了,根据执行结果进行后续业务处理。erlang节点:
erlang类似JVM,erlang节点能自动尝试启动所在节点的应用程序。一、安装erlang、socat、mq
软件包地址:安装erlang所需的依赖包
yum -y install make gcc gcc-c++ kernel-devel m4 ncurses-devel openssl-devel安装erlang的rpm包
rpm -ivh erlang-18.1-1.el7.centos.x86_64.rpm安装rabbit-mqserver的rpm包
[root@i-ds3e3eg6 ~]# rpm -ivh rabbitmq-server-3.6.10-1.el6.noarch.rpm warning: rabbitmq-server-3.6.10-1.el6.noarch.rpm: Header V4 RSA/SHA512 Signature, key ID 6026dfca: NOKEYerror: Failed dependencies:socat is needed by rabbitmq-server-3.6.10-1.el6.noarch处理报错
yum -y install socat 或者 yum install rabbitmq-server-3.6.10-1.el6.noarch.rpm[root@i-idzmbvhr ~]# rpm -ivh rabbitmq-server-3.6.10-1.el6.noarch.rpmwarning: rabbitmq-server-3.6.10-1.el6.noarch.rpm: Header V4 RSA/SHA512 Signature, key ID 6026dfca: NOKEYPreparing... ################################# [100%]Updating / installing...1:rabbitmq-server-3.6.10-1.el6 ################################# [100%]验证erlang是否安装成功:
root@i-ds3e3eg6 ~]# erlErlang/OTP 18 [erts-7.1] [source] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]Eshell V7.1 (abort with ^G)
1> quit1> BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded(v)ersion (k)ill (D)b-tables (d)istribution重复安装rpm
[root@prod-wuliu-rabbitmq-42 ~]# rpm -qa | grep rabbitmq-serverrabbitmq-server-3.6.10-1.el6.noarch[root@prod-wuliu-rabbitmq-42 ~]# rpm -e rabbitmq-server-3.6.10-1.el6.noarchStopping rabbitmq-server (via systemctl): [ OK ][root@prod-wuliu-rabbitmq-42 ~]#二、修改host配置
cat /etc/hosts172.16.42.13 prod-wuliu-rabbitmq-42-13172.16.42.14 prod-wuliu-rabbitmq-42-14三、设置 Erlang Cookie
Erlang Cookie 文件:/var/lib/rabbitmq/.erlang.cookie。这里将 node1 的该文件复制到 node2、node3,由于这个文件权限是 400,所以需要先修改 node2、node3 中的该文件权限为 777:然后将 node1 中的该文件拷贝到 node2、node3,最后将权限和所属用户/组修改回来:
四、使用 -detached 参数运行各节点
启动方式/ect/init.d/rabbit-server start rabbitmq-server start &rabbitmq-server -detached 推荐使用定制rabbitmq的启动方式https://www.cnblogs.com/ylsforever/p/6600925.html启动rabbitmq启动:
查看服务端口是否正常启动:
[root@i-ds3e3eg6 ~]# lsof -i:5672COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEbeam.smp 20425 rabbitmq 53u IPv6 38571 0t0 TCP *:amqp (LISTEN)[root@i-ds3e3eg6 ~]#5673和5674分别为rabbitmq-node1和rabbitmq-node2的client连接端口;
15673和15674分别为rabbitmq-node1和rabbitmq-node2后台监控系统访问端口;五、创建集群:
启动节点BABBITMQ_NODE_PORT=5672 RABBITMQ_NODENAME=rabbit rabbitmq-server -detached(默认端口:5672,默认节点名称:rabbit)停止RabbitMQ应用程序:rabbitmqctl -n rabbit_1@hostname stop_app清空元数据,重置节点状态:rabbitmqctl -n rabbit_1@hostname reset加入到第一个集群节点:rabbitmqctl -n rabbit_1@hostname cluster rabbit@hostname rabbit_1@hostname ,-n参数:在指定节点上执行命令而非默认节点;cluster后面的参数:指定集群中的磁盘节点。启动RabbitMQ应用程序:rabbitmqctl -n rabbit_1@hostname start_app查看集群:rabbitmqctl cluster_status将prod-wuliu-rabbitmq-42-13 和 prod-wuliu-rabbitmq-42-14两个节点组成集群:
rabbit1为主节点,另外两个为从节点搭建,主节点不用动,只在两个从节点运行如下命令,我这里只举一个节点(rabbit2)的例子,rabbit3执行相同的命令[root@rabbit2 rabbitmq]# rabbitmqctl stop_appStopping rabbit application on node rabbit@rabbit2 ...[root@rabbit2 rabbitmq]# rabbitmqctl resetResetting node rabbit@rabbit2 ...[root@rabbit2 rabbitmq]# rabbitmqctl join_cluster rabbit@prod-wuliu-rabbitmq-42-13Clustering node rabbit@rabbit2 with rabbit@rabbit1 ...[root@rabbit2 rabbitmq]# rabbitmqctl start_appStarting node rabbit@rabbit2 ...此时 13 与 14也会自动建立连接;
如果要使用内存节点,则可以使用
node2 # rabbitmqctl join_cluster --ram rabbit@node1 加入集群。集群配置好后,可以在 RabbitMQ 任意节点上执行 rabbitmqctl cluster_status 来查看是否集群配置成功。设置内存节点
rabbitmq要求集群中至少一个磁盘节点【为了提高性能,不需要全部节点都是disc的节点】,所以我们可以启动部分节点为RAM模式当节点加入或者离开集群时,他们必须通知到至少一个磁盘节点。如果集群内就1个磁盘节点,其余都是内存节点。如果这个唯一的一个磁盘节点宕机了,那么集群还是可以路由消息的。但是这个时候不支持如下操作:
创建队列、创建交换器、创建绑定、添加用户、更改权限、添加或删除集群节点其中–ram指的是作为内存节点,要是想做为磁盘节点的话,就不用加–ram这个参数了加入内存节点集群node2 # rabbitmqctl join_cluster --ram rabbit@node1只要在节点列表里包含了本身,它就成为一个磁盘节点。在RabbitMQ集群里,必须至少有一个磁盘节点存在。更改节点属性
node2 $ rabbitmqctl stop_app # 停止rabbitmq服务node2 $ rabbitmqctl change_cluster_node_type ram # 更改节点为内存节点Turning rabbit@node2 into a ram nodenode2 $ rabbitmqctl change_cluster_node_type disc # 更改节点为磁盘节点Turning rabbit@node2 into a disc nodenode2 $ rabbitmqctl start_app # 开启rabbitmq服务查看单个mq的服务状态:
oot@prod-wuliu-rabbitmq-42-14 ~]# rabbitmqctl status 或者rabbitmqctl node_health_check[root@prod-wuliu-rabbitmq-42-13 ~]# rabbitmqctl node_health_checkTimeout: 70.0 secondsChecking health of node 'rabbit@prod-wuliu-rabbitmq-42-13'Health check passed查看集群的服务状态:
[root@prod-wuliu-rabbitmq-42-13 ~]# rabbitmqctl cluster_statusCluster status of node 'rabbit@prod-wuliu-rabbitmq-42-13' #第一行是集群中的节点成员,disc表示这些都是磁盘节点查看mq的默认账户:
[root@prod-rabbitmq-42 ~]# rabbitmqctl list_usersListing usersguest [administrator]启用管理插件:
默认端口 15672##默认账号/密码 guest/guest 不支持远程IP访问,只支持localhost访问##创建账号test;密码123456#./rabbitmqctl add_user test 123456##设置管理员权限#./rabbitmqctl set_user_tags test administrator##支持远程IP访问#./rabbitmqctl set_permissions -p "/" test "." "." "."rabbitmqctl set_permissions -p VHostPath User ConfP WriteP ReadP[root@prod-wuliu-rabbitmq-42-13 ~]# rabbitmqctl set_permissions -p "/" admin "." "." "."Setting permissions for user "admin" in vhost "/"[root@prod-rabbitmq-42 ~]# rabbitmq-plugins enable rabbitmq_management
The following plugins have been enabled:amqp_clientcowlibcowboyrabbitmq_web_dispatchrabbitmq_management_agentrabbitmq_managementApplying plugin configuration to rabbit@prod-rabbitmq-42... started 6 plugins.
[root@prod-rabbitmq-42 ~]# lsof -i:15672
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEbeam.smp 5639 rabbitmq 54u IPv4 20106 0t0 TCP *:15672 (LISTEN)[root@prod-rabbitmq-42 ~]#可以通过远程访问:
上面配置RabbitMQ默认集群模式,但并不保证队列的高可用性,尽管交换机、绑定这些可以复制到集群里的任何一个节点,
但是队列内容不会复制,虽然该模式解决一部分节点压力,但队列节点宕机直接导致该队列无法使用,只能等待重启,所以要想在队列节点宕机或故障也能正常使用,就要复制队列内容到集群里的每个节点,需要创建镜像队列六、设置镜像队列策略
镜像队列
RabbitMQ 的 Cluster 集群模式一般分为两种,普通模式和镜像模式。普通模式:默认的集群模式,以两个节点(rabbit01、rabbit02)为例来进行说明。对于 Queue 来说,消息实体只存在于其中一个节点 rabbit01(或者 rabbit02),rabbit01 和 rabbit02 两个节点仅有相同的元数据,即队列的结构。当消息进入 rabbit01 节点的 Queue 后,consumer 从 rabbit02 节点消费时,RabbitMQ 会临时在 rabbit01、rabbit02 间进行消息传输,把 A 中的消息实体取出并经过 B 发送给 consumer。所以 consumer 应尽量连接每一个节点,从中取消息。即对于同一个逻辑队列,要在多个节点建立物理 Queue。否则无论 consumer 连 rabbit01 或 rabbit02,出口总在 rabbit01,会产生瓶颈。当 rabbit01 节点故障后,rabbit02 节点无法取到 rabbit01 节点中还未消费的消息实体。如果做了消息持久化,那么得等 rabbit01 节点恢复,然后才可被消费;如果没有持久化的话,就会产生消息丢失的现象。
镜像模式:将需要消费的队列变为镜像队列,存在于多个节点,这样就可以实现 RabbitMQ 的 HA 高可用性。作用就是消息实体会主动在镜像节点之间实现同步,而不是像普通模式那样,在 consumer 消费数据时临时读取。缺点就是,集群内部的同步通讯会占用大量的网络带宽。镜像队列实现了 RabbitMQ 的高可用性(HA),具体的实现策略如下所示:ha-mode ha-params 功能
all 空 镜像队列将会在整个集群中复制。当一个新的节点加入后,也会在这 个节点上复制一份。exactly count 镜像队列将会在集群上复制 count 份。如果集群数量少于 count 时候,队列会复制到所有节点上。如果大于 Count 集群,有一个节点 crash 后,新进入节点也不会做新的镜像。nodes node name 镜像队列会在 node name 中复制。如果这个名称不是集群中的一个,这不会触发错误。如果在这个 node list 中没有一个节点在线,那么这个 queue 会被声明在 client 连接的节点。镜像队列概念
镜像队列可以同步queue和message,当主queue挂掉,从queue中会有一个变为主queue来接替工作。镜像队列是基于普通的集群模式的,所以你还是得先配置普通集群,然后才能设置镜像队列。镜像队列设置后,会分一个主节点和多个从节点,如果主节点宕机,从节点会有一个选为主节点,原先的主节点起来后会变为从节点。queue和message虽然会存在所有镜像队列中,但客户端读取时不论物理面连接的主节点还是从节点,都是从主节点读取数据,然后主节点再将queue和message的状态同步给从节点,因此多个客户端连接不同的镜像队列不会产生同一message被多次接受的情况。设置镜像队列策略
在普通集群的中任意节点启用策略,策略会自动同步到集群节点命令格式set_policy [-p vhostpath] {name} {pattern} {definition} [priority]在任意一个节点上执行[root@node1 ~]# rabbitmqctl set_policy -p / ha-allqueue "^message" '{"ha-mode":"all"}'Setting policy "ha-allqueue" for pattern "^message" to "{\"ha-mode\":\"all\"}" with priority "0"注意:"^message" 这个规则要根据自己修改,这个是指同步"message"开头的队列名称,配置时使用的应用于所有队列,所以表达式为"^"集群重启
集群重启时,最后一个挂掉的节点应该第一个重启,如果因特殊原因(比如同时断电),而不知道哪个节点最后一个挂掉。可用以下方法重启:先在一个节点上执行$ rabbitmqctl force_boot$ service rabbitmq-server start在其他节点上执行$ service rabbitmq-server start查看cluster状态是否正常(要在所有节点上查询)。$ rabbitmqctl cluster_status镜像队列节点宕机的情况:
如果镜像队列丢失了一个从节点,则对任何消费者都不会有影响。主节点宕机,集群内部会重新选主。消费者需要重新附加到主队列。配置镜像队列:
在任意一个节点上执行:rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}' -p /这个命令会将/ 这个vhost的所有队列设置为镜像队列,即队列会被复制到各个节点,各个节点状态保持一致。rabbitmqctl add_vhost vh4
rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}' -p vh4这个命令会将vh4 这个vhost的所有队列设置为镜像队列,即队列会被复制到各个节点,各个节点状态保持一致。至此,RabbitMQ 高可用集群就已经搭建好了,最后一个步骤就是搭建均衡器虚拟主机vhost:
每个vhost相当于一个mini的rabbitmq服务器,有独立的权限控制机制。不同的vhost可以存在同名的交换器和队列名。在rabbitmq中,权限控制是以vhost为单位的。rabbitmqctl [add_vhost|delete_vhost] vhost1 即可添加/删除一个名为vhost1的虚拟主机设置vhost,和user,这里设计的是一个项目一个vhost,一个项目用户
添加项目用户后,把项目用户的vhost授权给管理员[root@prod-wuliu-rabbitmq-42-13 ~]# rabbitmqctl set_permissions -p wuliu_vhost_qianlima admin "." "." "."Setting permissions for user "admin" in vhost "wuliu_vhost_qianlima"[root@prod-wuliu-rabbitmq-42-13 ~]# rabbitmqctl set_permissions -p wuliu_vhost_transport admin "." "." "."Setting permissions for user "admin" in vhost "wuliu_vhost_transport"给vhost设置policy
[root@prod-wuliu-rabbitmq-42-13 ~]# rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}' -p wuliu_vhost_qianlimaSetting policy "ha-all" for pattern "^" to "{\"ha-mode\":\"all\"}" with priority "0"[root@prod-wuliu-rabbitmq-42-13 ~]# rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}' -p wuliu_vhost_transportSetting policy "ha-all" for pattern "^" to "{\"ha-mode\":\"all\"}" with priority "0"[root@prod-wuliu-rabbitmq-42-13 ~]#创建virtual host 虚拟主机
查看vhosts:rabbitmqctl list_vhosts创建vhost:rabbitmqctl add_vhost [vhost_name]删除vhost:rabbitmqctl delete_vhost [vhost_name]列出Rabbit服务器上的vhost:rabbitmqctl list_vhosts查看队列bbitmqctl list_queues
查看exchange rabbitmqctl list_exchanges查看bangding rabbitmqctl list_bindingsvhost
rabbitmqctl set_policy ha-all "^(?!amq.).*" '{"ha-sync-mode":"automatic"}' -p wuliu_vhost_qianlima清理错误的policy
vhost:wuliu_vhost_qianlima name:root@prod-wuliu-rabbitmq-42-13 ~]# rabbitmqctl clear_policy -p wuliu_vhost_qianlima wuliu_vhost_qianlimaClearing policy "wuliu_vhost_qianlima"我们通过 rabbitmqctl add_vhost命令新建一个virtual host : rabbitmqctl add_vhost test
我们通过 rabbitmqctl list_vhosts命令看看现在系统有几个vhost了。可以看到有两个,一个是系统默认的 '/', 还有一个就是我们新建的 test_host。 但是到这里是不够的,我们只是声明了一个vhost,我们还要给它分配访问权限。rabbitmqctl set_permissions -p test_host test "test-""." ".*",如此用户名为test的用户就可以访问vitrual host为test_host的资源了,并且具备读写的权限。// 使用户user1具有vhost1这个virtual host中所有资源的配置、写、读权限以便管理其中的资源
rabbitmqctl set_permissions -p vhost1 user1 '.' '.' '.*'// 查看权限
rabbitmqctl list_user_permissions user1rabbitmqctl list_permissions -p vhost1// 清除权限rabbitmqctl clear_permissions [-p VHostPath] UserRabbitMQ用户角色及权限控制
官方文档:add_user <username> <password>
delete_user <username>
change_password <username> <newpassword>
clear_password <username>
set_user_tags <username> <tag> ...
list_users
add_vhost <vhostpath>
delete_vhost <vhostpath>
list_vhosts [<vhostinfoitem> ...]
set_permissions [-p <vhostpath>] <user> <conf> <write> <read>
clear_permissions [-p <vhostpath>] <username>
list_permissions [-p <vhostpath>]
list_user_permissions <username>
set_parameter [-p <vhostpath>] <component_name> <name> <value>
clear_parameter [-p <vhostpath>] <component_name> <key>list_parameters [-p <vhostpath>]add_user <username> <password>
delete_user <username>
change_password <username> <newpassword>
clear_password <username>
set_user_tags <username> <tag> ...
list_users
add_vhost <vhostpath>
delete_vhost <vhostpath>
list_vhosts [<vhostinfoitem> ...]
set_permissions [-p <vhostpath>] <user> <conf> <write> <read>
clear_permissions [-p <vhostpath>] <username>
list_permissions [-p <vhostpath>]
list_user_permissions <username>
set_parameter [-p <vhostpath>] <component_name> <name> <value>
clear_parameter [-p <vhostpath>] <component_name> <key>list_parameters [-p <vhostpath>]RabbitMQ的用户角色分类:
none、management、policymaker、monitoring、administratorRabbitMQ各类角色描述:
none不能访问 management pluginmanagement
用户可以通过AMQP做的任何事外加:列出自己可以通过AMQP登入的virtual hosts 查看自己的virtual hosts中的queues, exchanges 和 bindings查看和关闭自己的channels 和 connections查看有关自己的virtual hosts的“全局”的统计信息,包含其他用户在这些virtual hosts中的活动。policymaker
management可以做的任何事外加:查看、创建和删除自己的virtual hosts所属的policies和parametersmonitoring
management可以做的任何事外加:列出所有virtual hosts,包括他们不能登录的virtual hosts查看其他用户的connections和channels查看节点级别的数据如clustering和memory使用情况查看真正的关于所有virtual hosts的全局的统计信息administrator
policymaker和monitoring可以做的任何事外加:创建和删除virtual hosts查看、创建和删除users查看创建和删除permissions关闭其他用户的connections创建用户并设置角色:
可以创建管理员用户,负责整个MQ的运维,例如:$sudo rabbitmqctl add_user dmin Aa@adm赋予其administrator角色:$sudo rabbitmqctl set_user_tags dmin administrator可以创建RabbitMQ监控用户,负责整个MQ的监控,例如:
$sudo rabbitmqctl add_user monitoring Aa@mon赋予其monitoring角色:$sudo rabbitmqctl set_user_tags monitoring monitoring可以创建某个项目的专用用户,只能访问项目自己的virtual hosts
$sudo rabbitmqctl add_user transport Aa@tra赋予其monitoring角色:$sudo rabbitmqctl set_user_tags transpor transport可以创建某个项目的专用用户,只能访问项目自己的virtual hosts
$sudo rabbitmqctl add_user qianlima Aa@qia赋予其monitoring角色:$sudo rabbitmqctl set_user_tags transpor transport创建和赋角色完成后查看并确认:
$sudo rabbitmqctl list_users(1) 设置用户权限
rabbitmqctl set_permissions -p VHostPath User ConfP WriteP ReadP(2) 查看(指定hostpath)所有用户的权限信息
rabbitmqctl list_permissions [-p VHostPath](3) 查看指定用户的权限信息
rabbitmqctl list_user_permissions User(4) 清除用户的权限信息
rabbitmqctl clear_permissions [-p VHostPath] Userrabbitmq理解:
镜像策略---没有看懂 rabbitmq winfromrabbitmq的几种安装方式:
rabbitmq配置文件相关集群高可用
rabbimq用户配置管理:
镜像队列
rabbitmq控制资源消耗
语言理解四种类型
开发角度理解中类型:经典的图介绍四种类型为啥要用mq如何创建queue和echange
定制rabbitmq的启动方式:
UserParameter=java-num.count, ps -ef | grep java| grep -v grep |wc -l
UserParameter=wbms.process[*],ps -ef|grep java|grep -e '$1'|grep -v grep|wc -l生产消费验证:
转载于:https://blog.51cto.com/firephoenix/2144760