RabbitMQ(四)-- 限流和监控方式
消费端限流
假设一个场景,首先,我们 Rabbitmq 服务器积压了有上万条未处理的消息,我们随便打开一个消费者客户端,会出现这样情况: 巨量的消息瞬间全部推送过来,但是我们单个客户端无法同时处理这么多数据!
当数据量特别大的时候,我们对生产端限流肯定是不科学的,因为有时候并发量就是特别大,有时候并发量又特别少,我们无法约束生产端,这是用户的行为。所以我们应该对消费端限流,用于保持消费端的稳定,当消息数量激增的时候很有可能造成资源耗尽,以及影响服务的性能,导致系统的卡顿甚至直接崩溃。
TTL
Time To Live,消息过期时间设置
声明队列时,指定即可
TTL:过期时间
- 队列统一过期
- 消息单独过期
如果设置了消息的过期时间,也设置了队列的过期时间,它以时间短的为准。
-
队列过期后,会将队列所有消息全部移除
-
消息过期后,只有消息在队列顶端,才会判断其是否过期(移除掉)
死信队列
死信队列,英文缩写:DLX 。Dead Letter Exchange(死信交换机),当消息成为Dead message后,被重新发送到另一个交换机,这个交换机就是DLX
消息成为死信的三种情况:
-
队列消息长度到达限制;
-
消费者拒接消费消息,basicNack/basicReject,并且不把消息重新放入原目标队列,requeue=false;
-
原队列存在消息过期设置,消息到达超时时间未被消费;
队列绑定死信交换机:
给队列设置参数: x-dead-letter-exchange 和 x-dead-letter-routing-key
也就是说此时Queue作为"生产者"
延迟队列
延迟队列,即消息进入队列后不会立即被消费,只有到达指定时间后,才会被消费
需求:
下单后,30分钟未支付,取消订单,回滚库存。
新用户注册成功7天后,发送短信问候。
实现方式:
定时器 (×)
延迟队列 (√)
实现步骤:
在RabbitMQ中并未提供延迟队列功能
替代实现: TTL+死信队列 组合实现延迟队列的效果
设置队列过期时间30分钟,当30分钟过后,消息未被消费,进入死信队列,路由到指定队列,调用库存系统,判断订单状态。
RabbitMQ 监控
了解 RabbitMQ 的运行状态,主要有三种途径:Management UI,rabbitmqctl 命令和 REST API 以及使用 prometheus + grafana,当然大厂的话都会自定开发基于 api监控系统
- Management UI
RabbitMQ 给我们提供了丰富的 Web 管理功能,通过页面,我们能看到 RabbitMQ 的整体运行状况,交换机和队列的状态等,还可以进行人员管理和权限配置,相当全面。
但如果想通过页面来监控,那出不出问题只能靠缘分。看到出问题了,是运气好,看不到出问题,那是必然。
备注:通过 http://127.0.0.1:15672 来访问 Web 页面,默认情况下用户名和密码都是 guest,但生产环境下都应该改掉的。
- rabbitmqctl 命令
与前端页面对应的就是后端的命令行命令了,同样非常丰富。平时自己测试,或者临时查看一些状态时,也能用得上
# 启动服务
rabbitmq-server
# 停止服务
rabbitmqctl stop
# vhost 增删查
rabbitmqctl add_vhost
rabbitmqctl delete_vhost
rabbitmqctl list_vhosts
# 查询交换机
rabbitmqctl list_exchanges
# 查询队列
rabbitmqctl list_queues
# 查看消费者信息
rabbitmqctl list_consumers
# user 增删查
rabbitmqctl add_user
rabbitmqctl delete_user
rabbitmqctl list_users
- REST API
自动化监控和一些需要批量的操作,通过调用 API 来实现是最好的方式。比如有一些需要初始化的用户和权限,就可以通过脚本来一键完成,而不是通过页面逐个添加,简单又快捷。
下面是一些常用的 API:
# 概括信息
curl -i -u guest:guest http://localhost:15672/api/overview
# vhost 列表
curl -i -u guest:guest http://localhost:15672/api/vhosts
# channel 列表
curl -i -u guest:guest http://localhost:15672/api/channels
# 节点信息
curl -i -u guest:guest http://localhost:15672/api/nodes
# 交换机信息
curl -i -u guest:guest http://localhost:15672/api/exchanges
# 队列信息
curl -i -u guest:guest http://localhost:15672/api/queues 345678910111213141516
一般来讲 overview 和 queues 这两个 API 就可以满足需求。
下面是一个demo代码,主要使用HttpClient以及jackson来调用相关参数。
相关maven如下:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.4</version>
</dependency>
public class MonitorDemo {
public static void main(String[] args) {
try {
Map<String, ClusterStatus> map = fetchNodesStatusData("http://localhsot:15672/api/nodes", "root", "root");
for (Map.Entry entry : map.entrySet()) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static Map<String, ClusterStatus> fetchNodesStatusData(String url, String username, String password) throws IOException {
Map<String, ClusterStatus> clusterStatusMap = new HashMap<String, ClusterStatus>();
String nodeData = getData(url, username, password);
JsonNode jsonNode = null;
try {
jsonNode = JsonUtil.toJsonNode(nodeData);
} catch (IOException e) {
e.printStackTrace();
}
Iterator<JsonNode> iterator = jsonNode.iterator();
while (iterator.hasNext()) {
JsonNode next = iterator.next();
ClusterStatus status = new ClusterStatus();
status.setDiskFree(next.get("disk_free").asLong());
status.setFdUsed(next.get("fd_used").asLong());
status.setMemoryUsed(next.get("mem_used").asLong());
status.setProcUsed(next.get("proc_used").asLong());
status.setSocketUsed(next.get("sockets_used").asLong());
clusterStatusMap.put(next.get("name").asText(), status);
}
return clusterStatusMap;
}
public static String getData(String url, String username, String password) throws IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);
HttpGet httpGet = new HttpGet(url);
httpGet.addHeader(BasicScheme.authenticate(creds, "UTF-8", false));
httpGet.setHeader("Content-Type", "application/json");
CloseableHttpResponse response = httpClient.execute(httpGet);
try {
if (response.getStatusLine().getStatusCode() != 200) {
System.out.println("call http api to get rabbitmq data return code: " + response.getStatusLine().getStatusCode() + ", url: " + url);
}
HttpEntity entity = response.getEntity();
if (entity != null) {
return EntityUtils.toString(entity);
}
} finally {
response.close();
}
return "";
}
public static class JsonUtil {
private static ObjectMapper objectMapper = new ObjectMapper();
static {
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
}
public static JsonNode toJsonNode(String jsonString) throws IOException {
return objectMapper.readTree(jsonString);
}
}
public static class ClusterStatus {
private long diskFree;
private long diskLimit;
private long fdUsed;
private long fdTotal;
private long socketUsed;
private long socketTotal;
private long memoryUsed;
private long memoryLimit;
private long procUsed;
private long procTotal; // 此处省略了Getter和Setter方法
@Override
public String toString() {
return "ClusterStatus{" + "diskFree=" + diskFree + ", diskLimit=" + diskLimit + ", fdUsed=" + fdUsed + ", fdTotal="
+ fdTotal + ", socketUsed=" + socketUsed + ", socketTotal=" + socketTotal + ", memoryUsed=" + memoryUsed
+ ", memoryLimit=" + memoryLimit + ", procUsed=" + procUsed + ", procTotal=" + procTotal + '}';
}
}
}
通过对返回结果进行解析,就可以判断 RabbitMQ 的整体运行状态,如果发生超阈值的情况,可以发送告警或邮件,来达到监控的效果。
针对队列积压情况的监控判断,有两种方式:
-
一是设置队列积压长度阈值,如果超过阈值即告警;
-
二是保存最近五次的积压长度,如果积压逐渐增长并超阈值,即告警。
第二种方式更好,判断更加精准,误告可能性小,但实现起来也更复杂。
- prometheus + grafana 监控rabbitmq
前言
第一种:RabbitMQ内部集成Prometheus来获取指标
- 3.8.0之前版本,RabbitMQ可以使用单独的插件prometheus_rabbitmq_exporter来向Prometheus公开指标,要单独下载到RabbitMQ安装目录中进行安装;
prometheus_rabbitmq_exporter:https://github.com/deadtrickster/prometheus_rabbitmq_exporter
- 3.8.0版开始,RabbitMQ附带了内置的Prometheus&Grafana支持。虽然内置了该插件,但也要进行安装
rabbitmq-prometheus:https://github.com/rabbitmq/rabbitmq-prometheus
第二种:使用独立程序来获取指标(RabbitMQ_exporter)
不管什么版本都能使用,要单独启动exporter进程
rabbitmq_exporter:https://github.com/kbudde/rabbitmq_exporter
RabbitMQ 官方监控介绍:
https://www.rabbitmq.com/monitoring.html
https://www.rabbitmq.com/prometheus.html#overview-prometheus
先介绍采用第二种方式实现。(因为企业中使用的rabbitmq基本都是3.8.x之前的版本居多。)
采用docker方式启动
一、使用独立程序来获取指标(RabbitMQ_exporter)
安装rabbitmq_exporter
注:在RabbitMQ集群下的任意一个节点部署它。
- 上传解压
wget https://github.com/kbudde/rabbitmq_exporter/releases/download/v0.26.0/rabbitmq_exporter-0.26.0.linux-amd64.tar.gz
tar -xvf rabbitmq_exporter-0.26.0.linux-amd64.tar.gz
cd rabbitmq_exporter-0.26.0.linux-amd64/
- 配置
使用默认配置
- 启动
进入根目录下,输入以下命令:
cd rabbitmq_exporter-0.26.0.linux-amd64/
RABBIT_USER=guest RABBIT_PASSWORD=guest OUTPUT_FORMAT=json PUBLIC_PORT=9090 RABBIT_URL=http://localhost:15672 nohup ./rabbitmq_exporter & tail -1000f nohup.out
参数说明:
RABBIT_USER:rabbit用户名
RABBIT_PASSWORD:rabbit密码
RABBIT_URL:rabbit服务地址和端口
OUTPUT_FORMAT:输出格式
PUBLIC_PORT:暴露端口
启动成功后,可以访问 http://10.0.101.100:9090/metrics/ ,(IP和端口要改成相应环境的)
看抓取的信息如下:
使用docker-compose方式启动prometheus和grafana
下载监控压缩包 rabbitmq-monitor.tar.gz,提取码:rppe
上传到服务器解压,参照上面的部署安装好docker和docker-compose,进入文件夹中执行:
docker-compose up -d
#查看服务启动是否正常
docker-compose ps
如果没用问题,就可以执行下面的步骤。
Prometheus配置
- 配置
修改prometheus组件的prometheus.yml加入rabbitMQ节点:
vim prometheus.yml
- 启动验证
用以下命令重启它,然后查看targets:
docker-compose restart prometheus
注:State=UP,说明成功
Grafana配置
导入仪表盘模板
通过浏览器访问:http://IP:3000
导入监控图表
以上仪表盘导入后再结合自身业务修改过的最终仪表盘:
通过浏览器访问:http://grafana服务器IP:3000
导入监控图表
以上仪表盘导入后再结合自身业务修改过的最终仪表盘:
- 预警指标
序号 | 预警名称 | 预警规则 | 描述 |
---|---|---|---|
1 | 集群状态预警 | 当集群状态不符合预期【!=1】时进行预警 | |
2 | 节点状态预警 | 当节点状态不符合预期【!=1】时进行预警 | |
3 | 等待消费预警 | 当等待消费的消息数量达到阈值【>1000】时进行预警 | 延迟消费 |
4 | 消费预警 | 当消费中的消息数量达到阈值【>1000】时进行预警 | 消费速度慢 |
二、RabbitMQ内部集成Prometheus来获取指标
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!