先来说一下基本概念。
什么是消息队列
消息队列本身就是一个存放消息的容器,如果非要从数据结构的角度来理解,那就是一个有序集合。这个集合中的每个对象都是消息,先进先出。
那么什么是消息呢?
消息就像一个指令,一个命令。举个例子,你妈喊你回家吃饭了,这就是一个消息,但是至于你怎么吃,这是你的事情,我觉得你妈或者其他人并不会感兴趣,因为怎么吃,是你自己决定的。
那么队列呢?可以理解成,你妈妈喊你回家吃饭,然后叮嘱让你把饭吃干净,然后再洗碗。这里面就存在着一个队列,先吃饭,让你吃干净点,再洗碗。这里面就好几个消息。这就是一个队列。
那么消息队列的作用是什么?
消峰
为什么叫消峰,出现峰峰值,把这个峰峰值给铺平,就叫消峰。
很多时候,服务器的压力并不大,但是某个时候,服务器的压力陡增怎么办?
比如像淘宝,只有双11,618或者搞某些活动的时候。用户大量下单,请求的流量才会暴增。
那么面对这种情况,解决方案确实很多,加服务器,用nginx去负载均衡,这是一种可行的方法,不过大多数的时候服务器都是闲置的,就会是资源浪费了。避免资源浪费的话,只能前提部署,用完撤走,那这样子是不是很麻烦?
另外考虑一个场景,如果服务器只支持1000个用户同时下单,假设每处理一个客户的订单需要一秒,那后面每多一个客户,后面的客户就需要等待(n - 1000)秒。等的人多了,基于服务器的线程模型(定长线程池),一下子就撑不住了(队列的长度也不是无限的),只能强迫性的不让后面的客户去等,直接告诉他奔溃了?这体验也很不好吧?
那么是不是可以考虑采取一种措施,告诉客户下单的操作成功,但是成功还是失败后面再告诉客户?这样子服务器的压力也不会那么大,因为没有那么多内容在队列中堆积。告诉客户操作成功只需要0.1秒,而告诉客户下单成功(需要1秒)。同样资源的情况下,意味着同样的时间内,吞吐提高了10倍。假如把陡增的请求,堆积的任务队列形容成山峰,那么消息队列的作用,就是增加服务的吞吐,把堆积的任务队列尽快的消化。
这个角度其实是空间换时间,用空间去存储消息,多浪费点内存,但是让服务的性能保持平稳。
解耦
举个例子,如果一个客户下单,有一个A服务是专门接收订单的。B服务是专门消费订单的。
A服务B服务直接的通信,可以通过http请求,但是这样做意味着强耦合。B服务需要强制性的去定义一个请求体,用于处理来自A服务的请求。当B服务定义的结构体发生变更的时候,A服务就会调用失败。
消息队列则实质上并不会去考虑业务结构体,消息的本身是一个通用的结构,发起方与消费方,都需要遵守这个协议,需要去考虑的只是这个结构体的内容。
如果想要去主动的去处理某些业务,只需要遵守这个结构体,发起请求即可。这样子所有的系统,都可以接入,同时不存在耦合。
消息队列提供了一个消息转换的过程,让各个不同业务服务之间进行解耦。
消息分发
可以简单的理解成,不同的业务有着不同的队列,他们之间的消费互不干扰。
各种mq的比较
各种mq的对比因为有一些mq我是没用过的,所以这块的话,是从网上找的资料。
从上面的图来看。
rocketmq是具备一定的优势的,针对大并发,且延时性相对高一些的应用场景。
此外rocketmq的功能相对完善,拓展性强,另外前身也是阿里开发的,只是后面送给了阿帕奇社区。
至于为什么那么强大,估计得后面才知道为什么。
rocketmq的结构
rocketmq的结构图NameServer
概念:其实说白了就是注册中心(AP),AP使得rocketmq的设计比较简单也轻量,因为减少了nameServer之间的通信。
作用:路由功能。
nameServer中存储了路由信息(topic(可以粗略理解成消息的类型)与对应的broker实际地址的关系)
producer可以通过topic找到需要的Broker的实际地址,决定把消息发哪里去
consumer可以通过topic找到需要的broker的实际地址,决定从哪里获取消息
Broker
概念:说白了就是存储消息队列的容器。
作用: 消息的持久化
Producer
概念:生产者
作用:用于生产消息,将消息发送到存储容器
Consumer
概念:消费者
作用:消费消息,从消息的存储容器中获取消息,并且进行具体的业务实现。
rocketmq的特性
其实特性有很多,不过我了解的还不是很深入,暂时就只举例这些。
1.有序性
在某些特定业务场景,可能对消息的顺序有要求。比如日志,需要一条一条打印,这就需要顺序。
Topic的队列是我们实现有序性的关键,一个topic中,任意队列内部的所有消息均可以认为是有序的,均满足先进先出的有序条件。
针对有序性的需求,围绕队列展开,通常有两种解决方案。
1.1全局有序(单队列)
全局有序是指,业务对有序性对要求是一个topic内所有消息全部有序。为了达到全局有序的要求,可以将topic的队列数设置为1,即是说所有消息,均投递至同一个队列中,自然也就达到全局有序的效果。
1.2分组有序
分组有序是指,业务对一个topic内的所有消息按照某种条件水平拆分为不同的分组后,组内有序。已知topic的单个队列天然有序,那么只需要将水平拆分后的一组消息,全部发送至同一个topic的队列,即可实现分组有序。
那么为什么只有这俩种有序方式呢?倘若一个topic有多个队列,且消息类型完全是一样的(即同种业务),对于同个队列来说必然是先进先出,但是如果俩个容量不同的队列,前面发出的消息恰好加在了任务比较多堆积的队列,后面发出的消息恰好加在了任务堆积比较少的队列,这个时候就不能保证有序了。
2.事务
消息在生产或者消费的过程中可能会出现异常,rocketmq支持事务,但是这个事务的处理过程是由开发人员自己去实现的
3.重试机制
4延时消费
消息允许被延时消费
5消息可靠性
RocketMQ支持消息的高可靠,影响消息可靠性的几种情况:
Broker正常关闭
Broker异常Crash
OS Crash
机器掉电,但是能立即恢复供电情况
机器无法开机(可能是cpu、主板、内存等关键设备损坏)
磁盘设备损坏
1)、2)、3)、4) 四种情况都属于硬件资源可立即恢复情况,RocketMQ在这四种情况下能保证消息不丢,或者丢失少量数据(依赖刷盘方式是同步还是异步)。
5)、6)属于单点故障,且无法恢复,一旦发生,在此单点上的消息全部丢失。RocketMQ在这两种情况下,通过异步复制,可保证99%的消息不丢,但是仍然会有极少量的消息可能丢失。通过同步双写技术可以完全避免单点,同步双写势必会影响性能,适合对消息可靠性要求极高的场合,例如与Money相关的应用。注:RocketMQ从3.0版本开始支持同步双写。
6 负载均衡
一个topic分布在多个broker上,一个broker可以配置多个topic,它们是多对多的关系。一个queue对应一个Broker集群
如果某个topic消息量很大,应该给它多配置几个队列,并且尽量多分布在不同broker上,减轻某个broker的压力。
topic消息量都比较均匀的情况下,如果某个broker上的队列越多,则该broker压力越大。
生产者可以考虑选择合适的队列(根据队列的状态,比如是否堆积了过多的任务),去存储消息
需要的一些技术基础
netty(nio的框架,轻量高效,可能不懂这个,源码没法看)
java基础
网友评论