李成笔记网

专注域名、站长SEO知识分享与实战技巧

高并发架构——消息队列(消息队列重发)

为什么要使用消息队列?

解耦、异步、削峰

mysql每秒写入2000就会出现瓶颈。


消息队列有什么优缺点?

系统可用性降低,如 mq挂了,整个系统就崩溃了;

系统复杂度提高,如怎么保障消息没有重复、顺序性、消息丢失问题;

一致问题,如a系统成功返回,但是bc 系统中 ,c处理失败。


如何保证消息队列的高可用性

rabbitmq 分以下几种模式:

单机模式;

普通集群模式(无高可用性):

多台机器上启动多个实例,每个机器上启动一个。创建的queue,只会在一个rabbitmq实例上,但每台实例都会同步所有的queue的元数据(元数据就是queue的一些配置信息,通过元数据可以找到对应的queue实例)。当消费连到另外的B实例,那么B实例会从queue所在A实例上拉取数据过来,会导致数据拉取开销。当固定连接queue实例会导致单实例性能瓶颈。

镜像集群模式(高可用性):

每个实例上都有所有实例的全量的元数据和queue的消息。

好处--任何一台宕机都没影响,其他实例包含这个实例queue的完整实例。

坏处--性能开销太大,消息需要同步到所有实例上,导致带宽和消耗;没法线性扩展,不是分布式,新加机器也要包含所有的queue数据。


kafka高可用性

kafka基本组成:由多个broker组成,每个broker是一个节点;创建一个topic可以划分为多个partition,每个partition可以存在于不同的broker上,每个partition放一部分数据。

高可用机制:replica(复制品)副本机制。每个partition的数据都会同步到其他机器上,形成多个replica副本。所有replica会选举一个leader出来,生产和消费都跟这个leader打交道,然后其他replica是follower。写入时,leader会负责把数据同步到所有follower上去,读取时就直接读leader上数据。只读写leader,如果要随意读写每个follower,那么就得关心数据一致性的问题。kafka会均匀地将一个partition的所有replica分布在不同机器上,提供容错性。

kafka消费时,只会读leader,但是只有当一个消息被所有follower都同步成功返回ack的时候,这个消息才会被消费者读到。


如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?

rabbitmq、kafka都会出现消息重复的情况,这是正常的。我们应该在业务开发时保证消息不重复消费。

幂等性,指同一个请求给你重复多次,数据库得保证对应的数据不会改变,不能出错。解决此问题要结合业务来,比如:在生产者方给每条数据加一个全局变量id, 消费时在缓存里面检查一下是否已经消费过


如何保证消息的可靠性传输?或者说,如何处理消息丢失问题?

rabbitmq消息丢失:

生产者端:开启rabbitmq事务,(同步,不推荐);开启confirm模式(异步,推荐)

mq端:开启rabbitmq持久化;

消费者端:关闭rabbitmq自动ack;


kafka消息丢失:

消费者端:消费者自动提交了offset,让kafka以为已经消费好这个消息,但你才刚准备处理这个消息,但你还没来得及处理,自己就先挂掉。

kafka端:某个broker宕机,然后重选partition的leader,此时宕机,follower没同步完数据,然后再选举leader,会出现数据丢失。一般设置几个参数可以防止:

给topic设置 replication.factor参数:这个值大于1,且每个partition要有2个副本。

给kafka服务端设置min.insync.replicas参数:值大于1,这个值要求一个leader至少感应一个follower跟自己保持联系,这样才能在leader宕机时,还有一个follower数据是同步完成的。

在生产者端设置acks=all 参数: 要求每条数据,必须写入所有replica副本后,才可认为是写成功;

在生产者端设置retries=MAX参数:要求写失败后,进行无限重试。


如何保证消息的顺序性?

rabbitmq

拆分多个queue,每个queue一个consumer。


kafka

一个topic,一个partition,一个consumer,内部单线程消费,单线程吞吐低,一般不会用这个;

写N个内存queue,具体相同key的数据都到一个内存queue,然后对于N个线程,每个线程分别消费一个内存queue即可。


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

大量消息积压,只能紧急扩容,如下思路:

先修复消费者问题,确保其恢复消费速度,然后将现有消费都停掉;

新建一个topic,partition是原来10倍,临时建立好原来10倍的queue数量;

然后写一个临时的分发数据的消费者程序,这个应用部署上去消费积压的数据,消费后不做耗时处理,直接均匀写入临时建好的10倍数量的queue。

接着临时征用10倍的机器来部署消费者,每批消费者消费一个临时queue的数据。相当于临时将queue和consumer资源扩大10倍,以正常10倍速度来消费数据。

等快速消费完积压数据之后,得恢复原先部署的架构,重新用原先的consumer机器来消费消息。


mq中消息过期失效

对于Rabbitmq可以设置过期时间TTL。消息过期大量的数据会被直接丢弃。可以采取批量重导,过了用户使用高峰,用新写的程序,将丢失的数据,一点点查找出来并重新灌入mq里,把丢失的补救回来。


mq快写满了

临时程序来消费,消费一个丢一个,快消费掉所有消息,走第二个方案,晚上补救数据。


如果让你写一个消息队列,该如何进行架构设计?谈下思路

消息队列系统,如下几个角度:

mq具备可伸缩性,支持快速扩容,随时增加吞吐量和容量。如kafka设计理念,broker->topic->partition,每个partition放一个机器,就存一部分数据。如果资源不够用就给topic增加partition,然后做数据迁移,增加机器,不就可以存放更多数据提高吞吐量了。

mq数据要落地磁盘,才能保证别的进程挂了数据不会就丢了。保证磁盘 顺序写 ,这样就没磁盘随机读写的寻址开销,磁盘顺序读写性能很高,这是kafka思路。

mq可用性,kafka的高可用性保障机制,多副本->leader&follower->broker挂了重新选举leader

mq支持0数据丢失。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言