【NOTE】架构原则与案例分析

# 原则与步骤

3 个原则:合适、简单、演化。其中,合适最重要,避免过度设计。

步骤上:

  • 根据场景,识别设计复杂度所在。多个复杂度,需要按照优先级排序。
  • 针对复杂度设计备选方案
  • 挑选合适方案
  • 深入详细设计

# 场景

用户发一条微博后,微博子系统需要通知审核子系统进行审核,然后通知统计子系统进行统计,再通知广告子系统进行广告预测,接着通知消息子系统进行消息推送……一条微博有十几个通知,目前都是系统间通过接口调用的。每通知一个新系统,微博子系统就要设计接口、进行测试,效率很低,问题定位很麻烦,经常和其他子系统的技术人员产生分岐,微博子系统的开发人员不胜其烦。

用户等级达到 VIP 后,等级子系统要通知福利子系统进行奖品发放,要通知客服子系统安排专属服务人员,要通知商品子系统进行商品打折处理……等级子系统的开发人员也是不胜其烦。

问题在于:各业务子系统强耦合,使用消息队列可以对子系统解耦。

这个消息队列:

  • 高性能:业务会增长,需要考虑性能余量
  • 高可用:很重要,vip 体验、言论安全等等
  • 可扩展:要求不高

# 几种方案

  • 开源消息队列:Kafka
  • 基于 sql 存储:集群+mysql
  • 基于自研存储:集群+自研存储

# 方案细节

考虑到 kafka 是针对大容量日志消息传输,而系统关键点是业务数据高可用传输。并且运维难度高,所以排除。
自研存储人力不够。
最后选择方案 2。

细节部分:
1、 数据表设计:日志表+消息表,定时清除
2、数据复制:mysql 自带的主从复制,只复制消息表。
3、主备转换:ZooKeeper 做主备决策
4、业务写入消息:提供 sdk,简单轮询(不行就下一个节点)写入
5、业务读取消息:sdk 读取,消息服务器需要记录消费状态,自动返回下一条未消费的消息
6、通信协议:传输 tcp(兼容性),数据格式用 protoco buf(压缩效率高)

# 更多细节

1、消息消费采用 pull 还是 push?
考虑 push 模式会更复杂,故放弃,采用 pull 模式,消费端主动去拉,为了达到与 push 模式相同的低延迟效果,可以采用长轮询的方式,消费端轮询拉取消息费,当有消费可消费时,返回消息,如果没有可消费的消息,挂起当前线程,直到超时或者有可消费的消息为止。
2、消息重复问题
消息中间件不解决消息重复的问题,有业务系统自己根据业务的唯一 id 去重。
3、顺序消息
发送端在发生顺序消息时,只发送到相同 broker 的相同队列,消费端消费时,顺序消息只能由同一个消费端消息。
4、定时消息
发送端指定消息延时多长时间消费,broker 端定时扫描定时消息(涉及时间轮算法),达到延时时间的消息加入到消费队列。
5、事务消息
发送端分两步,先预发送消息,broker 端只记录消息为预发送状态,再执行本地事务,然后再根据本地事务的成功或者失败发送确认消息(回滚还是提交),这步如果发生异常,broker 启动定时任务,把未确认的消息发送给发送端回查事务状态(需要发送端提供回查接口)。

# 参考