主从复制:主从复制的概述、一主一从架构搭建主从复制的原理、同步数据一致性问题

article/2025/9/27 9:36:27

文章目录

  • 1. 主从复制的概述
    • 1.1 如何提升数据库的并发能力
    • 1.2 主从复制的作用
  • 2. 主从复制的原理
    • 2.1 原理剖析
    • 2.2 复制的最大问题
    • 2.3 复制的基本原则
  • 3. 一主一从架构搭建
    • 3.1 准备工作
    • 3.2 主机配置文件
    • 3.3 从机配置文件
    • 3.4 建立账户并授权
    • 3.5 配置需要复制的主机
    • 3.6 测试
    • 3.7 停止主从同步
  • 4. 同步数据一致性问题
    • 4.1 理解主从延迟问题
    • 4.2 解决一致性问题

1. 主从复制的概述

1.1 如何提升数据库的并发能力

在实际工作中,我们常常将Redis作为缓存与MySQL配合来使用,当有请求的时候,首先会从缓存中进行查找,如果存在就直接取出。如果不存在再访问数据库,这样就提升了读取的效率,也减少了对后端数据库的访问压力。Redis的缓存架构是高并发架构中非常重要的一环。
在这里插入图片描述
此外,一般应用对数据库而言都是“读多写少”,也就说对数据库读取数据的压力比较大,有一个思路就是采用数据库集群的方案,做主从架构、进行读写分离,这样同样可以提升数据库的并发处理能力。但并不是所有的应用都需要对数据库进行主从架构的设置,毕竟设置架构本身是有成本的。

如果我们的目的在于提升数据库高并发访问的效率,那么首先考虑的是如何优化SQL和索引,这种方式简单有效;其次才是采用缓存的策略,比如使用Redis将热点数据保存在内存数据库中,提升读取的效率;最后才是对数据库采用主从架构,进行读写分离。

按照上面的方式进行优化,使用和维护的成本是由低到高的。

1.2 主从复制的作用

主从同步设计不仅可以提高数据库的吞吐量,还有以下3个方面的作用。

第1个作用:读写分离。我们可以通过主从复制的方式来同步数据,然后通过读写分离提高数据库并发处理能力。
在这里插入图片描述
其中一个是Master主库,负责写入数据,我们称之为:写库。

其它都是Slave从库,负责读取数据,我们称之为:读库。

当主库进行更新的时候,会自动将数据复制到从库中,而我们在客户端读取数据的时候,会从从库中进行读取。

面对“读多写少”的需求,采用读写分离的方式,可以实现更高的并发访问。同时,我们还能对从服务器进行负载均衡,让不同的读请求按照策略均匀地分发到不同的从服务器上,让读取更加顺畅。读取顺畅的另一个原因,就是减少了锁表的影响,比如我们让主库负责写,当主库出现写锁的时候,不会影响到从库进行SELECT的读取。

第2个作用就是数据备份。我们通过主从复制将主库上的数据复制到了从库上,相当于是一种热备份机制,也就是在主库正常运行的情况下进行的备份,不会影响到服务。

第3个作用是具有高可用性。数据备份实际上是一种冗余的机制,通过这种冗余的方式可以换取数据库的高可用性,也就是当服务器出现故障宕机的情况下,可以切换到从服务器上,保证服务的正常运行。

关于高可用性的程度,我们可以用一个指标衡量,即正常可用时间/全年时间。比如要达到全年99.999%的时间都可用,就意味着系统在一年中的不可用时间不得超过365*24*60*(1-99.999%)=5.256分钟(含系统崩溃的时间、日常维护操作导致的停机时间等),其他时间都需要保持可用的状态。

实际上,更高的高可用性,意味着需要付出更高的成本代价。在现实中我们需要结合业务需求和成本来进行选择。

2. 主从复制的原理

Slave会从Master读取binlog来进行数据同步。

2.1 原理剖析

在这里插入图片描述

二进制日志转储线程(Binlog dump thread)是一个主库线程。当从库线程连接的时候,主库可以将二进制日志发送给从库,当主库读取事件(Event)的时候,会在Binlog上加锁,读取完成之后,再将锁释放掉。

从库I/O线程会连接到主库,向主库发送请求更新Binlog。这时从库的I/O线程就可以读取到主库的二进制日志转储线程发送的Binlog更新部分,并且拷贝到本地的中继日志(Relay log)。

从库SQL线程会读取从库中的中继日志,并且执行日志中的事件,将从库中的数据与主库保持同步。

2.2 复制的最大问题

延时

2.3 复制的基本原则

  • 每个Slave只有一个Master
  • 每个Slave只能有一个唯一的服务器ID
  • 每个Master可以有多个Slave

3. 一主一从架构搭建

一台主机用于处理所有写请求,一台从机负责所有读请求,架构图如下:
在这里插入图片描述

3.1 准备工作

  1. 准备2台CentOS虚拟机
  2. 每台虚拟机上需要安装好MySQL(可以是MySQL8.0)

3.2 主机配置文件

建议mysql版本一致且后台以服务运行,主从所有配置项都配置在[mysqld]节点下,且都是小写字母。

  • 必选
#[必须]主服务器唯一ID
server-id=1
#[必须]启用二进制日志,指名路径。比如:自己本地的路径/log/mysqlbin
log-bin=/log/mysqlbin
  • 可选
#[可选]0(默认)表示读写(主机),1表示只读(从机)
read-only=8#设置日志文件保留的时长,单位是秒
binlog_expire_logs_seconds=6090#控制单个二进制日志大小,此参数的最大和默认值是1GB
max_binlog_size=200M#[可选]设置不要复制的数据库
binlog-ignore-db=test#[可选]设置雨要复制的数据库,默认全部记录。比如:binlog-do-db=atguigu_master_slave
binlog-do-db=需要复制的主数据库名字#[可选]设置binlog格式
binlog_format=STATEMENT

重启后台mysql服务,使配置生效。

3.3 从机配置文件

要求主从所有配置项都配置在my.cnf[mysqld]栏位下,且都是小写字母。

  • 必选
#[必选]从服务器唯一ID
server-id=2
  • 可选
#[可选]启用中继日志
relay-log=mysql-relay

重启后台mysql服务,使配置生效。

3.4 建立账户并授权

#在主机MySQL里执行授权主从复制的命令
GRANT REPLICATION SLAVE ON *.* TO 'slave1'@'从机器数据库IP'IDENTIFIED BY'abc123';#5.5,5.7

注意:如果使用的是MySQL8,需要如下的方式建立账户,并授权slave:

CREATE USER 'slave1'@ '%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE ON *.* TO 'slave1'@ '%';
#此语句必须执行。否则出错。
ALTER USER 'slave1'@ '%' IDENTIFIED WITH mysql_native_password BY '123456';
flush privileges;

查询Master的状态,并记录下File和Position的值。

show master status;

3.5 配置需要复制的主机

**步骤1:**从机上复制主机的命令

CHANGE MASTER TO
MASTER_HOST='主机的IP地址',
MASTER_USER='主机用户名',
MASTER_PASSWORD='主机用户名的密码',
MASTER_LOG_FILE='mysql-bin.具体数字',
MASTER_LOG_POS=具体值;

步骤2:

#启动slave同步
START SLAVE;

3.6 测试

主机新建库、新建表、insert记录,从机复制:

3.7 停止主从同步

stop slave;

4. 同步数据一致性问题

主从同步的要求

  • 读库和写库的数据一致(最终一致);
  • 写数据必须写到写库;
  • 读数据必须到读库(不一定);

4.1 理解主从延迟问题

进行主从同步的内容是二进制日志,它是一个文件,在进行网络传输的过程中就一定会存在主从延迟(比如500ms),这样就可能造成用户在从库上读取的数据不是最新的数据,也就是主从同步中的数据不一致性问题。

4.2 解决一致性问题

  • 异步复制
    异步模式就是客户端提交COMMIT之后不需要等从库返回任何结果,而是直接将结果返回给客户端,这样做的好处是不会影响主库写的效率,但可能会存在主库宕机,而Binlog还没有同步到从库的情况,也就是此时的主库和从库数据不一致。这时候从从库中选择一个作为新主,那么新主则可能缺少原来主服务器中已提交的事务。所以,这种复制模式下的数据一致性是最弱的。
    在这里插入图片描述
  • 半同步复制

MySQL5.5版本之后开始支持半同步复制的方式。原理是在客户端提交COMMIT之后不直接将结果返回给客户端,而是等待至少有一个从库接收到了Binlog,并且写入到中继日志中,再返回给客户端。

这样做的好处就是提高了数据的一致性,当然相比于异步复制来说,至少多增加了一个网络连接的延迟,降低了主库写的效率。

在MysQL5.7版本中还增加了一个rpl_semi_sync_master_wait_for_slave_count参数,可以对应答的从库数量进行设置,默认为1,也就是说只要有1个从库进行了响应,就可以返回给客户端。如果将这个参数调大,可以提升数据一致性的强度,但也会增加主库等待从库响应的时间。
在这里插入图片描述

  • 组复制

异步复制和半同步复制都无法最终保证数据的一致性问题,半同步复制是通过判断从库响应的个数来决定是否返回给客户端,虽然数据一致性相比于异步复制有提升,但仍然无法满足对数据一致性要求高的场景,比如金融领域。MGR很好地弥补了这两种复制模式的不足。

组复制技术,简称MGR(MySQL Group Replication)。是MySQL在5.7.17版本中推出的一种新的数据复制技术,这种复制技术是基于Paxos协议的状态机复制。

MGR是如何工作的

首先我们将多个节点共同组成一个复制组,在执行读写(RW)事务的时候,需要通过一致性协议层(Consensus层)的同意,也就是读写事务想要进行提交,必须要经过组里“大多数人”(对应Node节点)的同意,大多数指的是同意的节点数量需要大于(N/2+1),这样才可以进行提交,而不是原发起方一个说了算。而针对只读(RO)事务则不需要经过组内同意,直接COMMIT即可。

在一个复制组内有多个节点组成,它们各自维护了自己的数据副本,并且在一致性协议层实现了原子消息和全局有序消息,从而保证组内数据的一致性。
在这里插入图片描述


http://chatgpt.dhexx.cn/article/tyDyiHEF.shtml

相关文章

c/c++经典面试题(高频考点)

一、数据结构及算法(快排、归并、堆排等) 十大排序算法 数据结构(c/c版)-严蔚敏 数据结构与算法(思维导图) E:\学习\4.数据结构(C语言版)].严蔚敏_吴伟民.扫描版.pdf 数据结构分为8类有:数组、栈、队列、链表、树、散列表、堆、图 1.快速排…

吐血整理 | 最常见的 C/C++ 面试题(含答案)

大家好,我是 K 哥! 最近群里有小伙伴想跳槽,问我有没有常见的 C/C 面试题。这不正好,K 哥之前整理了一份 PDF,里面包含了各种经典的 C/C 题目,当然更重要的是还附带了非常详细的答案。 K 哥不仅面试之前会反…

2018秋招C/C++面试题总结

博主从8月中旬开始大大小小面试了十几家公司,至今也许是告一段落吧,希望后面会有好结果,因此总结记录一些C/C方向常见的问题。和大家一起学习! 参考了互联网的各种资源,自己尝试归类整理,谢谢~ 一、C和C的区…

C++面试题总结,一篇就够了

C面试题汇总 1. C基础1.1 内存模型1.1.0 内存四区1.1.1 简述C、C程序编译的内存分配情况1.1.2 分配函数与释放函数1.1.2.1 malloc / free1.1.2.2 new / delete1.1.2.3 new/delete 与 malloc/free 区别1.1.2.5 calloc 、realloc1.1.2.6 在C中,使用malloc申请的内存能…

C面试题--汇总

目录 一、C语言基础面试题1. gcc编译器编译的完整流程,分别有什么作用?2.什么是回调函数?3.地址能否使用 printf函数中的 %u形式打印?4.结构体与共用体(联合体)的区别5. static、const、volatile关键字有什…

C/C++ 最常见50道面试题

C/C经典面试题 面试题 1:变量的声明和定义有什么区别 为变量分配地址和存储空间的称为定义,不分配地址的称为声明。一个变量可以在多个地方声明, 但是只在一个地方定义。加入 extern 修饰的是变量的声明,说明此变量将在文件以外或…

C语言经典面试题学习

1. 请填写bool , float, 指针变量 与“零值”比较的if 语句。 提示:这里“零值”可以是0, 0.0 , FALSE 或者“空指针” 。例如int 变量n 与“零值”比较的if 语句为: if ( n 0 ) if ( n ! 0 ) 以此类推。 (1)请写出bool flag 与“…

C语言面试题目大全

http://blog.chinaunix.net/uid-12077574-id-145080.html 1.求下面函数的返回值(微软) int func(x) { int countx 0; while(x) { countx ; x x&(x-1); } return countx; } 假定x 9999。 答案:8 思路:将x转化为2进制&am…

C语言常见面试题汇总

文章目录 gcc的编译过程&#xff1f;static关键字变量/函数的声明和定义之间有什么区别各种指针指针常量与常量指针“引用”与指针的区别是什么&#xff1f;C语言参数传递方式&#xff1a;结构体的浅拷⻉与深拷⻉#include<> 与#include ""的区别&#xff1f;宏…

c语言打印菱形图案

1.打印空心菱形 #include<stdio.h> int main() {int n,i,m,j,k;scanf("%d", &n);m (n 1) / 2;for (i 1; i < n; i) //一行一行的循环打印{if (i < m) //分两种情况&#xff0c;上半部分和下半部分{for (j m - i; j > 0; j--)pri…

菱形的打印

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 菱形的打印 前言菱形的打印是对于初学者对for循环结构嵌套的考察&#xff0c;学会了菱形的打印基本也就掌握了for循环结构的嵌套&#xff0c;下面让我们一起看看吧~ 一、如何…

打印菱形的两种方法

1.利用字符串数组输出图案 思路&#xff1a; 用字符串数组来输出&#xff0c;第一次循环向这个字符串数组中填 ‘ * ’&#xff0c;i 从中间向左(⬅️)&#xff0c;j 从中间向右(➡️)。 第二次循环填 ‘ ’&#xff0c;i 从左向右(➡️)&#xff0c;j 从右向左(⬅️)。 char s…

JavaScript打印菱形

<!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body><script type"text/javascript">// 请打印出菱形//1 3 5 7 9 7 5 3 1 九行 //1 2 3 4 5 6 7 8 9// 首先我们实现…

打印菱形图案

题目&#xff1a; 打印菱形 题目内容&#xff1a; 用C语言在屏幕上输出以下图案&#xff1a; 思路&#xff1a; 这道题的解决办法有很多&#xff0c;大多都是拆分法&#xff0c;这里捡一种我觉得最方便的方法作以介绍&#xff1a;首先我们需要明白&#xff0c;这种图案形式打…

【C】 打印菱形图案

使用VS2019 ISO C14 标准 (/std:c14) 打印菱形图案 打印出如下图案&#xff08;菱形&#xff09;。 ********* **************** 代码&#xff1a; //打印菱形图案 #include<stdio.h> int main() {//分析&#xff0c;菱形图案由空格和*号组成//声明函数void print(in…

打印菱形图案C语言详解

这是菱形图案 这是完整代码 #include<stdio.h> int main() {while(1)//这一步目的可以打印多次菱形{int i0,j0,k0,t0,n0,x0; scanf("%d",&n); //n的含义是菱形的长对角线的长度,因此n必须是奇数,也可以说是菱形竖着放时的高度x(n1)/2; //这是菱形边长…

打印菱形(两种思路)

一、输入的行数等于上半部分的金字塔行数 思路&#xff1a; 仔细观察图形&#xff0c;可以发现&#xff0c;此图形中是由空格和*按照不同个数的输出组成的。 上三角&#xff1a;先输出空格&#xff0c;后输出*&#xff0c;每行中空格&#xff1a;从上往下&#xff0c;一行减少一…

C语言实现——打印菱形

目录 前言 如何实现 代码实现 定义一个变量line来接收输入的行数 实现上半部分 实现下半部分 代码汇总 前言 输入一个数&#xff0c;打印对应的菱形 该菱形表现为&#xff1a; 从第一行到中间行的行数为输入的数&#xff0c; 从中间行到结束行的行数为输入的数。 如…

c语言经典例题:打印菱形

题目&#xff1a;打印出如下图案&#xff08;菱形&#xff09; 思路&#xff1a; 菱形这个图案很有趣&#xff0c;图案里的*数量&#xff0c;从上到下看&#xff0c;有着独特的规律&#xff0c; 1 &#xff0c;3&#xff0c;5&#xff0c;7&#xff0c;5&#xff0c;3&#xf…

【C语言】打印菱形详解

打印菱形 写法一&#xff1a;下半部分的循环用i的方法打印 #include <stdio.h> int main() {int line 0;int i 0;int j 0;printf("请输入你要打印的行数\n");scanf("%d", &line);//先打印上部分的三角形for (i 1; i < line; i) //打印上…