聊聊消息中间件的Push模型和Pull模型
RabbitMQ两种模式都有,一般用Push模式,设置Qos避免内存爆了。
- Pull模式大致用:
--------------------
GetResponse response = channel.basicGet(QUEUE_NAME, false);
System.out.println(new String(response.getBody()));
channel.basicAck(response.getEnvelope().getDeliveryTag(),false);
--------------------
什么是推拉(Push/Pull)模式?
-一般大概把MQ分为三部分:producer、broker、consumer
- Push模式:producer生产完消息后,传递给broker,然后broker马上推给consumer(我们多数用RabbitMQ的模式)
- Pull模式:consumer会主动去broker拉取消息,根据自身消费能力拉取
推拉(Push/Pull)模式的优缺点?
- Push模式
–优点:实时(服务端broker一收到消息就推给consumer)
–缺点:
容易造成消息堆积(消息保存在服务端broker)
需维护每次传输状态,遇到问题要重试
服务短需要根据消费者能力做流控(比如rabbitmq用qos来限制)
- Pull模式
– 优点:保存在消费端,获取方便
传输失败,不需要重试
消费者可根据自身能力来决定流空(因为就是他自己拉取)
– 缺点:实时性不高,短轮询间隔时间大,实时性就低。有其他优化方式,比如CMQ、kafka(腾讯云的服务)也会采用长轮询优化(长轮询如果拉取失败不会直接断开,而是挂在那里wait,如果服务端有新消息就返回最新数据)
中间件
push模型
pull模型
RabbitMQ
支持
支持
Kafka
—
支持(只有短轮询+长轮询)
RocketMQ
支持
支持
上面说到rabbitmq的推模式推的太快了,那怎么限制?限制方式如下:
RabbitMq Qos prefetch 消息堵塞问题(设置Qos上限时用于 Push模式)
可以设置qos prefetch_count,指单一消费者最多能消费的unacked messages数目
如果不设置Qos?
如果不设置Qos,客户端默认是无限缓存,会一直缓存mq服务发过来的待消费消息,这样坏处如下:
1 无线缓存消息,容易撑爆客户端内存
2 如果新增mq消费者,但是消息都缓存到之前的mq待消费队列中,那这个新增的mq也拿不到消息来消费
如何设置,根据什么做指标?
假设MQ服务传递到客户端的网络IO等事件花费 50 ms(A), 客户端返回ack给MQ处理花费 50 ms(B)。客户端处理消息需要 4 ms(C)。
这样处理一条消息的总时间 = A + B + C = 104 ms,如果Qos prefetch_count设置为 1,这样同时间在客户端缓存队列中存在一条未ack数据,导致(A + B) = 100ms 都浪费掉(因为要处理完这条消息才能继续拿下一条),所以一般要根据往返处理的时间(A + B)来判断 prefetch_count的值
公式为:prefetch_count = (A + B) / 4 = 25,就是设置成25才是最完美的,但是这个很难评定,毕竟各种环境和网络都是因素
备注:如果prefetch_count设置大了,就会导致等待新的mq进来,如果没有新消息,也不能马上消费。
参考: https://segmentfault.com/a/1190000022586723?utm_source=tag-newest