消息队列作用一文介绍了为什么要使用消息队列。我们再来讨论下如何有效使用消息队列。
消息队列模式
目前主流消息队列主要由两种模式,1个是点对点模式,1个是发布订阅模式。简单做下介绍
- 点对点模式
1个消息只会被一个消费者消费。可以有一个或者多个消费者同时消费一个队列,但是被消费的消息不会重复。 - 发布订阅模式
消息可以被多个消费者消费。此类队列一般被称为一个topic,所有订阅该topic的consumer都可消费所有消息。
目前市面上有很多消息队列产品,ActiveMq,RabbitMQ,Kafka,ZeroMQ,golang实现的NSQ,支持的队列模式基本都可以以上面两个模式总结,只是实现方式不同,具体选型需要根据自己的使用场景选择。
比如kafka以其优异的性能应用在日志收集,hadoop技术体系等场景中,但是目前不支持消费端的ack机制,需要consumer自己实现消费的可靠性。
再比如我们考虑优先级队列的场景。kafka可以把不同优先级的消息放到topic里指定的partition,给高优先级队列提供性能更好的consumer。如果使用amq,rmq等,可以拆分出不同的queue来实现kafka的分区功能。根据自己的技术栈选择即可。
另外还要考虑技术选型的可维护性,社区的完善性等。
解耦了吗
这里再讲一下消息队列的设计问题。
提供一个场景,社交类APP里有很多实体,feed内容,评论,用户信息等,同时有一个需求,提供统一的open api,将App里的实体信息提供给第三方。
我们选择消息队列的方式将各个模块的数据同步给open api,实体信息发生的变化都都需要通过队列来发布。
使用消息队列,在部署层面上,各个模块与open api实现了解耦。我们来考虑下细节,消息体如何设计更合适。
我们可能有两种思路(可能更多,多思考)。
- 所有模块将消息发送到open api定义的队列里,队列的消息体由open api定义,open api消费自己的队列更新数据。
- 每个模块有自己的更新topic,比如评论定义自己的topic,发生变化时,将评论id连带信息发送到队列里。open api订阅各个模块的topic,组装成自己的实体信息。
思考下,这两种方式有何优缺点?
第一种方式,优点是open api实现简单,不依赖其他系统具体实现,消费消息更新数据即可。有没有什么缺点呢?还是有的。首先各个模块需要知道open api的数据定义方式(消息体),对open api还是有一定依赖。另外,如果还有一个系统,比如审核系统也需要同步评论数据做审核,评论模块还要再发送一个审核队列,数据格式可能还不相同。再有open api需要要做数据检验,不能让评论模块发成feed的数据。
第二种方式,优点是各个实体模块实现简单,不需要关注open api实现细节,同时提供topic模式,其他微服务都可以监听评论的更新消息,更加灵活。缺点就是open api承受了所有的数据转换工作,对实体模块的消息定义有些依赖。
既然各有优缺点,我们如何抉择呢?需要我们权衡下利弊。有些像CAP原理,不能完全解耦的情况下,二者取其轻。
我个人理解是这样,
设计模式里有一个基本原则是封装变化,首先看哪边变化的多,如果open api数据格式经常变化,建议选第二种方式,反之,选第一种。
第一种方式还有一个缺点是有些更新比较频繁的实体会影响其他类型实体进入open api,如果存在消费瓶颈,可以选第二种方式。第二种方式还可以对频繁更新实体增加消费能力,相当于优先级队列。
有疑问加站长微信联系(非本文作者)