一、连接池参数的容量测算
连接池容量不是越大越好。数据服务的并发处理能力有上限,超过之后增加连接只会加剧上下文切换与锁竞争,吞吐反而下降。测算的基本公式是所需连接数等于目标每秒事务数乘以单事务的均值执行耗时。若目标是每秒八百事务、单事务耗时十五毫秒,理论需要十二个连接,考虑波动与长尾,取二十到二十四较为合适。
实践中很多团队把最大连接数设成两百,远超实际需要。这不仅浪费数据服务的连接槽位,还会在故障恢复时形成连接风暴:下游短暂不可用后恢复,所有应用实例同时重建连接,瞬间打满连接上限。合理做法是把最大连接数按测算值的一点五倍设定,并开启获取连接的排队超时。
最小空闲连接与最大生命周期同样关键。最小空闲设为最大值的三分之一,可以规避低谷后突发时的建连延迟;最大生命周期建议设为二十五分钟,短于中间设备的会话老化时间,让连接在被静默断开之前主动重建。某服务调整后,因连接失效导致的偶发错误从每天四十余次降到零次。连接池还要开启有效性检测。取出连接前做一次轻量探测,或采用后台定期检测的方式,两者各有取舍:前者每次取用都有额外开销,后者可能取到刚失效的连接。折衷做法是设定空闲阈值,仅对空闲超过三十秒的连接做探测,既控制开销又覆盖大部分失效场景。探测语句要足够轻量,不要用复杂查询代替。
二、代理层选路:读写分流与延迟感知
代理层的核心职责是把请求送到合适的节点。读写分流的基本规则是写语句与事务内语句走主节点,只读语句走副本。但规则之外有大量例外:显式声明只读的事务可以走副本;含有临时表或用户变量的语句必须固定节点;带有锁提示的查询应回主节点执行。
副本选路要感知延迟。主从之间的复制延迟随写入压力波动,若把请求发到延迟三秒的副本,用户可能读不到刚提交的数据。代理应周期采集各副本的延迟值,把超过阈值的副本临时摘除,恢复后再放回。阈值按业务容忍度设定,一般在五百毫秒到两秒之间。
权重分配要考虑规格差异。若副本规格不同,等权轮询会让小规格节点先饱和。按规格设定权重并结合实时活跃连接数做动态调整,能让各节点利用率更均衡。某业务接入代理层后,主节点的查询占比从百分之百降到百分之三十一,主节点的处理器利用率从七成八降到四成二,读扩展能力得到充分释放,后续扩容也只需增加副本。选路还要处理副本的健康状态。副本可能因为磁盘故障、回放卡住或资源耗尽而处于亚健康,此时延迟指标未必立刻反映问题。建议同时采集副本的查询成功率与响应时延,任一项异常即降权,连续异常则摘除。摘除后要有恢复探测,用少量流量试探,确认稳定后再逐步加权,规避反复摘除与放回造成的抖动。
三、会话保持与事务一致性边界
会话保持决定了一致性边界。写后立即读是最常见的一致性诉求,处理方式有三种:一是写操作后的固定时间窗口内该会话的读请求全部回主节点,实现简单但会增加主节点压力;二是记录写操作的日志位点,读请求携带该位点,代理选择已追上该位点的副本;三是由业务显式声明本次读是否需要看到最新数据。
第二种方案精度最高,代价是需要副本上报位点并在代理侧维护映射。实测在写入压力中等的场景下,携带位点的读请求约有百分之七十八能在副本上得到满足,其余回主节点,整体主节点压力下降明显,而一致性体验与全部回主没有差别。
事务边界要清晰。跨语句的事务一旦开启,全部语句必须固定在同一节点,代理不能中途切换,否则会话状态会丢失。因此应尽量缩短事务范围,把只读查询移到事务之外。长事务还会阻塞主节点的日志清理与副本回放,是复制延迟的常见诱因,建议对超过三秒的事务设置告警并逐一治理,通常拆分后就能解决。预处理语句的会话状态也需要注意。若应用使用预处理并缓存句柄,代理切换节点后句柄会失效。解决方式有两种:一是代理在新节点上重新预处理并透明重放,二是应用侧关闭句柄缓存改用文本协议。前者对应用无侵入但实现复杂,后者简单却损失少量性能,选择时要看语句复用率的高低。
四、限流、熔断与故障演练
下游异常时,代理层是最后一道防线。限流要分维度:按数据服务实例设置总并发上限,按应用标识设置配额,按语句模板设置单模板并发上限。第三类尤其有用,它能防止某个慢查询模板耗尽全部连接,让其他正常请求继续通行。
熔断策略要区分错误类型。连接超时与执行超时通常意味着下游过载,应快速熔断并进入半开探测;语法错误与约束冲突是业务问题,不应触发熔断。半开阶段放行少量请求探测,连续成功后再逐步恢复流量,规避恢复瞬间的二次打垮。
演练必不可少。定期注入主节点故障验证切换耗时,注入副本延迟验证摘除逻辑,注入网络抖动验证重试是否幂等。每次演练记录客户端侧的实际影响时长,与设计目标对照。某系统通过季度演练把主节点切换的业务影响时长从五十八秒压缩到十九秒,其中大部分改进来自客户端连接池的失效检测提速与代理侧的位点推进优化,而不是数据服务本身的变更。客户端的重试逻辑同样要审视。无条件重试写操作可能造成重复提交,正确做法是只对明确未执行的错误重试,例如建连失败;对超时这类结果未知的错误,要么依赖幂等设计,要么直接失败并交由业务补偿。重试还要带退避与总次数上限,否则下游恢复瞬间会被重试洪峰再次打垮,形成反复震荡。
结语:接入层的设计质量决定了数据服务能否被充分利用。连接池按测算配置而非凭感觉设定,代理选路兼顾延迟与规格,一致性诉求通过位点而非全量回主来满足,异常时靠分维度限流与分类熔断守住底线。这些细节做到位,同样的规格能支撑高出数倍的业务压力。