写点什么

记一次差点跑路的 RabbitMQ 运维经历

用户头像
看山
关注
发布于: 2021 年 06 月 11 日
记一次差点跑路的 RabbitMQ 运维经历

你好,我是看山。


这是一次比较苦逼的运维,完全不熟悉的系统、不清楚环境、不清楚配置,两眼一抹黑。为啥?就是因为原来的负责人撤了、交接人休假、再次交接人也休假,再再次交接人只有一份不全的文档。而我是再、再、再次交接人,连文档也没有。更要命的是,这是生产环境,大家都懂得,生产环境就是不能出问题,自封一个“奉命于危难之间”吧。


抱怨了一整段了,还是简单的说下这次运维吧,运维的是 RabbitMQ 集群,3 个节点 A、B、C,每个节点上启动了 2 个实例 a1/a2、b1/b2、c1/c2,其中 a1、b1、c1 组成一套集群环境 rabbit cluster1,a1 是磁盘节点;a2、b2、c2 组成一套集群环境 rabbit cluster2,c2 是磁盘节点。


就是因为完全不熟悉 RabbitMQ 集群,所以基本上趟了一堆的坑,碰到了一堆不应该出现的错误,也算是新手村长经验了。按照套路,这里先说说正确的启动方式,然后再说说碰到的异常。

1. 正确启动

1.1 启动各个节点

因为找不到自己启动的历史了,就是摘取 官网 的部分内容放在这里。有 3 个服务器节点,hostname 分别是:rabbit1、rabbit2、rabbit3。


分别在 3 个节点上启动 Rabbit MQ:


rabbit1$ rabbitmq-server -detached
rabbit2$ rabbitmq-server -detached
rabbit3$ rabbitmq-server -detached
复制代码


通过命令rabbitmq-server -detached就可以启动 rabbit 服务。


然后在每个节点上查看集群状态:


rabbit1$ rabbitmqctl cluster_statusCluster status of node rabbit@rabbit1 ...[{nodes,[{disc,[rabbit@rabbit1]}]},{running_nodes,[rabbit@rabbit1]}]...done.
rabbit2$ rabbitmqctl cluster_statusCluster status of node rabbit@rabbit2 ...[{nodes,[{disc,[rabbit@rabbit2]}]},{running_nodes,[rabbit@rabbit2]}]...done.
rabbit3$ rabbitmqctl cluster_statusCluster status of node rabbit@rabbit3 ...[{nodes,[{disc,[rabbit@rabbit3]}]},{running_nodes,[rabbit@rabbit3]}]...done.
复制代码


RabbitMQ 服务节点的名字是 rabbit@shorthostname,所以上面 3 个节点分别是 rabbit@rabbit1、rabbit@rabbit2、rabbit@rabbit3。需要注意的是使用rabbitmq-server基本执行的名字都是小写的,如果是在 Windows 中使用rabbitmq-server.bat,那节点名字就是大写的了,比如 rabbit@RABBIT1。

1.2 创建集群

这里把 rabbit@rabbit2 和 rabbit@rabbit3 加入 rabbit@rabbit1 中,也就是说 rabbit@rabbit1 是磁盘节点,其他两个都是内存节点。


先把 rabbit@rabbit2 加入到 rabbit@rabbit1 中:


rabbit2$ rabbitmqctl stop_appStopping node rabbit@rabbit2 ...done.
rabbit2$ rabbitmqctl join_cluster rabbit@rabbit1Clustering node rabbit@rabbit2 with [rabbit@rabbit1] ...done.
rabbit2$ rabbitmqctl start_appStarting node rabbit@rabbit2 ...done.
复制代码


如果没有报错,rabbit@rabbit2 就已经加入到 rabbit@rabbit1 中了,可以使用命令rabbitmqctl cluster_status查看集群状态:


rabbit1$ rabbitmqctl cluster_statusCluster status of node rabbit@rabbit1 ...[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]}]}, {running_nodes,[rabbit@rabbit2,rabbit@rabbit1]}]...done.
rabbit2$ rabbitmqctl cluster_statusCluster status of node rabbit@rabbit2 ...[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]}]}, {running_nodes,[rabbit@rabbit1,rabbit@rabbit2]}]...done.
复制代码


通过join_cluster --ram可以指定节点以内存节点的形式加入集群。然后在 rabbit@rabbit3 上执行相同的操作即可,这里不再赘述。

1.3 拆分集群

拆分集群实际上就是在想要从集群中删除的节点上执行reset即可,他会通知集群中所有的节点不要再理这个节点了。


rabbit3$ rabbitmqctl stop_appStopping node rabbit@rabbit3 ...done.
rabbit3$ rabbitmqctl resetResetting node rabbit@rabbit3 ...done.
rabbit3$ rabbitmqctl start_appStarting node rabbit@rabbit3 ...done.
复制代码


在各个节点上查看集群状态:


rabbit1$ rabbitmqctl cluster_statusCluster status of node rabbit@rabbit1 ...[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]}]}, {running_nodes,[rabbit@rabbit2,rabbit@rabbit1]}]...done.
rabbit2$ rabbitmqctl cluster_statusCluster status of node rabbit@rabbit2 ...[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]}]}, {running_nodes,[rabbit@rabbit1,rabbit@rabbit2]}]...done.
rabbit3$ rabbitmqctl cluster_statusCluster status of node rabbit@rabbit3 ...[{nodes,[{disc,[rabbit@rabbit3]}]},{running_nodes,[rabbit@rabbit3]}]...done.
复制代码


还可以在某节点上删除别的节点,可以使用forget_cluster_node来进行,这里不进行赘述,后面的一种异常中会用到这个命令。

2. 几个异常

2.1 一台机器上启动多个实例

RabbitMQ 允许在一台机器上启动多个实例,自己在这次运维中占用时间最长的就是不知道这 3 个节点上部署了两套集群,通过ps -ef|grep rabbit命令看到有两个实例,就天真的以为是有一个没有成功关闭,所以直接把两个都kill了。所以这里记录一下如果在一台机器上启动多个实例。


$ RABBITMQ_NODE_PORT=5673 RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15673}]" RABBITMQ_NODENAME=hare rabbitmq-server -detached$ rabbitmqctl -n hare stop_app$ rabbitmqctl -n hare join_cluster rabbit@rabbit1$ rabbitmqctl -n hare start_app
复制代码


执行命令需要使用-n来指定执行命令的实例,这个是需要记住的。

2.2 Bad cookie in table definition rabbit_durable_queue

这个已经找不到错误的具体描述了,就从 Google 上找了一条,基本类似。


rabbitmqctl cluster rabbit@vmrabbitaClustering node rabbit@vmrabbitb with [rabbit@vmrabbita] ...Error: {unable_to_join_cluster,          [rabbit@vmrabbita],          {merge_schema_failed,              "Bad cookie in table definition rabbit_durable_queue: rabbit@vmrabbitb = {cstruct,rabbit_durable_queue,set,[],[rabbit@vmrabbitb],[],0,read_write,[],[],false,amqqueue,[name,durable,auto_delete,arguments,pid],[],[],{{1266,16863,365586},rabbit@vmrabbitb},{{2,0},[]}}, rabbit@vmrabbita = {cstruct,rabbit_durable_queue,set,[],[rabbit@vmrabbitc,rabbit@vmrabbita],[],0,read_write,[],[],false,amqqueue,[name,durable,auto_delete,arguments,pid],[],[],{{1266,14484,94839},rabbit@vmrabbita},{{4,0},{rabbit@vmrabbitc,{1266,16151,144423}}}}\n"}}
复制代码


主要的就是Bad cookie in table definition rabbit_durable_queue这句,这是因为节点之间是通过“the Erlang Cookie”彼此识别的,存储在 $HOME/.erlang.cookie 中。如果因为某种原因,集群中几个节点服务器上的 cookie 不一致,就会不能够彼此识别,出现这样那样的错误。更多的是上面的这个"Bad cookie。",还会有"Connection attempt from disallowed node"、 "Could not auto-cluster"。

2.3 already_member

这个问题就是比较 2 的一个问题了,自己给自己挖的坑,只能自己填了。集群几个节点之间不能通信,然后我就把一个内存节点的var/lib/rabbitmq/mnesia中的文件夹删了,然后又执行了reset,当执行join_cluster命令的时候,就会报出错误:


Error: {ok,already_member}
复制代码


分析一下可以明白,当前节点上没有待加入集群的信息,但是待加入集群中已经有了该节点的信息,但是发现两个信息不一致。所以当当前节点期望加入到集群的时候,出于安全考虑,集群就说你小子已经是集群里的一员了,不要再加了。扒出日志来看:


=INFO REPORT==== 25-Jul-2016::20:11:10 ===Error description:   {could_not_start,rabbitmq_management,       {{shutdown,            {failed_to_start_child,rabbit_mgmt_sup,                {'EXIT',                    {{shutdown,                         [{{already_started,<23251.1658.0>},                           {child,undefined,rabbit_mgmt_db,                               {rabbit_mgmt_db,start_link,[]},                               permanent,4294967295,worker,                               [rabbit_mgmt_db]}}]},                     {gen_server2,call,                         [<0.618.0>,{init,<0.616.0>},infinity]}}}}},        {rabbit_mgmt_app,start,[normal,[]]}}}
Log files (may contain more information): ./../var/log/rabbitmq/hare.log ./../var/log/rabbitmq/hare-sasl.log
复制代码


既然集群中已经有个该节点信息,所以不要该节点重复加入。那就把集群里该节点信息删了,再加入集群,不就应该类似与一个全新的节点加入集群一样吗?


rabbitmqctl -n hare forget_cluster_node hare@rabbit1
复制代码


这样,集群中就没有 hare@rabbit1 的信息了,之后就重新执行join_cluster命令即可。

2.4 千万不要在磁盘节点上删除 var/lib/rabbitmq/mnesia 中的文件

这个文件夹中的内容是磁盘节点用于记录集群信息的文件,一旦删除,会出现各种各样的异常。


  1. 如果是磁盘节点,集群中配置的 Exchanges、Queues、User 等信息全都丢失

  2. 如果是内存节点,连接集群的信息丢失,重新加入集群是会失败


因为是两套集群,这两个问题我都碰到了。生产环境啊,可以想象当我正在为集群正常启动后得意的时候,突然发现所有的 Exchanges、Queues 信息全都没了的时候的心情吗?幸亏还有一套预生产环境,直接把预生产环境的内容导出,然后在生产环境导入。


唉,有种劫后余生的感动。


你好,我是看山,公众号:看山的小屋,10 年老猿,开源贡献者。游于码界,戏享人生。关注我,领取资料。

发布于: 2021 年 06 月 11 日阅读数: 16
用户头像

看山

关注

公众号「看山的小屋」 2017.10.26 加入

游于码界,戏享人生。 未来不迎,当时不杂,既过不恋。

评论

发布
暂无评论
记一次差点跑路的 RabbitMQ 运维经历