zoukankan      html  css  js  c++  java
  • 数据存储---Mysql双机互为热备方案实践

    Mysql作为一个流行的数据库,对于怎么样构建高性能、高可用、可扩展的MySQL集群,的确是一个讨论很多的话题。方案多种多样,看到知乎上面的https://www.zhihu.com/question/21307639,这些方案应该说都有道理,但是都有缺点,由于CAP的原因,很难鱼和熊掌前的兼得。把二楼的回答稍作修改摘录如下:

         1. 做读写分离,关于这方面的原因解释太多次数(增加技术复杂度、可能导致读到落后的数据等),只说一点:99.8%的业务场景没有必要做读写分离,只要做好数据库设计优化 和配置合适正确的主机即可,一般不适用。

        2. Keepalived+MySQL --确实有脑裂的问题,还无法做到准确判断mysqld是否HANG的情况;DRBD+Heartbeat+MySQL  --同样有脑裂的问题,还无法做到准确判断mysqld是否HANG的情况,且DRDB是不需要的,增加反而会出问题;

        3. MySQL Proxy -- 不错的项目,可惜官方半途夭折了,不建议用,无法高可用,是一个写分离;

        4. MySQL Cluster -- 社区版本不支持NDB是错误的言论,商用案例确实不多,主要是跟其业务场景要求有关系,这几年发展有点乱不过现在已经上正规了、对网络要求高;

        5. MySQL + MHA -- 可以解决脑裂的问题,需要的IP多,小集群是可以的,但是管理大的就麻烦,其次MySQL + MMM 的话且坑很多,有MHA就没必要采用MMM建议:1.若是双主复制的模式,不用做数据拆分,那么就可以选择MHA或 Keepalive 或 heartbeat2.若是双主复制,还做了数据的拆分,则可以考虑采用Cobar;3.若是双主复制+Slave,还做了数据的拆分,需要读写分类,可以考虑Amoeba;上述所有的内容都要依据公司内部的业务场景、数据量、访问量、并发量、高可用的要求、DBA人群的数量等 综合权衡。

         没有最好的方案,只有挑当前最适用的方案。这里来实践下Mysql双机互为热备方案。在进行讨论的时候一定要考虑到很多的因素,其中在各种环境下应用的时候需要格外的引起注意。按照上面说的复制模式,一般有2种方案。1,双机热备它的工作原理是使用两台服务器,一台作为主服务器(Master或者Active),运行应用系统来提供服务。另一台作为备机,安装完全一样的应用系统,但处于待机状态(Slave或者叫Standby)。当Master服务器出现故障时,通过软件诊测将Slave机器激活,保证应用在短时间内完成恢复正常使用。2,另外一种形式就是,双机互备方式则是在双机热备的基础上,两个相对独立的应用在两台机器同时运行,但彼此均设为备机,当某一台服务器出现故障时,另一台服务器可以在短时间内将故障服务器的应用接管过来,从而保证了应用的持续性,这种方式实际上是双机热备方案的一种应用。

          Mysql的复制原理,复制方案,网络上有很多介绍,具体不细说。这里以CentOS7 上面安装Server version: 5.7.20-log MySQL Community Server为例,来实操下。

          A机器:192.168.37.128

          B机器:192.168.37.129

          分别安装好Mysql。A机器修改配置文件/etc/my.cnf

    server-id = 1
    log-bin=mysql-bin 
    binlog-do-db = test
    binlog-do-db = dbtest
    binlog-ignore-db = mysql
    #主-主形式需要多添加的部分
    log-slave-updates
    sync_binlog = 1
    auto_increment_offset = 1
    auto_increment_increment = 2
    replicate-do-db = test
    replicate-do-db = dbtest

    B机器修改配置文件/etc/my.cnf

    server-id = 2
    log-bin=mysql-bin 
    #master-slave need
    replicate-do-db = test
    replicate-do-db = dbtest
    replicate-ignore-db = mysql,information_schema,performance_schema
    binlog-do-db = test
    binlog-do-db = dbtest
    binlog-ignore-db = mysql
    log-slave-updates
    sync_binlog = 1
    auto_increment_offset = 2
    auto_increment_increment = 2

    各个配置项的意义是:

    server-id:ID值唯一的标识了复制群集中的主从服务器,因此它们必须各不相同。
    log-bin:表示打开binlog,打开该选项才可以通过I/O写到Slave的relay-log,也是可以进行replication的前提。
    binlog-do-db:表示需要记录二进制日志的数据库。如果有多个数据可以用逗号分隔,或者使用多个binlog-do-dg选项。
    binglog-ingore-db:表示不需要记录二进制日志的数据库,如果有多个数据库可用逗号分隔,或者使用多binglog-ignore-db选项。
    replicate-do-db:表示需要同步的数据库,如果有多个数据可用逗号分隔,或者使用多个replicate-do-db选项。
    replicate-ignore-db:表示不需要同步的数据库,如果有多个数据库可用逗号分隔,或者使用多个replicate-ignore-db选项。
    master-connect-retry:表示从服务器与主服务器的连接没有成功,则等待n秒(s)后再进行管理方式(默认60s)。如果从服务器存在mater.info文件,它将忽略些选项。
    log-slave-updates:配置从库上的更新操作是否写入二进制文件,如果这台从库,还要做其他从库的主库,那么就需要打这个参数,以便从库的从库能够进行日志同步。
    slave-skip-errors:在复制过程,由于各种原因导致binglo中的sql出错,默认情况下,从库会停止复制,要用户介入。可以设置slave-skip-errors来定义错误号,如果复制过程中遇到的错误是定义的错误号,便可以路过。如果从库是用来做备份,设置这个参数会存在数据不一致,不要使用。如果是分担主库的查询压力,可以考虑。
    sync_binlog=1 Or N
    sync_binlog的默认值是0,MySQL不会同步到磁盘中去。这样的话,Mysql依赖操作系统来刷新二进制日志binary log,就像操作系统刷新其他文件的机制一样。因此如果操作系统或机器(不仅仅是Mysql服务器)崩溃,有可能binlog中最后的语句丢失了。要想防止这种情况,可以使用sync_binlog全局变量,使binlog在每N次binlog写入后与硬盘同步。当sync_binlog变量设置为1是最安全的,因为在crash崩溃的情况下,你的二进制日志binary log只有可能丢失最多一个语句或者一个事务。
    即使sync_binlog设置为1,出现崩溃时,也有可能表内容和binlog内容之间存在不一致性。如果使用InnoDB表,Mysql服务器处理COMMIT语句,它将整个事务写入binlog并将事务提交到InnoDB中。如果在两次操作之间出现崩溃,重启时,事务被InnoDB回滚,但仍然存在binlog中。可以用-innodb-safe-binlog选项来增加InnoDB表内容和binlog之间的一致性。
    auto_increment_offset和Auto_increment_increment


            启动数据库:systemctl start mysqld,然后登陆mysql控制台,mysql -u root -p

            GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;   #修改root密码,如果不能修改,可以执行下面的试试

             set global validate_password_length=1; #设置密码长度,一般不要执行
             set global validate_password_policy=0; #设置密码策略,一般不要执行

            服务器A和服务器B互为主从,需要建立一个同步用户,在控制台执行  grant replication slave on *.* to 'replicate'@'%' identified by '123456';

            使用show master statusG分别查看AB机器的状态:

           mysql> show master statusG;
    *************************** 1. row ***************************
                 File: mysql-bin.000001
             Position: 604
         Binlog_Do_DB: test,dbtest
     Binlog_Ignore_DB: mysql

    mysql> show master statusG;
    *************************** 1. row ***************************
                 File: mysql-bin.000001
             Position: 604
         Binlog_Do_DB: test,dbtest
     Binlog_Ignore_DB: mysql

    通过SQL语句在B上指定master为A:

    change master to master_host='192.168.37.128',master_user='replicate',master_password='123456',master_log_file=' mysql-bin.000001',master_log_pos=604;
    同样在A上执行(当然log_file和log_pos要看上面的情况,可能不同):
    change master to master_host='192.168.37.129',master_user='replicate',master_password='123456',master_log_file=' mysql-bin.000001',master_log_pos=604;

    然后在两台机器上启动slave io-thread,检查slave的状态:

    mysql>start slave;
    mysql>show slave statusG;

    当下面两项值均为Yes,则表示设置slave服务器成功。
    Slave_IO_Running: Yes
    Slave_SQL_Running: Yes        

    如果出错,可以查看mysql的日志,默认的是/var/log/mysqld.log,遇到下面这个错误:

       Last_IO_Errno: 1236
       Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'

    百度了半天,最后通过执行 flush logs; 这样master_log_file和master_log_pos都会变化。也要检查CHANGE MASTER语句到底是在哪台机器上执行,不然搞错了,会遇到各种奇怪的问题。

    CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002',MASTER_LOG_POS=154;

    然后重启就解决了。遇到连接的错误:

    2018-01-02T10:26:18.587050Z 4 [ERROR] Slave I/O for channel '': error connecting to master 'replicate@192.168.37.128:3306' - retry-time: 60  retries: 39, Error_code: 1130
    2018-01-02T10:27:18.589837Z 4 [ERROR] Slave I/O for channel '': error connecting to master 'replicate@192.168.37.128:3306' - retry-time: 60  retries: 40, Error_code: 1130

    考虑下是不是授权不对,没有从远程机器访问的权限: grant replication slave on *.* to 'replicate'@'%' identified by '123456';  ###注意%号是所有机器都可以访问

    排除错误,直到show slave statusG;看到Slave_IO_Running和Slave_SQL_Running都为YES,且

    Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates

    说明2台机器互为热备了,下面开始检查下:

    use dbtest;

    CREATE TABLE userinfo( id INT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(32) );

    INSERT INTO userinfo(NAME) VALUES ('aaa');

    SELECT * FROM userinfo;

    可以看到,在一台机器上插入数据,另外一台机器上面也能查询到。

    就像网络上说的,这种方案也是很多地方有坑。如果遇到各种异常情况,数据不能同步,那就麻烦了。

    我在A上插入一条记录,由于开始没有同步复制到B,删除那条记录的时候结果后面就出现错误:

         Last_SQL_Errno: 1032
         Last_SQL_Error: Could not execute Delete_rows event on table dbtest.tb_user; Can't find record in 'tb_user', Error_code: 1032; handler error HA_ERR_END_OF_FILE; the event's master log mysql-bin.000005, end_log_pos 711

    参考这个文章http://blog.51cto.com/liuer/1313733,解决了问题。

    stop slave;

    set global sql_slave_skip_counter=1;

    start slave;

    show slave statusG;

    要是实际生产,可能遇到的问题更多。参考文章http://blog.csdn.net/steven_liwen/article/details/53423699。还是那句话,没有最好的,只有最适用的。

    当然上面只是做了互为主备的配置,没有配置keepalived或者Heartbeat,需要对外访问的,可以参照前面一篇博文来解决。

  • 相关阅读:
    一致性哈希算法
    Tcp 3次握手 4次挥手
    计算机字符编码编年史
    虚拟机字节码指令表 JVM
    计算机是如何计算的、运行时栈帧分析(神奇i++续)
    神奇的i++
    记一次 springboot 参数解析 bug调试 HandlerMethodArgumentResolver
    String+、intern()、字符串常量池
    签名和加密的区别(详细)
    java之设计模式汇总
  • 原文地址:https://www.cnblogs.com/lidabo/p/14254333.html
Copyright © 2011-2022 走看看