为什么我们要用MQ? 最关键点我认为是解耦,这样各系统间不用有太多的相互依赖,按需消费即可。再者是异步,提高服务性能。然后就是削峰,防止过多流量涌入而给服务器带来压力。
那用MQ会有哪些问题呢?我们调用接口的话基本就是调用成功或超时重试再不行打个日志,那MQ呢,首先属于中间件产品,它本身的可用性有没有保证?如何保证的?发的消息可能丢失吗?会不会延迟?重复发?到达的消息能按顺序吗?如果都可以的话,该怎么选择适合自己的MQ呢,运维成本怎么样?...都可以反问自己。
MQ会不会丢消息呢?这点可以想下哪些链路可能导致消息丢失呢,无非是三点:调用方到MQ的过程丢了 ;MQ本身重启了;MQ到消费方过程丢了。其实都是有办法避免的,MQ本身有确认机制,比如我们配置当MQ收到消息并持久化成功后再返回调用方一个ack,这样就能保证1,2点正常,同理,当消费方成功消费后再返回MQ一个ack,否则一直重试,这样第3点也保证了。
MQ消息延迟怎么办?也可以从为什么延迟出发,是不是消息太多了呢,是否需要增加消费者,是否可以先简单记录快速丢弃再找个时间补齐数据;
MQ消息会不会重复发?关于这点呢,我觉得最好的做法是自己服务去保证就算重发了也不会有什么问题,比如设置消息id什么的,或者一些幂等处理之类。
MQ消息顺序能保证吗?关于这点可以根据具体的MQ来思考下,比方说kafka,它可以根据key做分片,比如某一个产品id下的始终路由到一台消费机,这个时候如果是单线程是有序的,多线程的话其实可以再考虑根据规则弄一个内存队列,这样去保证某一个key下的消息顺序消费。其它MQ类似的去思考。如果实在不能保证,消息可以带上时间戳,比如评论的场景,先收到删除,再收到添加,这个时候发现添加的时间戳大于删除就放弃执行也是可以的。
回到很重点的一个问题,MQ如何保证高可用呢,万一运行着突然挂了,或者磁盘坏了,那没有消费完成的数据怎么办?这个又得结合具体的某一款MQ来分析了,比如kafka,这个据说天然分布式的设计是怎么样的:它采用划分分片+HA副本机制来设计的,一个topic的消息可以被划分成多个partition,每个partition又可以放入不同的节点去,这样达到了分布式;然后每个partition会同步数据到其它的机器,形成多副本,并选举leader,生产消费只和leader打交道,还可以设置消息写入所有副本之后才表示成功,这样是不是就搞定啦。至于RabbitMQ,这个的设计并不是分布式的,但是有普通集群模式和镜像集群模式两种,单机的就不说了哈,普通集群模式:queue只会放在一台实例,消费的时候如果拉到了其它实例,会从原queue在的实例再拉一下,这样如果原queue的挂了,貌似就gg了;镜像集群模式:每个实例都会同步queue的全部信息。这样也有个问题是queue不能太大了,不能超过单实例的存储限制。
如果是你自己设计MQ,你会怎么设计呢?