如何破防Rabbitmq触发内存回收机制
需求
一般情况下我们使用Zabbix来监控Rabbitmq集群节点的存活状况以及queue队列的消费情况,虽然在一定程度上满足了我们对可用性的监控需求,可一旦节点宕机或进程莫名挂掉,却让我们摸不着头脑。
因为无论是Rabbitmq的Web管理界面以及Zabbix监控都有局限性:
-
Rabbitmq Web管理界面收集的是实时状态,无法有效统计历史数据; -
Zabbix监控主要面向的是queue队列的消费挤压情况,虽然有历史记录但无法更进一步提供queue的内存使用情况;
针对Rabbitmq节点的异常宕机,经过我们进一步排查,原因基本为rabbitmq进程占用内存过多,触发了Linux系统的内存回收机制,被操作系统OOM杀死进程。因此我们需要进一步了解queue的内存使用情况。
解决方案
我们借助
rabbitmq-top
插件来进一步分析Rabbitmq集群每个节点的queue的使用情况。
-
按进程 ID、内存使用或减少/秒(CPU 使用的近似度量)排序。 -
单击进程描述(例如“我的队列”)以查看该对象的管理视图。 -
单击进程 ID(例如“<0.3423.0>”)以查看更多 Erlang 进程详细信息。
# 安装
# use sudo as necessary
rabbitmq-plugins enable rabbitmq_top
插件安装完成后,我们就可以使用
rabbitmq-top
具体的API,其访问路径如下:
-
/api/top/<节点名称> 进程列表。采用与其他列表、排序、sort_reverse 和列类似的查询字符串参数。排序非常重要,因为它目前硬编码返回前 20 个进程。
-
/api/process/
因此我们最终的解决方案为
-
python 访问
/api/top/<节点名称>,将Top20进程写入到日志文件; -
filebeat收集日志,写入到Elasticsearch; -
Grafana 接入ES日志源,实现多维度图形化展示;
具体实施
1.python获取Top20进程
# vim rabbitmq_monitor.py
#!/usr/bin/python3
# coding=utf-8
import urllib.request
import urllib.error
import json
import time
log_file = "/tmp/rabbitmq.monitor.log"
user = "admin"
passwd = "Top20"
server = "http://10.10.20.88:15672"
passwdmgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
passwdmgr.add_password(None, server, user, passwd)
handler = urllib.request.HTTPBasicAuthHandler(passwdmgr)
opener = urllib.request.build_opener(handler)
def list_nodes():
url = server + '/api/nodes'
request = urllib.request.Request(url)
response = opener.open(request)
data = json.loads(response.read())
nodes = []
for node in data:
name = node['name'].split('@')[1]
element = {'{#NODENAME}': name,
'{#NODETYPE}': node['type']}
nodes.append(element)
return nodes
def get_node_process():
nodes = list_nodes()
proce_data = []
for node in nodes:
node_name = 'rabbit@' + node['{#NODENAME}']
url = server + "/api/top/" + node_name
try:
request = urllib.request.Request(url)
response = opener.open(request)
data = json.loads(response.read())
for proce in data['processes']:
memory = int(proce['memory'])
tmp = {'node':node['{#NODENAME}'],'pid': proce['pid'],'name':proce['name'],'memory': memory}
proce_data.append(tmp)
except:
pass
return proce_data
if __name__ == '__main__':
while True:
f = open(log_file, 'a+')
for data in get_node_process():
json.dump(data,f)
f.write('\n')
f.close()
time.sleep(30)
具体日志如下:
# cat /tmp/rabbitmq.monitor.log
{"node": "node03", "pid": "<0.13714.0>", "name": {"supertype": "queue", "type": "rabbit_mirror_queue_slave", "queue_name": "TEST1.q1", "vhost": "/"}, "memory": 7675288}
{"node": "node03", "pid": "<0.10254.0>", "name": {"supertype": "queue", "type": "gm", "queue_name": "TEST02.q2", "vhost": "/"}, "memory": 163952}
{"node": "node03", "pid": "<0.6129.0>", "name": {"supertype": "queue", "type": "rabbit_mirror_queue_slave", "queue_name": "TEST03.q3", "vhost": "/"}, "memory": 7675336}
2.supervisor 守护
为保证日志的持续输出,我们最好使用supervisor启动rabbitmq_monitor.py 。
# vim /etc/supervisord.d/rabbitmq_monitor.ini
[program:rabbitmq_monitor]
user=work
command=python rabbitmq_monitor.py
numprocs=1
directory=/data/script
autostart=true
autorestart=true
startsecs=10
startretries=3
# 启动
supervisorctl add rabbitmq_monitor
supervisorctl start rabbitmq_monitor
3.filebeat 收集日志到ES
4.Grafana 展示
总结
通过这套方案一旦出现节点宕机的情况,我们只需通过Grafana或ELK查看对应时间段的队列内存占用情况,即可知晓是否有队列过多占用内存,从而触发Linux系统回收机制。 另外我们也可以利用Grafana+Alertmanager接入钉钉、微信等多告警渠道,便于我们更快地发现问题。1.运维思索系列
2.运维管理系列
3. 运维监控之路
4.蓝鲸之路
5. CI/CD之路
6.Ansible之路
札记:天才就是百分之一的灵感,和百分之九十九的汗水。 但是,这百分之一的灵感远比百分之九十九的汗水重要。 -- 爱迪生 喜欢这篇文章,记得 点赞+在看 哦~