中间件(二):MQ技术

x33g5p2x  于2021-09-28 转载在 其他  
字(10.6k)|赞(0)|评价(0)|浏览(331)

1、技术调研应该怎么做?

技术调研:就是对一个技术去找到一些业内常用的开源实现,然后对各种不同的实现都进行一些调研,对比一下他们的优劣势,看看谁比较符合我们的需求,谁比较适合我们来使用。
具体来说,比如对于我们现在的情况,你只知道有一个MQ的概念,但是你要考虑一下:

  1. 业内常用的MQ有哪些?
  2. 每一种MQ各自的表现如何 ?MQ的优劣势?
  3. 这些MQ在同等机器条件下,能抗多少QPS(每秒抗几千QPS还是几万QPS)?
  4. 性能有多高(发送一条消息给他要2ms还是20ms)?
  5. 可用性能不能得到保证(要是MQ部署的机器挂了怎么办)?
  6. 他们会不会丢失数据?
  7. 如果需要的话能否让他们进行线性的集群扩容(就是多加几台机器)?
  8. 消息中间件经常需要使用的一些功能他们都有吗(比如说延迟消息、事务消息、消息堆积、消息回溯、死信队列,等等)?
  9. 另外还得考虑这些MQ在文档是否齐全?
  10. 社区是否活跃?
  11. 在行业内是否广泛运用?
  12. 是用什么语言编写的?

2、Kafka、RabbitMQ、RocketMQ三种技术调研

说明:ActiveMQ主要是几年以前较多公司使用,现在几乎国内用的公司都很少了。

2.1、kafka

Kafka的吞吐量几乎是行业里最优秀的,在常规的机器配置下,一台机器可以达到每秒十几万的QPS。Kafka性能也很高,基本上发送消息给Kafka都是毫秒级的性能。可用性也很高,Kafka是可以支持集群部署的,其中部分机器宕机是可以继续运行的。

Kafka比较为人诟病的一点,似乎是丢数据方面的问题,因为Kafka收到消息之后会写入一个磁盘缓冲区里,并没有直接落地到物理磁盘上去,所以要是机器本身故障了,可能会导致磁盘缓冲区里的数据丢失。 而且Kafka另外一个比较大的缺点,就是功能非常的单一,主要是支持发送消息给他,然后从里面消费消息,其他就没有什么额外的高级功能了。

基本行业里的一个标准,是把Kafka用在用户行为日志的采集和传输上,比 如大数据团队要收集APP上用户的一些行为日志,这种日志就是用Kafka来收集和传输的。

2.2、RabbitMQ

RabbitMQ的优势在于可以保证数据不丢失,也能保证高可用性,即集群部署的时候部分机器宕机可以继续运行,然后支持部分高级功能,比如说死信队列,消息重试之类的。

缺点就是RabbitMQ的吞吐量是比较低的,一般就是每秒几万的级别。 一个较为致命的缺陷,就是他的开发语言是erlang。

2.3、RocketMQ

RocketMQ是阿里开源的消息中间件,久经沙场,非常的靠谱。他几乎同时解决了Kafka和RabbitMQ的缺陷。 RocketMQ的吞吐量也同样很高,单机可以达到10万QPS以上,而且可以保证高可用性,性能很高,而且支持通过配置保证数据绝对不丢失,可以部署大规模的集群,还支持各种高级的功能,比如说延迟消息、事务消息、消息回溯、死信队列、消息积压,等等。
而且RocketMQ是基于Java开发的 。

 有一点美中不足的地方,就是经过我的调查发现,RocketMQ的官方文档相对简单一些。

3、MQ面试

  1. 了解过哪几种MQ?
  2. 然后你过往的工作中使用过哪几种MQ?
  3. 你对这些了解过的MQ有什么看法?
  4. 你觉得他们的优劣势分别是什么?
  5. 如果你以前用过MQ,那么你用他解决了什么问题?
  6. 当时解决的效果如何?
  7. 另外你在使用某个MQ的时候感受如何,觉得他好用吗?
  8. 你是否觉得用过的MQ存在某些缺陷?
  9. 如果现在你们公司里就部署了MQ,是哪一种MQ?
  10. 你的系统里使用到MQ了吗?
  11. 用MQ来解决什么问题呢?
  12. 解决的效果如何?是否遇到过什么问题?
  13. 另外,有没有思考过,为什么你们要选用这个MQ?
  14. 当时选用他的理由是什么?

4、Rocket原理

  • Rocket是如何运行的,即原理?
  • RocketMQ是如何集群化部署来承载高并发访问的?
  • 如果RocketMQ中要存储海量消息,如何实现分布式存储架构?

4.1、MQ如何集群化部署来支撑高并发访问?

假设RocketMQ部署在一台机器上,即使这台机器配置很高,但是一般来说一台机器也就是支撑10万+的并发访问。
没关系,RocketMQ是可以集群化部署的,可以部署在多台机器上,假设每台机器都能抗10万并发,然后你只要让几十万请求分散到多台机器上就可以了,让每台机器承受的QPS不超过10万不就行了。

4.2**、MQ如果要存储海量消息应该怎么做?**

MQ会收到大量的消息,这些消息并不是立马就会被所有的消费方获取过去消费的,所以一般MQ都得把消息在自己本地磁盘存储起来,然后等待消费方获取消息去处理。
既然如此,MQ就得存储大量的消息,可能是几百万条,可能几亿条,甚至万亿条,这么多的消息在一台机器上肯定是没法存储的,RocketMQ是如何分布式存储海量消息的呢?

RocketMQ存储海量消息的机制就是分布式的存储。
        所谓分布式存储,就是把数据分散在多台机器上来存储,每台机器存储一部分消息,这样多台机器加起来就可以存储海量消息了!

每台机器上部署的RocketMQ进程一般称之为Broker,每个Broker都会收到不同的消息,然后就会把这批消息存储在自己本地 的磁盘文件里这样的话,假设你有1亿条消息,然后有10台机器部署了RocketMQ的Broker,理论上不就可以让每台机器存储1000万条消息。

4.3、高可用如何保障?

要是任何一台Broker突然宕机了怎么办?那不就会导致RocketMQ里一部分的消息就没了吗?这就会导致MQ的不可靠和不可用,这个问题怎么解决?
高可用:Broker主从架构以及多副本策略。

这个就是RocketMQ最基本的一个架构原理图。

Master Broker收到消息之后会同步给Slave Broker,这样Slave Broker上就能有一模一样的一份副本数据! 这样同一条消息在RocketMQ整个集群里不就有两个副本了,一个在Master Broker里,一个在Slave Broker里! 这个时候如果任何一个Master Broker出现故障,还有一个Slave Broker上有一份数据副本,可以保证数据不丢失,还能继续对外提供 服务,保证了MQ的可靠性和高可用性

4.4、如何数据路由?

大家怎么知道有哪些Broker?怎么知道要连接到哪一台Broker上去发送和接收消息?
NameServer:他也是独立部署在几台机器上的,然后所有的Broker都会把自己注册 到NameServer上去,NameServer不就知道集群里有哪些Broker了。

  • 如果他要发送消息到Broker,会找NameServer去获取路由信息,就是集群里有哪些Broker等信息
  • 如果系统要从Broker获取消息,也会找NameServer获取路由信息,去找到对应的Broker获取消息。

5、从架构原理对吧kafka、rocketMQ、robbitMQ

他们都是如何集群化部署抗高并发的?

他们对海量消息是如何分布式存储的?
他们是如何实现主从多备份的高可用架构的?

他们是如何实现集群路由让别人找到对应的机器发送消息和接收消息的

6、RocketMQ总结

实RocketMQ这个技术一共是包含了四个核心的部分:

  • 第一块就是他的NameServer,这个东西很重要,他要负责去管理集群里所有Broker的信息,让使用MQ的系统可以通过他感知到集群里有哪些Broker。
  • 第二块就是Broker集群本身了,必须得在多台机器上部署这么一个集群,而且还得用主从架构实现数据多副本存储和高可用。
  • 第三块就是向MQ发送消息的那些系统了,这些系统一般称之为生产者,这里也有很多细节是值得深究的,因为这些生产者到底是如何从NameServer拉取路由信息的?如何选择Broker机器建立连接以及发送消息的?
  • 第四块就是从MQ获取消息的那些系统,这些系统一般称之为消费者。

7、NameServer的技术原理

7.1、NameServer需要集群化?

要部署RocketMQ,就得先部署NameServer,那么这个NameServer到底可以部署几台机器呢? 是一台机器?还是可以部署多台机器?如果部署多台机器,他们之间是怎么协同工作的?

NameServer是可以集群化部署的,保证高可用。NameServer一定会多机器部署,实现一个集群,起到高可用的效果,保证任何一台机器宕机,其他机器上的NameServer可以继续对外提供服务!

7.2、Broker在启动时是把自己的信息注册到哪个NameServer上去?

每个Broker启动都得向所有的NameServer进行注册 。也就是说,每个NameServer都会有一份集群中所有Broker的信息。

 7.3、系统如何从NameServer获取Broker信息?

每个系统自己每隔一段时间,定时发送请求到NameServer去拉取最新的集群Broker。自己主动去NameServer拉取Broker信息的
        路由信息,大致可以理解为集群里的Broker信息以及其他相关的数据信息。

通过这些路由信息,每个系统就知道发送消息或者获取消息去哪台Broker上去进行了,这起到一个把消息路由到一个Broker上的效果,所以一般我们把这种信息叫做路由信息。

 7.4、如果Broker挂了,NameServer是怎么感知到的?

靠的是Broker跟NameServer之间的心跳机制,Broker会每隔30s给所有的NameServer发送心跳,告诉每个NameServer自己目前还活着。

每次NameServer收到一个Broker的心跳,就可以更新一下他的最近一次心跳的时间 。然后NameServer会每隔10s运行一个任务,去检查一下各个Broker的最近一次心跳时间,如果某个Broker超过120s都没发送心跳了, 那么就认为这个Broker已经挂掉了。

7.5、Broker挂了,系统是怎么感知到的?

如果Broker挂掉了,那么作为生产者和消费者的系统是怎么感知到的呢?难道必须得NameServer发送请求给所有的系统通知他们吗?

可以有两种解决办法。

  • 首先,你可以考虑不发送消息到那台Broker,改成发到其他Broker上去。
  • 其次,假设你必须要发送消息给那台Broker,那么他挂了,他的Slave机器是一个备份,可以继续使用,你是不是可以考虑等一会儿去跟他的Slave进行通信?
    总之,这些都是思路,但是现在我们先知道,对于生产者而言,他是有一套容错机制的,即使一下子没感知到某个Broker挂了,他可以 有别的方案去应对。 而且过一会儿,系统又会重新从NameServer拉取最新的路由信息了,此时就会知道有一个Broker已经宕机了。

总结:

集群化部署、Broker会注册到所有NameServer去、30s心跳机制和120s故障感知机制、生产者和消费者的客户端容错机制

8、kafka和robbitMQ的路由中心区别

 Kafka的路由中心实际上是一个非常复杂、混乱的存在。他是由ZooKeeper以及某个作为Controller的Broker共同完成的。

RabbitMQ的话自己本身就是由集群每个节点同时扮演了路由中心的角色。而RocketMQ是把路由中心抽离出来作为一个独立的NameServer角色运行的

9、Borker原理

9.1、Master Broker是如何将消息同步给Slave Broker的?

为了保证MQ的数据不丢失而且具备一定的高可用性,所以一般都是得将Broker部署成Master-Slave模式的,也就是一个Master Broker对应一个Slave Broker。

RocketMQ的Master-Slave模式采取的是Slave Broker不停的发送请求到Master Broker去拉取消息。 就是RocketMQ自身的Master-Slave模式采取的是Pull模式拉取消息

9.2、RocketMQ 实现读写分离了吗?

作为消费者的系统在获取消息的时候,是从Master Broker获取的?还是从Slave Broker获取的?

有可能从Master Broker获取消息,也有可能从Slave Broker获取消息

作为消费者的系统在获取消息的时候会先发送请求到Master Broker上去,请求获取一批消息,此时Master Broker是会返回一批消息给消费者系统的。然后Master Broker在返回消息给消费者系统的时候,会根据当时Master Broker的负载情况和Slave Broker的同步情况,向消费者系
统建议下一次拉取消息的时候是从Master Broker拉取还是从Slave Broker拉取。

举例:

  • 例1、要是这个时候Master Broker负载很重,本身要抗10万写并发了,你还要从他这里拉取消息,给他加重负担,那肯定是不合适的。所以此时Master Broker就会建议你从Slave Broker去拉取消息。
  • 例2、本身这个时候Master Broker上都已经写入了100万条数据了,结果Slave Broke不知道啥原因,同步的特别慢,才同步了96万条数据,落后了整整4万条消息的同步,这个时候你作为消费者系统可能都获取到96万条数据了,那么下次还是只能从Master Broker去拉取消息。因为Slave Broker同步太慢了,导致你没法从他那里获取更新的消息了。
    所以这一切都会由Master Broker根据情况来决定,

  • 在写入消息的时候,通常来说肯定是选择Master Broker去写入的
  • 在拉取消息的时候,有可能从Master Broker获取,也可能从Slave Broker去获取,一切都根据当时的情况

9.3、如果Slave Broke挂掉了有什么影响?

**有一点影响,但是影响不太大。**因 为消息写入全部是发送到Master Broker的,然后消息获取也可以走Master Broker,只不过有一些消息获取可能是从Slave Broker去走的。所以如果Slave Broker挂了,那么此时无论消息写入还是消息拉取,还是可以继续从Master Broke去走,对整体运行不影响。只不过少了Slave Broker,会导致所有读写压力都集中在Master Broker上。

9.4、如果Master Broker挂掉了该怎么办?

这个时候就对消息的写入和获取都有一定的影响了。但是其实本质上而言,Slave Broker也是跟Master Broker一样有一份数据在的, 只不过Slave Broker上的数据可能有部分没来得及从Master Broker同步。

9.5、基于Dledger实现RocketMQ高可用自动切换

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,继续对外服务,一切都是自动的。

9.6、问题

有主从同步机制,那么有没有主从数据不一致的问题?Slave永远落后Master一些数据,这就是主从不一致。那么这种不一致 有没有什么问题?有办法保证主从数据强制一致吗?这样做又会有什么缺点呢?

10、MQ生产架构部署

首先做到高可用,要保证整个系统运行过程中任何一个环节宕机都不能影响系统的整体运行。

10.1、nameserver集群化部署,保证高可用

建议可以部署在三台机器上,这样可以充分保证NameServer作为路由中心的可用 性,哪怕是挂掉两台机器,只要有一个NameServer还在运行,就能保证MQ系统的稳定性。

NameServer的设计是采用的Peer-to-Peer的模式来做的,也就是可以集群化部署,但是里面任何一台 机器都是独立运行的,跟其他的机器没有任何通信。 每台NameServer实际上都会有完整的集群路由信息,包括所有的Broker节点信息,我们的数据信息,等等。所以只要任何一台 NameServer存活下来,就可以保证MQ系统正常运行,不会出现故障。

10.2、Broke集群化部署

选择基于 Dledger的主备自动切换的功能来进行生产架构的部署。 而且Dledger技术是要求至少得是一个Master带两个Slave,这样有三个Broke组成一个Group,也就是作为一个分组来运行。一旦

Master宕机,他就可以从剩余的两个Slave中选举出来一个新的Master对外提供服务。然后Master Broker还会把数据同步给两个Slave Broker,保证一份数据在不同机器上有多份副本。 

10.3、Broker是如何跟NameServer进行通信的?

这个Broker会每隔30秒发送心跳到所有的NameServer 上去,然后每个NameServer都会每隔10s检查一次有没有哪个Broker超过120s没发送心跳的,如果有,就认为那个Broker已经宕机了,从路由信息里要摘除这个Broker。

Broker跟NameServer之间的通信是基于什么协议来进行的?

  • 在RocketMQ的实现中,采用的是TCP长连接进行通信。
  • 也就是说,Broker会跟每个NameServer都建立一个TCP长连接,然后定时通过TCP长连接发送心跳请求过去

所以各个NameServer就是通过跟Broker建立好的长连接不断收到心跳包,然后定时检查Broker有没有120s都没发送心跳包,来判定集群里各个Broker到底挂掉了没有。

10.4、生产消费者集群化部署

建议,就是无论作为生产者还是消费者的系统,都应该多机器集群化部署,保证他自己本身作为生产者或者消费者的高可用性。

因为一个系统如果就部署在一台机器上,然后作为生产者向MQ发送消息,那么一旦哪天机器上的生产者系统挂了,整个流程就断开了,不能保证高可用性。但是如果在多台机器上部署生产者系统,任何一台机器上的生产者挂了,其他机器上的生产者系统可以继续运行。
 

11、MQ的核心数据模型

11.1**、**Topic到底是什么?

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等等。

11.2、Topic作为一个数据集合是怎么在Broker集群里存储的?

分布式存储。

例如:我们有一个订单Topic,可能订单系统每天都会往里面投递几百万条数据,然后这些数据在MQ集群上还得保留好多天,那么最终可能会有几千万的数据量,这还只是一个Topic。那么如果有很多的Topic,并且里面都有大量的数据,最终加起来的总和也许是一个惊人的数字,此时这么大量的数据本身是不太可能存放在一台机器上的。
在创建Topic的时候指定让他里面的数据分散存储在多台Broker机器上,比如一个Topic里有1000万条数据,此时有2台Broker,那么就可以让每台Broker上都放500万条数据。这样就可以把一个Topic代表的数据集合分布式存储在多台机器上了。

每个Broke在进行定时的心跳汇报给NameServer的时候,都会告诉NameServer自己当前的数据情况,比如该Broker有哪些Topic的哪些数据,都是属于路由信息的一部分。

11.3**、生产者系统是如何将消息发送给Broker的?**

  • 在发送消息之前,得先有一个Topic,然后在发送消息的时候你得指定你要发送到哪个Topic里面去。
  • 跟NameServer建立一个TCP长连接,然后定时从他那里拉取到最新的路由信息,包括集群里有哪些Broker,集群里有哪些Topic,每个Topic那些数据都存储在哪些Broker上。
  • 然后生产者系统自然就可以通过路由信息找到自己要投递消息的Topic分布在哪几台Broker上,此时可以根据负载均衡算法,从里面选择一台Broke机器出来,比如round robine轮询算法,或者是hash算法。

生产者一定是投递消息到Master Broker的,然后Master Broker会同步数据给他的Slave Brokers,实现 一份数据多份副本,保证Master故障的时候数据不丢失,而且可以自动把Slave切换为Master提供服务。 比如:生产者发送订单数据,首先指定订单topic,然后根据nameserver从topic所在的broker中选一个,建立长链接发送数据。

11.4、消费者是如何从Broker上拉取消息的?

他们也会跟NameServer建立长连接,然后拉取路由信息,接着找到自己要获取消息的Topic在哪几台Broker上,就可以跟Broker建立长连接,从里面拉取消息。消费者系统可能会从Master Broker拉取消息,也可能从Slave Broker拉取消息,都有可能,一切都看具体 情况。

总结

整体架构:高可用、高并发、海量消息、可伸缩

  • 实现完全高可用的,因为NameServer随便一台机器挂了都不怕,他是集群化部署的,每台机器都有完整的路由信息;Broker随便挂了一台机器也不怕,挂了Slave对集群没太大影响,挂了Master也会基于Dledger技术实现自动Slave切换为Master;生产者系统和消费者系统随便挂了一台都不怕,因为他们都是集群化部署的,其他机器会接管工作。
  • 抗下高并发,因为假设订单系统对订单Topic要发起每秒10万QPS的写入,那么只要订单Topic分散在比如5台Broker上,实际上每个Broker会承载2万QPS写入,也就是说高并发场景下的10万QPS可以分散到多台Broker上抗下来。
  • 然后集群足以存储海量消息,因为所有数据都是分布式存储的,每个Topic的数据都是存储在多台Broker机器上的,用集群里多台Master Broker就足以存储海量的消息。所以,用多个Master Broker部署的方式,加上Topic分散在多台Broker上的机制,可以抗下高并发访问以及海量消息的分布式存储。
  • 然后每个Master Broker有两个Slave Broker结合Dledger技术可以实现故障时的自动Slave-Master切换,实现高可用性。
  • 伸缩性,就是说如果要抗更高的并发,存储跟多的数据,完全可以在集群里加入更多的Broker机器,这样就可以线性扩展集群了。

12、中间件压测

  • (1)中间件系统在压测或者上生产之前,需要对三大块参数进行调整:OS内核参数、JVM参数以及中间件核心参数
  • **(2)**OS内核参数主要调整的地方都是跟磁盘IO、网络通信、内存管理以及线程管理有关的,需要适当调节大小
  • **(3)**JVM参数需要我们去中间件系统的启动脚本中寻找他的默认JVM参数,然后根据机器的情况,对JVM的堆内存大小,新生代大小,Direct Buffer大小,等等,做出一些调整,发挥机器的资源
  • **(4)**中间件核心参数主要也是关注其中跟网络通信、磁盘IO、线程数量、内存 管理相关的,根据机器资源,适当可以增加网络通信线程,控制同步刷磁盘或者异步刷磁盘,线程数量有多少,内存中一些队列的大小

13、最高负载 

最高负载: 在RocketMQ的TPS和机器的资源使用率和负载之间取得一个平衡。

比如RocketMQ集群在机器资源使用率极高的极端情况下可以扛到10万TPS,但是当他仅仅抗下8万TPS的时候,你会发现cpu负载、内存使用率、IO负载和网卡流量,都负载较高,但是可以接受,机器比较安全,不至于宕机。那么这个8万TPS实际上就是最合适的一个最高负载,
做压测:其实最主要的是综合TPS以及机器负载,尽量找到一个最高的TPS同时机器的各项负载在可承受范围之内,这才是压

测的目的。

14、压测总结

千兆网卡的理论上限是每秒传输128M数据,但是一般实际最大值是每秒传输100M数据。

到底应该如何压测:应该在TPS和机器的cpu负载、内存使用率、jvm gc频率、磁盘io负载、网络流量负载之间取得一个平衡,尽量让TPS尽可能的提高,同时让机器的各项资源负载不要太高。

实际压测过程:采用几台机器开启大量线程并发读写消息,然后观察TPS、cpu load(使用top命令)、内存使用率(使用free命令)、jvm gc频率(使用jstat命令)、磁盘io负载(使用top命令)、网卡流量负载(使用sar命令),不断增加机器和线程,让TPS不断提升上去,同时观察各项资源负载是否过高。
生产集群规划:根据公司的后台整体QPS来定,稍微多冗余部署一些机器即可,实际部署生产环境的集群时,使用高配置物理机,同时合理调整os内核参数、jvm参数、中间件核心参数,如此即可。

相关文章

微信公众号

最新文章

更多

目录