-
Notifications
You must be signed in to change notification settings - Fork 614
Otter 入门
从上层来看,复制分成三步:
-
master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events,可以通过show binlog events进行查看);
-
slave将master的binary log events拷贝到它的中继日志(relay log);
-
slave重做中继日志中的事件,将改变反映它自己的数据。
原理相对比较简单:
-
canal模拟mysql slave的交互协议,伪装自己为mysql slave,向mysql master发送dump协议
-
mysql master收到dump请求,开始推送binary log给slave(也就是canal)
-
canal解析binary log对象(原始为byte流)
答: 在回答这问题之前,首先来看一张canal&otter和mysql复制的类比图.
基于canal&otter的复制技术和mysql复制类似,具有类比性.
- Canal对应于I/O thread,接收Master Binary Log.
- Otter对应于SQL thread,通过Canal获取Binary Log数据,执行同步插入数据库.
两者的区别在于:
-
otter目前嵌入式依赖canal,部署为同一个jvm,目前设计为不产生Relay Log,数据不落地.
-
otter目前允许自定义同步逻辑,解决各类需求.
a. ETL转化. 比如Slave上目标表的表名,字段名,字段类型不同,字段个数不同等. b. 异构数据库. 比如Slave可以是oracle或者其他类型的存储,nosql等. c. M-M部署,解决数据一致性问题 d. 基于manager部署,方便监控同步状态和管理同步任务.
定位: 基于数据库增量日志解析,准实时同步到本机房或异地机房的mysql/oracle数据库.
原理描述:
-
基于Canal开源产品,获取数据库增量日志数据。 什么是Canal, 请点击
-
典型管理系统架构,manager(web管理)+node(工作节点)
a. manager运行时推送同步配置到node节点
b. node节点将同步状态反馈到manager上
- 基于zookeeper,解决分布式状态调度的,允许多node节点之间协同工作.
- 异构库同步
a. mysql -> mysql/oracle. (目前开源版本只支持mysql增量,目标库可以是mysql或者oracle,取决于canal的功能)
- 单机房同步 (数据库之间RTT < 1ms)
a. 数据库版本升级
b. 数据表迁移
c. 异步二级索引
- 异地机房同步 (比如阿里巴巴国际站就是杭州和美国机房的数据库同步,RTT > 200ms,亮点)
a. 机房容灾
- 双向同步
a. 避免回环算法 (通用的解决方案,支持大部分关系型数据库)
b. 数据一致性算法 (保证双A机房模式下,数据保证最终一致性,亮点)
- 文件同步
a. 站点镜像 (进行数据复制的同时,复制关联的图片,比如复制产品数据,同时复制产品图片).
说明:
a. 数据on-Fly,尽可能不落地,更快的进行数据同步. (开启node loadBalancer算法,如果Node节点S+ETL落在不同的Node上,数据会有个网络传输过程)
b. node节点可以有failover / loadBalancer.
说明:
a. 数据涉及网络传输,S/E/T/L几个阶段会分散在2个或者更多Node节点上,多个Node之间通过zookeeper进行协同工作 (一般是Select和Extract在一个机房的Node,Transform/Load落在另一个机房的Node)
b. node节点可以有failover / loadBalancer. (每个机房的Node节点,都可以是集群,一台或者多台机器)
说明:为了更好的支持系统的扩展性和灵活性,将整个同步流程抽象为Select/Extract/Transform/Load,这么4个阶段.
Select阶段: 为解决数据来源的差异性,比如接入canal获取增量数据,也可以接入其他系统获取其他数据等。
Extract/Transform/Load 阶段:类似于数据仓库的ETL模型,具体可为数据join,数据转化,数据Load的
说明:
- otter通过select模块串行获取canal的批数据,注意是串行获取,每批次获取到的数据,就会有一个全局标识,otter里称之为processId.
- select模块获取到数据后,将其传递给后续的ETL模型. 这里E和T模块会是一个并行处理
- 将数据最后传递到Load时,会根据每批数据对应的processId,按照顺序进行串行加载。 ( 比如有一个processId=2的数据先到了Load模块,但会阻塞等processId=1的数据Load完成后才会被执行)
简单一点说,Select/Load模块会是一个串行机制来保证binlog处理的顺序性,Extract/Transform会是一个并行,加速传输效率.
类似于tcp滑动窗口大小,比如整个滑动窗口设置了并行度为5时,只有等第一个processId Load完成后,第6个Select才会去获取数据。
实际测试中,otter的同步速度相比于mysql的复制,约有5倍左右的性能提升,这取决于其同步算法的实现. 抛弃了强一致性,得到了性能提升
1. insert + insert -> insert (数据迁移+数据增量场景)
2. insert + update -> insert (update字段合并到insert)
3. insert + delete -> delete
4. update + insert -> insert (数据迁移+数据增量场景)
5. update + update -> update
6. update + delete -> delete
7. delete + insert -> insert
8. delete + update -> update (数据迁移+数据增量场景)
9. delete + delete -> delete
说明.
-
insert/行记录update 执行merge sql,解决重复数据执行
-
合并算法执行后,单pk主键只有一条记录,减少并行load算法的复杂性(比如batch合并,并行/串行等处理)
入库算法采取了按pk hash并行载入+batch合并的优化
a. 打散原始数据库事务,预处理数据,合并insert/update/delete数据(参见合并算法),然后按照table + pk进行并行(相同table的数据,先执行delete,后执行insert/update,串行保证,解决唯一性约束数据变更问题),相同table的sql会进行batch合并处理
b. 提供table权重定义,根据权重定义不同支持"业务上类事务功能",并行中同时有串行权重控制.
业务类事务描述:比如用户的一次交易付款的流程,先产生一笔交易记录,然后修改订单状态为已付款. 用户对这事件的感知,是通过订单状态的已付款,然后进行查询交易记录。
所以,可以对同步进行一次编排: 先同步完交易记录,再同步订单状态。 (给同步表定义权重,权重越高的表相对重要,放在后面同步,最后达到的效果可以保证业务事务可见性的功能,快的等慢的. )
-
单机房同步
a. 100tps , 延迟100ms
b. 5000tps, 延迟1s
-
中美异地机房同步
a. 100tps , 延迟2s
b. 5000tps ,延迟10s
ps. 性能指标取决于目标数据库性能,数据大小等多个因素,单机房100b大小,极限tps可以1w+
- 网络不可靠,异地机房尤为明显.
- manager/node的jvm不可靠,需要考虑异常crash情况
- 数据库不可靠,需要考虑数据库切换,比如binlog获取和数据载入时,都需要考虑数据库HA机制
- 系统发布时,排除正常的jvm关闭和启动
- 考虑node和manager独立部署
- 建议异常流程处理机制
- node节点监控 zk
- 数据库主备切换
按照实现不同,可分为两类:
- 数据处理自定义,比如Extract , Transform的数据处理. 目前Select/Load不支持数据自定义处理
- 组件功能性扩展,比如支持oracle日志获取,支持hbase数据输出等.
Extract模块:
- EventProcessor : 自定义数据处理,可以改变一条变更数据的任意内容
- FileResolver : 解决数据和文件的关联关系
目前两者都只支持java语言编写,但都支持运行时动态编译&lib包载入的功能。
- 通过Otter Manager直接发布source文件代码,然后推送到node节点上即时生效,不需要重启任何java进程,有点动态语言的味道
- 可以将class文件放置到extend目录或者打成jar包,放置在node启动classpath中,也可以通过Otter Manager指定类名的方式进行加载,这样允许业务完全自定义。(但有个缺点,如果使用了一些外部包加入到node classpath中,比如远程接口调用,目前EventProcessor的调用是串行处理,针对串行进行远程调用执行,效率会比较差. )
- Pipeline:从源端到目标端的整个过程描述,主要由一些同步映射过程组成
- Channel:同步通道,单向同步中一个Pipeline组成,在双向同步中有两个Pipeline组成
- Node : 处理同步过程的工作节点,对应一个jvm
wiki.hongxi.org
首页
Java核心技术
- JUC JMM与线程安全
- JUC 指令重排与内存屏障
- JUC Java内存模型FAQ
- JUC 同步和Java内存模型
- JUC volatile实现原理
- JUC AQS详解
- JUC AQS理解
- JUC synchronized优化
- JUC 线程和同步
- JUC 线程状态
- JUC 线程通信
- JUC ThreadLocal介绍及原理
- JUC 死锁及避免方案
- JUC 读写锁简单实现
- JUC 信号量
- JUC 阻塞队列
- NIO Overview
- NIO Channel
- NIO Buffer
- NIO Scatter与Gather
- NIO Channel to Channel Transfers
- NIO Selector
- NIO FileChannel
- NIO SocketChannel
- NIO ServerSocketChannel
- NIO Non-blocking Server
- NIO DatagramChannel
- NIO Pipe
- NIO NIO vs. IO
- NIO DirectBuffer
- NIO zero-copy
- NIO Source Code
- NIO HTTP Protocol
- NIO epoll bug
- Reflection 基础
- Reflection 动态代理
- JVM相关
- 设计模式典型案例
Netty
RocketMQ深入研究
kafka深入研究
Pulsar深入研究
Dubbo源码导读
- Dubbo SPI
- Dubbo 自适应拓展机制
- Dubbo 服务导出
- Dubbo 服务引用
- Dubbo 服务字典
- Dubbo 服务路由
- Dubbo 集群
- Dubbo 负载均衡
- Dubbo 服务调用过程
微服务架构
Redis
Elasticsearch
其他
- Dubbo 框架设计
- Dubbo 优雅停机
- dubbo-spring-boot-starter使用指南
- rocketmq-spring-boot-starter使用指南
- Mybatis multi-database in spring-boot 2
- RocketMQ 客户端简单封装
- Otter 入门
杂谈
关于我