思维训练-怎样设计一个MQ

架构师需要做各种设计,要不断地提高自己的设计能力。这有没有方法可以训练呢?有的,就是看到什么、想到什么,就假设对面坐着产品经理,一起讨论怎么把它设计出来。比如怎样设计一个MQ

我:首先我确认一下需求。从功能性需求和非功能性需求两方面来看。先看功能性需求:要设计MQ,本身来说就要求: 发送、接收和存储,存储是先进先出的。那还有其他的需求吗?比如我是只需要在程序逻辑中用JVM内实现,还是需要跨进程、跨平台?

产品经理:需要跨进程、跨平台

我:那假设发送端是producer、接收端是consumer,存储端是broker。i那就需要解决broker与两端的通信问题。可以使用成熟的RPC框架,这样就不需要考虑 服务注册与发现、负载均衡和序列化方式的问题了。

先把最简单的架构图画出来:

需要支持发布订阅吗?

产品经理:需要支持发布订阅

我:可以给发布的消息设置主题,将一类消息发布到同一个主题中,消费端来订阅相关主题的消息。

再来考虑一下非功能需求。在高可用方面有什么要求吗?

产品经理:需要保证高可用

我:可以使用多副本模式增加复制因子(kafka MQ里有个主题复制因子的概念,其实就是副本数)来提高可用性,通过服务注册与发现、超时与重试、负载均衡、发送和消费时的ack来保证可用性。存储方面,对性能和可靠性有要求吗?

产品经理:有要求怎么办,没有要求怎么办呢?

我:如果不追求很高的性能可以使用数据库等方案。可靠性要求不高的话直接用内存或者分布式缓存也可以。追求性能的话,目前主流的方式是采用追加写日志顺序写盘+索引文件的方式。索引设计上可以考虑稀疏或者稠密索引(稠密索引是所有的数据条目都能通过索引找到,稀疏索引是数据分段出现在索引中,通过索引可以找到第一个数据的地址,再通过第一个数据找到想要的数据)。查找消息可以采用跳表或者二分查找等。还可以通过操作系统的页缓存和零拷贝等技术来提高操作系统的读写性能。

对吞吐量有什么要求?

产品经理:需要每秒处理500M的消息

我:kafka单节点处理能力在每秒100M左右,那就需要建立多个分区来进行水平扩展。如果没有特殊要求的话,生产端到分区,分区到消费端都可以采用轮询的策略来进行分区分配。

产品经理:有的消息,需要保证它的顺序,这个需要处理一下。

我:可以在生产端到分区的分配策略上,如果指定了分区就发到指定分区,如果指定了key可以按照key来进行hash分配,如果这两个都没指定再按照轮询来分配。这样,指定了分区的和指定了key的都会发到一个分区中,在同一个分区中的消息是有序的。

总结

按照这种思维方式思考下去,MQ的原理都可以思考地很明白,同时也提高了设计能力。思考的过程中还会将具体的用词在脑子过一遍,有些不清楚可以通过搜索学习来让自己的用词更加专业,从而达到一个总体的技术提升。