消息队列:丢失、重复和积压

消息丢失

检测消息丢失的方法

  • 可以在生产端增加一个连续递增的序号,在消费端检查序号的连续性。
  • 大多数消息队列的客户端都支持拦截器,可以在生产者发消息前的拦截器中将序号注入到消息,在消费者收到消息的拦截器中检测序号。
  • 由于RocketMQ和Kafka在Topic不保证严格有序,仅在队列或分区中有序,所以序号中要带有分区信息,每个分区单独检测消息序号连续性。
  • 如果有多个生产者,则消息序号中还需要带上生产者的的标识。

可能丢消息的地方

在这里插入图片描述

  • 生产阶段,发消息时正确处理broker返回值或者捕获异常,就可以保证消息不丢失。特别的,异步发送需要在回调方法里检查发送结果。
  • 存储阶段,需要通过配置Broker参数来避免因为宕机而丢消息。对于单个节点的Broker,需要配置在收到消息后,将消息写入磁盘后再给生产者返回确认。对于多个节点的集群,需要配置成至少将消息发送给2个以上节点时,再给生产者返回确认
  • 消费阶段,要在执行完所有消费逻辑后,再返回消费确认。不要在收到消息时就立即确认。

消息重复

MQTT协议

  • 给出了三种传递消息时能够提供的服务质量标准,这三种服务质量从低到高依次是:
  • At most once:最多一次,允许丢消息
  • At least once:最少一次,不允许丢消息,允许有重复。
  • Exactly once:恰好一次,不允许丢也不允许重复。

幂等性

  • 在消费端保证操作具有幂等性。
  • 比如,利用数据库唯一约束、为更新数据设置前置条件,记录消息全局id并在操作前检查。

消息积压

  • 消息积压的直接原因,一定是系统中的某个部分出现了性能问题,来不及处理上游发送的消息,才会导致消息积压
  • 发送端性能优化:使用并发或者批量发送。
  • 消费端性能优化:优化消费逻辑,或者扩充分区和消费者数量,确保 Consumer 的实例数和分区数量是相等的。
  • 注意,不要使用将消息暂存在内存中的方式来提高消费者的吞吐量,这样很容易丢失消息。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
关于消息队列的Permission denied问题,可能是由于以下原因导致的: 1.没有正确设置消息队列的权限。 2.没有正确挂载/dev/mqueue。 3.消息队列已经存在,但是没有正确清理。 针对这些问题,可以尝试以下解决方法: 1.检查消息队列的权限设置是否正确,可以使用chmod命令进行修改。 2.检查是否正确挂载/dev/mqueue,可以使用mount命令查看。 3.如果消息队列已经存在,可以使用mq_unlink命令进行清理。 下面是一个关于消息队列的例子,可以参考: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <sys/stat.h> #include <mqueue.h> #define QUEUE_NAME "/test_queue" #define MAX_MSG_SIZE 256 #define MSG_BUFFER_SIZE (MAX_MSG_SIZE + 10) int main(int argc, char **argv) { mqd_t mq; struct mq_attr attr; char buffer[MSG_BUFFER_SIZE]; int msg_len; // 设置消息队列属性 attr.mq_flags = 0; attr.mq_maxmsg = 10; attr.mq_msgsize = MAX_MSG_SIZE; attr.mq_curmsgs = 0; // 创建消息队列 mq = mq_open(QUEUE_NAME, O_CREAT | O_RDWR, 0644, &attr); if (mq == (mqd_t)-1) { perror("mq_open"); exit(1); } // 发送消息 sprintf(buffer, "Hello, world!"); msg_len = strlen(buffer); if (mq_send(mq, buffer, msg_len, 0) == -1) { perror("mq_send"); exit(1); } // 接收消息 memset(buffer, 0, MSG_BUFFER_SIZE); if (mq_receive(mq, buffer, MSG_BUFFER_SIZE, NULL) == -1) { perror("mq_receive"); exit(1); } printf("Received message: %s\n", buffer); // 关闭消息队列 if (mq_close(mq) == -1) { perror("mq_close"); exit(1); } // 删除消息队列 if (mq_unlink(QUEUE_NAME) == -1) { perror("mq_unlink"); exit(1); } return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值