mysqlAB复制 mysql主从复制有利于数据库的健壮性、提升访问速度和易于维护管理。 总结: 从库上配置账户、ip、用户名、密码、链接文件的位置、pos点,在从库上同步数据前要把主库之前的数据导入到从库,然后在实行数据同步。 开启开关之前,主从库数据要一致 在打开开关之前要在主库上建立授权,链接从库的账号 主库必须要打开bin-log开关 要启动 start slave;来开始同步 dns主-----> dns从 非实时 mysql主------------------> mysql从 实时 延时是很严重的问题 mysql replication mysql AB 复制技术(主从) 原理非常类似 oracle dataguard oracle DG (dataguard) MySQL支持单向、异步复制,复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。 同步复制需要使用ndb(各集群节点都可读可写)或者drbd(网络raid)这些技术,或者是新版mysql的半同步复制 异步 优点:主速度快 缺点:数据可能主从不同步 同步 优点和缺点和异步正好相反 mysql主 ----------> mysql从 create table aaa; bin-log --------> relay-bin-log io sql create table aaa; 把主上的二进制日志(bin-log)的内容传到从上的一个新的日志叫relay-bin-log 从上的 IO 线程 负责传输 从上的 SQL 线程 负责从服务器解析日志 由两个线程 去进行复制的过程 IO线程 sql线程 (以前只使用一个线程,两个是改进后才有的) 复制的过程: 1,slave端的IO线程连上master端,请求 2,master端返回给slave端,bin log文件名和位置信息 3,IO线程把master端的bin log内容依次写到slave端relay bin log里,并把master端的bin-log文件名和位置记录到master.info里。 4,salve端的sql线程,检测到relay bin log中内容更新,就会解析relay log里更新的内容,并执行这些操作;也就是说salve执行和master一样的操作而达到数据同步的目的; ============================================================================= AB复制前准备 1,准备两台机器 2,安装两台全新的mysql(这里使用rpm版,方便,源码版可以课后自行做测试;两台版本最好一致,不一致可能会有兼容性问题) yum -y install mysql* 3,主机名配置及其绑定(两台互相绑定) vim /etc/hosts (主机名和ip相互绑定只绑自己的) 4,时间同步 5,防火墙,selinux关闭 准备两台虚拟机:最好是全新 master ---- slave 172.16.14.2 172.16.14.3 第一步;改配置文件,并重启服务 # vim /etc/my.cnf master上 (主文件) [mysqld] log-bin=mysql-bin 二进制日志必须打开 server-id=2 slave上 (副文件) [mysqld] server-id=3 /etc/init.d/mysqld restart 用脚本重启 第二步:主授权 在主文名字是主到 ip写从到 master上授权,super和replication slave都是复制要用的权限 mysql> grant super,replication slave on *.* to 'li'@'172.16.14.X' identified by '123'; 在主授权给从的ip地址,让他以主到身份登录 li代表的是主机名 mysql> flush privileges; 第三步:查看master的正在写的二进制文件名和位置 mysql> show master status; --只有打开二进制日志,这句命令才有结果,表示当前数据库的二进制日志写到什么位置 +------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000003 | 473 | | | +------------------+----------+--------------+------------------+ 第四步:在slave(从)上连接master(主),并指定从哪个position开始复制 在(从端操作)下面 mysql> change master to -> master_user='li', --对应前面主授权时的用户 -> master_password='123', --对应前面主授权时的密码 -> master_host='172.16.14.2', --主的IP -> master_port=3306, --端口,如果为3307就要换成3307 -> master_log_file='mysql-bin.000003', --主上面查到的文件名 -> master_log_pos=473; --主上面查到的位置号 这部报错的话把stop slave; 切记必须关掉之后在修改,然后启动 mysql> start slave; mysql> show slave statusG 查看表 ...... Slave_IO_Running: Yes Slave_SQL_Running: Yes --这两人个线程为yes,代表集群搭建成功 ...... ============================================================================= 问题一: 思考几种情况下做复制的区别: 1, 业务还没有上线的情况,全新安装的mysql做复制 2,主已经跑了一年,一直都有开着二进制日志,并且日志无丢失 直接从一年前的起始位置开始复制(但要注意初始化的数据不要重复初始化的数据) 3,主已经跑了一年,但没有打开二进制日志 骤一:master打开二进制日志,重启 步骤二:master全备,并恢复到slave(假设要30分钟) 步骤三;30分钟后,slave从备份的position开始复制 4, 主以前跑了半年没打开二进制日志,后半年打开了二进制日志,你现在要做从 骤一:master全备,并恢复到slave(假设要30分钟) 步骤二;30分钟后,slave从备份的position开始复制 主 从 .000001 1 跑了一年 跑了一年的数据 现在 .000054 563 563 备份恢复 30分钟 .000054 800 问题二: 主要打开二进制日志,从要不要开二进制日志? 从mysql可开可不开,要看情况 问题三: 主和从的读写情况怎么做? 从不能写,从只能读;主可读可写; 所以有些时候做主只写,从只读,也就是读写分离 问题四: 我做了读写分离的一主一从的架构,请问我前端的程序(web,游戏,业务等)如何来访问数据库? 如果装前端web(假设phpwind),填写数据库的IP为主的IP,那么这种情况, mysql从就完全变成了一个实时备份的服务器,所有的读写全在主上 所以要在前端程序和数据库之间加入代理层程序,也就是填写的数据库IP不是主的也不是从的, 而是代理的,由代理来负责把写操作给主,读操作给从 客户 | | web程序,游戏程序(c,php,java.......) | | 代理层(中间件)(mysqlproxy,amoeba,cobar,mycat) | | mysql主 ----> mysql从 问题五: 关于单点故障的问题,如果从挂掉了,怎么解决?如果主挂掉了,怎么解决? 从挂掉,再恢复的过程图: 代理 mysql主 ----> mysql从 写 读 从挂了 写读 很久之后,从要启动,启动之前可以手动写防火墙,让代理访问不到从 启动,会自动连主,主会把这段时间写的复制给从 复制完后,手动确认(可以在从启动前在主上show master status;查看主写到哪了.然后在从上可以show slave status查看写到主的postion或者这个positsion之后,则表示数据都复制过来了),然后去掉防火墙 代理发现从OK了,会把读给从 写 读 主挂掉,再恢复的过程图:(这样最好做双主,右边的主平时正常情况然后做只读的从,只在左边的主挂了,才会做写操作) 代理 mysql主 <----> mysql从(打开二进制日志) 写 读 主挂了 写 读 很久之后,主要启动,启动之前手动写防火墙,让代理访问不到主 主启动,自动连上后,因为是双主,从可以把这段时间写的复制回主 复制完后,手动确认,然后去掉主上的防火墙 代理发现主OK了,会把写给回主 写 读 ============================================================================= 一主一从 关于另几种架构的探讨: 一主多从 -- salve master -- salve -- salve --适合于以读为主的业务,使用多个salve分担读的压力,但要注意的是这种架构,salve越多,那么master复制的压力就越大(成本增大) 多主一从 --这种架构不支持 主A phpwind 从C 主B discuz 双主架构 master A <--> master B phpwind主 discuz主 上面已经讨论了双主架构的一个用法(就是一个平时仍然为主,另一个平时为从,只在主挂了才会去从上写) 1,会循环复制吗? 他们不会循环复制,因为做复制时会指定ID值,并且不一致 2,两边真的能同时写相同的数据吗? 可能会有问题 如下表所示: 时间点 master A master B 1 id=1改为id=2 2 id=1改为id=3 3 master A的改变复制过来,并解析,id会又改为2 4 master B的改变复制过来并解析,id又会改为3 问题产生,数据不一致 3,两边可以写不同的数据吗? 可以 可以通过业务程序层,指定一些表的写操作全在一端,另一些表的写操作全在另一端,也就是说两边不会同时写相同的表(当然这是理想状态,因为业务复杂的话会有表的联结等情况) 然后通过指定mysql复制的参数,一部分表或库会从A复制到B,另外一部分表或库从B复制到A就可以避免上面的问题了 或者两个库,一个库master A来写,另一个库master B来写 数据切分 ------------------------------------------------------ master C | | 环型架构 master A -- master B --不可行 ------------------------------------------------------ -- salve 级联架构 master -- salve -- salve -- salve 为了解决一主多从的master的复制压力 可以把slave做为下一级从机的master 增加复制的级联层次,造成的延迟更长 所以这种架构并不是很推荐,一般会进行分拆集群 -------------------------------------------------- 双主和级联合起来 master ----salve --slave | | -- slave master ---salve -- slave -- slave ----------------------------------------------------- 优化原则:分 大型结构的数据量太大,要用到数据切分(水平,垂直) mysqlproxy amoeba cobar ============================================================================= 一主多从的做法 就是上面的步骤有几个从就做几次 双主架构的做法: 反着做一遍就行 级联架构 master -slave -slave 我的结构图 master A slave B slave C 172.16.14.2 172.16.14.3 172.16.14.4 sever-id=2 server-id=3 server-id=4 log-bin=master log-bin=mid-slave log-slave-updates=1 bin-log relay-bin-log relay-bin-log bin-log ------> relay-bin-log 打开log-slave-updates=1 让第一台传过来relay日志记录 到自己的二进制日志 bin-log -------> relay-bin-log 练习: 实现下面的结构图(这里包括了一主一从,一主多从,双主,级联架构) mysql1 《----》 mysql2 ----》 mysql3 ============================================================================= 半同步复制 MySQL的默认复制其实是异步操作,而不是同步,也就意味着允许主从之间的数据存在一 定的延迟,mysql当初这样设计的目的也是基于可用性的考虑,为了保证master 不受slave的影响,并且异步复制使得master处于一种性能最优的状态: 写完binlog后即可提交而不需要等待slave的操作完成。这样存在一个隐患,当你使用slave作为备份时 如果master挂掉,那么会存在部分已提交的事务未能成功传输到slave的可能,这就意味着数据丢失! mysql 主 ---- mysql从 所谓的半同步复制就是master每commit一个事务,要slave应用这个事物后回给master信号。这样master才能把事物成功commit。这样就保证了master-slave的数据绝对的一致(但是以牺牲master的性能为代价).但等待时间也是可以调整的。 mysql半同步复制等待时间超时后(默认时间为10秒),会自动转换成异步复制 ========================================= 搭建环境 两台虚拟机 master -- slave 先安装mysql5.5之后的版本,因为这个版本之后才实现的半同步复制 第一大步: 先要搭建好mysqlAB异步复制 过程省略 第二大步:在异步基础上转成半同步复制 1,在master上安装这个插件 master> install plugin rpl_semi_sync_master soname 'semisync_master.so'; Query OK, 0 rows affected (0.00 sec) --删除插件的方法 mysql > uninstall plugin rpl_semi_sync_master; master> show global variables like 'rpl_semi_sync%'; --安装OK后,主上会多几个参数 +------------------------------------+-------+ | Variable_name | Value | +------------------------------------+-------+ | rpl_semi_sync_master_enabled | OFF | --是否启用master的半同步复制 | rpl_semi_sync_master_timeout | 10000 | --默认主等待从返回信息的超时间时间,10秒。 | rpl_semi_sync_master_trace_level | 32 | --监控 | rpl_semi_sync_master_wait_no_slave | ON | --是否允许每个事物的提交都要等待slave的信号.on为每一个事物都等待 +------------------------------------+-------+ 2,在slave上安装插件 slave> install plugin rpl_semi_sync_slave soname 'semisync_slave.so'; Query OK, 0 rows affected (0.03 sec) slave> show global variables like 'rpl_semi_sync%'; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | rpl_semi_sync_slave_enabled | OFF | | rpl_semi_sync_slave_trace_level | 32 | +---------------------------------+-------+ 3,master上激活半同步复制 master> set global rpl_semi_sync_master_enabled =on; Query OK, 0 rows affected (0.00 sec) 4,slave上激活半同步复制 slave> set global rpl_semi_sync_slave_enabled=on; slave> stop slave IO_THREAD; slave> start slave IO_THREAD; 5,在master查看状态 master > show global status like 'rpl_semi_sync%'; +--------------------------------------------+-------+ | Variable_name | Value | +--------------------------------------------+-------+ | Rpl_semi_sync_master_clients | 1 | --有一个从服务器启用半同步复制 | Rpl_semi_sync_master_net_avg_wait_time | 0 | --master等待slave回复的平均等待时间。单位毫秒 | Rpl_semi_sync_master_net_wait_time | 0 | --master总的等待时间。单位毫秒 | Rpl_semi_sync_master_net_waits | 0 | --master等待slave回复的总的等待次数 | Rpl_semi_sync_master_no_times | 0 | --master关闭半同步复制的次数 | Rpl_semi_sync_master_no_tx | 0 | --master 等待超时的次数 | Rpl_semi_sync_master_status | ON | --标记master现在是否是半同步复制状态 | Rpl_semi_sync_master_timefunc_failures | 0 | --master调用时间(如gettimeofday())失败的次数 | Rpl_semi_sync_master_tx_avg_wait_time | 0 | --master花在每个事务上的平均等待时间 | Rpl_semi_sync_master_tx_wait_time | 0 | --master花在事物上总的等待时间 | Rpl_semi_sync_master_tx_waits | 0 | --master事物等待次数 | Rpl_semi_sync_master_wait_pos_backtraverse | 0 | --后来的先到了,而先来的还没有到的次数 | Rpl_semi_sync_master_wait_sessions | 0 | --当前有多少个session因为slave回复而造成等待 | Rpl_semi_sync_master_yes_tx | 0 | --标记slave是否在半同步状态 +--------------------------------------------+-------+ 6,在slave上查看状态就只有下面一条信息 slave > show global status like 'rpl_semi_sync%'; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Rpl_semi_sync_slave_status | ON | +----------------------------+-------+ 第三大步 测试: master > insert into a values (3); Query OK, 1 row affected (0.01 sec) master > show global status like 'rpl_semi_sync%_yes_tx'; +-----------------------------+-------+ | Variable_name | Value | +-----------------------------+-------+ | Rpl_semi_sync_master_yes_tx | 1 | --表示这次事物成功从slave返回一次确认信号 +-----------------------------+-------+ 模拟错误,把slave上的mysql停掉 --再回到master上测试 master> insert into a values (4); Query OK, 1 row affected (10.00 sec) --这次插入一个值需要等待10秒(默认的等待时间) master> insert into a values (5); Query OK, 1 row affected (0.01 sec) --现在自动转成了原来的异步模式(类似oracle DG里的最大性能模式) 再次把slave启动,看到半同步复制没启来,是异步模式 重新按下面的步骤把同步模式再启起来就可以了 slave> set global rpl_semi_sync_slave_enabled=on; slave> stop slave IO_THREAD; slave> start slave IO_THREAD; slave启起来后,查看表,发现刚才slave关闭期间的那几条数据还是会自动复制过来,数据又回到一致 ===================================================================== mysql的延时复制(IO线程是实时,只是把SQL线程延时了) 异步或同步复制 A ----------> B | |-------> C 延时1天 误删除一张用了好几年的数据表 恢复方法: 1,通过每周的备份来恢复(假设周一0点全备,周三误删除) 先恢复周一的全备到测试库上,然后再恢复全备到现在的二进制日志(除了误删除的那句),再把那张表导出来,导回到生产库上 2,完全通过二进制日志来恢复 需要把这几年内所有的二进制日志先合并,再通过sed,grep,awk等把这张表从建表到现在的所有操作按顺序找出来(当然要除掉你最后误删除的那条),然后应用回去 3,有延时复制的话,在C上导出这张表,导回A mysql开源管理工具 软件路径在 笔记目录下/mysql/mysql_soft/maatkit-7540.tar.gz --在mysql AB的slave上安装(只需要在slave上安装,包含下面的步骤都是在slave上做的) # tar xf maatkit-7540.tar.gz -C /usr/src/ # cd /usr/src/maatkit-7540/ 安装方法README文件里有写 # perl Makefile.PL --如果不成功,需要安装perl有关的多个包,可以yum install perl* # make install # ls bin/ --这些命令,就是各个管理工具 mk-archiver mk-purge-logs mk-checksum-filter mk-query-advisor mk-config-diff mk-query-digest mk-deadlock-logger mk-query-profiler mk-duplicate-key-checker mk-show-grants mk-error-log mk-slave-delay mk-fifo-split mk-slave-find mk-find mk-slave-move mk-heartbeat mk-slave-prefetch mk-index-usage mk-slave-restart mk-kill mk-table-checksum mk-loadavg mk-table-sync mk-log-player mk-table-usage mk-merge-mqd-results mk-tcp-model mk-parallel-dump mk-upgrade mk-parallel-restore mk-variable-advisor mk-profile-compact mk-visual-explain --使用--help查看一个命令的使用方法 # mk-slave-delay --help mk-slave-delay starts and stops a slave server as needed to make it lag behind the master. The SLAVE-HOST and MASTER-HOST use DSN syntax, and values are copied from the SLAVE-HOST to the MASTER-HOST if omitted. For more details, please use the --help option, or try 'perldoc /usr/bin/mk-slave-delay' for complete documentation. --mysql AB(无论同步或异步)正在运行OK的情况下,使用下面的命令在slave上运行;做之间建议把时间同步一下 # mk-slave-delay --defaults-file=/etc/my.cnf --delay=1m --interval=15s --user=root --password=123 --quiet localhost & --表示延时1分钟,才会应用SQL线程;这里是测试所以才使用很小的时间,实际情况可以调成1小时或2小时 测试: 在master上随便插入几条数据 然后在slave上发现没有马上同步过来 slave > show slave statusG; --查看状态会发现SQL线程状态为NO Slave_IO_Running: Yes Slave_SQL_Running: NO 大概等1分钟,就会自动延时同步过来了; --注意:日志已经传到slave的relay-bin log里了,但由SQL线程延时去解析