• MySQL数据库 主从复制与读写分离


    读写分离是什么

    读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。

    为什么要进行读写分离

    因为数据库的“写”(写10000条数据可能要3分钟)操作是比较耗时的。

    但是数据库的“读”(读10000条数据可能只要5秒钟)。

    所以读写分离,解决的是,数据库的写入,影响了查询的效率。

    何时要进行读写分离

    数据库不一定要读写分离,但如果程序使用数据库较多,而更新少,查询多的情况下会考虑使用。利用数据库主从同步,再通过读写分离可以分担数据库压力,提高性能。

    主从复制与读写分离

    在实际的生产环境中,对数据库的读和写都在同一个数据库服务器中,是不能满足实际需求的。无论是在安全性、高可用性还是高并发等各个方面都是完全不能满足实际需求的。因此,通过主从复制的方式来同步数据,再通过读写分离来提升数据库的并发负载能力。有点类似于rsync,但是不同的是rsync是对磁盘文件做备份,而mysql主从复制是对数据库中的数据、语句做备份。

    MySQL支持的复制类型

    STATEMENT:基于语句的复制。在服务器上执行sql语句,在从服务器上执行同样的语句,mysql默认采用基于语句的复制,执行效率高。

    ROW:基于行的复制。把改变的内容复制过去,而不是把命令在从服务器上执行一遍。

    MIXED:混合类型的复制。默认采用基于语句的复制,一旦发现基于语句无法精确复制时,就会采用基于行的复制。

    主从复制的过程

    主(Master):dump线程,二进制日志

    从(Slave):I/O线程,SQL线程,中继日志

    1、主中数据进行更新,并写入二进制日志。

    2、从开启IO线程,并勘测主的二进制日志是否有更新,请求读取二进制日志。

    3、主为从的IO线程开启dump线程,向从发送二进制日志

    4、从保存二进制日志到中继日志中

    5、从开启SQL线程读取中继日志,解析成sql语句,实现主从同步
     

    数据库主从数据不一致解决方案

    一:忽略错误后,继续同步 该方法适用于主从库数据相差不大,或者要求数据可以不完全统一的情况,数据要求不严格的情况

    二:重新做主从,完全同步 该方法适用于主从库数据相差较大,或者要求数据完全统一的情况

    MYSQL读写分离原理

    读写分离就是只在主服务器上写,只在从服务器上读。基本的原理是让主数据库处理事务性操作,而从数据库处理select查询。数据库复制被用来把主数据库上事务性操作导致的变更同步到集群中的从数据库。

    目前较为常见的MysQL读写分离分为以下两种:

    基于程序代码内部实现

    在代码中根据select、insert进行路由分类,这类方法也是目前生产环境应用最广泛的。

    优点是性能较好,因为在程序代码中实现,不需要增加额外的设备为硬件开支;缺点是需要开发人员来实现,运维人员无从下手。

    但是并不是所有的应用都适合在程序代码中实现读写分离,像一些大型复杂的Java应用,如果在程序代码中实现读写分离对代码改动就较大。

    基于中间代理层实现

    代理一般位于客户端和服务器之间,代理服务器接到客户端请求后通过判断后转发到后端数据库,有以下代表性程序。

            MySQL-Proxy

    MySQL-Proxy为MysQL开源项目,通过其自带的1ua脚本进行sQL判断。

            Atlas

    是由奇虎360的Web平台部基础架构团队开发维护的一个基于MysQL协议的数据中间层项目。它是在mysql-proxy 0.8.2版本的基础上,对其进行了优化,增加了一些新的功能特性。360内部使用atlas运行的mysql业务,每天承载的读写请求数达几干保条。支持事物以及存储过程。

            Amoeba

    由陈思儒开发,作者曾就职于阿里巴巴。该程序由Java语言进行开发,阿里巴巴将其用于生产环境。但是它不支持事务和存储过程。

    Amoeba是一个非常容易使用、可移植性非常强的软件。因此它在生产环境中被广泛应用于数据库的代理层。

            Mycat

    是一款流行的基于Java语言编写的数据库中间件,是一个实现了MySq1协议的服务器,其核心功能是分库分表。配合数据库的主从模式还可以实现读写分离 由于使用MysQLProxy需要写大量的ua脚本,这些Lua并不是现成的,而是需要自己去写。这对于并不熟悉MysQLProxy 内置变量和MySQL Protocol的人来说是非常困难的。

    MySQL主从复制延迟的原因

    1、master服务器高并发,形成大量事务

    2、网络延迟

    3、主从硬件设备导致:cpu主频、内存io、硬盘io

    4、本来就不是同步复制、而是异步复制

    从库优化Mysql参数。比如增大innodb_buffer_pool_size,让更多操作在Mysql内存中完成,减少磁盘操作。

    从库使用高性能主机。包括cpu强悍、内存加大。避免使用虚拟云主机,使用物理主机,这样提升了i/o方面性。

    从库使用SSD磁盘

    网络优化,避免跨机房实现同步

    主从复制配置

    1. #准备
    2. Master 服务器:20.0.0.30 mysql5.7
    3. Slave1 服务器:20.0.0.40 mysql5.7
    4. Slave2 服务器:20.0.0.120 mysql5.7
    5. #关闭防火墙及安全机制
    6. systemctl stop firewalld
    7. systemctl disable firewalld
    8. setenforce 0

    Mysql主从服务器时间同步

    1. #主服务器设置(20.0.0.30)
    2. #安装ntp
    3. yum install ntp -y
    4. vim /etc/ntp.conf
    5. --末尾添加--
    6. server 127.0.0.0 #设置本地是时钟源,注意修改网段 127.0.0.0
    7. fudge 127.0.0.0 stratum 8 #设置时间层级为8(限制在15内)
    8. service ntpd start
    9. systemctl start ntpd
    10. #从服务器设置(20.0.0.4020.0.0.120)
    11. yum install ntp ntpdate -y
    12. service ntpd start
    13. systemctl start ntpd
    14. /usr/sbin/ntpdate 20.0.0.30 #进行时间同步 20.0.0.30
    15. #可添加定时任务,实现自动同步
    16. crontab -e
    17. */30 * * * * /usr/sbin/ntpdate 20.0.0.30

    主服务器的mysql配置

    1. vim /etc/my.cnf #MySQL的配置文件
    2. server-id = 1
    3. log-bin=master-bin #添加,主服务器开启二进制日志
    4. binlog_format = MIXED #设置日式格式为混合模式
    5. log-slave-updates=true #添加,允许slave从master复制数据时可以写入到自己的二进制日志
    6. #重启MySQL服务
    7. systemctl restart mysqld
    8. mysql -u root -p123456
    9. GRANT REPLICATION SLAVE ON *.* TO 'myslave'@'20.0.0.%' IDENTIFIED BY '123456'; #给从服务器的网段授权
    10. #刷新
    11. FLUSH PRIVILEGES;
    12. show master status;
    13. //如显示以下
    14. +-------------------+----------+--------------+------------------+
    15. | File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
    16. +-------------------+----------+--------------+------------------+
    17. | master-bin.000001 | 447 | | |
    18. +-------------------+----------+--------------+------------------+
    19. 1 row in set (0.00 sec)
    20. #File 列显示日志名,Position 列显示偏移量

    从服务器的mysql配置

    1. vim /etc/my.cnf
    2. server-id = 2 [server-id = 3] #修改,注意id与Master的不同,两个Slave的id也要不同
    3. relay-log=relay-log-bin #添加,开启中继日志,从主服务器上同步日志文件记录到本地
    4. relay-log-index=slave-relay-bin.index #添加,定义中继日志文件的位置和名称,一般和relay-log在同一目录
    5. relay_log_recovery = 1
    6. #relay_log_recovery = 1 选配项:当 slave 从库宕机后,假如 relay-log 损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的 relay-log,并且重新从 master 上获取日志,这样就保证了relay-log 的完整性。默认情况下该功能是关闭的,将 relay_log_recovery 的值设置为 1 时, 可在 slave 从库上开启该功能,建议开启。
    7. systemctl restart mysqld
    8. mysql -u root -123456
    9. CHANGE master to master_host='20.0.0.30',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=447;
    10. #配置同步,注意 master_log_file 和 master_log_pos 的值要与Master查询的一致
    11. start slave; #启动同步,如有报错执行 reset slave;
    12. show slave status\G #查看 Slave 状态
    13. //确保 IO 和 SQL 线程都是 Yes,代表同步正常。
    14. Slave_IO_Running: Yes #负责与主机的io通信
    15. Slave_SQL_Running: Yes #负责自己的slave mysql进程

    查看从配置不正常的情况

    1. #一般 Slave_IO_Running: No 的可能性:
    2. 1、网络不通
    3. 2、my.cnf配置有问题
    4. 3、密码、file文件名、pos偏移量不对
    5. 4、防火墙没有关闭

    验证主从复制效果

    1. #当主数据库进行增添或修改时,从数据库会同步记录主的数据
    2. #在主数据库增添数据(20.0.0.30)
    3. mysql> create database xxxx;
    4. Query OK, 1 row affected (0.00 sec)
    5. #此时查看配置的两台从服务器数据库
    6. #20.0.0.40
    7. mysql> show databases;
    8. +--------------------+
    9. | Database |
    10. +--------------------+
    11. | information_schema |
    12. | bbs |
    13. | mysql |
    14. | performance_schema |
    15. | sys |
    16. | test |
    17. | test1 |
    18. | wordpress |
    19. | xxxx |
    20. +--------------------+
    21. #20.0.0.120
    22. mysql> show databases;
    23. +--------------------+
    24. | Database |
    25. +--------------------+
    26. | information_schema |
    27. | mysql |
    28. | performance_schema |
    29. | sys |
    30. | test1 |
    31. | test2 |
    32. | xxxx |
    33. +--------------------+

    读写分离配置

    基于上面的主从复制

    1. #准备
    2. Master 服务器:20.0.0.30 mysql5.7
    3. Slave1 服务器:20.0.0.40 mysql5.7
    4. Slave2 服务器:20.0.0.120 mysql5.7
    5. Amoeba 服务器:20.0.0.41 jdk1.6、Amoeba
    6. 客户端 服务器:20.0.0.41 mysql
    7. #关闭防火墙及安全机制
    8. systemctl stop firewalld
    9. systemctl disable firewalld
    10. setenforce 0

    做读写分离实验之前必须有一 主 两从 环境

    1. #Amoeba服务器配置
    2. ##安装 Java 环境##
    3. 因为 Amoeba 是基于 jdk1.5 开发的,所以官方推荐使用 jdk1.51.6 版本,高版本不建议使用。
    4. cd /opt/
    5. cp jdk-6u14-linux-x64.bin /usr/local/
    6. cd /usr/local/
    7. chmod +x jdk-6u14-linux-x64
    8. ./jdk-6u14-linux-x64.bin
    9. //按yes,按enter
    10. #重命名目录
    11. mv jdk1.6.0_14/ /usr/local/jdk1.6
    12. #修改系统配置文件
    13. vim /etc/profile
    14. export JAVA_HOME=/usr/local/jdk1.6
    15. export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
    16. export PATH=$JAVA_HOME/lib:$JAVA_HOME/jre/bin/:$PATH:$HOME/bin
    17. export AMOEBA_HOME=/usr/local/amoeba
    18. export PATH=$PATH:$AMOEBA_HOME/bin
    19. #执行
    20. source /etc/profile
    21. #查看当前java环境
    22. java -version
    23. #安装 Amoeba软件
    24. mkdir /usr/local/amoeba
    25. tar zxvf amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba/
    26. chmod -R 755 /usr/local/amoeba/
    27. /usr/local/amoeba/bin/amoeba
    28. #如显示amoeba start|stop说明安装成功
    29. #配置 Amoeba读写分离,两个 Slave 读负载均衡##
    30. #先在Master(20.0.0.30)、Slave1(20.0.0.40)、Slave2(20.0.0.120) 的mysql上开放权限给 Amoeba 访问
    31. grant all on *.* to test@'20.0.0.%' identified by '123456';
    32. #再回到amoeba服务器配置amoeba服务:
    33. cd /usr/local/amoeba/conf/
    34. #备份
    35. cp amoeba.xml amoeba.xml.bak
    36. vim amoeba.xml #修改amoeba配置文件
    37. --30行--
    38. "user">amoeba
    39. --32行--
    40. "password">123456
    41. --115行--
    42. "defaultPool">master
    43. --117-去掉注释-
    44. "writePool">master
    45. "readPool">slaves
    46. #备份
    47. cp dbServers.xml dbServers.xml.bak
    48. vim dbServers.xml #修改数据库配置文件
    49. --23行--注释掉 作用:默认进入test库 以防mysql中没有test库时,会报错
    50. --26--修改
    51. "user">test
    52. --28-30--去掉注释
    53. "password">123456
    54. --45--修改,设置主服务器的名Master
    55. "master" parent="abstractServer">
    56. --48--修改,设置主服务器的地址
    57. "ipAddress">192.168.10.15
    58. --52--修改,设置从服务器的名slave1
    59. "slave1" parent="abstractServer">
    60. --55--修改,设置从服务器1的地址
    61. "ipAddress">192.168.10.14
    62. --58--复制上面6行粘贴,设置从服务器2的名slave2和地址
    63. "slave2" parent="abstractServer">
    64. "ipAddress">192.168.10.16
    65. --65行--修改
    66. "slaves" virtual="true">
    67. --71行--修改
    68. "poolNames">slave1,slave2
    69. /usr/local/amoeba/bin/amoeba start& #启动Amoeba软件,按ctrl+c 返回
    70. netstat -anpt | grep java #查看8066端口是否开启,默认端口为TCP 8066

    测试读写分离

    1. yum install -y mariadb-server mariadb
    2. systemctl start mariadb.service
    3. ———————————————————— 可选,也可以用MySQL
    4. 在客户端服务器上测试(20.0.0.41):
    5. mysql -u amoeba -p123456 -h 20.0.0.41 -P8066
    6. #通过amoeba服务器代理访问mysql ,在通过客户端连接mysql后写入的数据只有主服务会记录,然后同步给从--从服务器
    7. #在客户端(20.0.0.41)更新
    8. mysql> create database amoeba;
    9. Query OK, 1 row affected (0.04 sec)
    10. #查看主(20.0.0.30)、从1(20.0.0.40)、从2(20.0.0.120)
    11. mysql> show databases;
    12. +--------------------+
    13. | Database |
    14. +--------------------+
    15. | information_schema |
    16. | amoeba |
    17. | bbs |
    18. | mysql |
    19. | performance_schema |
    20. | sys |
    21. | test |
    22. | test1 |
    23. | wordpress |
    24. +--------------------+
    25. 9 rows in set (0.01 sec)
    26. #当关闭两台从服务器(20.0.0.40、20.0.0.120)
    27. stop slave; #关闭同步
    28. use amoeba;
    29. create table test(id int,name varchar(20),text varchar(30));
    30. //在slave1上:
    31. insert into test values('1','zhangsan','this_is_slave1');
    32. //在slave2上:
    33. insert into test values('2','lisi','this_is_slave2');
    34. //在主服务器上:
    35. insert into test values('3','wangwu','this_is_master');
    36. //在客户端服务器上:
    37. use amoeba;
    38. select * from test; //客户端会分别向slave1和slave2读取数据,显示的只有在两个从服务器上添加的数据,没有在主服务器上添加的数据
    39. mysql> select * from test;
    40. +------+----------+----------------+
    41. | id | name | text |
    42. +------+----------+----------------+
    43. | 1 | zhangsan | this_is_slave1 |
    44. +------+----------+----------------+
    45. 再次执行select * from test;
    46. mysql> select * from test;
    47. +------+------+----------------+
    48. | id | name | text |
    49. +------+------+----------------+
    50. | 2 | lisi | this_is_slave2 |
    51. +------+------+----------------+
    52. #在客户端(20.0.0.41) 插入新条目
    53. insert into test values('4','qianqi','this_is_client');
    54. #只有主服务器(20.0.0.30)上有此数据
    55. mysql> select * from test;
    56. +------+--------+----------------+
    57. | id | name | text |
    58. +------+--------+----------------+
    59. | 3 | wangwu | this_is_master |
    60. | 4 | qianqi | this_is_client |
    61. +------+--------+----------------+
    62. //在两个从服务器(20.0.0.40、20.0.0.120)上执行 start slave; 即可实现同步在主服务器上添加的数据
    63. start slave;
    64. #(20.0.0.40)
    65. mysql> select * from test;
    66. +------+----------+----------------+
    67. | id | name | text |
    68. +------+----------+----------------+
    69. | 1 | zhangsan | this_is_slave1 |
    70. | 3 | wangwu | this_is_master |
    71. | 4 | qianqi | this_is_client |
    72. +------+----------+----------------+
    73. #(20.0.0.120)
    74. mysql> select * from test;
    75. +------+----------+----------------+
    76. | id | name | text |
    77. +------+----------+----------------+
    78. | 2 | lisi | this_is_slave2 |
    79. | 3 | wangwu | this_is_master |
    80. | 4 | qianqi | this_is_client |
    81. +------+----------+----------------+

  • 相关阅读:
    Model-Free TD Control: Sarsa
    vue 下载的插件从哪里上传?npm发布插件详细记录
    机器学习从入门到放弃:卷积神经网络CNN(二)
    C++11 move和forward实现原理
    【java学习—十五】线程的通信(6)
    AI与医疗保健:革命性技术如何拯救生命
    SQL Server事务隔离级别
    Oracle基本介绍与基本使用
    Meta官方吐槽大会?Connect 2022卡马克演讲全文回顾
    select实现延时函数
  • 原文地址:https://blog.csdn.net/ZZZ_CCC01/article/details/132619602