news 2026/10/19 14:28:40

MySQL中间件Atlas实践:读写分离、分表与踩坑全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL中间件Atlas实践:读写分离、分表与踩坑全指南

刚开始看到“atlas”这个名字,我脑子里瞬间闪过好几个东西:希腊神话里扛天的泰坦神,地图册的英文名,波士顿动力的双足机器人,Facebook的广告系统……但如果你是个干后端、搞数据库的,大概率第一反应是那个曾经在国内互联网圈子里很火的MySQL中间件。没错,这篇文章的主角就是它——奇虎360开源的数据库中间件Atlas。

这个项目源代码托管在GitHub上,奇虎360在2013年左右开源出来,定位是MySQL代理层。它的核心价值说白了就是两个:读写分离和分表。你可以把它理解成数据库门口的智能分流闸机——读请求往从库去,写请求往主库去,还能把一张千万级的大表按规则拆成多张小表,分摊存储和查询压力。在那个MySQL官方还没出什么像样的中间件方案、MyCat还没声量那么大的年代,Atlas确实算是很多团队的首选。

这篇东西我不打算写成一份照抄官方README的说明书,而是从实际落地角度出发,把部署、配置、原理、踩坑一条线捋清楚。如果你正在用或者准备选型Atlas,这篇文章能帮你少走不少弯路。文章里所有的操作步骤和配置示例都基于CentOS 7 + MySQL 5.7的环境,版本差异比较大的地方我会单独标出来。

1. 为什么选择Atlas:一个老牌中间件的价值与边界

先说清楚一个观点:Atlas不是万能的,它解决的问题非常聚焦。但正因为聚焦,它在自己的领域里做得相当纯粹。很多时候我们选型失败,不是因为工具不好,而是因为期望值放错了位置。

1.1 解决了什么问题

在MySQL主从架构里,一台主库负责写,若干台从库负责读。如果没有中间层,你的业务代码就得自己感知哪台是主、哪台是从。比如你要写数据就得连主库,要读数据就得连从库,一旦主从切换,所有连接配置都要跟着改。这在小团队、小业务量时还能凑合,一旦服务多了,维护成本就上来了。

Atlas就是为了解决这个痛点出现的。业务方只需要连接Atlas,完全不用理会背后有几台MySQL、哪台是什么角色。你发给Atlas一条SQL,它会自己判断这条语句该发到主库还是从库,然后把结果返回给你。这相当于把“数据库拓扑感知”这件事从业务端下沉到代理层,业务代码瞬间变得干净了。

另外一个杀招是分表。单表数据量超过千万甚至亿级的时候,索引再优化也扛不住写入和查询的延迟。Atlas支持按某个字段的哈希值取模,把一张逻辑大表拆分成物理上的多张小表。业务还是按原表名去查,Atlas在中间做映射和路由。这确实是解决大表问题的有效手段,后文我会详细讲它的局限在哪。

1.2 哪些场景不适合用Atlas

Atlas是基于MySQL协议的代理,它天然有一些限制。比如对事务的支持就不够完美——开启事务后,事务里的语句默认还是走读写分离规则,如果你的事务内是先写后读,就可能出现读到旧数据的情况。另一个是跨库跨表的JOIN和子查询,性能会很差,因为Atlas需要把数据从多个后端节点捞回来再做关联。所以这个方案更适合OLTP场景下的简单查询,复杂分析类SQL建议直接上专门的OLAP方案或数仓,别在Atlas这里硬扛。

我还见过有人拿Atlas做分库分表之外的“高可用”兜底,这个用法其实有点错位。Atlas本身不是集群方案,它自身就是单点。真要防Atlas这台机器挂掉,得靠Keepalived做VIP浮动,或者前置一层负载均衡(比如HAProxy)来做故障转移,否则它一挂整个数据库入口就瘫了。

1.3 与其他老牌/同期方案对比

下面这个表格是我在选型时候做的对比,当时备选的几个方案都列出来了,便于你有个直观印象:

方案读写分离分表分库管理界面协议兼容性活跃度
Atlas支持支持(单键哈希)不支持管理端口命令高,基于MySQL原生协议维护状态,社区活跃度一般
MyCat支持支持支持有Web管理高,支持多协议社区比Atlas活跃,但配置复杂
ShardingSphere-JDBC支持支持支持无中间件层,嵌入应用极高,应用内集成很活跃,云原生友好
MySQL官方Router支持不支持不支持有API高官方维护,但功能少

看这张表你就明白了,Atlas对比同期方案最大的优势是轻量、部署简单、MySQL协议兼容性好。业务几乎不用改代码,接上就能跑。对比现在的ShardingSphere-JDBC这种应用内集成方案,Atlas的劣势是功能不够全、扩展性偏弱,但它作为独立代理层,对业务代码的侵入性为零,运维维护上也更直观。这两种路线各有各的适用场景,没有绝对的好与坏。

2. 核心架构拆解:读写分离和分表在Atlas内部是怎么跑起来的

知其然更要知其所以然。我把Atlas内部几个关键机制捋了一遍,这块搞清楚了,后面配置和排错会轻松很多。

2.1 连接管理:前端连接与后端连接池

Atlas本质上是一个代理,但它不是简单的转发。它内部维护了两类连接:一类是业务程序连接到Atlas的连接,叫前端连接;另一类是Atlas连接到后端MySQL数据库的连接,叫后端连接。

这里有一个很关键的机制:后端连接是池化的。前端来一个连接,Atlas不会立刻向后端建立一个对应的MySQL连接,而是从空闲连接池里取一个分配给前端。用完归还。这样做的好处是避免每个业务请求都要进行一次完整的MySQL握手认证,大幅降低后端数据库的连接建立开销。

类比一下,就像你去银行办事,大堂经理(Atlas)不会每次都在柜台新开一个窗口(MySQL连接)给你,而是把你引导到已有的空闲窗口。窗口数量是有限的,业务量再大,后端数据库的连接数也能被控制在合理区间。我在生产环境里就遇到过因为连接管理不当导致MySQL连接数被打满的故障,Atlas这个机制帮了大忙。

2.2 读写分离的判断逻辑:MySQL协议层玩儿的正则匹配

Atlas怎么判断一条SQL是读还是写呢?如果你以为它解析了SQL语法,那就太小看它了。它的判断逻辑非常简单直接:对SQL语句进行正则匹配。

如果一个语句以SELECT开头(去掉注释、空白符后),并且不是SELECT ... FOR UPDATE这种带锁的查询,Atlas就把它归为读请求;其余的全部归为写请求。包括INSERT、UPDATE、DELETE、CREATE、ALTER、DROP等凡是修改数据或结构的一律走主库。

这里注意两个容易被忽略的点:一是“SELECT ... FOR UPDATE”会被识别为写请求,这是合理的,因为FOR UPDATE加的是行级排他锁,必须走主库;二是一些看似读实则写的情况,比如自定义函数里执行了更新,外部套了SELECT。这类SQL会被判断成读请求而路由到从库,一旦从库是只读复制状态,就会报错。这种边角情况在业务里确实会遇到,后面踩坑部分我会专门说。

2.3 分表实现:哈希取模的规则世界

Atlas的另一个标志性功能是分表。它支持的是一种哈希取模的分片策略:指定分表键(shard key)和分表数量N,然后计算分表键的哈希值,跟N取模,得到的结果就对应物理分表的表后缀。

举个例子,订单流水表叫T_ORDER,分表键是ORDER_ID,分表数量是16。那哈希值对16取模的结果就是表后缀,实际物理表就是T_ORDER_0、T_ORDER_1、T_ORDER_2……一直到T_ORDER_15。业务插入一条数据时,Atlas根据ORDER_ID算出该去哪个分表,然后把SQL改写后路由到对应分表。

但这里有个极大的坑:如果你的分表规则设计不合理,查询时没有带分表键,那Atlas就只能对所有分表做全表扫描,把每条分表的结果全部合并返回。这在数据量小的时候问题不明显,等数据量大了,一次查询可能要打几十张表,性能直接崩掉。所以分表键的选择和查询习惯的设计,是分表方案能否跑得好的核心前提,比中间件本身还重要。

2.4 主库故障下的主从切换:一个需要你提前准备的动作

Atlas自身不具备数据库高可用切换能力。也就是说,它只是知道哪台是主库、哪台是从库,如果主库挂了,它不会自动把从库提升为主库并修改自己的配置。这需要借助外部工具做故障转移,比如MHA(Master High Availability)或者自研脚本去触发MySQL主从切换,然后把Atlas.conf里的Master和Slave配置改掉,再重启Atlas。

我看到很多初次使用Atlas的团队都会忽略这个问题,默认以为Atlas会自己搞定,结果主库一挂,整个服务直接瘫痪。所以务必在前期架构设计时就把主从切换的流程想清楚,并且做好演练。后面我会专门有一节讲这个踩坑。

3. 部署实操:从源码编译到生产环境上线

Atlas的安装方式主要有两种:官方提供了编译好的二进制包,至少有CentOS和Ubuntu版本;另一个是自己从源码编译。我强烈建议一般团队直接使用官方二进制包,省时省力,只有需要定制化内核或改代码的团队才需要走编译这条路。

3.1 环境准备与依赖检查

操作系统层面,我用的CentOS 7 x86_64。依赖方面,Atlas需要依赖libevent、glib2、mysql-devel这些基础库。如果你下载的二进制包在启动时报缺少动态库的错误,通常就是这些依赖没装齐。

yum install -y libevent libevent-devel glib2 glib2-devel mysql-devel ncurses-devel

建一个专用的系统用户来跑Atlas,不推荐直接用root,这是个基本的安全习惯。

useradd -M -s /sbin/nologin atlas mkdir -p /usr/local/mysql-proxy chown -R atlas:atlas /usr/local/mysql-proxy

3.2 安装与目录规划

把二进制包解压到/usr/local/mysql-proxy目录后,里面会有bin和conf两个目录。bin里是一个叫mysql-proxy的可执行文件,Atlas的运行就是靠它。注意,虽然它继承了mysql-proxy的名字,但奇虎360在原版基础上做了大规模改造,和MySQL官方的mysql-proxy已经完全不是同一个东西了。

Atlas启动之后主要监听两个端口:一个默认是1234,这是业务流量入口,就是给应用连的;另一个是2345,这是管理端口,运维人员和脚本通过这个端口执行管理命令。配置文件放在conf目录下,一般叫Atlas.conf。还有个重要的文件是分表规则文件,默认叫shard.conf或者加在Atlas.conf尾部,各版本命名有差异,按实际来。

我习惯这样规划目录:

  • conf/Atlas.conf —— 主配置文件
  • conf/sharding.conf(或Atlas.conf中的分表段) —— 分表规则
  • logs/ —— 日志目录,包括sql.log和error.log
  • bin/mysql-proxy —— 可执行程序

3.3 配置文件的详细解析

下面是一份我在生产环境中用的Atlas.conf模板,去掉了敏感信息,每个关键项都注释了含义:

[mysql-proxy] # 是否以后台守护进程方式运行 daemon = true # 管理端口绑定的地址和端口 admin-address = 0.0.0.0:2345 # 业务流量入口绑定的地址和端口 proxy-address = 0.0.0.0:1234 # 管理接口的用户名和密码,用于连接管理端口 admin-username = admin admin-password = admin_pwd # 后端主从MySQL配置 # 主库(可写) proxy-backend-addresses = 10.0.0.2:3306 # 从库(可读),多个从库用逗号分隔 proxy-read-only-backend-addresses = 10.0.0.3:3306,10.0.0.4:3306 # 连接Atlas自身的认证用户 pwds = root:xxxxxx # 分表规则所在的文件 shard-file = /usr/local/mysql-proxy/conf/shard.conf # 日志级别,debug级别会输出每条SQL,生产建议用message,诊断问题临时开debug log-level = message log-path = /usr/local/mysql-proxy/logs # 工作线程数,建议与CPU核数相同 event-threads = 8 # 会话空闲超时时间,单位秒 wait-timeout = 60

这里面有几个容易踩坑的地方:

第一,pwds是连接Atlas的认证用户配置,格式是“用户名:加密后的密码”。这里的密码不是明文,是MySQL加密后的密码串。怎么获取?在MySQL服务器上执行SQL来生成:

SELECT PASSWORD('your_password');

把返回的那一串密码填进去。千万不要直接填明文,否则Atlas会拒绝认证。这是新人使用Atlas最常见的坑。

第二,如果暂时不分表,shard-file可以留空或不配置。但一旦配置了,Atlas启动时就会强制校验分表规则文件的格式,格式不对会启动失败。

3.4 启动、停止与验证

启动很简单:

/usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/usr/local/mysql-proxy/conf/Atlas.conf

注意,Atlas默认使用/etc/mysql-proxy.cnf作为配置文件,如果你把配置放在了别的路径,一定要用--defaults-file指定。而且配置文件要求权限是0600,否则启动时会报错。这也算是一个隐蔽坑,我遇到过直接复制配置文件过去忘了改权限的情况。

启动后验证两件事:

  • 业务端口是否监听:netstat -tlnp | grep 1234
  • 管理端口是否监听:netstat -tlnp | grep 2345

然后用管理端口连进去看后端状态:

mysql -h127.0.0.1 -P2345 -uadmin -padmin_pwd

执行SELECT * FROM backends;,应该能看到主库和从库的状态。正常状态下主库的type是rw,从库type是ro,status是up。

为了业务流量连通性,最好再用一个有业务的账号试连一下1234,跑一条简单的SELECT,确认读写分离生效:

mysql -h127.0.0.1 -P1234 -uappuser -papppass -e "SELECT 1;"

如果这条能通,整体链路基本就算起来了。把Atlas注册成systemd服务也好,写个启动脚本扔进rc.local也好,反正要保证开机自启。

4. 分表与读写分离配置实战:让规则真正跑起来

我见过很多团队部署完Atlas,测试读写分离正常,然后就开始跑业务了。但用到分表功能时,由于分表配置不正确或使用方法不对,上线当天就出了线上事故。这一节我专门把分表配置的前前后后讲透。

4.1 分表规则文件到底怎么写

我用的shard.conf是一个Python风格的规则文件,核心就是注册一个函数,函数返回分表后的表名。例如:

def main(): # 读取分表键的值 from atlas_shard_rule import * return get_shard_table(4)

稍微解释一下逻辑:Atlas的分表规则文件使用Python语法,Atlas在启动和路由SQL时会加载并执行这个文件,根据你写的规则确定物理表名。整个配置文件里可以写多个规则函数,每个函数对应一种分表模式。函数的返回值就是实际路由到的物理表名,Atlas会用它替换SQL里的逻辑表名。

我自己的分表规则文件一般长这样:

def rule_order(): table_name = "T_ORDER" shard_num = 16 return get_shard_table(shard_num) def rule_user(): table_name = "T_USER" shard_num = 8 return get_shard_table(shard_num)

等等,这个写法其实还需要再细化。前面例子里的get_shard_table内部会拿到当前语句的分表键值,再对分表数量取模。具体使用哪个分表键,是在SQL语句的WHERE条件里体现的。Atlas会从句法层面解析出分表键的值,带入Python函数,函数计算出目标分表名后,Atlas再改写SQL并路由。

4.2 建分表的最佳实践:提前建好还是动态创建

Atlas本身不负责自动创建分表。你必须在MySQL实例上把所有分表手动建好。假设逻辑表名是T_ORDER,分16个分表,你必须先在数据库里创建T_ORDER_0、T_ORDER_1、一直到T_ORDER_15这16张表。每张表的表结构完全一致,索引也一致。如果业务端有DDL变更,也要同步到所有分表上。

我强烈建议你在项目启动脚本里,或者在发布流程里,写一个遍历建表和遍历改表的脚本,确保所有分表结构完全一致。否则后期排查数据缺失问题会痛不欲生。我自己就经历过因为某分表少了索引,个别订单查询奇慢无比的问题。

不同MySQL实例上的分表怎么分布,Atlas支持在不同后端MySQL节点上放不同的分表。比如主库上放T_ORDER_0到T_ORDER_7,从库上放T_ORDER_8到T_ORDER_15。这种情况下,路由逻辑会先根据哈希值找到分表名,再根据分表名找到对应的后端节点。这个功能在生产上非常有用,可以把一个大表的数据分散到不同机器上,进一步降低单机压力。

4.3 分表后SQL编写的硬性要求

分表规则生效后,SQL写入和查询时必须带上分表键。我给你的最实在的建议是,在项目初期的代码规范里就明确下来:所有涉及分表的表,查询、更新、删除必须强制带上分表键。例如:

-- 错误示范:没有带分表键,Atlas只能全分表扫描 SELECT * FROM T_ORDER WHERE ORDER_STATUS = 'PAID'; -- 正确示范:带分表键,Atlas可以直接路由到唯一分表 SELECT * FROM T_ORDER WHERE ORDER_ID = 'A123456789';

如果确实需要在不带分表键的情况下查询,虽然Atlas会广播到所有分表再合并结果,但这种操作应该被严格控制,尽量在业务低峰期执行,或者提前在中间层缓存/搜索引擎里做条件查询。说实话,广播查询在分表数量少(比如4张、8张)且数据不是特别巨大时,勉强能用,到了16张以上基本就别指望了,延迟会指数级上升。

还有一个容易被忽略的点:分表键不能更新。如果你把某行的分表键值改了,它的哈希值就变了,理论上的位置也跟着变,但实际上数据还在老分表里,查新分表就找不到了。所以一条铁律:分表键只支持新增和查询,不支持修改。

4.4 读写分离加分表联调测试

配置完成之后,我是这样做的联调验证:

  1. 先在主库上手动插入几条测试数据,分表规则比如ORDER_ID=100和ORDER_ID=101,会路由到不同的分表,插入成功后再去各分表确认数据落位正确。
  2. 通过在代码里同时发读请求和写请求,观察Atlas日志里SQL实际被路由到了哪个后端、哪个分表。
  3. 开启debug日志临时观察:
    • 在Atlas.conf中把log-level改成debug
    • 重启Atlas
    • 执行几条典型的CRUD
    • 查看logs/sql.log里的实际路由信息

确认无误后,再把log-level改回message并重启,避免生产环境留下大量调试日志。

5. 生产环境踩坑实录:这些问题网上真的搜不到现成答案

在写这篇文章之前,我特意翻了翻以前运维Atlas这段时间积累的排障笔记。有些问题在当时花了很大力气才定位,现在回想起来,如果早点有人写出来,真的能省很多功夫。下面这些都是我实际踩过的坑,按踩坑的频率和影响程度排个序。

5.1 连接全部挂起:问题出在backends状态不一致

有一次线上突然出现大面积请求超时,检查Atlas的backends,发现主库和从库都显示up,但业务就是卡住不动。后来仔细排查,发现问题出在MySQL端:主库因为一次大事务导致临时表空间满了,所有写请求堵塞,连带Atlas的业务线程全部卡在等待后端响应上。

当时的解决办法是先把主库上的慢事务杀掉,等主库恢复后,Atlas自然就恢复了。但这个过程我意识到一个很重要的问题:Atlas没有健康检查机制,它不会自动把挂掉的后端从轮询列表里移出去。你的监控系统必须覆盖到Atlas这一层,否则你只会看到业务超时,却不知道根源在哪。

后来我加了一个定时脚本,每30秒检查一次Atlas的backends状态,只要发现某个后端状态异常或响应耗时超高,立刻报警。这类脚本网上没有现成的统一方案,我建议就自己在服务器上写个Python脚本,连上管理端口拉状态,推送报警到钉钉或者企业微信,非常管用。

5.2 主从切换后Atlas还指向旧主库

这是几乎每个用Atlas的团队都会遇到的问题,只是早晚。当主库宕机,你用MHA把从库提升为新主库之后,必须手动修改Atlas.conf中的proxy-backend-addresses和新从库地址,然后重启Atlas。

我踩过的坑是:MHA切换完成后,网站还是慢得一塌糊涂。因为旧主库恢复了,但已经变成从库,还在被Atlas当成主库接收所有写流量,新主库只是作为只读从库在背后默默复制。数据看着没丢,但高可用完全失效了。

后来我总结出一套相对顺畅的切换流程:

  1. 确认MHA完成主从切换,新主库状态正常
  2. 修改Atlas.conf,把旧的proxy-backend-addresses改成新主库地址,把旧主库地址加入proxy-read-only-backend-addresses
  3. 用mysql-proxy --defaults-file=... --reload(有些版本是HUP信号)尝试热加载配置,如果版本不支持就重启Atlas
  4. 重启后立刻在管理端口执行SELECT * FROM backends;确认主从角色正确
  5. 让业务侧做一轮功能回归测试,确认写入读取都正常

整个切换过程我们后来控制在分钟级别,而且专门做了演练,确保操作人员不需要临时翻文档就能执行。

5.3 FOR UPDATE语句导致的死锁误判

有一次业务频繁报死锁,但数据库自身的死锁日志根本不显示任何记录。查了半天发现,是业务代码里在事务里用了SELECT ... FOR UPDATE,Atlas判断正确地将它路由到了主库,但由于同一个事务里的普通SELECT被路由到了从库,瞬间产生了两个不同的连接:一个在主库锁定行,一个在从库读取快照。此时如果主库的行一直锁着,从库读请求依赖的binlog位置就会一直等待,业务表现为死锁超时。

这个问题的根源是Atlas的读写分离粒度太粗,它对“事务内语句”没有明确的黏合机制。解决思路有几种:一是把此类需要严格一致性的查询都显式加上FOR UPDATE,强制走主库;二是在配置里将所有该业务的用户设为只走主库,也就是把该用户加进非读写分离名单;三是修改代码,把事务内的查询和写库操作合并到同一个连接上执行。

第三种方案最彻底,但需要业务配合改动。我当时是让业务把事务内的读改成了FOR UPDATE,或者干脆在事务里只做写操作,事务结束之后再做查询。这个方案治标也治本,至少业务保持一致性了。

5.4 连接数被打满:Atlas自身线程和MySQL连接数的联动关系

Atlas默认的连接池行为是:一个前端连接对应一个后端连接。如果业务方连接池配置得比较大,比如最小连接数200,最大连接数500,同时有多个服务连同一个Atlas,那Atlas到后端的MySQL连接数会非常夸张。MySQL默认最大连接数是151,很快就被打满了。

解决这个问题需要多端联动:

  • 调大MySQL的max_connections,但要有度,别把系统资源拖垮
  • 控制业务连接池大小,不要在连接池里设置过大的空闲连接数
  • 在Atlas层面,event-threads线程数不要盲目调大,设成CPU核数比较合适
  • 让Atlas和MySQL之间保持内网通信,降低TCP连接建立时间

我这里给出一个我经过压测调优后的参数组合,供参考:

参数位置参数名推荐值说明
my.cnfmax_connections1000根据最大并发和内存综合评估
my.cnfwait_timeout60让空闲连接尽快释放
Atlas.confevent-threadsCPU核数太高反而引入上下文切换开销
Atlas.confwait-timeout60和MySQL保持一致
业务连接池maximum-pool-size50~100按服务实例数和吞吐量评估

5.5 分表键没走索引:少了一个普通的WHERE条件引发的惨案

分表键的选择也很讲究。前面说业务查询必须带上分表键,但如果你带的是个区分度很低的字段,比如状态字段,那分表本身意义不大,因为哈希结果会集中在某几个分表上,造成数据倾斜。更严重的是,如果你在建表时没有为分表键建索引,那么即使路由对了分表,在分表内部也会产生全表扫描。分表只是把你的大表变成多张小表,但如果你不建索引,每张小表依然要全扫。

所以设计表结构时,必须把分表键纳入索引设计的第一优先级。一般建议分表键同时是查询高频条件,比如订单号、用户ID。这样既能精准路由,又能在单表内用上索引,性能才真正有保障。

6. 日常运维与监控:让Atlas稳定运行的管理手段

一个中间件跑起来之后,日常维护工作其实不少。Atlas本身提供的功能有限,但用好管理和监控手段,还是能过得比较从容。

6.1 管理接口的实用命令

管理端口是整个运维的核心入口,以下命令是我最常用的:

-- 查看所有后端节点的状态 SELECT * FROM backends; -- 动态加入一个从库节点,避免重启 ADD RO BACKEND '10.0.0.5:3306'; -- 动态下线一个后端节点,常见于数据库实例维护 REMOVE BACKEND 3; -- 查看当前Atlas的配置信息 SELECT * FROM config;

动态上下线功能特别重要。比如要从库做备份或者升级,直接REMOVE再ADD,业务侧完全无感知,不需要重启Atlas。

6.2 日志是排障的第一现场

Atlas的日志目录下一般有sql.log和error.log。sql.log在log-level=debug时记录每一条SQL的路由详情,error.log则记录运行时的错误信息。平时排障,我的顺序是:先看error.log,再看sql.log,最后看系统层面的dmesg和MySQL慢查询日志。

调试SQL路由问题时,一条典型的debug日志大概长这样:

[DEBUG] 2024-05-20 10:15:30: (sql) SELECT * FROM T_ORDER WHERE ORDER_ID = '123' -> route to backend 10.0.0.3:3306, table: T_ORDER_5

看到这行日志,你就能明确知道这条SQL被路由到了哪个从库、哪个分表。如果发现路由结果和预期不符,先检查分表规则文件,再检查SQL是否带了正确的分表键。

6.3 监控项:不盯这些,出了问题只能干瞪眼

根据我对Atlas长期的运维观察,下面这几个监控指标至少要有:

  • Atlas进程是否存活:最简单,一个进程监控脚本或systemd守护就能解决
  • 管理端口能不能连:能连说明进程本身没死,但可能处在异常状态
  • backends里各节点的连接数:如果某个后端节点连接数异常高,大概率是有慢查询堵住了连接池
  • Atlas到后端的响应延迟:可以用tcprstat之类工具统计Atlas和MySQL之间的网络延迟,也可以直接在MySQL端开general_log观察Atlas过来的请求是否变慢
  • 分表数据分布是否均匀:定期抽查各分表的行数,确认数据没有严重倾斜

这些监控项不用全部自己造轮子,如果你有Zabbix或Prometheus,可以直接接进去。Atlas没有官方exporter,我当年是用脚本轮询管理端口拿到状态数据,再转成metrics推到Prometheus,画到Grafana上。效果挺好,中间件自身的状态一目了然。

6.4 高可用架构的完整形态

最后说一个理想的Atlas部署形态,避免读者在搭建时只在单台机器上跑一个Atlas就以为完事了。

我建议的架构是:两台机器各部署一个Atlas实例,前置一台HAProxy做负载均衡,后端的MySQL主从由MHA或自研工具负责切换。这样任意一台Atlas挂了,HAProxy会自动摘除,业务流量全部转发到存活的那台。Atlas本身是无状态的代理,配置保持一致即可,不涉及数据同步问题,所以高可用实现起来并不难。

后端MySQL层面,主库挂了MHA自动切换,然后通过外部脚本更新两台Atlas的配置。整个链路里,HAProxy是唯一还需要再考虑高可用的点,通常再配一组Keepalived漂移VIP就能解决。

这套架构跑下来,数据库入口层基本就没有明显的单点了。业务方只认一个VIP,背后具体是哪个Atlas在扛、哪台MySQL是主,都跟业务无关,运维自主可控。

回到Atlas这个项目本身,虽然它不像今天云原生时代的很多新组件那么花哨,但作为MySQL中间件领域一个极其务实的开源项目,它的设计思路和实现方式,放到现在的很多场景里依然有参考价值。如果你正在评估轻量级读写分离方案,或者想理解代理层数据库中间件的工作机制,Atlas确实是个值得研究的样本。

最后留一句实在话:任何中间件都只是工具,用得好不好,关键还是理解它背后的路由逻辑和边界条件。配置照着抄很简单,真正考验功力的,是出了问题之后,你能不能从一堆日志里,快速定位到它把SQL送到了哪里、为什么会送错。掌握这个能力,比会装一个Atlas值钱多了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/19 14:28:09

2026年AI招聘产品盘点:从ATS进化到对话式招聘机器人

这两年AI招聘产品在人力资源行业的热度,有点出乎我早年的预料。三年前大家聊的还是“简历解析准不准”,今天HR圈子里讨论的已经是“AI能不能替我把整个校招季跑完”。2026年这个时间节点,市面上真正被HR群体高频使用、愿意续费、甚至愿意主动…

作者头像 李华
网站建设 2026/10/19 14:26:15

旋转目标检测数据格式转换:roLabelImg的XML转YOLO OBB txt实战

写这篇东西的起因很简单:我手头有一批用 roLabelImg 标好的旋转目标检测数据,标注文件全是 XML。项目中途决定换到 YOLO 系列做训练,结果发现 XML 不能直接用,必须转成 txt。光看这个需求觉得不就是改个后缀吗?真动手才…

作者头像 李华
网站建设 2026/10/19 14:25:19

FPGA实现VGA显示系统:从时序控制到EDID读取的完整工程实践

简介:本资源是一套面向FPGA初学者与嵌入式硬件开发者的VGA显示系统实践资料包,聚焦视频输出、外设通信与存储扩展三大核心能力培养,适用于课程设计、毕业设计及小型图像处理项目开发。包内涵盖VGA时序驱动代码(含乒乓球游戏实例&a…

作者头像 李华
网站建设 2026/10/19 14:24:49

CMake execute_process 指令深度解析:构建时系统交互核心机制

1. 项目概述:为什么一个看似“冷门”的指令值得单独写三千字? execute_process 这个指令在 CMake 官方文档里只有一页半的说明,连示例都只给了三个最基础的用法。我第一次在某开源项目的 CMakeLists.txt 里看到它时,还以为是自…

作者头像 李华
网站建设 2026/10/19 14:23:08

从零搭建可用的skills技能管理体系:分类、评估与动态维护实操指南

1. 从“skills”这个词说起:为什么它突然成了高频搜索词最近一段时间,“skills”这个词在各类社区和搜索榜单上出现的频率明显高了起来。不管是在职场交流群、技术社区,还是各种学习型社群里,大家都在讨论“skills”相关的话题。有…

作者头像 李华
网站建设 2026/10/19 14:22:25

树莓派5上的YOLOv5部署:ONNX Runtime推理优化实践

把YOLOv5模型从训练环境搬到树莓派5上跑目标检测,最直接的办法当然是在树莓派上装PyTorch,然后老老实实跑detect.py。但真走到部署这步,你会发现这条路在ARM开发板上走得太不顺:依赖装起来费劲,推理慢,内存…

作者头像 李华