前几天在 QQ 群里跟 网友 讨论了一下 12306 架构 , 把 讨论的一些想法整理一下 。
总的来说 , 12306 的解决可以分为 2 个 流派 : 1 技术流 , 2 业务流 。
我们先来看看这篇文章 https://www.cnblogs.com/netfocus/p/5187241.html , 这篇文章应该算 “业务流” 吧 ! 不过有意思的是这篇文章的 回复 。 ^^
我们再来看看这篇文章 https://www.csdn.net/article/2015-03-03/2824091 , 这篇文章里有一幅 架构图 :
从这个架构图里 , 我们可以把问题 分成 2 个问题来看 : 1 海量请求的分流 , 2 数据的一致性 和 同步 。
我前几天写过一篇博客 《Grid Virtual Server 和 网格计算》 https://www.cnblogs.com/KSongKing/p/9486434.html , 在这篇文章里也提到了这 2 个问题 。
实际上 , 12306 的问题也是 未来的互联网 要解决的问题 。
在 《Grid Virtual Server 和 网格计算》 里提到 , 分流 采用的是 Client 自主智能 的 选择 Server 节点 (多中心化) , 数据一致性 和 同步 采用 乐观 和 松耦合 的 方式 。
乐观 松耦合 可能需要 换一种 售票 和 购票 观念 。 所谓 新的 售票 观念 和 购票 观念 , 比如 预约 , 预约的方式 。 Book a Ticket 。
乐观 就是类似 乐观锁定 的 那种 方式 , 比如 在 12306 这个 场景上, 乐观 可以是 预定 , Book a Ticket 。
我们现在是 买票 , 买票 就是 看有没有 符合要求的 票 , 有就买, 如果 有人 比你先抢到 , 那你就后一个买 , 如果 被 抢完了 , 那 你就 买不到 , 只能再等 。
这种 “抢” 的 方式 会造成 大量的 访问 在 同一时间 拥挤 向 服务器 。
如果是 预定 的 方式 , 你 可以在 任何 时候 做 一个 预定 , 系统 可以 随时 受理 你的 预定 , 系统 受理 预定, 并不表示 现在就 购票成功 , 也 不表示 未来一定有票 , 但是 系统 会在 一定的时间 结算 某一批 预定, 然后 根据 票况 给予 预定 的 结果 。
如果 符合你的 要求 有票 , 那么 系统 会 回复 消息 给你 “您 预定的票 已可购买 , 在 1 个 小时内 回复 xxx 确定购买 ” 。
那么 , 你 在 1个 小时内 回复 xxx 的话 (当然包括了 支付 钱) , 那么 就购买成功了 。
如果 没有 符合要求的票, 或者 符合要求的 票 已经 用完了(安排 给 在你之前 预定的 人们 了) , 那么 系统 会回复 你 “没有 符合您的 要求的 票” 或者 “符合要求的 票 已预定完 , 请再次 预定” 。
你 可以 再次 预定 , 然后 等待 系统通知 , 如此 循环 。
如果 从 架构 的 角度 来 解释 预定 这种 业务 , 可以 这样解释 , 传统的 购买 相当于 同步 , 预定 相当于 异步 , 预定(异步) 可以解决 同一时间 大量请求 拥挤向 服务器 的 问题 。
同时可以解决 数据 一致性 和 同步 的 问题 。
异步 可以 在 一定的时间 进行 一次 “结算” , 就不需要像 同步方式 那样 为了 数据一致性 和 数据同步 而 需要 极致 的 服务器资源 和 网络资源 。
你把 需求 提给 服务器 , 服务器 不是 即时(同步) 答复 , 而是, “先考虑一下” , 把 很多 用户 的 需求 都 汇集 一下 , 再统一答复一次 。
消息队列 是 “架构” 里 异步 的 代表 , 但在这里说的 解决方案 中, 具体的 技术 可以是 各种各样 。
轮询 Redis , 甚至 轮询 数据库 也是可以的么 。 ^^
事实上 , 用户的 需求 会先持久化 , 所以, 可能 会 轮询 数据库 。
因为 是 异步 乐观 松耦合 的 架构 , 所以 , 轮询 数据库 也是 很轻松 的 ,不会给 系统造成 负担 。
我们再看上面的那个 架构图 , 图的下方 列出了 余票查询集群 、 用户登录集群 、 订单分级查询 、 票价计算集群 、 实名制身份确认集群 5 项 。
我们可以看到图的中央 , 红色 粗的 箭头 “海量购票请求” , 这个就是来自于 全国 的 用户 的 购票请求。这个 请求 是 指向 “铁路总公司数据中心” 。
中央 还有一个 蓝色 的 比较细 的 箭头 , 是 “余票查询请求分流” , 指向 阿里云 公有云 数据中心 , 也就是说, 阿里云 公有云 数据中心 可以 来 分担 “余票查询” 业务 。
而 左侧 有一个 “主数据库” , 主数据库 的 数据 来自于 18 个路局 的 数据汇总 , 主数据库 同时 向 铁路总公司数据中心 和 阿里云数据中心(负责 余票查询分流) 提供数据(同步数据) 。
从 这个 图 的 架构 中 我们 可以看到 , 核心 交易 是 发生在 “铁路总公司 数据中心” , 就是说, 这是 一个 实时的, 中心化 的 数据库 支持 的 业务系统 。
同时 也可以 判定, 余票 查询 不是 实时 的 , 是一个 参考性 的 资料 。 具体 能不能 买这个 票, 在 真正 买票(在 铁路总公司 数据中心 中 发生交易) 时 才能 知道 结果 。 而 “铁路总公司 数据中心” 这个 中心数据库 , 它 的 承载能力 来自于 一个 分布式数据库 Gemfire 。
QQ 群里有网友发了一段节选资料 :
也可以看这一段 :
可以看到, 12306 核心的 数据 承载能力 来自于
1 中心数据库 是 一个 可扩展的 计算机集群
2 中心数据库 是 一个 内存数据库 , 而且 Gemfire 是一个 key value 数据库, 不是 关系数据库
架构图 左边 的 18个路局 到 主数据库 可能是 把 车况 和 票况 汇总给 铁路总公司 数据中心 吧 。
所谓 “两地三中心” , 两地 应该是指 铁路总公司 和 铁科院 吧 。 三中心 应该就是 铁路总公司数据中心 铁科院数据中心 阿里公有云数据中心 吧 。
总的来说呢 , 这种 中心化 的 设计 , 核心 的 处理能力 来自于 中心数据库 。 而 12306 是通过 Gemfire 这样一个 可以构建 集群 的 内存数据库 并且是 key value 数据库 来 做到这一点的 。
下面 , 这是根据我上面说的 多中心化 乐观(异步 预定) 画的架构图 :