技术调研:就是对一个技术去找到一些业内常用的开源实现,然后对各种不同的实现都进行一些调研,对比一下他们的优劣势,看看谁比较符合我们的需求,谁比较适合我们来使用。
具体来说,比如对于我们现在的情况,你只知道有一个MQ的概念,但是你要考虑一下:
说明:ActiveMQ主要是几年以前较多公司使用,现在几乎国内用的公司都很少了。
Kafka的吞吐量几乎是行业里最优秀的,在常规的机器配置下,一台机器可以达到每秒十几万的QPS。Kafka性能也很高,基本上发送消息给Kafka都是毫秒级的性能。可用性也很高,Kafka是可以支持集群部署的,其中部分机器宕机是可以继续运行的。
Kafka比较为人诟病的一点,似乎是丢数据方面的问题,因为Kafka收到消息之后会写入一个磁盘缓冲区里,并没有直接落地到物理磁盘上去,所以要是机器本身故障了,可能会导致磁盘缓冲区里的数据丢失。 而且Kafka另外一个比较大的缺点,就是功能非常的单一,主要是支持发送消息给他,然后从里面消费消息,其他就没有什么额外的高级功能了。
基本行业里的一个标准,是把Kafka用在用户行为日志的采集和传输上,比 如大数据团队要收集APP上用户的一些行为日志,这种日志就是用Kafka来收集和传输的。
RabbitMQ的优势在于可以保证数据不丢失,也能保证高可用性,即集群部署的时候部分机器宕机可以继续运行,然后支持部分高级功能,比如说死信队列,消息重试之类的。
缺点就是RabbitMQ的吞吐量是比较低的,一般就是每秒几万的级别。 一个较为致命的缺陷,就是他的开发语言是erlang。
RocketMQ是阿里开源的消息中间件,久经沙场,非常的靠谱。他几乎同时解决了Kafka和RabbitMQ的缺陷。 RocketMQ的吞吐量也同样很高,单机可以达到10万QPS以上,而且可以保证高可用性,性能很高,而且支持通过配置保证数据绝对不丢失,可以部署大规模的集群,还支持各种高级的功能,比如说延迟消息、事务消息、消息回溯、死信队列、消息积压,等等。
而且RocketMQ是基于Java开发的 。
有一点美中不足的地方,就是经过我的调查发现,RocketMQ的官方文档相对简单一些。
假设RocketMQ部署在一台机器上,即使这台机器配置很高,但是一般来说一台机器也就是支撑10万+的并发访问。
没关系,RocketMQ是可以集群化部署的,可以部署在多台机器上,假设每台机器都能抗10万并发,然后你只要让几十万请求分散到多台机器上就可以了,让每台机器承受的QPS不超过10万不就行了。
MQ会收到大量的消息,这些消息并不是立马就会被所有的消费方获取过去消费的,所以一般MQ都得把消息在自己本地磁盘存储起来,然后等待消费方获取消息去处理。
既然如此,MQ就得存储大量的消息,可能是几百万条,可能几亿条,甚至万亿条,这么多的消息在一台机器上肯定是没法存储的,RocketMQ是如何分布式存储海量消息的呢?
RocketMQ存储海量消息的机制就是分布式的存储。
所谓分布式存储,就是把数据分散在多台机器上来存储,每台机器存储一部分消息,这样多台机器加起来就可以存储海量消息了!
每台机器上部署的RocketMQ进程一般称之为Broker,每个Broker都会收到不同的消息,然后就会把这批消息存储在自己本地 的磁盘文件里这样的话,假设你有1亿条消息,然后有10台机器部署了RocketMQ的Broker,理论上不就可以让每台机器存储1000万条消息。
要是任何一台Broker突然宕机了怎么办?那不就会导致RocketMQ里一部分的消息就没了吗?这就会导致MQ的不可靠和不可用,这个问题怎么解决?
高可用:Broker主从架构以及多副本策略。
这个就是RocketMQ最基本的一个架构原理图。
Master Broker收到消息之后会同步给Slave Broker,这样Slave Broker上就能有一模一样的一份副本数据! 这样同一条消息在RocketMQ整个集群里不就有两个副本了,一个在Master Broker里,一个在Slave Broker里! 这个时候如果任何一个Master Broker出现故障,还有一个Slave Broker上有一份数据副本,可以保证数据不丢失,还能继续对外提供 服务,保证了MQ的可靠性和高可用性
大家怎么知道有哪些Broker?怎么知道要连接到哪一台Broker上去发送和接收消息?
NameServer:他也是独立部署在几台机器上的,然后所有的Broker都会把自己注册 到NameServer上去,NameServer不就知道集群里有哪些Broker了。
他们都是如何集群化部署抗高并发的?
他们对海量消息是如何分布式存储的?
他们是如何实现主从多备份的高可用架构的?
他们是如何实现集群路由让别人找到对应的机器发送消息和接收消息的
实RocketMQ这个技术一共是包含了四个核心的部分:
要部署RocketMQ,就得先部署NameServer,那么这个NameServer到底可以部署几台机器呢? 是一台机器?还是可以部署多台机器?如果部署多台机器,他们之间是怎么协同工作的?
NameServer是可以集群化部署的,保证高可用。NameServer一定会多机器部署,实现一个集群,起到高可用的效果,保证任何一台机器宕机,其他机器上的NameServer可以继续对外提供服务!
每个Broker启动都得向所有的NameServer进行注册 。也就是说,每个NameServer都会有一份集群中所有Broker的信息。
每个系统自己每隔一段时间,定时发送请求到NameServer去拉取最新的集群Broker。自己主动去NameServer拉取Broker信息的。
路由信息,大致可以理解为集群里的Broker信息以及其他相关的数据信息。
通过这些路由信息,每个系统就知道发送消息或者获取消息去哪台Broker上去进行了,这起到一个把消息路由到一个Broker上的效果,所以一般我们把这种信息叫做路由信息。
靠的是Broker跟NameServer之间的心跳机制,Broker会每隔30s给所有的NameServer发送心跳,告诉每个NameServer自己目前还活着。
每次NameServer收到一个Broker的心跳,就可以更新一下他的最近一次心跳的时间 。然后NameServer会每隔10s运行一个任务,去检查一下各个Broker的最近一次心跳时间,如果某个Broker超过120s都没发送心跳了, 那么就认为这个Broker已经挂掉了。
如果Broker挂掉了,那么作为生产者和消费者的系统是怎么感知到的呢?难道必须得NameServer发送请求给所有的系统通知他们吗?
可以有两种解决办法。
集群化部署、Broker会注册到所有NameServer去、30s心跳机制和120s故障感知机制、生产者和消费者的客户端容错机制
Kafka的路由中心实际上是一个非常复杂、混乱的存在。他是由ZooKeeper以及某个作为Controller的Broker共同完成的。
RabbitMQ的话自己本身就是由集群每个节点同时扮演了路由中心的角色。而RocketMQ是把路由中心抽离出来作为一个独立的NameServer角色运行的
为了保证MQ的数据不丢失而且具备一定的高可用性,所以一般都是得将Broker部署成Master-Slave模式的,也就是一个Master Broker对应一个Slave Broker。
RocketMQ的Master-Slave模式采取的是Slave Broker不停的发送请求到Master Broker去拉取消息。 就是RocketMQ自身的Master-Slave模式采取的是Pull模式拉取消息
作为消费者的系统在获取消息的时候,是从Master Broker获取的?还是从Slave Broker获取的?
有可能从Master Broker获取消息,也有可能从Slave Broker获取消息
作为消费者的系统在获取消息的时候会先发送请求到Master Broker上去,请求获取一批消息,此时Master Broker是会返回一批消息给消费者系统的。然后Master Broker在返回消息给消费者系统的时候,会根据当时Master Broker的负载情况和Slave Broker的同步情况,向消费者系
统建议下一次拉取消息的时候是从Master Broker拉取还是从Slave Broker拉取。
举例:
**有一点影响,但是影响不太大。**因 为消息写入全部是发送到Master Broker的,然后消息获取也可以走Master Broker,只不过有一些消息获取可能是从Slave Broker去走的。所以如果Slave Broker挂了,那么此时无论消息写入还是消息拉取,还是可以继续从Master Broke去走,对整体运行不影响。只不过少了Slave Broker,会导致所有读写压力都集中在Master Broker上。
这个时候就对消息的写入和获取都有一定的影响了。但是其实本质上而言,Slave Broker也是跟Master Broker一样有一份数据在的, 只不过Slave Broker上的数据可能有部分没来得及从Master Broker同步。
RocketMQ支持了一种新的机制,叫做Dledger,本身这个东西是基于Raft协议实现的一个机制。
把Dledger融入RocketMQ之后,就可以让一个Master Broker对应多个Slave Broker,也就是说一份数据可以有多份副 本,比如一个Master Broker对应两个Slave Broker。
一旦Master Broker宕机了,就可以在多个副本,也就是多个Slave中,通过Dledger技术和Raft协议算法进行leader选举,直接将 一个Slave Broker选举为新的Master Broker,然后这个新的Master Broker就可以对外提供服务了。整个过程也许只要10秒或者几十秒的时间就可以完成,这样的话,就可以实现Master Broker挂掉之后,自动从多个Slave Broker中选举出来一个新的Master Broker,继续对外服务,一切都是自动的。
有主从同步机制,那么有没有主从数据不一致的问题?Slave永远落后Master一些数据,这就是主从不一致。那么这种不一致 有没有什么问题?有办法保证主从数据强制一致吗?这样做又会有什么缺点呢?
首先做到高可用,要保证整个系统运行过程中任何一个环节宕机都不能影响系统的整体运行。
建议可以部署在三台机器上,这样可以充分保证NameServer作为路由中心的可用 性,哪怕是挂掉两台机器,只要有一个NameServer还在运行,就能保证MQ系统的稳定性。
NameServer的设计是采用的Peer-to-Peer的模式来做的,也就是可以集群化部署,但是里面任何一台 机器都是独立运行的,跟其他的机器没有任何通信。 每台NameServer实际上都会有完整的集群路由信息,包括所有的Broker节点信息,我们的数据信息,等等。所以只要任何一台 NameServer存活下来,就可以保证MQ系统正常运行,不会出现故障。
选择基于 Dledger的主备自动切换的功能来进行生产架构的部署。 而且Dledger技术是要求至少得是一个Master带两个Slave,这样有三个Broke组成一个Group,也就是作为一个分组来运行。一旦
Master宕机,他就可以从剩余的两个Slave中选举出来一个新的Master对外提供服务。然后Master Broker还会把数据同步给两个Slave Broker,保证一份数据在不同机器上有多份副本。
这个Broker会每隔30秒发送心跳到所有的NameServer 上去,然后每个NameServer都会每隔10s检查一次有没有哪个Broker超过120s没发送心跳的,如果有,就认为那个Broker已经宕机了,从路由信息里要摘除这个Broker。
Broker跟NameServer之间的通信是基于什么协议来进行的?
所以各个NameServer就是通过跟Broker建立好的长连接不断收到心跳包,然后定时检查Broker有没有120s都没发送心跳包,来判定集群里各个Broker到底挂掉了没有。
建议,就是无论作为生产者还是消费者的系统,都应该多机器集群化部署,保证他自己本身作为生产者或者消费者的高可用性。
因为一个系统如果就部署在一台机器上,然后作为生产者向MQ发送消息,那么一旦哪天机器上的生产者系统挂了,整个流程就断开了,不能保证高可用性。但是如果在多台机器上部署生产者系统,任何一台机器上的生产者挂了,其他机器上的生产者系统可以继续运行。
topic就是一个数据集合的意思。
举例:现在你的订单系统需要往MQ里发送订单消息,那么此时你就应该建一个Topic,他的名字可以叫做:topic_order_info,也就是一个包含了订单信息的数据集合。然后你的订单系统投递的订单消息都是进入到这个“topic_order_info”里面去的,如果你的仓储系统要获取订单消息,那么他可以指定从“topic_order_info”这里面去获取消息,获取出来的都是他想要的订单消息了。
一句话:Topic其实就是一个数据集合的意思,不同类型的数据你得放不同的Topic里去。
举例:要是你有一些商品数据要发送消息到MQ里,你就应该创建一个Topic叫做“topic_product_info”,代表里面都是商品数据,那些想要从MQ里获取商品数据的系统就可以从“topic_product_info”里获取了。 所以简单来说,你的系统如果要往MQ里写入消息或者获取消息,首先得创建一些Topic,作为数据集合存放不同类型的消息,比如说 订单Topic,商品Topic等等。
分布式存储。
例如:我们有一个订单Topic,可能订单系统每天都会往里面投递几百万条数据,然后这些数据在MQ集群上还得保留好多天,那么最终可能会有几千万的数据量,这还只是一个Topic。那么如果有很多的Topic,并且里面都有大量的数据,最终加起来的总和也许是一个惊人的数字,此时这么大量的数据本身是不太可能存放在一台机器上的。
在创建Topic的时候指定让他里面的数据分散存储在多台Broker机器上,比如一个Topic里有1000万条数据,此时有2台Broker,那么就可以让每台Broker上都放500万条数据。这样就可以把一个Topic代表的数据集合分布式存储在多台机器上了。
每个Broke在进行定时的心跳汇报给NameServer的时候,都会告诉NameServer自己当前的数据情况,比如该Broker有哪些Topic的哪些数据,都是属于路由信息的一部分。
生产者一定是投递消息到Master Broker的,然后Master Broker会同步数据给他的Slave Brokers,实现 一份数据多份副本,保证Master故障的时候数据不丢失,而且可以自动把Slave切换为Master提供服务。 比如:生产者发送订单数据,首先指定订单topic,然后根据nameserver从topic所在的broker中选一个,建立长链接发送数据。
他们也会跟NameServer建立长连接,然后拉取路由信息,接着找到自己要获取消息的Topic在哪几台Broker上,就可以跟Broker建立长连接,从里面拉取消息。消费者系统可能会从Master Broker拉取消息,也可能从Slave Broker拉取消息,都有可能,一切都看具体 情况。
整体架构:高可用、高并发、海量消息、可伸缩
最高负载: 在RocketMQ的TPS和机器的资源使用率和负载之间取得一个平衡。
比如RocketMQ集群在机器资源使用率极高的极端情况下可以扛到10万TPS,但是当他仅仅抗下8万TPS的时候,你会发现cpu负载、内存使用率、IO负载和网卡流量,都负载较高,但是可以接受,机器比较安全,不至于宕机。那么这个8万TPS实际上就是最合适的一个最高负载,
做压测:其实最主要的是综合TPS以及机器负载,尽量找到一个最高的TPS同时机器的各项负载在可承受范围之内,这才是压
测的目的。
千兆网卡的理论上限是每秒传输128M数据,但是一般实际最大值是每秒传输100M数据。
到底应该如何压测:应该在TPS和机器的cpu负载、内存使用率、jvm gc频率、磁盘io负载、网络流量负载之间取得一个平衡,尽量让TPS尽可能的提高,同时让机器的各项资源负载不要太高。
实际压测过程:采用几台机器开启大量线程并发读写消息,然后观察TPS、cpu load(使用top命令)、内存使用率(使用free命令)、jvm gc频率(使用jstat命令)、磁盘io负载(使用top命令)、网卡流量负载(使用sar命令),不断增加机器和线程,让TPS不断提升上去,同时观察各项资源负载是否过高。
生产集群规划:根据公司的后台整体QPS来定,稍微多冗余部署一些机器即可,实际部署生产环境的集群时,使用高配置物理机,同时合理调整os内核参数、jvm参数、中间件核心参数,如此即可。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/mingyuli/article/details/120509912
内容来源于网络,如有侵权,请联系作者删除!