网易 IM 云分布式数据库架构介绍
网易 IM 云服务为百万商家亿级终端用户提供即时通信服务。商家产品爆款、用户活跃交流都在考验着我们的业务系统。如何保障系统的稳定运行,支撑更大的并发,提供真正的可扩展的 IM 云服务一直是我们非常关注的一个问题。
在数据库选择上我们使用了网易私有云中的分布式数据库服务 (云 DDB)
其架构图如下
云 DDB 主要包括以下几个组件
1. NLB 2. SQL Proxy 3. DBN 4.Master 5. SYSDB
- NLB 是负载均衡服务,基于 LVS 打造,负责将应用请求转发到后端 SQL Proxy, 同时定时检测后端 SQL Proxy 的可用性,及时将故障机器从集群中摘除
- SQL Proxy 实现了 MySQL 协议,接收客户端请求,同时负责将请求路由到具体的后端数据库节点,并返回数据给客户端。如果数据请求分布在多个节点,则可能使用 2PC 协议进行分布式事务 (保障数据一致性)
- DBN 则是底层真正负责数据存取的服务,通常是一个关系型数据库,目前支持 MySQL、Oracle
- Master 是管理服务,负责管理集群,比如新建表、设置数据路由策略、设置客户端连接池参数、DBN 切换、配置变更通知等,操作结果 (集群元数据) 将持久化到 SYSDB
- SYSDB 是一个数据库,负责存储分布式数据库的元数据信息,包括表、字段、权限、数据路由等信息
DBN 与 SYSDB 使用的是网易私有云 RDS,其它组件则部署在使用云主机上,云 DDB 服务的核心组件 SQL Proxy 以及 DBN 都是可扩展的,并且高可用的。
DDB 处理逻辑简单来说就是应用请求通过 NLB 转发到具体 SQL Proxy 上,SQL Proxy 解析 SQL 生成执行计划,下发请求至底层节点,收到 DBN 数据后做一定的处理返回给客户端
高可用分布式 DB 服务构建指南
网易 IM 云服务对客户承诺支持弹性扩展、消息必达。那就需要保证高吞吐、高性能的同时,对数据可用性要求也极高,数据可用性说白了就是数据存储服务要高可用并且数据不丢失
因关系型数据库发展几十年在稳定性方面对比其他数据存储方案来说存在非常大的优势,基于此,业务很多对数据一致性的场景都是直接依赖于 DB,比如为了保证消息准确到达,发送方的消息需要先持久化到 DB,再发送到接收方,接收方收到之后更新为已接收状态,因此对数据库是重度依赖。
对关系型数据库来说高性能高可用跟数据不丢失又往往是鱼跟熊掌的关系, 要保证数据完全不丢失的话,数据必然是要同时写入到主库与从库才算完成,此时如果从机异常,数据写入将失败,这将导致数据库服务不可用,相信很少有人能接受。所以通常在数据一致性与服务可用性上会做一定的妥协,即正常情况下表现为主从强一致性模式,异常情况下则退化为异步模式。这在 MySQL 里面我们称之为 Semi sync 复制,Oracle 复制 (DataGuard) 里面则为最大保护模式
在保证数据服务高性高吞吐的情况下尽量避免数据丢失,我们对网易云 DDB 底层 DBN 做了如下设置
- 将 sync_binlog 与 innodb_flush_log_at_trx_commit 同时设置为 1,每次数据库写操作都会持久化 binlog 与 redo log 到磁盘上,保证数据的持久性
- 开启 VSR(virtual sync replication),保证主从能实时一致
- 开启 Group Commit,以及从库的并行复制,提升主从性能
第 2 点里的 VSR,这个是网易 MySQL 分支 InnoSQL 的一个特性,InnoSQL 在官方半同步复制 (semi sync) 基础上做了部分改进,改善了主库宕机时主从数据不一致问题,实现机制如图所示
简单来说,MySQL5.5 版本中官方 semi sync 是在 binlog 与 redo 都写完后再将 binlog 传输到从库,而 vsr 则是在 binlog 写完后与 redo log 写之前传输 binlog,这样做的好处是可以避免事务日志提交后主库宕机恢复后数据幻读问题。(在官方 MySQL5.7 中这个问题得到解决, 见 rpl_semi_sync_master_wait_point 参数解释)
当然这样做也有缺点,事务需要等待数据传输到从库后再返还,肯定会增加一定的延迟时间,针对这个问题,优化方法就是第三点开启 group commit. 开启后多个事务的 binlog 一次性提交到磁盘跟传输至从库,这样可以减少磁盘 fsync 次数并提升吞吐量
以下是 sync_group (vsr+group commit) 与原生 semi sync、 sync(vsr) 、async(不开启 semi sync) 之间性能对比图,可以看到 vsr + group commit 性能与异步复制几无差别
同时为了从库及时同步数据,我们在从库上打开并行复制,主库上事务并行提交从库上也可以并行恢复,这样大并发写入下从库没有基本延时。
随着业务的暴涨,数据量规模及 QPS 也暴涨几百倍,经过多次扩容后,为了提升 DDB 性能及容量,我们将 IM 云底层 DBN 节点从 RDS 迁移到物理机,并且使用大量的 SSD 作为底层存储。迁出 RDS 后 DDB 底层节点便不再拥有高可用这一特性,为此我们自己开发了一套 DDB 底层节点监控与切换工具 DDB Monitor,此时 DB 高可用架构图变成
DDB Monitor 可用于执行日常数据库扩容切换、故障切换、状态监控等工作
故障切换模式下会定时 (几秒) 做如下事情:
- 状态检测,包括检测 DBN 存活状态,主从复制关系,binlog 位置点,semi 状态等
- 模拟数据写入,检查主库是否可写
在判断 MySQL 主从何时可以切换方面,与其它开源工具可能有些不同,需要满足以下情况才可能触发故障切换:
- DBN 主节点无法连接,错误号为 2000-3000 间指定几个(避免 max connection 等服务端反回的错误号造成误判)
- DBN 主节点指定时间内重试多次仍无法写入
- 从库接收到的 binlog 已经应用完成或者在若干秒时间内应用完成
- 上一次数据库 vsr(semi sync) 状态正常或上一次从库收到的 binglog 落后主库若干字节内 (根据业务数据重要程度设置)
- 如果主库无法连接,从库 show slave status 中 Slave_IO_Running 状态需为 NO (从库与 DDB Monitor 工具同时监控主库是否宕机,避免脑裂问题)
- 从库 Slave_SQL_Running 状态需为 Yes
其中条件 1 与条件 2 需要满足至少 1 者。 4 中表示如果对主从一致性要求很高需要满足上次检测 vsr(semi sync) 正常才能切换,而如果可以容忍一定的数据丢失那么可以设置检测上次主从同步 binlog 差值在指定范围内即可切换
故障切换后,SQL Proxy 收到 Master 消息会重新建立到正确 DBN 的连接,主库宕机情况下基本可以在秒级别完成切换
当然除了上面这些说的这些部署上保障高可用外之外,加强数据库设计与监控也是保障数据库稳定运行非常重要的一环
数据库设计方面的措施主要有:
- 按照数据库设计规范进行表、SQL 设计。表设计尽量精简,从数据访问角度设计表结构,在范式与反范式间要做合理的取舍
- 数据请求尽量精简快,并减少垮节点访问,提升数据库真正的服务时间
- 高频查询需要添加缓存,用户配置、群信息配置等少更新高访问请求走要缓存
- 对数据一致性要求不高以及数据分析统计类的请求放到从库查询
- 非核心功能、核心但数量少频次低模块走 RDS, 避免相互影响
- 与应用合作,添加对 DB 冲击较大业务场景 (比如聊天室) 提供限流支持
数据库监控方面我们主要做了如下以下几个方面:
- DDB 各个组件的网络、系统层面通用性指标监控
- SQL Proxy、DDB Master jvmgc 信息、连接数、cpu、请求量、响应时间内存使用率日志等监控
- DBN 节点 (MySQL) Global status、processlist、innodb engine status、slowlog、数据增长率、表分区、文件句柄等监控
- 数据运维平台上报表展示基于海量监控数据下通过一定算法得到数据库容量、运行状态、重要指标不同时间同比环比,风险点分析提示,风险 SQL 指示等
一套 DDB 内通常包含几百个维度的指标监控及几十个维度的报警项
多机房高可用实践
在过往的运维经历中,我们遇到过机柜掉电、机房大面积故障等事情,这种情况的发生会严重影响产品可用性。所以对于云信等重要产品,单机房高可用显然无法满足业务追求
多机房是个非常复杂的工程,不仅需要在部署上有多机房部署,在应用层面也需要支持多机房架构,虽然我们在产品发展初期就开始了多机房高可用建设,但到目前我们并没有完全做到自动化故障切换
这里介绍下我们做的工作也是拍砖引玉,希望大家提出宝贵意见
我们多机房高可用主要做到的工作
- 备机房距主机房至少需隔两百公里距离,机房间必须有专线
- 服务入口多机房,客户端请求根据流量配置转发到不同机房服务器
- 应用与依赖组件多机房高可用部署 (MQ、Hbase、对象存储服务等),部分组件需要应用双写多机房,比如 Hbase、对象存储的写入等
- 应用访问数据服务通过配置管理服务 (DISCONF) 获取,数据库与缓存通过使用功能 (MySQL) 或复制工具 (缓存) 做跨机房数据复制
- 监控多机房组件的可用性,PE 与 DBA 部署好自动化切换工具
- 确定基于 binlog 与应用日志的重要数据校验与补偿机制
最后数据库高可用架构图:
人工切换始终会存在一定的延时,不过我们运维部强大的运维协作工具 Stone 支持移动端执行服务器命令,可以随时随地执行切换操作
QA 环节
Q1:有什么好的方案能在保证业务不中断的情况下实现跨机房大数据库迁移,在这过程中又如何保证数据的实时性呢?
A1: 数据库的实时性 可以有专线网络 + DB 复制 来保障, 不终端服务实现跨机房的话 就需要系统相关的所有组件都支持跨机房高可用,并且需要实现自动化切换。补充一点, 跨机房服务部终端,会牺牲一定的数据一致性。
Q2:请问你们都有哪些自己研发的模块开源呢?很想学习下
A2:网易 InnoSQL 是开源的,另外 redis 复制迁移工具 redis-migration 也是开源的
Q3:关系型数据库 MySQL 很流行,但是也有不足,我们最近在考虑有没有替换的方案。能否将它和其他的对比一下?你们是怎样做的选择?
A3:首先我觉得最好是选择你最熟悉的,能搞定的数据库。GitLat 数据丢失事故 我认为很大的原因是因为他们的工程师对 postgresql 不是很懂。 另外 MySQL 发展其实非常快的,5.7 有很多非常好的特性,很多东西都借鉴了 Oracle。
Q4:你们有什么开源的跨机房数据实时同步工具吗。
A4:我们网易内部有一套自己开发的数据复制工具 DTS, 目前还没有开源, 缓存复制工具有开源 是 redis-migration。GitHub 上大家可以搜一下
Q5:你们的数据访问高峰是什么时候呢?还是说一直比较平缓?还有,有没有大规模迁移数据库的经历,可以讲一讲吗 ?
A5:业务肯定有高峰低估的,一般晚上黄金时段是高峰期,凌晨是低谷。
数据迁移的话其实做好工具后,数据大小量没有太大的差别,数据量大的话 需要做限流。
Q6:从技术上选择 MySQL 和 PG 有什么区别?选择他们的时候你们是选了最熟悉的还是做了技术选型的调研?
A6:我们选择了最熟悉并且最适合我们的。PG 跟 MySQL 都非常优秀,性能上也差不多。
Q7:能不能讲讲上次大规模故障的事情?多长时间内完成恢复?有哪些措施?数据如何备份?
A7: 故障恢复通常需要做好预案, 比如当你无法做到自动化切换的时候,就需要有一套切换的脚本,另外故障切换后通常需要做好一定的限流,不能切完再挂。
数据备份方面:我们一套数据库备份系统, 数据库的备份会备份到存储服务上
Q8:你们的采用分布式数据库与单节点数据库能完全兼容吗?
A8:大部分都能兼容,少数极端的 case 不兼容
Q9:你们线上业务单表数据量能去到多少?是如何对这些表进行优化?
A9:一般我们都会分表, 一张大表可能有几十到几百张字表,百亿级表很多的,比如我们的消息表。 表优化: 1 将历史数据迁移到离线数据库 2 精确好字段长度 3 尽量以 primary key 或者联合索引去访问表
Q10:为什么不在 sql proxy 层使用 mycat?最近使用了 mycat 感觉还不错
A10:SQL Proxy 跟我们 DDB 各组件是集成在一起的, DDB 是 2006 年开始研发的,比市面上任何一款分库分表工具都悠久,我们对比过 SQL Proxy 跟 mycat, 各有优缺点
感谢木环对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们。
评论 1 条评论