背景
Transfer是一个主从多线程同步工具,直接patch在MySQL中。2011年开发完成。于去年的12.12上线,并撑住高峰期主从,保证从库无延迟,使得应用能够直接从从库上读数据。
对Transfer1.0背景有兴趣的同学可以看我以前的一篇博客。
新功能
Transfer第一版本存在两个可改进的点:单表并发和事务支持。
a) Transfer2.0支持单表并发,基本原理就是按照更新行的主键id (因此有一个限制是同步的表必须要有主键)。
b) Transfer2.0支持slave回放主库事务时以事务为单位执行。
内部基本结构
Transfer1.0
为什么不直接写到slave里面?由于DBA同学觉得直接写在slave里面担心数据安全性,因此改造成第一个第三方工具。
Transfer2.0
外部主库和备库的行为相同,Trasnfer内部改为
性能效果
上周五在一个紧急项目中由于其他方案出问题,上线测试,从库tps性能从300+提升到2000+。
安装配置
Transfer的推荐配置结构是
Master ==> Transfer ==> Slave
假设你已经有Master和Slave,Transfer建议部署在slave同一个机器,当时我们上线是这么配置的,当然如果你机器多,也可以考虑放在单独一个机器,只是不必要。
Transfer的安装步骤:
a) 附件中三个mysqld,分别是官方版本mysql-5.1.48, percona 版本5.5.18和淘宝MySQL分支5.5.18打入patch后生成的三个bin文件。
需要你先安装你选择的对应的官方版本,然后替换mysqld。
b) My.cnf里面的[mysqld]下新增如下几行配置:
remote_slave_hostname = 127.0.0.1
remote_slave_username = root
remote_slave_password =
remote_slave_port = 3306
transfer_slave_thread = 16
slave_skip_errors=1062,1032
建议修改Slave上的配置(非必需)
net_read_timeout=3600
max_allowed_packet=1073741824
c) 将Slave中需要同步的表结构,导入到Transfer中。注意,只需要表结构,不需要数据。
其中remote_slave系列配置的是一个有super权限访问Slave的帐号。
重启即可。
在Transfer中的操作与在Slave中原本的操作相同,只是现在的关系是,Transfer注册为Master的主库,得到操作步骤后,更新Slave.
系统限制
1、Master上binlog格式必须是row based
2、每个表必须要有主键(显示的primay key)
Transfer变身Slave
有的同学说我不想维护多一个实例。其实就so easy,只要把trasnfer的目标指向自己即可。
为了安全起见,配置规则必须是
remote_slave_hostname配置为127.0.0.1 且 remote_slave_port与Transfer端口相同。
当然,如果Transfer自己是slave,配置时还少了一步拷贝表结构
由淘宝核心系统研发—数据库组开发的MySQL-Transfer,用于解决MySQL主从同步延迟的问题,从MySQL单线程到多线程的工作模式。可以观看@丁奇的相关资料:
MySQL多线程同步-Transfer使用说明
MySQL异步复制延迟解决的架构设计与运维架构—在线播放—优酷网
系统结构 :
传统的主从结构是 [Master] à [Slave], Master和slave主从关系;
使用transfer以后,[Master] à [Transfer] .--> [Slave], Master和Transfer主从关系,Transfer和Slave是Client-Server关系。
服务器环境:
主库:192.168.15.216 (3306端口)
从库:192.168.15.217 (3306端口)
Transfer: 192.168.15.217 (3307端口)
MySQL版本:mysql-5.5.18-linux2.6-x86_64.tar.gz
存储引擎:Innodb
Database: rocdata
MySQL-Transfer:Transfer.2.1-based-PS-5.5.18
注:
Tranfsfer相同的表使用同一个线程更新,若只有一个表,性能与原生版本相同。要体现效果,一般16个表或以上,考虑到线上大库都有分表,这个条件比较容易满足。
一、192.168.15.216主库配置
首先确认主库上使用row格式的binlog,配置/etc/my.cnf:
[client]
port = 3306
socket = /tmp/mysql.sock
[mysqld1]
port = 3306
socket = /tmp/mysql.sock
basedir=/usr/local/mysql
datadir=/mysqldata/
bind-address=192.168.15.216
skip-external-locking
skip-name-resolve
user=mysql
max_allowed_packet = 256M
query_cache_size=256M
max_connections=2000
max_connect_errors=10000
key_buffer_size=6000M
read_buffer_size=32M
read_rnd_buffer_size = 32M
myisam_sort_buffer_size=512M
tmp_table_size=1024M
old-passwords
interactive_timeout=60
wait_timeout=60
connect_timeout=60
table_cache=8192
thread_cache_size=512
sort_buffer_size=128M
back_log = 500
thread_concurrency=48
expire_logs_days=10
log-bin=mysql-bin
#binlog_format=STATEMENT
binlog_format=ROW
#binlog_format="MIXED
# master
server-id = 1
binlog-do-db = rocdata
binlog-ignore-db = mysql
启动MySQL,并查看Pos状态。
二、192.168.15.217从库配置。
MySQL端口3306和3307 ,建议MySQL TDIR目录区分开来。我的MySQL和Transfer目录:
/usr/local/mysql/
/usr/local/mysql-transfer
Transfer.2.1-based-PS-5.5.18替换T安装目录/usr/local/mysql-transfer/bin/下的mysqld。
1、配置3306端口,同步Master数据,这里不需要写主从同步信息,和单台MySQL配置一样。
/usr/local/mysql目录部署一个MySQL版本5.5.18(真实库),配置/etc/my.cnf:
[mysqld]
port = 3306
socket = /tmp/mysql.sock
basedir=/usr/local/mysql
datadir=/mysqldata/data3306
bind-address=192.168.15.217
skip-external-locking
skip-name-resolve
user=mysql
max_allowed_packet = 256M
query_cache_size=256M
max_connections=2000
max_connect_errors=10000
key_buffer_size=6000M
read_buffer_size=32M
read_rnd_buffer_size = 32M
myisam_sort_buffer_size=512M
tmp_table_size=1024M
old-passwords
interactive_timeout=60
wait_timeout=60
connect_timeout=60
table_cache=8192
thread_cache_size=512
sort_buffer_size=128M
back_log = 500
thread_concurrency=48
expire_logs_days=10
启动MySQL 3306端口,并导入数据,前提需要记录的Pos点,保证Transfer同步正常。和传统的主从拷贝数据一样。
此时3306端口的运行状态。
2、配置3307 Transfer服务
a) /usr/local/mysql-transfer/目录部署一个MySQL (T),版本5.5.18
b) 用附件中的mysqld替换T安装目录/usr/local/mysql-transfer/bin/下的mysqld
c) 在/usr/local/mysql-transfer/log 目录下执行下执行 for((i=0; i<=16; i++)); do mkdir $i;done
d) 配置/etc/my3307.cnf,做以下修改:
[mysqld]
port = 3307
socket = /tmp/mysql3307.sock
basedir=/usr/local/mysql
datadir=/mysqldata/data3307
bind-address=192.168.15.217
skip-external-locking
skip-name-resolve
user=mysql
max_allowed_packet = 1G
query_cache_size=256M
max_connections=2000
max_connect_errors=10000
key_buffer_size=6000M
read_buffer_size=32M
read_rnd_buffer_size = 32M
myisam_sort_buffer_size=512M
tmp_table_size=1024M
old-passwords
interactive_timeout=60
wait_timeout=60
connect_timeout=60
table_cache=8192
thread_cache_size=512
sort_buffer_size=128M
back_log = 500
thread_concurrency=48
expire_logs_days=10
#tranfer
transfer_slave_thread = 16
remote_slave_hostname = 192.168.15.217
remote_slave_username = transfer
remote_slave_password = transferpw
remote_slave_port = 3306
relay-log =/usr/local/mysql/log/mysqld-relay-bin
relay-log-index =/usr/local/mysql/log/mysqld-relay-bin.index
master-info-file =/usr/local/mysql/log/master.info
relay-log-info-file =/usr/local/mysql/log/relay-log.info
log_slave_updates = 0
slave_skip_errors=1062,1032
#slave 192.168.15.217
server-id = 3
replicate_do_db = rocdata
replicate-ignore-db = mysql
replicate-ignore-db = test
replicate-ignore-db = information_schema
[说明]配置给Transfer的这个uname必须有Slave的super权限
e) Transfer需要导入同步的数据库结构,不需要数据
f) Slave的 max_allowed_packet设置为1G (建议)
g) 启动Transfer并设置为Master的从库
具体步骤:
在3306端口上赋予Transfer 有Slave的super权限:
mysql> grant all privileges on *.* to 'transfer'@'192.168.15.217' identified by 'transferpw';
在主库192.168.15.216赋予Transfer 有 replicate privileges权限:
mysql> grant replication slave, reload, super on *.* to 'repluser216'@'192.168.15.217' identified by 'replpasswd216';
启动Transfer并设置为Master的从库:
mysql> CHANGE MASTER to MASTER_HOST='192.168.15.216', MASTER_PORT=3306, MASTER_USER='repluser216', MASTER_PASSWORD='replpasswd216', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=82104;
三、测试
1、在192.168.15.216主库rocdate上创建表test,并写入数据:
mysql> create table test ( id int(4));
mysql> insert into test values(1);
mysql> insert into test values(2);
2、查看192.18.15.216 MySQL(T)和MySQL真实库状态: