2021-06-03

分布式数据库系统如何做到平滑缩扩容?

Views: 4380 | Add Comments

分布式数据库系统的缩扩容能力(后面也称迁移)是最基础最基本的特性, 但是, 要实现平滑扩容并不容易, 需要服务端和客户端共同完成, 这两者只要缺少任何一方的参与和配合, 便绝不可能实现平滑扩容.

平滑迁移要解决的问题, 本质上就是故障容错(转移)处理.

客户端请求重试

请求重试是故障容错的最基础要求, 因为你永远无法避免遇到故障. 遇到故障时, 要么报错, 要么重试. 既然我们追求的是平滑, 那么, 一旦遇到故障, 绝对不能向上层反馈, 只能重试.

重试要配合服务发现, 不然故障点一直不恢复的话, 重试也没用.

重试策略的关键在于识别出可重试的故障, 对于某些故障, 如网络故障, 客户端无法确保请求到底有没有实际发出去, 或者已经被服务端处理, 冒然重试, 会导致非预期的后果.

实际上, 所有的接口的结果不是一般人所理解的两态(成功或者失败), 而是三态(成功, 失败, 未知). 对于未知结果, 我们什么也做不了, 只能向上反馈(向业务层报错), 这种情况, 无法重试, 也就无法容错.

客户端主动发现服务访问点(服务发现)

常见的数据库 client SDK(例如 libmysql, hiredis), 都是通过 ip:port 连接数据库, 很显然, 无法针对 ip 故障进行容错. 而我们迁移数据时, 往往要上线 n 台机器, 同时下线 m 台机器, 因此, 某个 ip 会突然不可用, 这是很显然的. 如果客户端没有主动发现服务访问点的功能, 那就会一直尝试连接故障 ip.

服务发现要求定期刷新服务列表(路由表), 刷新的频率和刷新的范围是个工程优化问题.

客户端提前预知故障

对于运维操作造成的故障, 客户端是可以提前预知的. 我们在操作之前, 提前一定的时间发布通告到服务注册中心, 客户端以一定的频率刷新服务列表(路由表), 便可以提前知道. 也即所谓的提前切走流量.

服务端提前预告故障

此项配合"客户端提前预知故障".

服务端增加代理服务

在服务端增加代理服务(Proxy), 然后把客户端的逻辑转移到代理层, 让客户端变成一个瘦客户端. 例如, 请求重试逻辑, 服务发现逻辑等, 都放到代理服务上面, 客户端直接访问代理.

增加代理服务的前提是代理服务本身是高可靠的, 一般情况下, 代理服务的可靠度都比数据库服务要高很多.

服务端重定向

基于注册中心的服务发现机制, 及时性是一个问题, 因为客户端不可能做到"及时"刷新. 真正的服务状态, 只有服务端自己才是最准确的(single source of truth), 所以, 服务端需要在客户端定位错误的时候, 告知客户端换一个访问点(重定向).

最佳实践

服务端 客户端
必要 重定向 重试, 服务发现, 重定向
优化 故障预告, Proxy

实践上, 一个追求容错(高可用)的系统, 必然要提供专属的定制化 SDK, 因为现存的常规 SDK 几乎完全没有"重试, 服务发现, 重定向".

在引入 Proxy 时, 可以把专属 SDK 的优先级放低, 暂时使用常规 SDK.

Related posts:

  1. SSH ProxyCommand及其思想
  2. 分布式系统Redirect和Proxy的区别
  3. SSDB 分布式的一些想法
  4. endless_tcp – 一种适应极端网络环境的网络软件架构
  5. Leader based 的集群也可以100%高可用
Posted by ideawu at 2021-06-03 22:41:55

Leave a Comment