Atlas数据库中间件实战:MySQL读写分离部署与配置详解

发布时间:2026/10/19 8:49:59
Atlas数据库中间件实战:MySQL读写分离部署与配置详解
到底什么是atlas如果不限定领域这名字能扯出好几份完全不同的事业线地图册、数据库中间件、机械臂末端执行器、放疗计划系统、一个开源的表情包数据集……技术圈里最常碰到、也最值得掰开揉碎聊聊的是数据库中间件这颗“旧糖”。我最早接触atlas是做MySQL读写分离改造的时候业务量涨到主库连接数撑不住又不想在应用里硬编码多数据源折腾了一圈最终落在atlas上。这篇文章不是官方文档的复读而是我把atlas从部署、配置、调优到踩坑这整套流程走完后的实操总结适合刚接手数据库中间件、或者正在为读多写少业务做架构选型的朋友参考。1. atlas整体设计与核心思路1.1 它真正解决的问题是什么先说清楚atlas到底干了什么。它本质上是一个位于应用和MySQL之间的代理层工作在MySQL协议层对客户端呈现为一个MySQL实例对后端则负责把SQL按规则转发到不同的真实MySQL节点。最常见的用法是读写分离主库处理写请求从库处理读请求这样一个逻辑入口就把后端的多节点拓扑藏起来了。我遇到过不少团队的初始方案是在业务代码里写两个数据源读走A连接写走B连接本地调试没问题一上灰度就出乱子事务B踩到只读从库、延迟导致读不到刚写入的数据、某张报表SQL把从库打爆。这些问题的根源是业务和数据库拓扑耦合了。atlas的价值在于把“请求该去哪个库”这个决策从业务代码中剥离出来由中间层统一处理客户端只需要连接atlas的地址像连普通MySQL一样发SQL就行。1.2 为什么是atlas而非其他方案市面上类似角色还有不少MySQL官方Route、MaxScale、ProxySQL、ShardingSphere等等。我当时选atlas核心原因是三个字轻、透、稳。轻是指部署简单单个二进制加一个配置文件就能起来不像ShardingSphere那样要么引入Java依赖做应用内代理要么搭一套独立的Java服务对中小团队来说维护成本偏高。透是指它专注在协议转发层不搞乱七八糟的额外功能连接池、读写分离、简单分表场景覆盖得刚刚好。稳则是因为它源自奇虎360经历过大流量线上环境的考验有很多像连接数管理、后台管理接口之类的细节考虑得比较周全。当然它也有先天不足比如对复杂分片支持有限、配置文件改动要重启进程才生效、后面维护节奏放慢等所以选型时别指望一个atlas包打天下它就是一把用得顺手的螺丝刀不要拿它当瑞士军刀使。1.3 一次SQL请求的完整旅行用一个具体例子说明atlas的工作流程。客户端发起SELECT * FROM user WHERE id100客户端建连到atlas监听端口atlas按配置的proxy-backend-addresses和proxy-read-only-backend-addresses分配后端的连接。SQL语句进入atlas的SQL解析模块判定类型。如果是SELECT、SHOW等读语句在没有开启事务的上下文时atlas会把请求哈希到只读后端中的某一个节点执行如果是INSERT、UPDATE、DELETE、DDL等写语句则路由到主库。如果客户端显式执行了BEGIN/START TRANSACTION在事务提交或回滚之前所有SQL一律走主库保证事务的隔离性和一致性。这个过程在客户端侧是无感的。你拿mysql -hatlas_ip -P1234去连执行SHOW VARIABLES之类还能正常返回但实际数据是从代理绕了一圈才拿到。2. 关键配置项与路由规则深度解析2.1 配置文件体系概述atlas的配置不像一些新项目用YAML或者键值对一套到底它分了两块主配置文件和分表规则文件。主配置文件在conf/目录下通常是以实例名命名的test.cnf。配置语法是Linux常见的key value格式。初次看到会觉得有点像MySQL的my.cnf但每一项的含义差很多。分表规则文件也叫tables文件路径由主配置里的tables项指定。主配置文件控制实例的基本行为分表规则文件描述哪些表做了分片、分片键是什么、分片算法怎么算。2.2 主配置里最重要的几个参数直接挑生产环境必须理解到位的几个参数说。proxy-address 0.0.0.0:1234atlas对外暴露的MySQL协议地址客户端连接这个端口。为了兼容习惯这个端口建议尽量用3306或者接近3306的端口有些老的ORM框架会对端口做特殊处理。proxy-backend-addresses 192.168.1.10:3306写后端也就是主库地址。可以配多个但这个中间件对多主场景不建议依赖它写路径还是单主更可靠。proxy-read-only-backend-addresses 192.168.1.11:3306,192.168.1.12:3306只读后端也就是从库实例。多个从库地址用逗号分隔写库要执行轮询算法进行负载分发。pwds root:加密密文客户端认证的账号和密码密码不是明文需要用atlas自带的加密工具对明文密码进行编码然后把密文写到配置里。admin-address 0.0.0.0:2345管理接口地址后续想查看后端状态、在线踢连接都靠这个接口。2.3 读写分离的路由逻辑细化把路由逻辑再往前推一步。atlas对于SELECT的处理不是无脑走从库有几个细节需要注意如果SQL语句带FOR UPDATE锁这类语句虽然语法上是SELECT但本质是写操作atlas对SELECT ... FOR UPDATE会识别出来并路由到主库。带LOCK IN SHARE MODE的查询也是类似逻辑。存储函数、存储过程中的读写操作atlas只能在调用层面判断函数内部的语句不会被分析和路由所以涉及存储过程尽量在配置层面把这类调用整体路由到主库或者避免用存储过程。对于不在事务里的SELECTatlas会在多个从库之间轮询分发第一次连A第二次连B依次循环。这个路由结果是希望在绝大多数场景下读压力能均匀分摊到各从库而不是一台被打到高负载。2.4 分表规则与分片键选择如果你有单表数据量过大、想按某种维度拆开存储的需求atlas也提供了基于分片键的分表能力。配置文件写法类似tables user.id.hash, order.id.range这个写法里每一段表示一张表的分表方式。以user.id.hash为例含义是对user表按id字段做哈希分片order.id.range表示按id做范围分片。分片数量在分表规则文件中定义比如user切成4张表哈希值的计算会对分片数取模落到对应分片。分片键的选择是分表的核心如果选错了整个分表的收益就是负数。实际经验是分片键必须出现在绝大多数查询的WHERE条件里否则中间件只能把查询广播到所有分片然后在内存里汇总这个开销巨大。分片键的基数要够大比如用户ID、订单ID、手机号都算可以别选性别、状态这种只有几个取值的字段。如果业务有按时间维度滚动查询range分片会更友好能把冷热数据分离如果是随机点查居多用hash分片更均匀。2.5 atlas的密码加密机制配置里所有业务账号的密码都必须用atlas自带的加密工具生成。这一步很多人会忽略直接写明文的pwds root:123456然后启动报错或者客户端认证失败。正确做法是在安装目录的bin下面能找到encrypt工具执行./bin/encrypt 123456终端会输出一串密文把这串密文粘贴到配置文件的pwds字段里。注意pwds字段的格式是用户名:密文多个用户用逗号分隔。在测试调试阶段也可以用--help看下选项不要直接在进程启动命令行里跨过配置写明文密码否则有泄露风险。3. 实操部署从安装到第一笔读写分离3.1 环境准备与依赖规划部署atlas之前先亮出我推荐的软硬件基线供你参考操作系统CentOS 7.x或Debian系都可以glibc版本不要太老。依赖库libevent、glib、mysql client库等安装时如果有缺失会有明确提示装好即可。部署目录建议单独放在/opt/atlas或者/data/atlas不要放在系统临时目录因为日志和配置要长期留存。建议以独立系统用户运行比如新建一个atlas用户避免直接用root跑代理进程。3.2 安装步骤详解atlas的安装方式比较简单官方提供的是编译好的二进制包解压即用。tar -zxvf atlas-2.2.1.el6.x86_64.tar.gz mv atlas-2.2.1.el6.x86_64 /opt/atlas cd /opt/atlas解压后的目录结构通常包含bin、conf、log等子目录。首次启动前需要确认二进制有执行权限配置文件是否就位。之后进入配置阶段这是整个部署里最容易出错的一步我用一个实际例子说明完整配置。[mysql-proxy] # 对外服务地址 proxy-address 0.0.0.0:1234 # 管理接口地址 admin-address 0.0.0.0:2345 # 管理员账号 admin-username admin admin-password admin # 主库地址多个用逗号分隔 proxy-backend-addresses 192.168.1.10:3306 # 从库地址 proxy-read-only-backend-addresses 192.168.1.11:3306,192.168.1.12:3306 # 业务账号 pwds root:OZkGX1fLfQ8 # 分表规则文件 tables conf/tables # 日志级别 log-level message # 日志路径 log-path log/配置完成后可以用以下命令把atlas启动起来/opt/atlas/bin/mysql-proxy -d --defaults-file/opt/atlas/conf/test.cnf-d表示以守护进程方式运行。启动后立刻看看进程是否存活ps -ef | grep mysql-proxy再到日志目录看有没有报错。如果进程起来了但客户端连不上优先查看监听端口netstat -tlnp | grep 12343.3 验证读写分离是否生效用mysql客户端连接atlas地址执行几条SQL观察效果。mysql -h127.0.0.1 -P1234 -uroot -p123456连上后先执行SELECT port;如果你发现返回值不是atlas的端口而是某个后端MySQL的真实端口说明代理已经工作了。接着做一次有说服力的测试对从库做标记法在从库上增加只属于从库的演示库例如在192.168.1.11的MySQL里执行CREATE DATABASE db_from_1;在192.168.1.12里执行CREATE DATABASE db_from_2;。连接atlas执行SHOW DATABASES;多执行几次如果能看到db_from_1和db_from_2交替出现说明读请求确实轮询到了不同从库。再执行写操作比如建一个测试表然后到主库上用SHOW TABLES确认写入已经到达主库。这个标记法是我在排障时最常用的路子直观、不易误判。比单纯看代码逻辑更可靠。3.4 管理接口的常用操作atlas的管理接口可以实时查看后端状态、连接状态用于运维管理。连接方式一样是mysql客户端只是端口换成admin-address。mysql -h127.0.0.1 -P2345 -uadmin -padmin进去之后有几个常用命令SELECT * FROM backends; SELECT * FROM clients; SELECT * FROM pools;backends视图可以看到每个后端类型是rw还是ro状态是up还是down还能看到连接数分配情况。这个管理接口的价值在排障时尤其明显连接数打满了是先看clients里有没有异常的长连接主从切换后用backends确认中间件是否发现了拓扑变化都不需要额外部署监控agent。4. 生产环境优化与高可用架构4.1 连接管理与超时参数调优atlas默认的后端连接管理有一套连接池机制连接池不是越大越好。我见过一个团队把连接池配得特别大结果主库连接数直接被打到了上限应用端的表现反而是更慢。几个和连接相关的配置项max-connections客户端到atlas的最大连接数要根据实际并发合理设置超出的连接会被拒绝不是无限排队。wait-timeout连接空闲超时时间。如果业务侧有长连接池这个值要适当放大或者直接把应用连接池的空闲检测时间调整到小于中间层超时避免中间层把连接断开又重连造成无谓开销。backend-connect-timeoutatlas和后端MySQL建立连接的超时时间网络抖动明显的场景可以适当调大。参数调优的原则是先看监控再动配置。没有监控就乱调最后都不知道是哪个改动让系统变慢的。4.2 高可用部署LVS多atlas节点单点atlas始终是个隐患进程挂了、机器宕机业务全断。生产中我建议把atlas放在LVS后面做负载均衡和高可用。部署架构类似LVS作为虚IP入口承担流量分发。LVS后面挂两台atlas节点一主一备或者同时工作互为主备。每台atlas分别连接相同的主库和从库集群。LVS的健康检查脚本可以定期检查atlas的admin端口或者服务端口探测不到就自动摘除节点。这个方案好在哪里它把atlas的故障隔离在接入层应用感知不到具体节点切换。注意LVS本身又成为新的单点所以LVS也要做双机热备用Keepalived做VRRP虚IP漂移。我之前在多个生产环境落地过这套整体效果稳定。如果团队根本没人会维护LVS也可以退一步用云负载均衡产品接入原理一致。4.3 主从切换后的atlas处理数据库主从切换后atlas不会自动感知后端角色变化这是必须牢记的一个点。比如原来192.168.1.10是主库现在主库挂了管理员把192.168.1.11提升为主库。此时atlas配置里写死的proxy-backend-addresses 192.168.1.10:3306已经指向一个不可用的实例客户端写请求就会失败。通常做法是修改atlas配置文件把新主库地址写到proxy-backend-addresses。平滑重启atlas。如果担心连接中断可以在业务低峰期操作或者在前面的LVS层先把流量切到备用atlas再重启另一个。如果不想频繁改配置文件可以尝试用管理接口调整backends状态具体能力受版本限制建议先小范围验证再依赖。这里插一句主从切换最好做成标准操作流程连atlas配置一起纳入变更单否则每次切换都靠人肉记住中间件配置迟早会出事。4.4 监控与告警的落地思路atlas的监控不像MySQL本身那么完备除管理接口的实时状态外比较有效的方法是在日志输出侧下功夫。我的做法是log-level调到一个稳定可用的等级message级别的日志会包含每一条转发SQL的关键信息但量很大生产环境慎重。把日志目录单独挂盘避免日志写满根分区。写脚本定时从admin接口拉取backends和clients信息上报到监控系统一旦某后端状态变为down或者连接数突增就告警。每条SQL转发耗时能在后续版本的日志或优化配置中体现如果业务有明显的慢查询优先排查后端数据库和SQL本身不要只盯着atlas。5. 常见问题与踩坑实录5.1 客户端认证失败典型报错是Access denied for user或者ERROR 1045 (28000)。排查顺序依次是配置文件里的pwds字段是否使用的是加密密文而不是明文。密码是否在MySQL后端存在且host匹配了atlas所在机器的IP。atlas里的用户名和密码是否和后端MySQL的实际账号对得上。中间件只是转发认证信息认证是在后端做的。有一次我排查半天最后发现是后端MySQL的账号host限制是192.168.1.%但atlas连后端时走的源IP是VIP导致认证被拒这类网络层问题光看配置很难一眼发现。5.2 事务中的读请求跑到从库如果你在应用中用了分布式事务、或者有跨库操作要留意atlas对BEGIN这类语句的识别。通常START TRANSACTION之后的SQL中间件能正确路由到主库。但如果业务代码隐性开启了事务而没用标准语句比如连接池开着autocommit0中间件看到的还是一串普通SELECT就可能路由到从库去。解决方式是规范业务代码里的事务写法强制要求写库和事务操作使用独立连接并且显式提交或回滚。5.3 分表键没走导致全分区扫描分表规则里定义了user.id.hash但SELECT * FROM user WHERE name张三这种查询没有带ID条件中间件只能把请求广播到所有分表。数据量小的时候还行分片一多性能立刻雪崩。这类问题的排查思路是先从慢查询日志看哪些SQL占了大部分耗时提取WHERE条件对比分片键是否覆盖没有覆盖的分片键查询能改业务SQL就改不能改就得考虑引入搜索引擎或做宽表冗余。指望中间件帮你全自动处理不存在的。5.4 网络层TCP连接数过高atlas在连接管理上对每个客户端的连接会保持一段时间高并发场景下后端MySQL连接数也会水涨船高。如果发现TCP连接数异常高用netstat看下是哪些IP在大量建连再回业务侧看连接池配置是否合理。有些ORM框架默认起来就建一批连接连接空闲后不主动回收时间久了就会在atlas上堆积不少CLOSE_WAIT。处理这类问题我习惯先把应用连接池的最大连接数调到一个业务实际能跑满的值不要照着示例配置抄一个大的再配合atlas的wait-timeout回收空闲连接基本能把连接数控制住。5.5 日志中常见的几个warning及应对cant connect to backendatlas连不上某个后端库。优先检查网络联通、后端端口、账号权限。no backend alive所有后端都不可用服务基本处于不可用状态。这种告警要最高优先级处理多半是后端数据库集体故障或者网络分区。too many connections后端MySQL连接数满了要么是连接池配置不合理要么是后端DB本身连接数被打满。先看应用侧能不能回收连接再考虑扩容。日志文件默认在log/目录下建议按天分片切割否则单文件无限增长会拖垮运维排查。我通常写一个简单的crontab脚本定期归档压缩日志避免日志盘被写满。最后再分享一个小技巧如果你准备在生产环境引入atlas但心里没底可以先搭一个最小实验环境一台主库、一台从库、一台atlas把读写分离和分表规则都验证一遍然后用上面的标记法把读写路径彻底搞清楚。我在实际部署中体会到atlas最怕的不是瓶颈而是对路由逻辑的不确定性。搞懂了它怎么路由、怎么连接后端后面调优和排查都是水到渠成的事。这个工具在今天的数据库技术栈里不算是主角但在没有庞大研发团队的场景下它依然是一个务实的选择。