关于可靠通信的三条基础定理
广义的可靠通信不限于计算机网络通信, 只要两个物体具有发送和接收能力, 或者两个物体之间有发送和接收动作, 均属于通信范畴. 例如人于人的声音对话, 身体语言等等. 可靠通信至少包括三项要求:
- 不重复
- 不丢包
- 完整性(原子性)
为了达到这三项要求, 对应有三条定理:
- 定理一(去重定理): 排队(串行化)是解决去重问题的 唯一正确方法
- 定理二(丢包定理): 确认和重传是解决丢包的问题 唯一正确方法
- 定理三(原子定理): 单点标记或者自校验是完整性(原子性)的 唯一正确方法
有些同学可能对排队理论有怀疑, 表示搞一个全局位图(标记集合)也能解决去重问题. 如果深究, 判断标记和修改标记本质上是独立的两步操作, 这两步操作就遇到去重问题, 也即, 对标记集合的操作本身也需要排队. 当然, CAS 是一种解决方案, 但 CAS 的实现内部本质也是排队.
用这三条基础理论可以解释许多问题, 指导我们具体的代码开发, 也能指导我们进行系统架构设计.
例如 TCP 为什么能实现可靠通信? 因为它至少遵循了这三条定理. TCP 的序号用于排队, TCP 有超时重传机制 兜底(还有选择重传, 快速重传等多项技术进行优化), TCP 有 checksum 校验数据的完整性.
例如设计一个在线商店系统, 库存超卖问题本质就是判断库存和下订单这两步操作, 是一个去重的问题. 我们做设计 review 的时候, 一定要紧紧抓住对应的基础定理, 挑战设计者有没有设计排队策略. 如果没有, 则根据定理可以直接否定设计方案. 当然, 具体实现时, 有很多技术可以实现排队策略, 比如引入外部的队列组件, 利用数据库的锁(悲观锁或者乐观锁, 显式锁或者隐式锁). 方法有很多, 但本质只对应一条定理.
还是在线商店系统的问题, 订单和支付一般是两套独立的系统, 这就是涉及到了不丢包的问题. 根据定理, 我们必须有定时任务进行确认和补单的机制. 所谓的分布式事务(XA), 本质也要依赖确认和重传.
数据库事务的原子性(Atomicity)的实现手段, 常常依赖单点标记(commit point), 对分散的多个对象进行确认. 还有一种比较取巧的方案, 但很少见, 那便是把多个对象相连组成一个环形, 从而不依赖单点标记即可自校验.
实际问题千变万化, 但本质定理就是这三条, 按定理做, 就是对的, 不按定理做, 就是错的. 以定理作为讨论基础, 大家有的放矢, 信息简炼, 能快速聚焦.
这也是我经常提到的, 要想保证系统的正确性, 一定要先在理论上, 确保基础的核心模型的正确性. 只要核心正确了, 整个系统的健壮性就能得到保证.