otter是一款基于Java且免费、开源基于数据库增量日志解析,准实时同步到本机房或异地机房的mysql/oracle数据库的解决方案。

工作流程

工作流程

otter基于zookeeper解决分布式状态调度,由manager(web管理)和node(工作节点)组成。manager运行时推送同步配置到node节点上,node节点将同步状态反馈到manger上。

环境

  • 主机A: 192.168.1.101
  • 主机B: 192.168.1.102
  • 系统: ubuntu 14.04.5
  • MySQL: 5.6.33
  • Zookeeper: 3.4.9
  • otter: 4.2.14

目标

实现主机A(manager+node+zookeeper)和主机B(node)两台主机上的mysql数据库test的双向同步。

名词解释

  • Pipeline:从源端到目标端的整个过程描述,主要由一些同步映射过程组成
  • Channel:同步通道,单向同步中一个Pipeline组成,在双向同步中有两个Pipeline组成
  • DataMediaPair:根据业务表定义映射关系,比如源表和目标表,字段映射,字段组等
  • DataMedia : 抽象的数据介质概念,可以理解为数据表/mq队列定义
  • DataMediaSource : 抽象的数据介质源信息,补充描述DateMedia
  • ColumnPair : 定义字段映射关系
  • ColumnGroup : 定义字段映射组
  • Node : 处理同步过程的工作节点,对应一个jvm

安装

MySQL(主机A、主机B)

apt install mysql-server-5.6

JDK(主机A、主机B)

add-apt-repository ppa:openjdk-r/ppa
apt update
apt install openjdk-8-jre
java -version
#=> openjdk version "1.8.0_111"

# or
add-apt-repository -y ppa:webupd8team/java
apt update
apt -y install oracle-java8-installer

aria2, otter的node端需要(主机A, 主机B)

apt install aria2

zookeeper (主机A)

wget http://mirror.jax.hugeserver.com/apache/zookeeper/zookeeper-3.4.9/zookeeper-3.4.9.tar.gz
tar zvxf zookeeper-3.4.9.tar.gz
mv zookeeper-3.4.9 /usr/local/zookeeper
cd /usr/local/zookeeper/conf
cp zoo_sample.cfg zoo.cfg
cd ../bin
./zkServer.sh start
# ZooKeeper JMX enabled by default
# Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
# Starting zookeeper ... STARTED

manager (主机A)

wget https://github.com/alibaba/otter/releases/download/v4.2.14/manager.deployer-4.2.14.tar.gz
mkdir -p /usr/local/otter_manager
tar zvxf manager.deployer-4.2.14.tar.gz -C /usr/local/otter_manager
cd /usr/local/otter_manager
# 配置数据库连接及zookeeper连接和管理信息
vim conf/otter.properties
# 启动
cd bin/
./startup.sh
# 查看log
cd ..
tail -f logs/manager.log
# 2017-01-05 18:25:26.196 [] INFO  com.alibaba.otter.manager.deployer.OtterManagerLauncher - ## start the manager server.
# 2017-01-05 18:25:35.981 [] INFO  com.alibaba.otter.manager.deployer.JettyEmbedServer - ##Jetty Embed Server is startup!
# 2017-01-05 18:25:35.981 [] INFO  com.alibaba.otter.manager.deployer.OtterManagerLauncher - ## the manager server is running now ......
# 查看进程
ps -ef | grep "/usr/local/otter_manager" | grep -v grep | awk '{print $2}'
# 11557
netstat -nutlp | grep 11557
# tcp        0      0 0.0.0.0:1099            0.0.0.0:*               LISTEN      11557/java
# tcp        0      0 0.0.0.0:8083            0.0.0.0:*               LISTEN      11557/java

node (主机A、主机B)

wget https://github.com/alibaba/otter/releases/download/v4.2.14/node.deployer-4.2.14.tar.gz
mkdir -p /usr/local/otter_node
tar zvxf node.deployer-4.2.14.tar.gz -C /usr/local/otter_node
cd /usr/local/otter_node
# 配置
vim conf/otter.properties
# 建立配置文件中的目录
mkdir htdocs download extend
# 在manager管理页面配置并添加node后,将生成的id写入nid文件
cd conf
# 这里主机A的nid为1,主机B的nid为2
echo 1 > nid
# 启动
cd bin
./startup.sh
# 查看log
cd ..
tail -f logs/node/node.log
# 2017-01-05 19:03:45.563 [main] INFO  com.alibaba.otter.node.deployer.OtterLauncher - INFO ## the otter server is running now ......
# 查看进程
ps -ef | grep "/usr/local/otter_manager" | grep -v grep | awk '{print $2}'

配置

配置mysql

在 my.cnf (/etc/mysql/my.cnf) 的 [mysqld] 节点下启用binlog和外部访问

log-bin=mysql-bin
binlog-format=ROW
character_set_server=utf8
# 这里manager端为1, node端为大于1的数字,每个node不重复
server-id=1
# 允许外部访问
bind-address = 0.0.0.0

建立用户otter,并设置外部访问权限

mysql> GRANT ALL PRIVILEGES ON *.* TO 'otter'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
mysql> FLUSH PRIVILEGES;

导入 manager 系统表

这里只需要导入主机A

wget https://raw.github.com/alibaba/otter/master/manager/deployer/src/main/resources/sql/otter-manager-schema.sql
mysql -uroot -p < otter-manager-schema.sql

# show databases;
# +---------------------+
# | Database            |
# +---------------------+
# | information_schema  |
# | mysql               |
# | otter               |
# | performance_schema  |
# +---------------------+
# 4 rows in set (0.01 sec)

导入 node 同步算法依赖的系统表

需要同步的两个数据库(主机A、主机B)都需要导入

wget https://raw.githubusercontent.com/alibaba/otter/master/node/deployer/src/main/resources/sql/otter-system-ddl-mysql.sql
mysql -uroot -p < otter-system-ddl-mysql.sql
# show databases;
# +--------------------+
# | Database           |
# +--------------------+
# | information_schema |
# | mysql              |
# | otter              |
# | performance_schema |
# | retl               |
# +--------------------+
# 5 rows in set (0.00 sec)

管理配置

打开 http://192.168.1.101:8080 并点击右上角图标进行管理员登录,默认帐号为 admin / admin

添加zookeeper主机

点击 机器管理 -> zookeeper管理 -> 添加

  • 集群名字: mysql_test
  • ZooKeeper集群: 192.168.1.101:2181; (多个分行)

点击保存

添加node

点击 机器管理 -> node管理 -> 添加

  • 机器名称: 101
  • 机器IP: 192.168.1.101
  • 机器端口: 2088
  • 下载端口: 9090
  • zookeeper集群: mysql_test

其他默认,点击保存,同理添加主机B

添加数据源

点击 配置管理 -> 数据源配置 -> 添加

  • 数据库名字: mysql_101
  • 类型: MySQL
  • 用户名: otter
  • 密码: 123456
  • URL: jdbc:mysql://192.168.1.101:3306
  • 编码: UTF8

点击保存,同理添加主机B的数据源

添加数据表

点击 配置管理 -> 数据表配置 -> 添加

这里添加主机A的数据表

  • schema name: test
  • table name: .* (这里是指同步所有数据表,所以两个数据库的数据表结构要完全一样)
  • 数据源: mysql_101

测试查询并保存,同理添加主机B的数据表

添加Canal配置

点击 配置管理 -> Canal配置 -> 添加

添加主机A的Canal配置

  • canal名称: mysql_101
  • zookeeper集群: mysql_test
  • 数据库地址: 192.168.1.101:3306;
  • 数据库帐号: otter
  • 数据库密码: otter (这里的帐号和密码都是来自otter-system-ddl-mysql.sql,生产环境请自行修改)
  • 位点自义定设置如下:

进入mysql命令行,使用如下命令查询binlog位点目录名及起始位置

show master status;
# +------------------+----------+--------------+------------------+-------------------+
# | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
# +------------------+----------+--------------+------------------+-------------------+
# | mysql-bin.000001 |   221277 |              |                  |                   |
# +------------------+----------+--------------+------------------+-------------------+
# 1 row in set (0.00 sec)

显示当前时间戳:

select unix_timestamp(now());
# +-----------------------+
# | unix_timestamp(now()) |
# +-----------------------+
# |            1483973034 |
# +-----------------------+
# 1 row in set (0.00 sec)

生成的位点信息如下:

{"journalName":"mysql-bin.000001","position":221277,"timestamp":1483973034};

其他选项使用默认,同理添加主机B的Canal配置

添加channel配置

一个channel配置两个pipeline。

注意: 两个单向的canal和映射配置,在一个channel下配置为两个pipeline。 如果是两个channel,每个channel一个pipeline,将不会使用双向回环控制算法,也就是会有重复回环同步。 每个pipeline各自配置canal,定义映射关系。

点击 同步管理 -> channel管理 -> 添加

  • channel name: 101<>102

其他选项使用默认。

添加pipeline配置

点击 同步管理 -> 101<>102 -> 添加

  • pipeline名字: 101»102
  • Select机器: mysql_101
  • Load机器: mysql_102
  • canal名字: mysql_101
  • 高级设置 -> 支持ddl同步: 否

其他使用默认,点击保存,同理添加反向(102»101)的pipeline配置

添加映射关系

点击 同步管理 -> 101<>102 -> 101»102 -> 添加

  • 源数据表: mysql_101数据源的test数据库
  • 目标数据表: mysql_102数据库的test数据库

点击保存,同理添加反向pipeline的映射关系

启动同步

回到 同步管理,点击名字为 101<>102 的channel后面的启用,即可开启同步。

然后就可以在101和102的名为test的数据库中建立测试表来查看两台机器是否实现同步。

关于双A同步(数据的一致性问题)

双A同步相比于双向同步,主要区别是双A机房会在两地修改同一条记录,而双向同步只是两地的数据做互相同步,两地修改的数据内容无交集。

所以双A同步需要额外处理数据同步一致性问题. 同步一致性算法:Otter数据一致性 ,目前开源版本主要是提供了单向回环补救的一致性方案。

双A同步相比于双向同步,整个配置主要是一些参数上有变化,具体步骤:

  • channel配置中的 “是否开启数据一致性” 设置为: 是
  • channel中的两个pipeline配置中需要将基中一个设置为主站点,并且在高级设置中,将其中一个设置为false,另一个设置为 true
  • 每个pipeline各自配置canal,定义映射关系

相关参考