2021-06-06

可靠通信的三条基本定理(可靠通信三原则)

Views: 8770 | 2 Comments

"通信"是一个广义的概念, 不仅限于计算机网络通信, 任何抽象或者具体的对象间的交互行为, 都是一种通信. 对象间一旦进行通信, 便有可靠通信的需求. 可靠通信至少包括三项要求:

  1. 不丢包
  2. 不重复
  3. 完整性(原子性)

为了达到这三项要求, 对应有三条定理(可靠通信三原则):

  • 定理一(重传定理): 确认和重传是解决丢包问题的唯一正确方法
  • 定理二(去重定理): 排队(串行化)是解决去重问题的唯一正确方法
  • 定理三(原子定理): 单点标记或者循环自校验是实现完整性(原子性)的唯一正确方法

有些同学可能对排队理论有怀疑, 表示搞一个全局位图(标记集合)也能解决去重问题. 如果深究, 判断标记和修改标记是独立的两步操作, 这两步操作就遇到去重问题, 也即, 对标记集合的操作本身也需要排队. 当然, CAS 是一种解决方案, 但 CAS 的实现内部本质也是排队.

用这三条基础理论可以解释许多问题, 指导我们具体的代码开发, 也能指导我们进行系统架构设计.

例如 TCP 为什么能实现可靠通信? 因为它至少遵循了这三条定理. TCP 的序号用于排队, TCP 有超时重传机制兜底(还有选择重传, 快速重传等多项技术进行优化), TCP 有 checksum 校验数据的完整性. Vinton Cerf 早年关于 TCP 协议的论文 - A Protocol for Packet Network Intercommunication

例如设计一个在线商店系统, 库存超卖问题本质就是判断库存和下订单这两步操作, 是一个去重的问题. 我们做设计 review 的时候, 一定要紧紧抓住对应的基础定理, 挑战设计者有没有设计排队策略. 如果没有, 则根据定理可以直接否定设计方案. 当然, 具体实现时, 有很多技术可以实现排队策略, 比如引入外部的队列组件, 利用数据库的锁(悲观锁或者乐观锁, 显式锁或者隐式锁). 方法有很多, 但本质只对应一条定理.

还是在线商店系统的问题, 订单和支付一般是两套独立的系统, 这就是涉及到了不丢包的问题. 根据定理, 我们必须有定时任务进行确认和补单的机制. 所谓的分布式事务(XA), 本质也要依赖确认和重传.

数据库事务的原子性(Atomicity)的实现手段, 常常依赖单点标记(commit point), 对分散的多个对象进行确认. 还有一种比较取巧的方案, 但很少见, 那便是把多个对象相连组成一个环形, 从而不依赖单点标记即可自校验.

实际问题千变万化, 但本质定理就是这三条, 按定理做, 就是对的, 不按定理做, 就是错的. 以定理作为讨论基础, 大家有的放矢, 信息简炼, 能快速聚焦.

这也是我经常提到的, 要想保证系统的正确性, 一定要先在理论上, 确保基础的核心模型的正确性. 只要核心正确了, 整个系统的健壮性就能得到保证.

Glossary:

  • 确认与重传, positive acknowledgment
  • 去重, eliminate duplicates

Related posts:

  1. 数据库事务ACID和锁
  2. 并发编程两原则
  3. 并发编程的核心技术 – 多版本(Multi Version)
  4. 为什么 Leader Based 的分布式协议 Raft 是更好的
  5. 我所理解的分布式系统
Posted by ideawu at 2021-06-06 13:50:46

2 Responses to "可靠通信的三条基本定理(可靠通信三原则)"

Leave a Comment