mysql主从复制案例及小结

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 status\G 查看表
......
             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 status\G;   --查看状态会发现SQL线程状态为NO

        Slave_IO_Running: Yes
        Slave_SQL_Running: NO


大概等1分钟,就会自动延时同步过来了;
--注意:日志已经传到slave的relay-bin log里了,但由SQL线程延时去解析

 

posted @ 2018-02-27 09:12  Mùtou  阅读(858)  评论(0编辑  收藏  举报