- 为什么要是用消息中间件?
- 低耦合: 低耦合,不管是程序还是模块之间,使用消息中间件进行间接通信。
- 异步通讯: 异步通信能力,使得子系统之间得以充分执行自己的逻辑而无需等待。
- 缓冲能力: 缓冲能力,消息中间件像是一个巨大的蓄水池,将高峰期大量的请求存储下来慢慢交给后台进行处理,对于秒杀业务来说尤为重要。
-
伸缩性: 通过不断向集群中加入服务器的手段来缓解不断上升的用户并发访问压力和不断增长的数据存储需求。就像弹簧一样挂东西一样,用户多,伸一点,用户少,缩一点。
衡量架构是否高伸缩性的主要标准:是否可用多台服务器构建集群,是否容易向集群中添加新的服务器。加入新的服务器后是否可以提供和原来服务器无差别的服务。集群中可容纳的总的服务器数量是否有限制。 - 扩展性: 主要标准就是在网站增加新的业务产品时,是否可以实现对现有产品透明无影响,不需要任何改动或者很少改动既有业务功能就可以上线新产品。比如用户购买电影票的应用,现在我们要增加一个功能,用户买了铁血战士的票后,随机抽取用户送异形的限量周边。怎么做到不改动用户购票功能的基础上增加这个功能。这个和设计模式中的开闭原则(对扩展开放,对修改关闭)在架构层面的一个原则。
- 中间件的适用场景
异步处理:
用户注册后,需要发注册邮件和注册短信。传统的做法有两种 1.串行的方式;2.并行方式。
A).串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端。
B).并行方式:将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间。-
应用解耦:
传统模式:用户下单后,订单系统需要通知库存系统。传统的做法是,订单系统调用库存系统的接口。
传统模式的缺点:
1) 假如库存系统无法访问,则订单减库存将失败,从而导致订单失败;
2) 订单系统与库存系统耦合;
消息队列方案:
1)订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功。
2)库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作。
-
流量削峰:
流量削峰也是消息队列中的常用场景,一般在秒杀或团抢活动中使用广泛。
应用场景:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列:可以控制活动的人数;可以缓解短时间内高流量压垮应用。
日志处理:
日志处理是指将消息队列用在日志处理中,比如 Kafka 的应用,解决大量日志传输的问题。
日志采集客户端,负责日志数据采集,定时写入 Kafka 队列:Kafka 消息队列,负责日志数据的接收,存储和转发;日志处理应用:订阅并消费 kafka队列中的日志数据;消息通讯:
消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等。
点对点通讯:客户端 A 和客户端 B 使用同一队列,进行消息通讯。
聊天室通讯:客户端 A,客户端 B,客户端 N 订阅同一主题,进行消息发布和接收。实现类似聊天室效果。
消息中间件和RPC的区别
RPC 和消息中间件的场景的差异很大程度上在于就是“依赖性”和“同步性”。
依赖性: 参考上述的订单系统和库存系统之间的耦合处理。
同步性:RPC 方式是典型的同步方式,让远程调用像本地调用。消息中间件方式属于异步方式。-
几种常用的中间件比较
选型建议:
- 用户访问量在 ActiveMQ 的可承受范围内,而且确实主要是基于解耦和异步来用的,可以考虑 ActiveMQ,也比较贴近 Java 工程师的使用习惯,但是ActiveMQ 现在停止维护了,同时 ActiveMQ 并发不高,所以业务量一定的情况下可以考虑使用。
- RabbitMQ 作为一个纯正血统的消息中间件,有着高级消息协议 AMQP 的完美结合,在消息中间件中地位无可取代,但是 erlang 语言阻止了我们去深入研究和掌控,对公司而言,底层技术无法控制,但是确实是开源的,有比较稳定的支持,活跃度也高。
- 所以中小型公司,技术实力较为一般,技术挑战不是特别高,用 ActiveMQ、RabbitMQ 是不错的选择;大型公司,基础架构研发实力较强,用 RocketMQ是很好的选择,因为 RocketMQ 诞生比较晚,并且更新迭代很快,这个意味着在使用过程中有可能会遇到很多坑。这个后面写到RocketMQ的时候详细介绍。
- 如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高。
从性能上来看,使用文件系统的消息中间件(kafka、RocketMQ)性能是最好的,所以基于文件系统存储的消息中间件是发展趋势。(从存储方式和效率来看 文件系统>KV 存储>关系型数据库)。