您的位置:  首页 > 技术杂谈 > 正文

【原创】RabbitMQ 之殇:聊聊 tracing 问题

2021-11-22 14:00 https://my.oschina.net/moooofly/blog/5313392 摩云飞 次阅读 条评论

背景

  • 在当前架构的设计中,会基于 RabbitMQ 的 tracing 功能抓取经过 MQ 的消息,即使明确知道存在严重的性能问题(这个事情一直是我最为不满的槽点)
  • 组内基于 shell 脚本实现 tracing 功能的使能和配置,但其中的处理逻辑让人看完就有一种“一定会存在问题”的预感,而这么实现的理由似乎是觉得其他方式更麻烦

当前脚本实现

start.sh

  • 能够看到该脚本的最重要的功能是启动 RabbitMQ server
  • 同时又看到,脚本中采用“后台运行”方式调用了 create_trace.sh 脚本

分析:

  • 启动 rabbitmq 和创建 trace 明显是存在先后关系的
  • 将创建 trace 放在用于启动 rabbitmq 的脚本中,并不合适

create_trace.sh

  • 通过 sleep 30 延时来确保大部分情况下当前脚本会在 rabbitmq 启动后才被执行
  • 通过 for 循环 + sleep 3 延时,确保 tracing 功能的启用,以及 trace 规则的建立

分析:

  • 直观上看,这种实现是丑陋的
  • 细节上,实现中的做法均属于“粗放式”策略,只能治标,不能治本;例如,假设 rabbitmq 完全启动需要大约 18s ,由于某种原因,rabbitmq 启动后就“挂掉”,之后再被重新拉起,反复N次;这种情况下,可能出现:
    • rabbitmqctl trace_on 卡住
    • curl 卡住
    • for 循环结束后,tracing 功能依然启动失败,trace 规则建立失

使用 rabbitmqctl 访问一个不存在的 node ,确认命令的执行并未卡住

install.sh

  • 主要是 enable 各种插件
  • 之所以能够在安装脚本中使用,源于该命令同时支持 on-line 变更和 off-line 变更两种方式,即当 rabbitmq 尚未运行时,采用的是离线变更,等 rabbitmq 上线后即可自动加载新配置

思考

  • rabbitmq 支持的 tracing 功能的具体表现形式
  • tracing 功能的使用场景
  • 启用 tracing 功能后会导致的问题
  • 使用 tracing 功能时最合理的配置和使能方式
  • 关于 tracing 功能,我们还需要知道些什么

0x01 tracing 功能的具体表现形式

从以下几处信息可知

  • firehose 是作为一个 feature 由 rabbitmq 内部直接提供的
  • rabbitmq_tracing 是作为一个 plugin ,构建于 firehose 之上,提供了 GUI 并能够将 traced 消息写入日志文件

RabbitMQ has a "firehose" feature, where the administrator can enable (on a per-node, per-vhost basis) an exchange to which publish- and delivery-notifications should be CCed.

 

0x02 tracing 功能的使用场景

无论是针对 firehose 的介绍,还是基于 rabbitmq_tracing 插件的说明 ,均指出该功能仅适用于开发和调试阶段,以及开发和 QA 环境

0x03 启用 tracing 功能后会导致的问题

从 firehose 的角度

从 rabbitmq_tracing 的角度

0x04 使用 tracing 功能时最合理的配置和使能方式

详见本文最后的“实验”内容

0x05 关于 tracing 功能,我们还需要知道些什么

  1. tracing 的“使能”状态不是持久化的,重启后,默认恢复到 off 状态

Note that the firehose state is not persistent; it will default of off at server start time.

  1. 如果在使能了 firehose 后,又使能了 rabbitmq_tracing 插件,则当管理员停掉最后一个 trace 规则(也可以说成 trace 实例)后,firehose 功能同时会被 disable

TL;DR If rabbitmq_tracing plugin is also enabled and the administrator stops the last Trace, it will disable Firehose tracing entirely in addition to stopping the Trace instance.

  1. 只要启用了 firehose 功能,就会造成性能影响,即使此时并没有使用起来

Having Firehose enabled has a negative performance impact even when there are no bindings on amq.rabbitmq.trace. Furthermore, it has a significant performance penalty when we define traces.

  1. 如果你的 tracing 功能是基于 firehose 使用的,则不要忘记手动清理你所创建的 queue

Don't forget to clean up any queues that were used to consume events from the Firehose.

  1. 可以基于管理页面或 HTTP API 在集群中的任意 node 上创建 trace 规则

It is now possible to set up a tracer on any cluster node via management UI and HTTP API.GitHub issue: rabbitmq/rabbitmq-tracing#24

  1. 针对插件的 enable ,可以采用 on-line 和 off-line 两种方式,建议采用基于配置文件的 off-line 方式

Plugins are activated when a node is started or at runtime when a CLI tool is used. For a plugin to be activated at boot, it must be enabled. To enable a plugin, use the rabbitmq-plugins.

The rabbitmq-plugins command enables or disables plugins by contacting the running node to tell it to start or stop plugins as needed. It is possible to contact an arbitrary node -n option to specify a different node.

Having a node running before the plugins are enabled is not always practical or operator-friendly. For those cases rabbitmq-plugins provides an alternative way. If the --offline flag is specified, the tool will not contact any nodes and instead will modify the file containing the list of enabled plugins (appropriately named enabled_plugins) directly. This option is often optimal for node provisioning automation.

实验

该实验的前提是“由于目前的架构设计,导致不得不利用 RabbitMQ 的 tracing 功能干一些xxx事情”,因此,这里要探究的是,组内目前的脚本编写是否合理;

操作流程如下:

  • 基于 docker-compose 启动 2-node RabbitMQ 集群
  • 通过 rabbitmqctl trace_off 命令将 rabbit1 和 rabbit2 上的 firehose 功能关掉(默认就是关的,这里是为了加强一下这个条件)
  • 通过 rabbitmq-plugins disable rabbitmq_tracing 命令将 rabbit1 和 rabbit2 上的 rabbitmq_tracing 插件去使能

rabbit1 上执行

rabbit2 上执行

从 rabbitmq 日志中可以看到

此时,从管理界面上看,节点 rabbit1 和 rabbit2 上显示的内容完全相同,以 rabbit1 为例

  • 在 rabbit1 上 enable 插件 rabbitmq_tracing

server 日志输出如下

此时,从管理页面上可以看到,rabbit1 比 rabbit2 多了名为 tracing 的 tab

确认 rabbit2 上的插件状态,没有变化

页面上也没有变化

  • 通过 curl 命令确认 tracing 功能是否已处于使能状态(可以看到,此时 tracing 值为 false,说明仅使能 rabbitmq_tracing 插件并未将 firehose 特性启用)

  • 通过 curl 创建 trace 规则

重新确认 tracing 状态,发现已经变成 true

从 server 日志中也可以看出,创建 trace 规则后,会自动使能 tracing 功能

  • 确认创建 trace 规则后,还有哪些变化
    • 会自动创建一个独占 queue ,并绑定到 amq.rabbitmq.trace 这个 exchange 上
    • 会自动创建一个特殊的 consumer ,从上面的独占 queue 中消费
    • 会自动创建一个 trace log 文件

  • 手动创建一个名为 xxxx 的测试 queue ,但不做任何 bind 操作,也不为其创建消费者

该 queue 状态如图所示

  • 直接在管理页面上为该 queue 创建 trace 规则,可以看到,同样会像上面一样创建出所有的东西

  • 手动发消息到 xxxx queue 中测试 tracing 功能

可以发现,trace 日志内容有了更新(这里由于 Pattern 配置的原因,trace log 仅被写入到了 my-trace.log 中)

结论

折腾了这么多,结论如下

  • 针对 tracing 功能的使用,其实完全可以跳过 firehose 这个点,这样就可以避免使用 rabbitmqctl 命令(该命令要求目标 node 必须处于 running 状态)
  • 当基于 rabbitmq-plugins 命令(或 enabled_plugins 配置文件)使能插件后,后续可以直接通过 HTTP API 达成“在创建 trace 规则的时候自动使能 tracing 功能”和“在删除最后一个 trace 规则的时候自动去使能 tracing 规则”的效果
  • 创建 trace 规则的动作,不应该放入 RabbitMQ 的启动脚本之中,更合理的实现,应该是有一个外部的服务,负责确认 RabbitMQ 是否已经处于正常运行状态,之后再完成各种规则的添加(已经其他需要完成的额外操作);
  • 最后,官方已经非常明确的说了“tracing 功能不适合在生产环境中使用,可能导致 66% 左右的性能损耗”,然而,我们依然在这样用,并且不确定还会这样用多久,how pathetic ~

 


 

原创不易,添加关注,点赞,在看,分享是最好的支持, 谢谢~

更多精彩内容,欢迎关注微信公众号 西风冷楼阙

  • 0
    感动
  • 0
    路过
  • 0
    高兴
  • 0
    难过
  • 0
    搞笑
  • 0
    无聊
  • 0
    愤怒
  • 0
    同情
热度排行
友情链接