Otter详解

版权声明:可自由转载,但务必说明转载出处 https://blog.csdn.net/u012853229/article/details/84490217

otter girthub链接: https://github.com/alibaba/otter

有兴趣的同学可以移步笔者的个人博客 更多博客

整体架构

子模块解释
  1. zooKeeper

分布式一致性协调服务,主要用来调度配置好的node模块。

  1. manager

管理中心,用来配置同步信息,接收node模块发来的状态反馈。

  1. node

node模块内嵌Canal,Canal监听数据库binlog中的变化传送给node的SETL模块。

原理描述
  1. 基于Canal开源产品,获取数据库增量日志数据。

  2. 典型管理系统架构,manager(web管理)+node(工作节点)

    a. manager运行时推送同步配置到node节点

    b. node节点将同步状态反馈到manager上

  3. 基于zookeeper,解决分布式状态调度的,允许多node节点之间协同工作.

安装部署

1.mysql

# 开启binlog
log-bin=mysql-bin
# 设置模式为ROW
binlog-format=ROW
# 设置默认字符集
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
# 验证
mysql> show variables like '%binlog_format%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+

2.安装aria2

apt-get -y install aria2
# 验证
aria2c -v
aria2 version 1.19.0

3.安装启动zookeeper

apt-get install zookeeper
${zooKeeperHOME}/bin ./zkServer.sh

4.打包otter

进入$otter_home目录
执行:mvn clean install -Dmaven.test.skip -Denv=release
发布包位置:$otter_home/target
完成后有两个tar包:manager、node

5.manager解压修改配置启动

# 配置
## otter manager domain name
otter.domainName = 114.215.29.139
## otter manager http port
otter.port = 8289
## jetty web config xml
otter.jetty = jetty.xml
## otter manager database config
otter.database.driver.class.name = com.mysql.jdbc.Driver
otter.database.driver.url = jdbc:mysql://114.215.29.139:3406/otter
otter.database.driver.username = root
otter.database.driver.password = 123456

## otter communication port
otter.communication.manager.port = 8290

## otter communication pool size
otter.communication.pool.size = 10

## default zookeeper address
otter.zookeeper.cluster.default = 114.215.29.139:2181
## default zookeeper sesstion timeout = 60s
otter.zookeeper.sessionTimeout = 60000

## otter arbitrate connect manager config
otter.manager.address = ${otter.domainName}:${otter.communication.manager.port}

## should run in product mode , true/false
otter.manager.productionMode = true

## self-monitor enable or disable
otter.manager.monitor.self.enable = true
## self-montir interval , default 120s
otter.manager.monitor.self.interval = 120
## auto-recovery paused enable or disable
otter.manager.monitor.recovery.paused = true
# manager email user config
otter.manager.monitor.email.host = smtp.gmail.com
otter.manager.monitor.email.username =
otter.manager.monitor.email.password =
otter.manager.monitor.email.stmp.port = 465

# 启动
sh startup.sh
# 验证
vi logs/manager.log

2018-03-08 10:19:45.911 [] WARN  com.alibaba.otter.manager.deployer.JettyEmbedServer - ##Jetty Embed Server is startup!
2013-03-08 10:19:45.911 [] WARN  com.alibaba.otter.manager.deployer.OtterManagerLauncher - ## the manager server is running now ......

6.node解压修改配置启动

机器名称:可以随意定义,方便自己记忆即可

机器ip:对应node节点将要部署的机器ip,如果有多ip时,可选择其中一个ip进行暴露. (此ip是整个集群通讯的入口,实际情况千万别使用127.0.0.1,否则多个机器的node节点会无法识别)

机器端口:对应node节点将要部署时启动的数据通讯端口,建议值:2088

下载端口:对应node节点将要部署时启动的数据下载端口,建议值:9090

外部ip :对应node节点将要部署的机器ip,存在的一个外部ip,允许通讯的时候走公网处理。

zookeeper集群:为提升通讯效率,不同机房的机器可选择就近的zookeeper集群.

node这种设计,是为解决单机部署多实例而设计的,允许单机多node指定不同的端口

# nid配置 (将环境准备中添加机器后获取到的序号,保存到conf目录下的nid文件,比如我添加的机器对应序号为1)
echo 1 > conf/nid
# 配置
## otter node dir
otter.htdocs.dir = ${otter.nodeHome}/htdocs
otter.download.dir = ${otter.nodeHome}/download
otter.extend.dir= ${otter.nodeHome}/extend

## default zookeeper sesstion timeout = 60s
otter.zookeeper.sessionTimeout = 60000

## otter communication pool size
otter.communication.pool.size = 10

## otter arbitrate & node connect manager config
otter.manager.address = 114.215.29.139:8290

# 启动
sh startup.sh
# 验证
vi logs/node/node.log
2018-03-08 10:42:16.886 [main] INFO  com.alibaba.otter.node.deployer.OtterLauncher - INFO ## the otter server is running now ......

使用

  1. 添加数据库

    a. 源库 jdbc:mysql://host:3306

    b. 目标库 jdbc:mysql://host:3306

  2. 添加canal

    a. 提供数据库ip信息

  3. 添加同步表信息

    a. 源数据表 test.example

    b. 目标数据表 test.example

  4. 添加channel

  5. 添加pipeline

    a. 选择node节点

    b. 选择canal

  6. 添加同步映射规则

    a. 定义源表和目标表的同步关系

  7. 启动

  8. 测试数据

manager说明及参数

otter系统自带了manager,所以简化了一些admin管理上的操作成本,比如可以通过manager发布同步任务配置,接收同步任务反馈的状态信息等。

同步配置管理
  1. 添加数据源
  2. canal解析配置
  3. 添加数据表
  4. 同步任务
同步状态查询
  1. 查询延迟
  2. 查询吞吐量
  3. 查询同步进度
  4. 查询报警&异常日志
用户权限:
  1. ADMIN : 超级管理员
  2. OPERATOR : 普通用户,管理某个同步任务下的同步配置,添加数据表,修改canal配置等
  3. ANONYMOUS : 匿名用户,只能进行同步状态查询的操作.
具体配置参数
channel参数
  1. 同步一致性. ==> 基于数据库反查(根据binlog反查数据库),基于当前变更(binlog数据)。针对数据库反查,在延迟比较大时比较有效,可将最新的版本快速同步到目标,但会对源库有压力.

  2. 同步模式. ==> 行模式,列模式。行模式特点:如果目标库不存在记录时,执行插入。列模式主要是变更哪个字段,只会单独修改该字段,在双A同步时,为减少数据冲突,建议选择列模式。

  3. 是否开启数据一致性. ==> 请查看数据一致性文档:Otter数据一致性

a. 数据一致性算法

b. 一致性反查数据库延迟阀值

pipeline参数
  1. 并行度. ==> 查看文档:Otter调度模型,主要是并行化调度参数.(滑动窗口大小)

  2. 数据反查线程数. ==> 如果选择了同步一致性为反查数据库,在反查数据库时的并发线程数大小

  3. 数据载入线程数. ==> 在目标库执行并行载入算法时并发线程数大小

  4. 文件载入线程数. ==> 数据带文件同步时处理的并发线程数大小

  5. 主站点. ==> 双A同步中的主站点设置

  6. 消费批次大小. ==> 获取canal数据的batchSize参数

  7. 获取批次超时时间. ==> 获取canal数据的timeout参数

pipeline 高级设置
  1. 使用batch. ==> 是否使用jdbc batch提升效率,部分分布式数据库系统不一定支持batch协议

  2. 跳过load异常. ==> 比如同步时出现目标库主键冲突,开启该参数后,可跳过数据库执行异常

  3. 仲裁器调度模式. ==> 查看文档:Otter调度模型

  4. 负载均衡算法. ==> 查看文档:Otter调度模型

  5. 传输模式. ==> 多个node节点之间的传输方式,RPC或HTTP. HTTP主要就是使用aria2c,如果测试环境不装aria2c,可强制选择为RPC

  6. 记录selector日志. ==> 是否记录简单的canal抓取binlog的情况

  7. 记录selector详细日志. ==> 是否记录canal抓取binlog的数据详细内容

  8. 记录load日志. ==> 是否记录otter同步数据详细内容

  9. dryRun模式. ==> 只记录load日志,不执行真实同步到数据库的操作

  10. 支持ddl同步. ==> 是否同步ddl语句

  11. 是否跳过ddl异常. ==> 同步ddl出错时,是否自动跳过

  12. 文件重复同步对比 ==> 数据带文件同步时,是否需要对比源和目标库的文件信息,如果文件无变化,则不同步,减少网络传输量.

  13. 文件传输加密 ==> 基于HTTP协议传输时,对应文件数据是否需要做加密处理

  14. 启用公网同步 ==> 每个node节点都会定义一个外部ip信息,如果启用公网同步,同步时数据传递会依赖外部ip.

  15. 跳过自由门数据 ==> 自定义数据同步的内容

  16. 跳过反查无记录数据 ==> 反查记录不存在时,是否需要进行忽略处理,不建议开启.

  17. 启用数据表类型转化 ==> 源库和目标库的字段类型不匹配时,开启改功能,可自动进行字段类型转化

  18. 兼容字段新增同步 ==> 同步过程中,源库新增了一个字段(必须无默认值),而目标库还未增加,是否需要兼容处理

  19. 自定义同步标记 ==> 级联同步中屏蔽同步的功能.

Canal参数
  1. connectionCharset ==> 获取binlog时指定的编码

  2. 位点自定义设置 ==> 格式:{“journalName”:"",“position”:0,“timestamp”:0};
    指定位置:{“journalName”:"",“position”:0};
    指定时间:{“timestamp”:0};

  3. 内存存储batch获取模式 ==> MEMSIZE/ITEMSIZE,前者为内存控制,后者为数量控制.  针对MEMSIZE模式的内存大小计算 = 记录数 * 记录单元大小
    内存存储buffer记录数
    内存存储buffer记录单元大小

  4. 心跳SQL配置 ==> 可配置对应心跳SQL,如果配置 是否启用心跳HA,当心跳SQL检测失败后,canal就会自动进行主备切换.

Node参数
  1. 机器名称 ==> 自定义名称,方便记忆

  2. 机器ip ==> 机器外部可访问的ip,不能选择127.0.0.1

  3. 机器端口 ==> 和manager/node之间RPC通讯的端口

  4. 下载端口 ==> 和node之间HTTP通讯的端口

  5. 外部Ip ==> node机器可以指定多IP,通过pipeline配置决定是否启用

  6. zookeeper集群 ==> 就近选择zookeeper集群

Zookeeper集群参数
  1. 集群名字 ==> 自定义名称,方便记忆

  2. zookeeper集群 ==> zookeeper集群机器列表,逗号分隔,最后以分号结束

拓展

数据合并
  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
数据入库算法

入库算法采取了按pk hash并行载入+batch合并的优化

  1. 打散原始数据库事务,预处理数据,合并insert/update/delete数据(参见合并算法),然后按照table + pk进行并行(相同table的数据,先执行delete,后执行insert/update,串行保证,解决唯一性约束数据变更问题),相同table的sql会进行batch合并处理

  2. 提供table权重定义,根据权重定义不同支持"业务上类事务功能",并行中同时有串行权重控制.
    业务类事务描述:比如用户的一次交易付款的流程,先产生一笔交易记录,然后修改订单状态为已付款. 用户对这事件的感知,是通过订单状态的已付款,然后进行查询交易记录。
    所以,可以对同步进行一次编排: 先同步完交易记录,再同步订单状态。 (给同步表定义权重,权重越高的表相对重要,放在后面同步,最后达到的效果可以保证业务事务可见性的功能,快的等慢的. )

高可用

仲裁器设计了三种异常机制指令:

  1. WARNING

只发送报警信息,不做任何S/E/T/L调度干预

  1. ROLLBACK

尝试获取分布式锁,避免并发修改,其次修改分布式Permit为false,停止后续的所有S/E/T/L调度,然后删除所有当前process调度信息,通过zookeeper watcher通知所有相关node,清理对应process的上下文,pipe的数据存储会通过TTL来进行清理,不需要ROLLBACK干预。完成后,释放锁操作
3. RESTART

前面几个步骤和ROLLBACK基本类似,唯一不同点在于,在释放锁之前会尝试修改分布式Permit为true,重新开启同步,然后释放锁.

罗列了一下不同异常对应的处理机制

两个节点通讯时网络异常,节点发起ROLLBACK
节点执行S/E/T/L模块,比如写数据库出现网络异常,节点发起ROLLBACK
节点发生了CRASH,由manager进行监听,manager发现后发起RESTART

拓展性

通过Otter Manager直接发布source文件代码,然后推送到node节点上即时生效,不需要重启任何java进程,有点动态语言的味道
可以将class文件放置到extend目录或者打成jar包,放置在node启动classpath中,也可以通过Otter Manager指定类名的方式进行加载,这样允许业务完全自定义。(但有个缺点,如果使用了一些外部包加入到node classpath中,比如远程接口调用,目前EventProcessor的调用是串行处理,针对串行进行远程调用执行,效率会比较差.)

EventProcessor接口示例:

/**
 * 业务自定义处理过程
 *
 * @author jianghang 2012-6-25 下午02:26:36
 * @version 4.1.0
 */
public interface EventProcessor {
/**
 * 自定义处理单条EventData对象
 *
 * @return {@link EventData} 返回值=null,需要忽略该条数据
 */
public EventData process(EventData eventData);

}

猜你喜欢

转载自blog.csdn.net/u012853229/article/details/84490217