消息队列的引入,什么时候使用MQ?
MQ(Message Queue),一种跨进程的通信机制,用于上下游传递消息。能达到解耦、异步、消峰限流的作用。举几个对应的适用例子。
解耦
1. 比如定时任务依赖的场景,晚上需要跑一些定时统计任务,任务2依赖任务1的结果,任务3依赖任务2的接口,一般开发人员会在每个定时任务之间,预留一些时间buffer处理。但是,当某一天其中一个任务超出常规时间,任务就跑乱套了,第二天肯定就有人来找到你了。这个场景就很适合用MQ去解耦,当任务1完成后,通知到任务2,任务二通过订阅消息去实现触发。
2. 比如统一充值网关服务,某个产品接入统一充值服务的微信渠道充值。充值成功后,微信服务端会通知到统一充值服务端,因为这些是异步的调用,且是公网接口,时间会相对长一些,业务上产品接入方会有需求想知道,到账的结果。这个到账通知就很适合MQ去实现。如果,这里由充值网关服务调用上游来通知结果的话,每次新增调用方,充值网关服务都需要修改代码发布,依赖反转了。充值网关+MQ的方式,业务调用方去订阅消息实现解耦。
异步
1.场景上游不关心执行结果。异步,rpc框架异步调用也可以。区别就是MQ消息会落地,并且消息中间件都会有HA的涉及,能保证消息语义的实现(至少一次、至少一次、至多一次)。rpc异步请求本身也会有本地内存队列,所以数据不是要求很重要的场景,差不多。只是在工程上,有一点,使用rpc处理这种业务,经验上要单拉出一个服务去调用下游,因为依赖倒置了。每增加接入方或者业务有修改,都要提供服务的工程去修改发布(有经验的同学应该深有体会),作为基础服务的话,应该减少这种依赖倒置的发布,独立出来一个服务处理的话,会减少风险。
业务的话,处理推荐日志,处理app埋点的统计数据
消峰限流
这个应该是MQ另一个最主要的作用之一。做活动访问量陡增,下游处理不过来的时候,使用消息队列达到限流的作用。工程上有个C10K问题(虽然现在已经有现在我们早已经突破了C10K这个瓶颈,具体的思路就是通过单个进程或线程服务于多个客户端请求,通过异步编程和事件触发机制替换轮训,IO 采用非阻塞的方式(reactor模型),减少不必要的性能损耗,等等)。但是这个要求下游的服务包括存储和依赖,都要做到这点,哪个环节弱都不行。可能还会浪费资源,平时的量用不着那么多服务器。
相应的,那些调用方需要被调用方立刻返回结果的需求,就不适用于MQ,需要根据业务去考虑,脱离了业务去引入新技术就是耍流氓。
业务上有对消息组件的需求后,市面上陆续出现了很多成熟的消息中间件
IBM webSphere MQ、Apache ActiveMQ、LinkedIn Kafka、阿里 rocketMQ、
java社区肯定要跟着一起玩的,社区也定义jms规范(JMS规范百度词条)maid。这些消息组件,前两个是基于jms规范实现的,后两个没有,rocketMQ开始是kafka的java版实现,现在已经从Apache社区正式毕业(17-0925),成为Apache顶级项目。在原有设计的基础上,比如提供事务消息等一些功能,kafka0.11版开始也提供可事务的支持,还没发布太久,效果还有待观察;但是都用别的方式实现了jms定义的一些功能,比如发布订阅,点对点通信。
如何设计实现一个消息队列:
实现一个消息组件不可避免的要处理如下问题(消息中间件精要设计):
1.通信协议的选择
2.消息的分布式存储设计,关系型数据库 磁盘 kv存储kafka消息存储设计
3.如何分布式设计生产者和消费者保证高吞吐
4.如何实现顺序消费
kafka能保证一个分区partition上的消息是顺序的
5.如何保证HA,在高吞吐和HA上做平衡kafka的HA设计
6.事务消息的支持事务消息的实现
7.push还是pull
8.单播、广播、订阅发布的实现
消费组的设计实现
9.性能的优化,同步异步、批量等
需要了解下生产者客户端,参数含义实现生产者消费者java客户端使用
以上问题有交叉,以这些问题出发,看看kafka是如何设计实现的。
网友评论