• Mysql集群及读写分离


    一、集群搭建之主从复制

    (一)主从复制原理

      这里需要了解两个文件,bin log和relay log(中继日志)文件。

      bin log:bin log记录所有的数据更改操作,可用于本机数据恢复和主从数据同步,其刷入磁盘方式有三种:每秒一次将数据刷新入磁盘;每次事务提交将数据刷新入磁盘;每一秒一次 + 每次事务提交   都会将数据刷入磁盘。

      relay log:中继日志会进行回访,从而使从数据库达到与主数据库主从同步的目的。

      主从复制的原理就是:

        主服务器会将binlog写入本地,从数据库定时请求增量binlog,然后主节点将binlog同步到从节点;

        从节点单独的线程将binlog 复制到从节点的 relaylog中

        从节点定时重放relaylog

      上面说到,主服务器会将数据变更刷入磁盘,那么刷新类型有三种模式。

      binlog的三种模式:

    模式 说明 优点 缺点
    statement level 每一条修改数据的sql都会被记录到master节点的bin-log中,slave在复制的时候,会将该sql重新执行一遍 其只需要关心在master节点上执行的sql及语句执行的上下文信息,不需要记录每一行数据的变化,减少了bin-log的数据量,节约io,提高性能, 由于该种模式记录的是执行sql,为了能让sql在slave上也能正常的执行,其需要记录sql执行的上下文信息,但是由于mysql发展很快,在执行一些特定函数的时候,已经发现不少会造成主从复制问题的情况,例如sleep()函数就不能正常复制    
    row level 日志中会记录成每一条数据被修改的形式,slave直接将数据进行修改 不需要记录修改数据的上下文信息,仅仅记录了被修改成什么样子,因此不存在无法被正确的主从复制的情况 由于需要记录每一条数据变更的数据,因此bin-log的日志量会很大,会增加io
    mixed 就是上面两种情况的结合体,在该种模式下,会根据sql语句的具体内容来选择使用statement level还是选择row level    

      查看binlog日志模式

    mysql> show variables like 'binlog_format';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | binlog_format | ROW   |
    +---------------+-------+
    1 row in set (0.00 sec)

      调整binlog日志模式

    mysql> set binlog_format=statement;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> show variables like 'binlog_format';
    +---------------+-----------+
    | Variable_name | Value     |
    +---------------+-----------+
    | binlog_format | STATEMENT |
    +---------------+-----------+
    1 row in set (0.00 sec)

      查看bin log和relay log日志

       首先查看binlog是否开启

    mysql> show variables like 'log%';
    +----------------------------------------+---------------------+
    | Variable_name                          | Value               |
    +----------------------------------------+---------------------+
    | log_bin                                | OFF                 |
    | log_bin_basename                       |                     |
    | log_bin_index                          |                     |
    | log_bin_trust_function_creators        | OFF                 |
    | log_bin_use_v1_row_events              | OFF                 |
    | log_builtin_as_identified_by_password  | OFF                 |
    | log_error                              | /var/log/mysqld.log |
    | log_error_verbosity                    | 3                   |
    | log_output                             | FILE                |
    | log_queries_not_using_indexes          | OFF                 |
    | log_slave_updates                      | OFF                 |
    | log_slow_admin_statements              | OFF                 |
    | log_slow_slave_statements              | OFF                 |
    | log_statements_unsafe_for_binlog       | ON                  |
    | log_syslog                             | OFF                 |
    | log_syslog_facility                    | daemon              |
    | log_syslog_include_pid                 | ON                  |
    | log_syslog_tag                         |                     |
    | log_throttle_queries_not_using_indexes | 0                   |
    | log_timestamps                         | UTC                 |
    | log_warnings                           | 2                   |
    +----------------------------------------+---------------------+

      可以看到binlog是关闭的(log_bin的值为OFF),需要开启,只需要在/etc/my.cnf文件中增加以下内容,然后重启mysql服务即可。

    log-bin=mysql-bin
    server-id=1
    binlog_format=ROW

      如果在/etc/my.cnf中没有设置binlog的位置,则默认在/var/lib/mysql文件夹中,会生成mysql-bin.0000*的文件,由于该文件是个二进制文件,没办法直接查看,这里可以使用mysql自带的mysqlbinlog工具进行解码,将该二进制文件转为可阅读的sql语句。

    mysqlbinlog --base64-output=decode-rows -v -v mysql-bin.000001 > binlog

      

       可以发现已经多了一个binlog文件, 然后,可以使用vim直接查看

    (二)基于binlog主从复制

      1、主从服务器都先关闭防火墙:

    #关闭防火墙
    systemctl stop firewalld
    #设置开机不启动
    systemctl disable firewalld.service

      2、主服务器配置

      (1)然后需要保证主服务器binlog是开启状态,如果未开启,需要修改my.cnf配置文件进行开启,同时,主从的service-id不能一致

    [mysqld]
    datadir=/var/lib/mysql
    socket=/var/lib/mysql/mysql.sock
    
    symbolic-links=0
    
    log-error=/var/log/mysqld.log
    pid-file=/var/run/mysqld/mysqld.pid
    
    
    # MySQL设置大小写不敏感:默认:区分表名的大小写,不区分列名的大小写 # 0:大小写敏感 1>:大小写不敏感
    lower_case_table_names=1
    # 默认字符集
    character-set-server=utf8
    
    log-bin=mysql-bin
    server-id=104

      (2)修改my.cnf配置文件需要重启服务。

      (3)给从服务器授权备份权限

      进入mysql后,可以使用如下命令进行授权操作  grant replication slave on *.* to '从服务器用户名'@'从服务器IP' identified by '从服务器密码';     其中  *.*  表示授权所有库的所有表。

    grant replication slave on *.* to 'root'@'192.168.1.106' identified by 'root';

      如果在执行语句过程中,提示密码策略不符合要求,可以先对密码策略做修改,修改密码策略详见 https://www.cnblogs.com/liconglong/p/14437439.html 中 第二点(安装)中第5点(修改初始密码)

      上述命令样例中,可以将从服务器的ip替换为%,表示不限制ip,只要用户名密码正确,就可以备份。

    grant replication slave on *.* to 'root'@'%' identified by 'root';

      (4)刷新权限

    flush privileges;

      (5)查看主服务器状态

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

      3、从服务器配置

      (1)修改从服务器配置

      修改从服务的配置文件my.cnf,设置service-id,要与主服务器区别开

      (2)删除错误的UUID

    rm -f /var/lib/mysql/auto.cnf

      (3)重启服务器

      (4)登录到mysql中,对从服务器进行配置

      需要配置从服务器的host、user、password等内容;

      其中主服务器的binlog文件名称,是在查看主服务器状态时的File的值;

      master_log_pos则是对应主服务器的positions;

      MASTER_AUTO_POSITION大小写敏感,必须为大写。

    change master to
    master_host='192.168.1.104',
    master_port=3306,
    master_user='root',
    master_password='root',
    master_log_file='mysql-bin.000001',
    master_log_pos=884,
    MASTER_AUTO_POSITION=0;

      (5)启动从服务器

    mysql> start slave;

      (6)查看从服务状态

    mysql> show slave status G;
    *************************** 1. row ***************************.............
                      Master_Host: 192.168.1.104
                      Master_User: root
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: mysql-bin.000001
              Read_Master_Log_Pos: 884
                   Relay_Log_File: bogon-relay-bin.000002
                    Relay_Log_Pos: 320
            Relay_Master_Log_File: mysql-bin.000001
                 Slave_IO_Running: Yes
                Slave_SQL_Running: Yes
    ..............

      其中Slave_IO_Running和Slave_SQL_Running必须为YES,否则的话就是没有配置成功。

      (7)测试

      最后就是测试了,在主服务器上创建库、表即增删改数据,都会同步到从数据库上。

    (三)主从同步延迟的原因及解决办法

      1、原因

      主从同步时,主服务器会把更新语句写入binlog,从服务器的IO线程(5.6.3之前的IO只有一个线程,5.6.3之后开始使用多线程,因此在5.6.3之后速度变快)会去读主服务器的binlog并且写入从服务器的relaylog,然后从服务器的sql线程会一个一个的执行relaylog中的sql,进行数据恢复。

      但是,主从复制的集群,只有主服务器对外提供服务,从服务器只作为备份使用,同时主服务器可能有多个客户端同时进行并发操作,但是从服务器读取binlog的线程只有一个,当某个sql执行时间较长,或者由于某个sql要进行锁表,就会导致主服务器的sql大量积压,从而未被同步到从服务器中,这也就是所谓的主从同步延迟。

      2、解决方案

      对于该种延迟的解决方法,并没有很确切的解决方案,但是我们可以提供一些环节措施。

      (1)调整binlog参数

      由于主服务器对安全性要求比较高,所以会设置一些参数,例如设置同步存储binlog、每次提交时更新binlog等(sync_binlog=1、innodb_flush_log_at_trx_commit=1),而从服务器不需要那么高的数据安全,完全可以异步更新binlog(sync_binlog=0)或者关闭binlog。innodb_flushlog、innodb_flush_log_at_trx_commit也可以设置为0来提高sql的执行效率(这个能很大程度的提高效率);另外一个就是可以使用比主库更好的硬件设备来作为从库。

      (2)从库只作为数据备份

      由于从库还有可能提供数据查询功能(读写分离),这样从库除了要获取主库的binlog之外,还要对外提供查询,可以将从库只作为数据备份库,不提供查询,从而降低从库的负载,从而提高效率。

      (3)增加从服务器。

      3、判断主从同步延迟

      查看从服务器的状态(show slave status G;),在输出结果中查看Seconds_Behind_Master的值,如果为0,表明主从复制状态正常,如果为NULL,说明主从同步发生了延迟或故障。

    二、集群搭建之读写分离

      主从复制只会保证主服务器对外提供服务,而从服务器不对外提供服务,只作为数据备份使用。

      读写分离,主服务器提供读写服务,从数据库提供读服务。

      其实也可以两个数据库互为主从,那么两个服务器就会同时对外提供读写服务。

      数据库读写分离可以使用Mysql-proxy或Mysql-Mouter实现

      上面已经使用192.168.1.104和192.168.1.106做了主从复制,在该基础上继续做读写分离

    (一)Mysql-Proxy

      1、下载&解压

      在一台新的服务器上下载Mysql-Proxy并解压

     wget https://cdn.mysql.com/archives/mysql-proxy/mysql-proxy-0.8.5-linux-el6-x86-64bit.tar.gz
    tar -zxvf mysql-proxy-0.8.5-linux-el6-x86-64bit.tar.gz
    mv mysql-proxy-0.8.5-linux-el6-x86-64bit mysql-proxy

      2、配置Mysql-Proxy配置文件

      创建mysql-proxy.cnf

    vi mysql-proxy.cnf

      内容

    [mysql-proxy]
    user=root
    admin-username=root
    admin-password=root
    proxy-address=0.0.0.0:3306
    proxy-backend-addresses=192.168.1.104:3306
    proxy-read-only-backend-addresses=192.168.1.106:3306
    proxy-lua-script=./share/doc/mysql-proxy/rw-splitting.lua
    log-file=./mysql-proxy.log
    log-level=debug
    keepalive=true
    daemon=true

      其中proxy-address为可以设置监控的ip和端口,proxy-backend-addresses为主服务器地址(提供读写服务),proxy-read-only-backend-addresses为从服务地址(提供写服务)

      修改配置文件权限

    chmod 660 mysql-proxy.cnf

      修改rw-splitting.lua脚本,位置在mysql-proxy/share/doc/mysql-proxy下,将最小连接和最大连接都改为1,方便模拟测试。

    if not proxy.global.config.rwsplit then
            proxy.global.config.rwsplit = {
                    min_idle_connections = 1,#默认超过4个连接数时,才开始读写分离,改为1 测试需要
                    max_idle_connections = 1,#默认8,改为1测试需要
                    is_debug = false
            }
    end

      3、启动

    ./bin/mysql-proxy --defaults-file=mysql-proxy.cnf > mysql-proxy.out 2>&1 &

      说明:Mysql-proxy虽然可以实现读写分离,但是Mysql官方并没有推出稳定版本,因此不推荐在生产中使用,在生产中使用推荐Mysql-Mouter。

    (二)Mysql-Mouter

       Mysql Router2.0是初始版本,目前已经废弃,2.1版本为支持Mysql InnoDB Cluster而引入,从2.1.5版本之后,就废弃了2.1.x的版本代号,转而使用8.0.x版本号,与mysql版本一致。

      1、下载&解压

    wget https://dev.mysql.com/get/Downloads/MySQL-Router/mysql-router-8.0.23-linux-glibc2.12-x86_64.tar.xz
    tar -xvJf mysql-router-8.0.23-linux-glibc2.12-x86_64.tar.xz
    mv mysql-router-8.0.23-linux-glibc2.12-x86_64 mysql-router

      2、配置mysqlrouter.cnf文件

    vi mysqlrouter.cnf

      内容

    [logger]
    level = INFO
    
    [routing:secondary]
    bind_address = localhost
    bind_port = 7001
    destinations = 192.168.1.104:3306,192.168.1.106:3306
    routing_strategy = round-robin
    
    [routing:primary]
    bind_address = localhost
    bind_port = 7002
    destinations = 192.168.1.134:3306,192.168.1.106:3306
    routing_strategy = first-available

      配置文件中配置了两个两个路由策略,一个是开放7001端口,通过循环的使用配置的ip,一个通过7002端口,只使用第一个ip

      3、启动mysqlrouter

    ./bin/mysqlrouter -c mysqlrouter.conf &

      4、测试

      修改主从服务器的hostname,以便可以区分连的是哪一台数据库,修改后重启服务器。

    vi /etc/hostname

      使用7001端口可以发现,是轮询使用。

    [root@bogon mysql-router]# mysql -uroot -proot -P7001 --protocol=tcp -e"select @@hostname"
    mysql: [Warning] Using a password on the command line interface can be insecure.
    +------------+
    | @@hostname |
    +------------+
    | mysql-106  |
    +------------+
    [root@bogon mysql-router]# mysql -uroot -proot -P7001 --protocol=tcp -e"select @@hostname"
    mysql: [Warning] Using a password on the command line interface can be insecure.
    +------------+
    | @@hostname |
    +------------+
    | mysql-104  |
    +------------+
    [root@bogon mysql-router]# mysql -uroot -proot -P7001 --protocol=tcp -e"select @@hostname"
    mysql: [Warning] Using a password on the command line interface can be insecure.
    +------------+
    | @@hostname |
    +------------+
    | mysql-106  |
    +------------+
    [root@bogon mysql-router]# mysql -uroot -proot -P7001 --protocol=tcp -e"select @@hostname"
    mysql: [Warning] Using a password on the command line interface can be insecure.
    +------------+
    | @@hostname |
    +------------+
    | mysql-104  |
    +------------+

      使用7002端口,可以发现,只使用了主服务器

    [root@bogon mysql-router]# mysql -uroot -proot -P7002 --protocol=tcp -e"select @@hostname"
    mysql: [Warning] Using a password on the command line interface can be insecure.
    +------------+
    | @@hostname |
    +------------+
    | mysql-106  |
    +------------+
    [root@bogon mysql-router]# mysql -uroot -proot -P7002 --protocol=tcp -e"select @@hostname"
    mysql: [Warning] Using a password on the command line interface can be insecure.
    +------------+
    | @@hostname |
    +------------+
    | mysql-106  |
    +------------+
    [root@bogon mysql-router]# mysql -uroot -proot -P7002 --protocol=tcp -e"select @@hostname"
    mysql: [Warning] Using a password on the command line interface can be insecure.
    +------------+
    | @@hostname |
    +------------+
    | mysql-106  |
    +------------+

      根据以上可以看到,主要是使用了routing_strategy来配置了轮询方案,对于轮询方案,有以下四种

      round-robin:轮询,以实现负载均衡

      roud-robin-with-fallback:用于InnoDB Cluster,每个新的连接都循环连接到下一个可用的SECONDARY服务器,如果SECONDARY服务器不可用,则以循环方式使用PRIMIARY服务器

      first-available:使用第一个可用的服务器

      next-valiable:使用第一个可用的服务器。与first-avaliable不同的是,如果一个服务器被标记为不可用,那么该服务器江湖被丢弃,并且永远不会再次用作目标。但是router重启,被丢弃的服务器将可再次使用。

    三、基于主从复制的高可用方案

      这种方案主要是双节点主从 + keepalived/heartbeat方案,一般来说,中小型规模的时候,采用这种架构是最省事的。两个节点可以采用简单的一主一从模式,或者双主模式,并且放置于同一个VLAN中,在master节点发生故障后,利用keepalived/heartbeat的高可用机制实现快速切换到slave节点。

      这里主要说明一点,把两个节点的auto_increment_increment(自增起始值)和auto_increment_offset(自增步长)设成不同值。其目的是为了避免master节点意外宕机时,可能会有部分binlog未能及时复制到slave上被应用,从而会导致slave新写入数据的自增值和原先master上冲突了,因此一开始就使其错开;当然了,如果有合适的容错机制能解决主从自增ID冲突的话,也可以不这么做。

    ------------------------------------------------------------------
    -----------------------------------------------------------
    ---------------------------------------------
    朦胧的夜 留笔~~
  • 相关阅读:
    XCode9打包上传遇到的问题
    iOS Category
    ios view生成图片
    xcode8 注释快捷键不能用的解决办法
    warning: templates not found
    Quartz 2D编程指南
    关于键盘输入中文控制字数 (找了很久,最好的写法)真是完美
    小知识
    UIView 的hitTest 添加屏蔽层 但不影响下一层操作
    ios 绘制不规则 图形
  • 原文地址:https://www.cnblogs.com/liconglong/p/14448456.html
Copyright © 2020-2023  润新知