资讯动态

Atlas数据库中间件详解:从读写分离到分库分表的实践指南

发布时间:2026/10/19 9:16:18 来源:尧图企业网站定制
在IT圈里“atlas”这个名字一出来不同背景的人会想到完全不同的东西搞机器人的想到波士顿动力的双足人形机器人做前端的可能想到图表库做数据库的则会立刻想起那个扛着整个集群读写压力的数据库中间件。我属于最后一类人。几年前我在公司负责线上数据库架构时从单库扛到主从再从主从扛到需要读写分离和分库分表就是在那个阶段我正式把Atlas用进了生产环境。这篇文章就以Atlas为蓝本聊透一个数据库中间件的诞生逻辑、配置原理、完整部署流程和真实踩坑记录。内容适合正在做数据库选型的后端开发、DBA也适合那些听说过中间件但对内部机制一知半解的架构师。我会尽量说人话先把原理拆开再给可以直接抄作业的步骤。1. 为什么需要“atlas”一个中间件的诞生逻辑1.1 没有中间件时的数据库困境先回到一个很朴素的问题数据库什么时候需要中间件答案不是“数据量大了就要”而是“连接方式变了才要”。早期业务量小时应用直连MySQL一台主库加一台从库主库写、从库读应用自己在代码里区分读和写的连接看起来也能跑。但一旦业务进入快速增长期问题就接踵而至。首先是连接数被打满。每个应用实例都维护一批数据库连接实例一多MySQL默认的151个连接上限很快被吃光。其次是读写分离完全靠应用自觉每个团队写一套自己的路由逻辑有的团队忘了切从库线上大查询直接打到主库主库的CPU瞬间飙高主从复制延迟跟着变大。再往后就是单表数据过亿一张表撑死也只有一千多万的容量必须拆表拆分库而拆完之后应用怎么知道数据在哪个库这些问题如果全部由业务方自己解决成本极高而且每个团队的做法还不统一。这时候就需要一个统一的入口把“数据库地址”从应用代码里剥离开来。应用只连一个代理地址由代理决定请求去主库还是从库、去哪个分片。这个代理层就是中间件。Atlas就是在这个背景下被设计出来的——它是一个位于应用与MySQL之间的透明代理核心职责是接管连接、转发SQL、做读写分离和分库分表。1.2 Atlas 的定位与核心能力Atlas 是奇虎360在2013年前后开源的数据库中间件基于MySQL-Proxy 0.8.2改造而来用C语言实现。它最大的特点是“稳定优先、功能克制”不追求大而全而是把读写分离、分库分表、负载均衡这几件最核心的事情做到位。具体来说Atlas做四件事。第一连接管理。应用连的是Atlas由Atlas维护到后端MySQL的长连接池这样一来应用侧不需要频繁建连MySQL侧看到的连接数也大幅减少。第二读写分离。写请求自动路由到主库读请求按权重分配到各个从库遇到事务或带锁的读请求则强制走主库保证一致性。第三分库分表。通过配置文件里的分片规则把同一张表的数据按某个字段的哈希或范围分布到不同的物理库和物理表上。第四负载均衡。多个从库之间可以配置权重Atlas按照权重分发读流量。相较于原生MySQL-ProxyAtlas做了一些关键增强支持MySQL官方备份工具、支持通过管理接口动态上下线后端节点、SQL日志功能更完善、对分片规则的表达能力更强。在当时那个时间点很多团队把Atlas当成了MySQL主从架构的标配组件。1.3 同一赛道里为什么选它很多人会问现在做中间件的选择那么多MyCat、ShardingSphere、ProxySQL为什么还要回头看Atlas我的观点是任何选型都要放在具体的时间点和场景里看。Atlas诞生时MyCat刚出来ShardingSphere还是当当内部的框架ProxySQL在国内还没流行。Atlas的C语言实现让它性能极好部署极简一个二进制文件加一个配置文件就能跑起来。它不依赖Java虚拟机不要求业务改代码只要把连接地址换成Atlas就行侵入性极低。对于“只想快速做主从读写分离”的团队这种“开箱即用”的体验非常难得。当然Atlas也有明显的短板。它的社区维护节奏慢官方发布的新版本不多部分高级功能需要自己改源码。分库分表规则比较机械不支持类似ShardingSphere那种灵活的分片策略。但如果你现在接手的是一个遗留系统生产环境里跑的正是Atlas这篇文章能帮你把它彻底吃透如果你在做新选型我也会在后面的内容里给出对比建议。能力项AtlasProxySQLShardingSphere部署方式单一二进制配置文件单一二进制配置文件Java依赖或独立Proxy读写分离支持权重配置简单支持查询规则灵活支持规则驱动分库分表支持规则较机械不支持SQL级分片支持策略丰富性能高C实现高C实现中高Java实现运维复杂度低中高社区活跃度低基本稳定高高2. 核心细节解析与实操要点2.1 配置体系拆解看懂Atlas的每个关键参数Atlas的配置集中在conf/test.cnf里整套配置是key value的结构。初次接触时很多人会被一堆参数搞晕其实拆开看就三类后端节点配置、前端监听配置、行为控制配置。后端节点配置是Atlas的“路标”proxy-backend-addresses指定主库地址proxy-read-only-backend-addresses指定只读从库地址从库后面可以用权重控制流量比例。前端监听配置是Atlas的“门牌”proxy-address表示应用连接的入口admin-address表示管理接口入口。行为控制配置则是Atlas的“性格”包括连接池大小、日志级别、SQL日志开关、字符集等。我最想提醒的是pwds参数。这里存的是后端MySQL账号的加密密文不是明文。生成方法是用Atlas自带的encrypt工具把“用户名:密码”作为输入得到一串加密串再填进配置。很多人图省事直接写明文结果启动时报错或者连接鉴权失败排查半天才发现是密码格式问题。配置里的charset也不能小看。如果应用端、Atlas、MySQL三处的字符集不一致很容易出现中文乱码。实际操作时我习惯把Atlas的charset显式指定为utf8同时在应用连接串里也加上characterEncodingutf8保持全链路一致。[mysql-proxy] # 主库地址 proxy-backend-addresses 10.0.0.11:3306 # 从库地址后面是权重 proxy-read-only-backend-addresses 10.0.0.12:33061,10.0.0.13:33062 # 应用访问入口 proxy-address 0.0.0.0:1234 # 管理接口入口 admin-address 0.0.0.0:2345 admin-username admin admin-password 123456 # 后端账号密文通过bin/encrypt生成 pwds proxy_user:xxxxx2.2 读写分离背后的原理与坑读写分离的原理不复杂但要把细节做对需要理解几个关键机制。Atlas收到应用发来的SQL语句后会先做一层解析。SELECT语句通常路由到从库INSERT、UPDATE、DELETE等写语句路由到主库。但这里有几个容易踩坑的例外。第一个例外是事务。应用执行BEGIN之后后续的所有SQL都必须走同一个连接否则事务就断了。Atlas的做法是一旦检测到事务开始事务内的所有请求全部锁定在同一个后端连接上直到COMMIT或ROLLBACK。所以如果你在用set autocommit0做批量更新别担心中间被切断Atlas对事务的粘性处理是可靠的。第二个例外是带锁的读。SELECT ... FOR UPDATE和SELECT ... LOCK IN SHARE MODE必须走主库否则在从库上加锁没有任何意义。Atlas会对SQL文本做关键字匹配识别出这类语句后强制路由到主库。这基本能覆盖大多数业务场景但如果你用了复杂的子查询、存储过程或者动态SQL拼接匹配就可能会失效。这时候有个保底手段在SQL前面加/*master*/注释Atlas看到这个注释就直接走主库。主从延迟是读写分离绕不开的话题。即使Atlas把读请求分发到从库如果主从复制有延迟应用可能会读到刚写完但还没同步到从库的旧数据。Atlas本身不直接阻止延迟读取它把选择权交给业务方。常用的兜底方案是对一致性要求极高的读操作强制走主库对可以容忍秒级延迟的读操作再走从库。这个取舍要结合具体业务做不能一刀切。2.3 分库分表规则拆库前必须想清楚的三件事Atlas的分库分表通过tables配置项实现格式大致为库名.表名.分片字段.起点值.终点值.分片个数。举个例子business.user.id.0.100000.8表示business库里user表按id字段分8个库数据范围从0到100000。这个规则本身很简单但拆库之前有三个问题必须想清楚否则后面会非常痛苦。第一分片字段怎么选。选id这种自增主键最省心但这会导致热点问题——新数据都往最后一个分片写。选user_id这类业务主键做分片可以让同一个用户的数据落在同一个分片查询时天然带分片键路由精准。最怕的是选了业务上经常变化的字段比如按用户名分片用户一改名数据就要跨库迁移这种坑踩过的人才知道有多痛。第二范围划分怎么定。Atlas的规则是连续的数值区间如果业务量增长超过预设的上限值超出部分就路由不到任何实际分片会直接报错。所以起点值、终点值的设置要给未来留出扩容余量。实测下来我的经验是“宁大勿小”就算当前数据量只有几百万也可以先把终点值设定到数十亿分片个数也可以适当多分几位后面数据量上来时可以直接用新的分片节点而不用重新洗数据。第三反向查询怎么办。分片键之外的条件查询Atlas默认是全库扫描后合并结果性能会非常差。比如按id分片但业务经常按phone查用户那就要做映射表或者引入额外的检索方案。这个不是Atlas的缺陷而是所有分库分表方案的通病提前设计好应对策略非常重要。3. 实操过程与核心环节实现3.1 环境准备与安装部署Atlas的安装非常轻量官方提供编译好的二进制包基本不需要额外安装依赖。下载后解压到/usr/local/mysql-proxy目录确认bin/mysql-proxy文件有执行权限即可。我的建议是先跑一下bin/mysql-proxy --help确认程序能正常加载动态库再继续后续步骤。如果报缺少.so库文件的错通常是系统缺少libevent等基础库用发行版的包管理工具补装一下就好。安装目录的完整结构是自动展开的bin下放可执行文件conf下放配置文件log下放日志文件。如果目录里没有log记得手动创建并给它写权限。我会习惯把Atlas单独放在一块数据盘或者日志盘上避免日志把系统盘写满。3.2 最小可用配置与启动验证安装之后照着下面的配置改一版最小配置先不要急着加复杂的分片规则把读写分离跑通再说。下面这个配置假设你有两个MySQL实例一个主库在10.0.0.11一个从库在10.0.0.12从库权重设为2主库没有权重参数。[mysql-proxy] proxy-backend-addresses 10.0.0.11:3306 proxy-read-only-backend-addresses 10.0.0.12:33062 proxy-address 0.0.0.0:1234 admin-address 0.0.0.0:2345 admin-username admin admin-password 123456 pwds app_user:加密后的密文 daemon true keepalive true event-threads 8 log-level message log-path /usr/local/mysql-proxy/log sql-log ON proxy-skip-host 127.0.0.1启动命令很简单/usr/local/mysql-proxy/bin/mysql-proxy \ --defaults-file/usr/local/mysql-proxy/conf/test.cnf启动后检查进程是否存在ps -ef | grep mysql-proxy | grep -v grep然后从应用服务器上用mysql客户端连接Atlas测试连通性mysql -h10.0.0.10 -P1234 -uapp_user -p我用一个技巧验证读写分离是否生效在Atlas的管理接口里查看每个后端的连接数然后执行一条查询再执行一条写入观察连接数变化。如果读请求打到了从库、写请求打到了主库说明路由正常。如果所有流量都集中在主库多半是配置接管了连接或者SQL解析没有命中写规则。3.3 管理接口与日常运维Atlas的管理接口是DBA日常打交道最多的地方。用mysql客户端连上admin-address指定的端口输入配置里的管理账号密码就能进入管理态。这里不是MySQL的标准数据库不能执行普通SQL但它支持一组专用命令关键是下面这几个。SELECT * FROM backends;这条命令列出所有后端节点每行会显示后端地址、类型rw或ro、状态up或down、当前连接数等信息。这是我每次巡检第一件要做的事一眼就能看出有没有从库宕机。SET OFFLINE 0; SET ONLINE 0;OFFLINE可以把指定的后端节点动态摘除ONLINE则是重新启用。这里的数字对应backends表里的序号。比如从库要重启升级可以先SET OFFLINE让它不再接收新连接等重启完成再SET ONLINE整个过程应用无感知。SELECT * FROM stats;这条命令查看流量统计能直观看到读写请求的比例。如果读比例长期为0就要检查路由规则是不是被业务方的连接串“绕过”了比如有些框架会直接连后端真实端口跳过中间件。日常运维还要重点关注SQL日志。sql-log ON会把所有经过Atlas的SQL记录到日志目录下这是我排查线上问题时最有力的证据。但生产环境建议根据实际QPS决定是否长期开启SQL日志在高并发下会产生大量IO一般只在排查问题时临时开几天。4. 常见问题与排查技巧实录4.1 高频踩坑场景Atlas进入生产环境后我陆续遇到过一些问题整理下来最典型的有六个场景每个都值得拿出来单独讲。第一个是连接数飙升。现象是应用侧大量报“Too many connections”但MySQL的连接数看起来还可以。排查后发现是Atlas的event-threads线程数设置过小连接处理不过来大量连接排队堆积在Atlas层。调整思路是结合应用实例数和单实例连接数把event-threads调到2到4倍的CPU核数同时把应用侧连接池的maxActive压到一个合理范围避免连接数无限制膨胀。第二个是主从延迟导致的读脏数据。业务方反馈刚提交的订单列表看不到刷新一下又出来了。定位后发现主库刚写入从库还没同步完成读请求已经路由过去了。为了快速止血我在订单查询接口的SQL前面加了/*master*/注释让关键查询强制走主库然后再去优化主从同步链路。第三个是分片键丢失。应用执行一条不带分片字段的查询Atlas会把这个请求广播到所有分片然后再合并结果。如果某个分片响应特别慢整个查询就会被拖死。这个问题没法靠Atlas单方面解决必须要求所有查询都带分片条件或者建立外部索引表。第四个是SQL语法不兼容。Atlas的SQL解析器对部分复杂SQL支持有限像SELECT ... FOR UPDATE、带WITH的递归查询等偶尔会出现路由错误。遇到这类问题我的第一建议是给SQL加/*master*/注释强制走主库绕开解析器的误判而不是尝试去改Atlas源码。第五个是failover之后路由不更新。主库宕机程序自动切换到了备用主库但Atlas还傻傻地往原主库发写请求报错“主库连接失败”。处理办法是修改proxy-backend-addresses指向新主库然后通过管理接口执行SET OFFLINE 0把旧节点摘除SET ONLINE 1把新节点加入。这里最关键的是要在切换脚本里加上通知Atlas的步骤。第六个是事务内偶发的“数据读不到”。场景是应用开启事务后先在一个从库上查数据再执行写操作MySQL会报“cant execute the given command because you have active locked tables”之类的错误。根因是应用把事务查询和写操作分散到了不同连接。Atlas对事务的粘性处理在大多数情况有效但如果应用用的是自动提交模式下的隐式事务就需要靠/*master*/注释强制统一路由。场景典型现象排查思路解决办法连接数飙升应用报连不上查Atlas线程数和后端连接数调大event-threads收敛连接池主从延迟读到旧数据查主从同步延迟关键查询走主库优化复制链路分片键丢失查询极慢看日志确认广播查询查询带分片条件建外部索引SQL不兼容路由错误抓SQL分析解析结果加强制注释走主库failover后写失败写请求报错查Atlas后端列表更新地址动态上下线节点隐式事务读不到事务内报错看日志确认连接变化统一走主库关掉隐式提交4.2 排查方法与工具排查Atlas问题我有三个屡试不爽的招。第一招是抓包看路由。用tcpdump在Atlas所在服务器上抓取1234端口的流量看客户端发来的SQL和Atlas转发出去的SQL走向。这个办法在判断“到底是谁路由错了”的时候特别有效。比如客户端发了一条SELECT但抓到的转发目标地址是主库那基本就是Atlas的解析器把它识别成了写操作针对SQL加上强制注释就能绕开。tcpdump -i eth0 -s 0 port 1234 -w atlas_debug.pcap抓包文件用Wireshark打开过滤MySQL协议报文能清楚看到完整的请求响应链路。我遇到过几次业务方信誓旦旦说“连的是Atlas”结果抓包发现应用直连了后端MySQL端口的案例这种问题靠看配置是看不出来的必须抓包。第二招是看SQL日志的前后对照。开启sql-log后同一个查询会记录两条日志一条是客户端到达Atlas一条是Atlas转发到后端。对比两条日志的时间和目标地址能快速定位延迟发生在哪一段。如果客户端到达时间正常但转发时间很晚说明Atlas层在排队要重点查连接池和线程配置。第三招是管理接口的stats命令。定期采集SELECT * FROM stats的结果能看出读写流量比例是否合理。如果某天读流量突然暴涨可能是某个新上线的报表功能没有加缓存直接打到了从库如果写比例异常高可能是某个批处理任务在高峰期跑全量更新需要调整任务时间。4.3 实战经验总结这篇文章写了Atlas从原理到部署到排障的完整链路我在实际项目里把它作为MySQL集群的接入层用了很长一段时间整体评价是它不是一个花哨的中间件但绝对是一个稳定、可控、容易理解的代理层工具。如果你正在维护一个MySQL主从集群想做读写分离但不想让业务改代码Atlas的轻量部署和极低侵入性能让你在半小时内完成上线。要我在这个环节给你一个明确的操作建议的话我强烈建议上线前做一次完整的路由验证把主库和从库分别建上不同的测试表通过Atlas执行读写操作确认读请求真正打到了从库而不是“假读写分离”。我见过太多团队上线后才发现写流量太大把主库打爆所谓读写分离根本没有生效原因就是从库权重配置太低读流量全被主库截走了。最后再分享一个小技巧不要在Atlas前面再做一层负载均衡。Atlas本身就是多节点的多个Atlas实例可以同时对外提供服务业务侧通过VIP或DNS轮询接入即可。每多一层LB出问题时排查链路就多一层迷雾而Atlas的管理接口已经提供了足够的节点状态信息真没必要再包一层。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑