美团Atlas实践
赵平仲	
  
2016.08
提纲
•  MTAtlas简介	
  
•  MTAtlas整体架构	
  
•  MTAtlas主要模块	
  
•  MTAtlas上线现状	
  
•  MTAtlas的未来计划	
  
•  Q&A
MTAtlas简介
•  基于MySQL协议的数据库中间件	
  
•  来自于360开源的Atlas
mysql-­‐proxy
(2011.8	
  )
开源Atlas
(360	
  2013.6)
MTAtlas
(2015.5	
  ~	
  now)
MTAtlas简介
•  MTAtlas的主要功能	
  
–  读写分离	
  
–  负载均衡	
  
–  结点上下线	
  
–  访问控制	
  
MTAtlas简介
Slave1 Master
ApplicaFon
readonly:slave1.sankuai.com.cn
readwrite:master.sankuai.com.cn
readonly:slave2.sankuai.com.cn
上线slave
DBA在集群中添加新从库
RD重新发布服务
下线slave
RD重新发布服务
DBA下线slave
负载均衡
ApplicaFon 实现
读写分离
ApplicaFon 实现
•  MTAtlas上线前数据库使用场景
Slave2
MTAtlas简介
MTAtlas
ApplicaFon
atlas:sankuai.com.cn
node1:slave1:port1	
  
node2:slave2:port2	
  
node3:master:port3	
  
•  MTAtlas上线后数据库使用场景
Slave1 Master Slave2
上线slave
DBA:	
  add	
  backend
下线slave
DBA:	
  remove	
  backend
负载均衡
MTAtlas实现
读写分离
MTAtlas实现
IDC2
MTAtlas整体架构
•  四层部署架构
IDC1
Atlas	
  集群
Slave1 Master Slave2
Atlas	
  集群
DNS
MGW MGW
MTAtlas整体架构-­‐软件模块
•  MTAtlas的软件模块
访问控制(用户、IP过滤)
SQL 解析 SQL 重写
SQL 执行
分库分表
管理
负载均衡 读写分离
MySQL 连接池
后台DB	
  
管理
日
志
管
理
监
控
管
理
连
接
管
理
MTAtlas主要模块-­‐连接管理
•  连接管理	
  
–  继承了开源Atlas版本按照协议机制自己处理连接建立,
数据收发的功能	
  
–  MTAtlas根据架构链路较长的特点,着重添加了对于连
接异常的检测与处理	
  
MGW MySQL
MTAtlas主要模块-­‐连接管理
–  链路模拟图
Client MTAtlas
socket1 socket2 socket3
socket4
pool
MTAtlas主要模块-­‐连接管理
–  MGW到Atlas网络异常
解决方案:	
  
•  socket2创建时添加
keepalive	
  
•  OS	
  keepalive	
  :	
  30/5/5	
  
•  OS	
  tcp_retries2:	
  5
效果:	
  
•  空闲连接,keepalive会在
1min 内检测到异常,将
链路关闭(socket2,	
  
socket3)	
  
•  发送状态,retry 机制也
会保证在1min关闭
socket2,同时socket3也关
闭
MGW MySQLClient MTAtlas
socket1 socket2 socket3
socket4
pool
MGW端socket2失效	
  
Atlas端未感知
Atlas到MySQL的链路还保持着,
如果在事务内,会引发大事务
MySQL
MTAtlas主要模块-­‐连接管理
–  Atlas到MySQL的链路异常
解决方案:	
  
•  socket3创建时添加
keepalive	
  
•  socket3 添加event事件	
  
	
   在其异常时报错	
  
•  OS	
  keepalive	
  :	
  30/5/5	
  
•  OS	
  tcp_retries2:	
  5
效果:	
  
•  空闲连接,keepalive 会在
1min 内检测到,将链路
关闭(socket2,	
  socket3)	
  
•  发送状态,retry 机制也
会保证在1min关闭
socket2,同时socket3也
关闭	
  
•  MySQL端主动关闭连接
时(wait_Fmeout),	
  event
机制可以及时发现问题
将socket3关闭
MGW端socket2失效	
  
Atlas端未感知
Atlas未感知socket3断开,分配给
socket2, 引起client查询失败
MGWClient MTAtlas
socket1 socket2 socket3
socket4
pool
MTAtlas主要模块-­‐连接管理
–  连接池中连接异常
解决方案	
  
•  socket4创建时添加
keepalive	
  
•  socket4 添加event事件	
  
	
   在其异常时报错	
  
•  OS	
  keepalive	
  :	
  30/5/5	
  
•  OS	
  tcp_retries2:	
  5
效果	
  
•  空闲连接,keepalive 会在
1min 内检测到,将链路
关闭(socket2,	
  socket3)	
  
•  MySQL端主动关闭连接
时(wait_Fmeout),	
  event
机制可以及时发现问题
将socket3关闭
MGW MySQLClient MTAtlas
socket1 socket2 socket3
socket4
pool
socket4被关闭后,如果Atlas未感知,
分配给socket2会引起client报错
MTAtlas主要模块-­‐连接管理
–  Atlas端的socket2/socket3异常	
  
解决方案	
  
•  socket2,socket3,	
  socket4
创建时添加keepalive	
  
•  添加event事件	
  
	
   在其异常或超时报错	
  
•  OS	
  keepalive	
  :	
  30/5/5	
  
•  OS	
  tcp_retries2:	
  5
效果	
  
•  由于添加了event机制,可
以检查出Atlas端socket的
状态变化	
  
•  socket2,socket3中有一方
关闭会触发另一方关闭,
保证链路安全
MGW MySQLClient MTAtlas
socket1 socket2 socket3
socket4
pool
MTAtlas主要模块-­‐连接管理
–  添加措施避免空闲连接占用
解决方案	
  
•  socket2:	
  
wait_Fmeout空闲等待时间	
  
•  socket3,	
  socket4:	
  
db-­‐connecFon-­‐max-­‐age,
连接的生命周期	
  
•  socket4:	
  
db-­‐connecFon-­‐idle-­‐
Fmeout,	
  连接池内空闲等
待时间	
  
MGW MySQLClient MTAtlas
socket1 socket2 socket3
socket4
pool
MTAtlas主要模块-­‐SQL处理模块
•  SQL处理模块
client
SQL解析/重写
SQL 执行
MySQL连接 MySQL 连接
…
2 3
1 4
连接池
client_conn
server_conn
MTAtlas主要模块-­‐SQL处理模块
•  MTAtlas	
  添加SESSION变量功能	
  
–  增加客户端连接与MySQL连接的SESSION参数
–  在分配到连接时后,先比较二者的会话级参数值,校
正参数后再执行查询
MTAtlas主要模块-­‐SQL处理模块
–  为什么要添加SESSION级变量的支持?	
  
client_con1
MySQL	
  连接
MySQL 连接
Q1:set	
  SQL_SELECT_LIMIT=1	
  
Q2:select	
  *	
  from	
  t1	
  where	
  id	
  =	
  10;
set	
  SQL_SELECT_LIMIT=1	
  
select	
  *	
  from	
  t1	
  where	
  id	
  =	
  10;	
  
Q3:select	
  *	
  from	
  t2	
  where	
  id	
  =10;(10	
  rows)	
  
client_con2
连接池SQL处理
set	
  SQL_SELECT_LIMIT=1;	
  
select	
  *	
  from	
  t1	
  where	
  id	
  =	
  10;	
  
select	
  *	
  from	
  t2	
  where	
  id	
  =10;	
  
MTAtlas主要模块-­‐SQL处理模块
client_con1
MySQL 连接
client_status=>(null)	
  
Q1:set	
  SQL_SELECT_LIMIT=1	
  
client_status=>(SQL_SELECT_LIMIT=1)	
  
Q2:select	
  *	
  from	
  t1	
  where	
  id	
  =	
  10;
client_status=>(null)	
  
Q3:select	
  *	
  from	
  t2	
  where	
  id	
  =10;(10	
  rows)	
  
client_con2
连接池SQL处理
sever_status=>(null)	
  
set	
  SQL_SELECT_LIMIT=1;	
  
status=>(SQL_SELECT_LIMIT=1)	
  
select	
  *	
  from	
  t1	
  where	
  id	
  =	
  10;	
  
set	
  SQL_SELECT_LIMIT=default;	
  
select	
  *	
  from	
  t2	
  where	
  id	
  =10;
MTAtlas主要模块-­‐SQL处理模块
–  下一步思考	
  
•  由支持SESSION变量进一步扩展到连接的所有上下文
信息,例如last_insert_id,	
  affected_rows等	
  
MTAtlas主要模块-­‐连接池管理
•  连接池管理	
  
–  将单一的连接池链表,修改成用户为key的hash表,
hash值是该用户所建立的连接	
  
pool MySQL连接 MySQL连接…
pool
Bucket1:user1
MySQL连接
(user1)
MySQL连接	
  
(user1)…
Bucket2:user2
MySQL连接
(user2)
MySQL连接	
  
(user2)…
MTAtlas主要模块-­‐连接池管理
–  为什么要做这样的修改
client_con1(user1)
MySQL 连接
client_status=>(null)	
  
Q3:select	
  *	
  from	
  t2	
  where	
  id	
  =10;(10	
  rows)	
  
client_con2(user2)
连接池SQL处理
client_status=>(null)	
  
Q1:set	
  SQL_SELECT_LIMIT=1	
  
client_status=>(SQL_SELECT_LIMIT=1)	
  
Q2:select	
  *	
  from	
  t1	
  where	
  id	
  =	
  10;
sever_status=>(null)	
  
set	
  SQL_SELECT_LIMIT=1;	
  
status=>(SQL_SELECT_LIMIT=1)	
  
select	
  *	
  from	
  t1	
  where	
  id	
  =	
  10;	
  
CHANGE_USER-­‐>user2:ERROR	
  
set	
  SQL_SELECT_LIMIT=default;	
  (user1)	
  
select	
  *	
  from	
  t2	
  where	
  id	
  =10;	
  (user1)	
  
MTAtlas主要模块-­‐连接池管理
–  按用户分配后的效果
client_con1(user1)
user1:conn_ad
client_status=>(null)	
  
Q3:select	
  *	
  from	
  t2	
  where	
  id	
  =10;(10	
  rows)	
  
client_con2(user2)
连接池SQL处理
user2:conn_ad
sever_status=>(null)	
  
set	
  SQL_SELECT_LIMIT=1;	
  
status=>(SQL_SELECT_LIMIT=1)	
  
select	
  *	
  from	
  t1	
  where	
  id	
  =	
  10;	
  
sever_status=>(null)	
  
select	
  *	
  from	
  t2	
  where	
  id	
  =10;
client_status=>(null)	
  
Q1:set	
  SQL_SELECT_LIMIT=1	
  
client_status=>(SQL_SELECT_LIMIT=1)	
  
Q2:select	
  *	
  from	
  t1	
  where	
  id	
  =	
  10;
MTAtlas主要模块-­‐访问控制
•  访问控制	
  
–  SQL 过滤	
  
•  创建黑名单,匹配一类查询	
  
–  示例1:”select * from	
  tbl	
  where	
  col2	
  =	
  ?”,	
  
–  示例2:“update	
  tbl	
  set	
  col1	
  =	
  ? where	
  pkey	
  =	
  ?”	
  
•  根据执行频率,执行时间自动添加黑名单	
  
•  提供手动添加黑名单	
  
–  根据后台Thread	
  running进行负载均衡	
  
–  用户IP限制	
  
–  从库流量配置	
  
MTAtlas主要模块-­‐访问控制
•  用户IP限制与从库流量配置示例
Atlas
user1:****atlas:sankuai.com.cn(host1)
node1:mastre	
  
node2:slave1:tag1	
  
node3:slave2r:tag2	
  
user1:tag1:host1,host2	
  
user2:tag2:host1	
  
user3:tag1,tag2:%
no	
  user1
user1:****atlas:sankuai.com.cn(host3)
host3	
  is	
  
forbidden
Slave1 Master Slave2
MTAtlas主要模块-­‐日志管理
•  日志管理	
  
–  日志时间精确到微秒: 解决了时间精度的问题	
  
–  admin中添加了对各个模块的Trace: 解决了上下文的问
题	
  
–  SQL日志增加了用户登录/退出,thread	
  id,慢查询,长
连接的记录: 增加对整个连接的完整信息	
  
–  SQL日志的自动rotate: 减少额外的处理工作	
  
–  下一步想法	
  
•  刷日志模块仍是同步方式,会有一定的性能影响	
  
	
  
MTAtlas主要模块-­‐监控管理
•  监控管理	
  
–  MTAtlas新增了监控体系:	
  
•  QPS:	
  read/write的查询个数	
  
•  processlist	
  
•  响应时间	
  
–  直方图方式展示响应时间趋势	
  
•  慢查询数量	
  
–  将出现的慢查询计数	
  
•  同步等待时间	
  
–  等待与唤醒event的时间	
  
•  Atlas到MySQL的连接数	
  
–  活动连接/连接池中连接	
  
•  client到Atlas的连接	
  
•  Atlas的Thread	
  running	
  
MTAtlas主要模块-­‐监控管理
MTAtlas主要模块-­‐监控管理
MTAtlas主要模块-­‐监控管理
MTAtlas主要模块-­‐性能改进
•  性能改进	
  
–  测试工具:sysbench	
  0.4	
  (99%	
  rt<10ms)	
  
–  优化策略	
  
•  词法分析器由串行改为并行	
  
•  连接状态切换方式改进	
  
70000	
  
210000	
  
0	
  
50000	
  
100000	
  
150000	
  
200000	
  
250000	
  
优化前 优化后
QPS	
  
QPS	
  
MTAtlas主要模块-­‐其它改进
•  其它的改进	
  
–  RPM包发布	
  
–  引入mysql-­‐test测试框架	
  
–  引入sysbench/BenchMarkSQL测试	
  
–  建立线上引流测试框架	
  
–  代码覆盖性测试	
  
–  分表若干问题(支持int64,	
  NULL类型)	
  
MTAtlas主要模块-­‐sharding版本
•  开源版本sharding的架构	
  
Atlas
tbl(1000~1999)
table=test.tbl;	
  
group=0,1	
  
group-­‐key=column_name	
  
groups=0:0~1000,1:1000~1999
group0
Slave1 Master Slave2
group1
Slave1 Master Slave2
tbl(0~1000)
MTAtlas主要模块-­‐sharding版本
•  开源sharding版本功能说明	
  
–  只⽀支持分库
–  支持hash/range的分库
–  增加了语法解析器lemon
–  不支持跨库的事务
MTAtlas主要模块-­‐sharding版本
•  MTAtlas	
  sharding版本架构
Atlas
tbl_0(0~999)	
  
tbl_1(1000-­‐1999)
table	
  =	
  test.tbl	
  
group-­‐type	
  =	
  hash	
  
group-­‐shard-­‐key	
  =	
  column_name	
  
table-­‐type	
  =	
  range	
  
table-­‐shard-­‐key	
  =	
  column_name	
  
groups	
  =	
  0,1	
  
tables	
  =	
  0-­‐999,1000-­‐1999
tbl_2(0~999)	
  
tbl_3(1000-­‐1999)
group0
Slave1 Master Slave2
group1
Slave1 Master Slave2
MTAtlas主要模块-­‐sharding版本
•  MTAtlas	
  sharding版本的改进说明	
  
–  分库 à 分库分表	
  
•  range+hash	
  
•  hash+hash	
  
•  hash+range	
  
•  hash/range分库	
  
•  hash/range分表	
  
–  改进lemon,兼容MySQL语法	
  
–  有限支持单个库内部的JOIN	
  
•  查询中涉及到的表都在同一个库	
  
–  支持单库的事务	
  
•  事务中涉及的表都在同一个库	
  
–  增加错误处理	
  
MTAtlas上线现状
支持了87%的服务,发布了5个正式版本  
MTAtlas版本上线  
Atlas开源(360)  
mysql-proxy	
  0.8.2	
  	
  MySQL社区发布  
2016.8	
  
2015.5	
  
2013.6	
  
2011.8	
  
MTAtlas的未来计划
•  未来的工作	
  
–  更强大的SQL处理	
  
•  SQL优化 row	
  cache、plan	
  cache	
  
•  分库分表全面的SQL支持,如聚集,排序	
  
•  更全面的连接上下文信息	
  
–  通用的平滑重启	
  
–  监控管理结合自动故障处理	
  
–  与MMHA融合支持自动故障切换
–  支持分布式事务
Q&A

美团点评技术沙龙010-美团Atlas实践