目录

消息队列

什么是消息队列?

  • 首先队列是先进先出,消息队列MQ可以简单理解成把要传输的数据放在队列中,主要解决应用耦合、异步消息、流量削锋等问题,

  • 我认为大多数项目引入消息队列都是为了解决错峰流控和服务解耦这两主要问题。

  • 错峰:线上部署的系统所面对的请求量会存在高峰和低谷,每天的23:00 - 8:00系统每秒接收的请求数为100,8:00 - 22:00系统每秒接收的请求数为3K+, 而到了22:00 - 23:00这个时间段,系统每秒接收的请求数为1W+。面对这种情况,我们不可能将系统的QPS(每秒查询)设计为1W+, 将MQ引入系统架构中,便解决了这种大流量冲击问题。假设将系统的QPS(每秒查询)设计为4K,满足了8:00 - 22:00的正常流量需求, 在22:00 - 23:00时间段里,可以先把所有的接收的请求放进MQ,系统仍然以4K的速度处理从MQ中请求,无法处理的积压在MQ中在23:00 - 8:00完成处理。 这样既防止了系统处理请求的速度始终没超过Max,也使系统在有限的资源情况下平稳的完成大流量请求。

  • 流控:系统的上下游接口对同一请求的处理速度是不一致的,上游的A接口一秒处理完100个请求就会把100份数据直接丢给下游B接口, 而B接口的处理速度可能是一秒50个,这种情况下便会让B接口直接挂掉。此时,如果引入了MQ,可以让A接口处理完后直接写入MQ, 在让MQ以每秒50个的速度发送给下游B接口处理,协调了系统各接口通信能力。

  • 服务解耦:以电商下单为例,下单步骤:用提交订单->预扣库存->生成订单->付款消费成功->通知配送系统->通知商家系统->通知后台系统计入财务、日志等模块这几个步骤。 当系统没有解耦时,顾客每个订单都是串行执行,需要等待时间太多,同时也浪费了接口的并发带来的性能提高。当引入消息队列对系统架构就行解耦, 用户可在订单系统生成订单后就直接返回,使用MQ后续同时处理剩余流程。既不影响整个业务的体验,而且在性能和响应速度上有了极大提升。

如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?

  • 消息积压处理办法:临时紧急扩容: 先修复 consumer(肯修摸) 的问题,确保其恢复消费速度,然后将现有 cnosumer 都停掉。 新建一个 topic,partition 是原来的 10 倍,临时建立好原先 10 倍的 queue数量。 然后写一个临时的分发数据的 consumer 程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理, 直接均匀轮询写入临时建立好的 10 倍数量的 queue。接着临时征用 10 倍的机器来部署 consumer,每一批 consumer 消费一个临时 queue 的数据。 这种做法相当于是临时将 queue 资源和 consumer 资源扩大 10 倍,以正常的 10 倍速度来消费数据。 等快速消费完积压数据之后,得恢复原先部署的架构,重新用原先的consumer 机器来消费消息。 MQ 中消息失效:假设你用的是 RabbitMQ,RabbtiMQ 是可以设置过期时间的,也就是 TTL。如果消息在 queue 中积压超过一定的时间就会被 RabbitMQ 给清理掉, 这个数据就没了。那这就是第二个坑了。这就不是说数据会大量积压在 mq 里,而是大量的数据会直接搞丢。 我们可以采取一个方案,就是批量重导,这个我们之前线上也有类似的场景干过。就是大量积压的时候,我们当时就直接丢弃数据了, 然后等过了高峰期以后,比如大家一起喝咖啡熬夜到晚上 12 点以后,用户都睡觉了。这个时候我们就开始写程序,将丢失的那批数据,写个临时程序, 一点一点的查出来,然后重新灌入 mq 里面去,把白天丢的数据给他补回来。也只能是这样了。假设 1 万个订单积压在 mq 里面,没有处理, 其中 1000个订单都丢了,你只能手动写程序把那 1000 个订单给查出来,手动发到 mq 里去再补一次。 mq 消息队列块满了:如果消息积压在 mq 里, 你很长时间都没有处理掉,此时导致 mq 都快写满了,咋办?这个还有别的办法吗? 没有,谁让你第一个方案执行的太慢了,你临时写程序,接入数据来消费,消费一个丢弃一个,都不要了,快速消费掉所有的消息。 然后走第二个方案,到了晚上再补数据吧。