V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
flikecn
V2EX  ›  数据库

一个分布式 MySQL Binlog 存储系统的架构设计

  •  1
     
  •   flikecn · 2019-01-27 08:00:18 +08:00 · 3370 次点击
    这是一个创建于 2116 天前的主题,其中的信息可能已经有所发展或是发生改变。

    1. kingbus 简介

    1.1 kingbus 是什么?

    kingbus 是一个基于 raft 强一致协议实现的分布式 MySQL binlog 存储系统。它能够充当一个 MySQL Slave 从真正的 Master 上同步 binglog,并存储在分布式集群中。同时又充当一个 MySQL Master 将集群中的 binlog 同步给其他 Slave。 kingbus 具有如下特性:

    • 兼容 MySQL 复制协议,通过 Gtid 方式同步 Master 上的 binlog,同时支持 slave 通过 Gtid 方式从 kingbus 拉取 binlog。
    • 跨地域数据复制,kingbus 通过 raft 协议支持跨地域间的数据复制。写入到集群的 binlog 数据在多个节点间保证强一致,并保证 binlog 顺序与 master 上完全一致。
    • 高可用,由于 kingbus 是构建在 Raft 强一致协议之上,能够实现集群中过半数节点存活的情况下,整个 binlog 拉取和推送服务高可用。

    1.2 kingbus 能解决什么问题?

    • kingbus 能降低 Master 的网络传输流量。在一主多从的复制拓扑中,Master 需要发送 binlog 到各个 slave,如果 slave 过多的话,网络流量很有可能达到 Master 的网卡上限。例如在 Master 执行 delete 大表或者 online DDL 等操作,都有可能造成瞬间生成大量的 binlog event,如果 master 下面挂 10 台 slave 的话,master 上的网卡流量就会放大 10 倍。如果 master 使用千兆网卡,产生了 10MB/S 以上的流量就有可能将其网卡跑满。通过 kingbus 连接 master 的方式,可以将 slave 分散到多台机器上,从而均衡传输流量。
    • 简化 Master Failover 流程,只需将连接在 kingbus 上的一台 Slave 提升为 Master,并将 kingbus 重新指向新的 Master,其他 slave 依旧连接在 kingbus 上,复制拓扑保持不变。
    • 节省 Master 存储 binlog 文件的空间。一般 MySQL 上都是较为昂贵的 SSD,如果 binlog 文件占用空间较多,就使得 MySQL 存储的数据不得不降低。可以通过将 binlog 都存储到 kingbus 中,从而降低 Master 上 binlog 文件的存储数量
    • 支持异构复制。通过阿里巴巴开源的 canal 连接到 kingbus,kingbus 源源不断推送 binlog 给 canal,canal 接收完 binlog 再推送给 kafka 消息队列,最终存入 HBase 里,业务部门通过 Hive 直接写 SQL 的方式来实现业务的实时分析。

    2.kingbus 总体架构

    kingbus 整体架构如下图所示:

    • storage 负责存储 raft log entry 和 Metadata,在 kingbus 中,将 raft log 和 mysql binlog 融合在一起了,通过不同的头部信息区分,raft log 的数据部分就是 binlog event,这样就不需要分开存储两类 log,节省存储空间。因为 kingbus 需要存储一些元信息,例如 raft 节点投票信息、某些特殊 binlog event 的具体内容( FORMAT_DESCRIPTION_EVENT )。
    • raft 复制 kingbus 集群的 Lead 选举、日志复制等功能,使用的是 etcd raft library。
    • binlog syncer,只运行在 Raft 集群的 Lead 节点上,整个集群只有一个 syncer。syncer 伪装成一个 slave,向 Master 建立主从复制连接,Master 会根据 syncer 发送的 executed_gtid_set 过滤 syncer 已经接受的 binlog event,只发送 syncer 没有接收过的 binlog event,这套复制协议完全兼容 MySQL 主从复制机制。syncer 收到 binlog event 后,会根据 binlog event 类型做一些处理,然后将 binlog event 封装成一个消息提交到 raft 集群中。通过 raft 算法,这个 binlog event 就可以在多个节点存储,并达到强一致的效果。
    • binlog server,就是一个实现了复制协议的 Master,真正的 slave 可以连接到 binlog server 监听的端口,binlog server 会将 binlog event 发送给 slave,整个发送 binlog event 的过程参照 MySQL 复制协议实现。当没有 binlog event 发送给 slave 时,binlog server 会定期发送 heartbeat event 给 slave,保活复制连接。
    • api server,负责整个 kingbus 集群的管理,包括以下内容:
      • raft cluster membership 操作,查看集群状态,添加一个节点、移除一个节点,更新节点信息等
      • binlog syncer 相关操作,启动一个 binlog syncer,停止 binlog syncer,查看 binlog syncer 状态。
      • binlog server 相关操作,启动一个 binlog server,停止 binlog server,查看 binlog server 状态。 server 层的各种异常,都不会影响到 raft 层,server 可以理解为一种插件,按需启动和停止。以后扩展 kingbus 时,只需要实现相关逻辑的 server 就行。例如实现一个 kafka 协议的 server,那么就可以通过 kafka client 消费 kingbus 中的消息。

    3.kingbus 核心实现

    3.1 storage 的核心实现

    storage 中有两种日志形态,一种是 raft 日志(以下称为 raft log ),由 raft 算法产生和使用,另一种是用户形态的 Log (也就是 mysql binlog event )。Storage 在设计中,将两种 Log 形态组合成一个 Log Entry。只是通过不同的头部信息来区分。Storage 由数据文件和索引文件组成,如下图所示:

    • segment 固定大小( 1GB ),只能追加写入,名字为 first_raft_index-last_raft_index,表示该 segment 的 raft index 范围。
    • 只有最后一个 segment 可写,其文件名为 first_raft_index-inprogress,其他 segment 只读。
    • 只读的 segment 和对应的 index file 都是通过 mmap 方式写入和读取。
    • 最后一个 segment 的 index 内容同时存储在磁盘和内存。读取索引是只需要在内存中读取。

    3.2 etcd raft 库的使用

    Etcd raft library 在处理已经 Apply 的日志、committed entries 等内容时,是单线程处理的。具体函数参考链接,这个函数处理时间要确保尽可能短,如果处理时间超过 raft 选举时间,会造成集群重新选举。这一点需要特别注意。

    3.3 binlog syncer 的核心实现

    binlog syncer 主要工作就是:

    • 拉取 binlog event
    • 解析并处理 binlog event
    • 提交 binlog event 到 raft 集群。 很明显可以通过 pipeline 机制来提个整个过程的处理速度,每个阶段 kingbus 都使用单独的 goroutine 来处理,通过管道来衔接不同阶段。 由于 binlog syncer 是按照 binlog event 一个一个接收的,syncer 并不能保证事务完整性,有可能在 syncer 挂了后,需要重新连接 Master,这时候最后一个事务有可能不完整,binlog syncer 需要有发现事务完整性的能力,kingbus 实现了事务完整性解析的功能,完全参考 MySQL 源码实现。

    3.4 binlog server 的核心实现

    binlog server 实现了一个 master 的功能,slave 与 binlog server 建立复制连接时,slave 会发送相关命令,binlog server 需要响应这些命令。最终发送 binlog event 给 slave。对于每个 slave,binlog server 会启动一个 goroutine 不断读取 raft log,并去掉相关头部信息,就变成了 binlog event,然后再发送给 slave。

    4. 总结

    本文简要介绍了 kingbus 整体架构和核心组件及流程,通过这篇文章,希望读者对 kingbus 有个较为全面的认识。

    开源地址: https://github.com/flike/kingbus 欢迎感兴趣的 star,谢谢

    13 条回复    2019-01-28 10:08:08 +08:00
    whileFalse
        1
    whileFalse  
       2019-01-27 08:48:09 +08:00
    LZ 这头像。。。以前是竞鹿的吗
    chinesestudio
        2
    chinesestudio  
       2019-01-27 08:58:14 +08:00 via Android
    任何需要用到阿里的 少用为妙 开源界 360
    flikecn
        3
    flikecn  
    OP
       2019-01-27 09:06:36 +08:00 via Android
    @whileFalse 不是,只是通过竞鹿系统设计的
    misaka19000
        4
    misaka19000  
       2019-01-27 09:32:41 +08:00 via Android   ❤️ 1
    不错,有时间好好研究下,话说这是楼主一个人开发的吗?
    mritd
        5
    mritd  
       2019-01-27 09:32:49 +08:00 via iPhone
    看了半天头像 果然没记错,kingshard 作者^_^
    flikecn
        6
    flikecn  
    OP
       2019-01-27 11:11:11 +08:00
    @misaka19000 是的。一个人开发。
    flikecn
        7
    flikecn  
    OP
       2019-01-27 11:11:44 +08:00
    @mritd ,是的。kingshard 也是我的一个开源项目,多谢支持。
    mritd
        8
    mritd  
       2019-01-27 11:16:57 +08:00
    @flikecn #7 以前调研过,不过后来由于我们数据库还有些存储过程啥的,所以 读写分离 还没搞
    scalaer
        9
    scalaer  
       2019-01-27 12:14:44 +08:00 via Android
    好东西,支持一下
    flikecn
        10
    flikecn  
    OP
       2019-01-27 15:00:40 +08:00 via Android
    @mggis0or1 谢谢
    zetaoyang
        11
    zetaoyang  
       2019-01-27 20:14:00 +08:00
    @flikecn 看头像
    flikecn
        12
    flikecn  
    OP
       2019-01-28 08:56:41 +08:00 via Android
    @zetaoyang 兄 dei
    pain400
        13
    pain400  
       2019-01-28 10:08:08 +08:00
    好像发过一次啊
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1149 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 22:56 · PVG 06:56 · LAX 14:56 · JFK 17:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.