读写分离与慢查询监控:在 SDK 层自己实现
前面两篇讲了 Java 版和 Python 版 SDK 的搭建。这一篇单独把读写分离和慢查询监控拎出来讲,因为这两个东西是整个 SDK 最核心的能力,而且都是我们自己在 SDK 层实现的,没碰任何中间件。
为什么不用中间件
先说为什么不选 ShardingSphere、MyCat、ProxySQL 这些。
2022 年那会儿,读写分离的方案大概分两类:
- 中间件层:ShardingSphere-JDBC / ShardingSphere-Proxy、MyCat、ProxySQL、MaxScale。SQL 先过中间件,中间件决定路由到主还是从。
- SDK 层:自己在应用里做路由。
中间件的优点是”对应用透明”,业务代码不用改,接上中间件就有读写分离。听起来很美,但我们最后没用。原因:
第一,运维成本太高。ShardingSphere-Proxy 和 MyCat 是独立进程,得部署、得监控、得高可用。我们当时 DBA 资源紧张,再引入一套中间件集群等于给自己加活。
第二,故障域变大。中间件一旦挂了,所有走它的服务全挂。这种单点风险我们不愿意背。SDK 层做路由,挂的只是一个服务,影响面小得多。
第三,SQL 兼容性。ShardingSphere 和 MyCat 对复杂 SQL 的支持有限,子查询、存储过程、某些 JOIN 场景会出问题。我们的业务 SQL 五花八门,不想踩这个坑。
我们是要完全可控,不是”啥都不想改”,所以选了 SDK 层。
第四,Python 那边没法用。
ShardingSphere-JDBC 是 Java 库,Python 服务用不了。如果读写分离做在中间件层,Python 服务还得另搞一套。SDK 层做的话,Java 和 Python 各自实现一份,行为对齐就行。
读写分离怎么做
Java 版
核心是 Spring 的 AbstractRoutingDataSource。它本质上是个”数据源路由器”,每次拿连接的时候问你:你要主还是从?
1 | public class DalRoutingDataSource extends AbstractRoutingDataSource { |
判断”是不是写操作”的方法:拦截 SQL,看开头是不是 INSERT/UPDATE/DELETE/REPLACE。我们用了一个简单的正则:
1 | private static final Pattern WRITE_PATTERN = |
这里有个细节很多人会漏:事务里的查询必须走主库。为什么?因为主从有延迟。你刚写了一条数据,马上在从库查,可能查不到。事务内的查询通常依赖于事务内的写入,走从库就会出 bug。
Python 版
Python 那边的做法在上一篇讲过:维护主从两个 Engine,在 Session 级别路由。规则和 Java 完全一致:
1 | class DalManager: |
两端规则一致比代码长得一样重要。
主从延迟怎么办
读写分离绕不开这个问题:从库延迟。
我们没有搞什么”延迟检测自动切主”的花活。做法很朴素:
- 强一致场景走主库。事务内的查询、刚写入马上要读的,统统走主库。SDK 层用事务上下文判断。
- 业务能容忍延迟的走从库。报表、列表查询、历史数据这些,延迟几百毫秒无所谓。
- 监控从库延迟。Percona 的
pt-heartbeat跑着,延迟超过 1 秒报警,超过 5 秒自动把读流量切回主库。
这套策略够用了。大部分业务的读请求其实不在乎那点延迟。
慢查询监控
慢查询监控分两部分:采集和上报。
采集
在 SDK 层拦截每一条 SQL 的执行时间。
Java 版通过 JDBC 的 PreparedStatement 包装类埋点:
1 | public class DalPreparedStatement extends PreparedStatementWrapper { |
Python 版用 SQLAlchemy 的事件钩子,上一篇文章里有代码,这里不重复了。
上报
慢查询数据报到两个地方:
- 监控平台(Prometheus / 内部 metrics 系统):聚合看趋势,P99、P999 慢查询数量。
- 日志系统(ELK):存原始 SQL 和调用栈,排查用。
1 | # 慢查询上报配置 |
阈值 200ms 是拍脑袋定的,后来根据数据调整过。实际上不同业务的容忍度不一样,报表类服务可以放到 1 秒,交易类服务收紧到 100ms。
效果
读写分离上了之后,主库的读压力直接降了 60% 以上。原来高峰期 CPU 经常飙到 80%,分离后稳在 30% 左右。
慢查询监控的价值更大。以前慢查询是用户投诉了才知道,上了监控之后,还没变慢就能先发现。每周从监控里捞 Top 10 慢查询,逐一优化,这就是后面”慢查询治理”那篇文章要讲的事。
监控的目的不是为了看数据好看,而是驱动行动。如果监控只是看个图,不做优化,那等于白装。慢查询监控一定要配上”每周优化 Top N”的机制,才能真正产生价值。