Shared-Nothing(无共享)里每个节点拥有独立的 CPU、内存、磁盘,节点之间只通过网络协作,是现代分布式数据库几乎统一的底座。本节讲清楚它的两个关键词——数据本地性与网络协作——以及它凭什么既延伸出水平扩展,又让首次接触的人总想"把别的机器上的数据拽过来"。
阅读完本节,你应当能够:
靠直觉想,Shared-Disk 把数据放在一块盘上,大家共享,不是更省事吗?可现实里主流系统几乎全选 Shared-Nothing。原因是前面埋的那句:数据共享带来的便利,永远抵不过共享带来的扩展天花板。Shared-Nothing 里每个节点是一台"自给自足"的小服务器,电压自己撑、存储自己管、故障自己扛,多一台机器就是多一份完全的算力。这种"各自为政"反而成就了"想扩就扩",这是那些看似更省事的共享方案给不了的东西。
Shared-Nothing 的第一原则是数据尽量留在离它最近的地方被处理,专业叫"数据本地性"。也就是说,绝大多数查询应当在单台节点内部完成,不跨节点搬数据。这不是洁癖,而是性能刚需——因为跨节点搬数据的代价是"一个网络来回",比本机内存访问慢几个数量级。设计分布式库的人整天在琢磨怎么让"查询跟着数据走":路由把请求直接送到数据所在节点(第 4 章),查询优化器尽量把过滤下推到数据源(第 7 章),为的都是保住这条本地性。
怎么测你对本地性有没有真的懂?给出一个判断:一个查询结束后,你数它"跨了几个节点搬运了多少数据"。跨得越少越好。真正好的分布式系统会把绝大多数请求控制在"单节点内完成"。
数据不可能永远完美地待在原处。总会遇到这种情况:聚合要跨所有分片、联表要碰两边的数据、副本要给老邻居同步日志。于是 Shared-Nothing 的第二原则登场——必要时刻,允许数据通过网络搬家,但每次搬家都要付账。这条原则决定了它的代价长什么样:查询规划时要估算网络成本,路由失败时要重新分配,节点挂了要重平衡。可以说,Shared-Nothing 的一切"麻烦",都源于"该搬的还得搬"。
我们看一场具体的一幕,把两原则串起来。假设集群四台节点,你要查"华东区库存全部不足的订单",其中订单表按区域哈希分片:
第1步 路由:按分区键"区域"定位, 华东的订单散在哪些节点 第2步 本地执行:在各节点内筛选"库存不足"的记录, 尽量在本地过滤 第3步 数据搬移:只把"命中库存不足"的那些行通过网络汇总到协调节点 第4步 最终汇聚:协调节点归并出结果返回给客户端
注意第 2 步藏在最要紧的位置:哈希分片 + 本地过滤,让"华东订单"不必整表搬过来,只搬"命中条件的少数行"。这就是数据本地性叠加下推(第7章)的真实配合。若反过来不分片地把整张订单表搬上网,那就是 Shared-Nothing 的典型翻车写法。
Shared-Nothing 没有共享硬件瓶颈,那它还有没有尽头?有,尽头在网络。当节点数越多、跨节点通信越频繁,网络汇聚到边缘可能成为新的瓶颈;再加上全球部署下的物理距离延迟,扩展不会无限平滑。但比起"磁盘带宽"那种硬伤,"网络"这种边界至少是可以用设计去疏导的——数据本地性、分区路由、压缩传输都是在和这个边界讨价还价。认清这一点,你就不会把 Shared-Nothing 误解成"没有边界",它只是把边界从"硬件共享"挪到了"网络协作"上。
别只停留在"Shared-Nothing 能扩展"的定性描述上,算一笔数你会更踏实。假设集群从 3 台扩到 9 台,理想情况算力 3 倍、存储 3 倍,只要新增节点保持"各自为政",单点硬件几乎不参与争抢,这就是它比 Shared-Disk 优雅的地方——你多搬一台机器进组,它就实打实多撑起一片数据的读写。代价是节点间的对等通信从 3 台的"三角"涨到 9 台的"四十五条线"级别的组合数,跨节点聚合、副本日志同步、全局元数据广播都随之变多。所以真正负责的人会反过来问一句:我家查询的本地性到底有多高?如果八成以上请求都能在单节点内完成,扩到 9 台很划算;如果每个查询都要全网聚合一遍,那扩得越多,网络开销越接近翻车线。 这条"本地命中率应该是线索"扑面而来的判断,正是衡量你该不该一路往深扩(数学)的现场工具。
刚上手 Shared-Nothing 的人,常犯同一个错:遇到缺一个字段,就直接"把别的节点上的数据拽过来拼"。这等于每次查询都强行触发全网搬家,把 Shared-Nothing 最大的优点亲手废掉。正解是先检查路由是否真的按分区键切分、能否通过下推在本地补齐字段,实在要跨节点就一定选"只搬命中的少数行"。一句话:在这个架构里,网络是能用就尽量别用的贷方,不是拿来挥霍的赠品。 记住这条,你在第 7 章学查询优化时就会格外有共鸣。
Shared-Nothing 把扩展边界推给了网络,而共享架构是把边界留在硬件上。下一节 3.3 回过头看"共享资源的两极"——Shared-Disk 与 Shared-Memory——它们各自的极简,恰恰也是各自的死穴。