【设计数据密集型应用】复制

news2024/10/23 20:17:00
  • 👏作者简介:大家好,我是爱敲代码的小黄,阿里淘天Java开发工程师,CSDN博客专家
  • 📕系列专栏:Spring源码、Netty源码、Kafka源码、JUC源码、dubbo源码系列
  • 🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
  • 🍂博主正在努力完成2023计划中:以梦为马,扬帆起航,2023追梦人
  • 📝联系方式:smallyellow521,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬👀

文章目录

  • 复制
    • 领导者与追随者
    • 同步复制与异步复制
    • 如何设置新从库
    • 处理节点宕机
      • 从库失效:追赶恢复
      • 主库失效:故障切换
    • 复制日志的实现
      • 基于语句的复制
      • 逻辑日志复制(基于行)
      • 基于触发器的复制
  • 复制延迟问题
      • 读已之写
      • 单调读
      • 一致前缀读
      • 多主复制
        • 运维多个数据中心
        • 需要离线操作的客户端
        • 协同编辑
      • 处理写入冲突
        • 同步与异步冲突检测
        • 避免冲突
        • 收敛至一致的状态
      • 多主复制拓扑
    • 无主复制
      • 节点故障
        • 读修复和反熵
  • 总结

与可能出错的东西比,“不可能”出错的东西最显著的特点就是:一旦真的出错,通常就彻底玩完了。

—— 道格拉斯・亚当斯(1992)

复制

简介:通过网络连接的多台机器上保留相同数据的副本。

原因:降低延时、可用性、吞吐量

  • 数据存放地与用户接近,减少网络请求延时
  • 避免单机故障,提升可用性
  • 机器数量可伸缩,提升读取吞吐量

困难:

  • 如果复制的数据不随时间而改变,复制将变的非常简单
  • 但复制的过程中,数据经常是变更的

解决:

在分布式场景下,一般使用三种变更复制算法:

  • 单领导者
  • 多领导者
  • 无领导者

领导者与追随者

副本:存储数据库拷贝的每个节点

问题:当存在多个副本时,如何确保所有数据都落在了所有的副本上?

解决方案:基于领导者的复制

原理:

image-20240219231709711

  • 我们将其中一个副本指定为 领导者(主库)
    • 当客户端想要写入数据时,必须将请求发送给领导者(主库)
    • 它将数据写入到本地存储
  • 其他副本成为追随者(只读副本)
    • 每当领导者将新数据写入本地存储时,它也会将数据变更发送给所有的追随者,称为复制日志。
    • 每个追随者从领导者拉取日志,并更新本地数据库副本,按照领导者相同的处理顺序来进行写入
  • 当客户想要从数据库查询数据
    • 领导者和任一追随者都可以查询
    • 只有领导者可以写入数据

同步复制与异步复制

image-20240219233053467

  • Follower 1:同步复制
    • 好处:保持与主库强一致的最新数据
    • 坏处:从库挂掉,主库也无法写入数据
  • Follower 2:异步复制
    • 好处:从库挂掉,主库也能写入数据
    • 坏处:无法保持与主库强一致的最新数据

目前业界常用方式:半同步

  • 在数据库中开启同步复制,其中一个从库是同步的,其余所有的从库均是异步的
  • 如果该从库不可用,则将另外一个异步从库改为同步复制

通常情况下,基于领导者的复制都配置成完全异步,一旦主库失效不可恢复,复制给从库的数据也将丢失。

即使已经向客户端确定成功,写入也不能保证是持久的。

当然也有优点:即使所有的从库都落后了,主库也可以正常写入。

如何设置新从库

原因:

  • 增加从库副本数量
  • 替换失败的节点

过程:

  • 在某个时刻获取主库的一致性快照
  • 将快照复制到新的从库节点
  • 从库链接主库并拉取快照后的所有数据变更
  • 等从库处理完快照之后的数据变更,从库就赶上了主库

复制过程可参考:RedisMySQL

处理节点宕机

系统中的任何节点都可能宕机,即使个别节点生效,也能保持整个系统的运行并尽可能控制节点停机带来的影响

从库失效:追赶恢复

在本地磁盘中,从库记录从主库收到的数据变更。

如果从库崩溃并重新启动或者网络中断等原因,从本地日志中获取最后一个事务

连接到主库,请求在从库断开期间发生的所有数据变更,当解决完这些变更之后,就赶上了主库,正常接受数据变更流。

主库失效:故障切换

故障切换:将其中一个从库提升为新的主库,重新配置客户端,将他们的写操作发送给新的主库,其他从库需要开始拉取来自新主库的数据变更。

过程:

  • 确定主库失效(心跳检测)
  • 选择一个新的主库(选举机制)
  • 重新配置系统以启动新的主库

问题:

  • 异步复制,新主库的数据落后老主库。解决方式:丢掉老主库中未复制的写入

  • 数据库与外部存储协调,丢弃写入内容极其危险

    例如在 GitHub 的一场事故中,一个过时的 MySQL 从库被提升为主库

    数据库使用自增 ID 作为主键,因为新主库的计数器落后于老主库的计数器,所以新主库重新分配了一些已经被老主库分配掉的 ID 作为主键

    这些主键也在 Redis 中使用,主键重用使得 MySQL 和 Redis 中的数据产生不一致,最后导致一些私有数据泄漏到错误的用户手中。

  • 脑裂,两个节点都误认为自己是主库

  • 超时时间的配置,如何正确的配置主库失效的超时时间

复制日志的实现

基于语句的复制

主库记录每个写入请求并将该语句发送给从库

问题:

  • 任何调用 非确定下函数 的语句,在每个副本生成不同的值。
    • NOW():获取当前时间
    • RAND():获取一个随机数
  • 语句必须按照顺序执行,避免并发问题
    • UPDATE … WHERE <某些条件>,必须现有某些条件数据,再进行 UPDATE

### 传输预写式日志(WAL)

存储引擎通常会将写操作追加到日志中

mysql 通过 redo、undo 日志实现 WAL。

redo log 称为重做日志,每当有操作时,在数据变更之前将操作写入 redo log,这样当发生掉电之类的情况时系统可以在重启后继续操作。

undo log 称为撤销日志,当一些变更执行到一半无法完成时,可以根据撤销日志恢复到变更之间的状态。

mysql 中用 redo log 来在系统 Crash 重启之类的情况时修复数据(事务的持久性),而 undo log 来保证事务的原子性。

缺点:由于日志记录的非常底层(WAL包含哪些磁盘块中的哪些字节发生了变化),当从库和主库运行不同版本时,会出现数据解析问题。

逻辑日志复制(基于行)

复制和存储引擎使用不同的日志格式,将复制日志从存储引擎的内部实现中解耦出来,这种复制日志被称为逻辑日志。

例如:MySQLBinlog

  • 插入行:日志包含所有列的新值
  • 删除行:日志包含主键
  • 更新行:日志包含主键及更新列的新值

优点:逻辑日志和存储引擎内部实现解耦,系统可以做到兼容。从而使主库和从库可以运行不同版本的数据库软件。

基于触发器的复制

将数据更改发生时的自定义代码记录在数据库系统中,使用外部程序读取该表,进行响应的复制。

复制延迟问题

当前存在一个主库,多个从库,在数据复制的过程中,如果从库落后于主库,我们会看到过时的信息。

对主库和从库执行相同的查询,得到不同的结果,等后续一段时间后,从库追上主库保持一致,被称为 最终一致性

读已之写

image-20240220234051681

用户在界面提交一些数据,将其写入到主库,主库异步复制给从库,从而从库追赶上主库。

但如果用户在提交完数据后,立即查询(从库),会发现自己提交的数据库丢失不见

这种情况下,我们需要 写后读一致性,也称为 读己之写一致性,我们需要保证:如果用户重新加载页面,他们总会看到他们自己提交的任何更新

解决方法:

  • 对于用户可能修改的内容,总是从主库获取
    • 用户个人资料只能本人编辑,而不能其他人编辑
    • 从主库读取自己的档案,其他用户档案去从库读取
  • 跟踪上次更新的时间,在数据更新的一分钟内,从主库读取
  • 监控从库的复制延迟,滞后主库超过一分钟的从库不接受查询请求

单调读

image-20240220235435088

当前从库 2 落后从库 1如果用户从不同从库读取

  • 先读取的从库 1,拿到了最新数据
  • 后续读取从库 2,拿到了旧数据

从用户体验来看,时间看上去好像回退了,所以我们需要单调的读取。

单调读 可以保证这种异常不会发生,其程度比 强一致性 弱,比 最终一致性 更强。

实现方式:每个用户总是从一个副本中进行读取(不同客户可以从不同副本读取)。可以基于用户 ID Hash 来选择副本,而不是随机选择读取的数据库副本。

一致前缀读

如果我们有两个因果关系的数据:

Mr. Poons

​ Mrs. Cake,你能看到多远的未来?

Mrs. Cake

​ 通常约十秒钟,Mr. Poons.

假如:

  • Cake 说的话是一个延迟较低的从库
  • Poons 说的话是一个延迟较高的从库

当第三个人在读取数据时,会出现这种情况:

Mrs. Cake

​ 通常约十秒钟,Mr. Poons.

Mr. Poons

​ Mrs. Cake,你能看到多远的未来?

如果某些分区的复制速度慢于其他分区,那么观察者可能会在看到问题之前先看到答案。

需要保证一致前缀读:如果一系列写入按照某个顺序进行,那么任何人读取这些写入时,也看以同样的顺序读取。

解决方案:确保任何因果相关的写入都写入到相同的分区

多主复制

如果数据库被分区,每个分区有一个主库。

多领导配置:处理写入的每个节点都必须将该数据变更转发给其他节点

在这种情况下,每个主库同时是其他主库的从库。

### 多主复制的应用场景

运维多个数据中心

image-20240222000840409

多主配置中在每个数据中心都有主库,每个数据中心内使用常规的主从复制;

在数据中心之间,每个数据中心的主库会将自身变更同步到其他主库。

单主和多主对比:

  • 性能
    • 单主:每个写入操作必须穿过互联网,进入主库所在的数据中心,网络延时较大
    • 多主:每个写入操作在本地数据中心进行处理,与其他数据中心异步复制,网络延时较小
  • 容忍数据中心停机
    • 单主:主库所在的数据中心发生故障,切换另一从库成为主库
    • 多主:数据中心可以独立于其他数据中心继续运行

多主复制的缺点:多主复制在数据库属于改装的功能,常常存在微妙的配置缺陷。因此,多主复制被认为是危险的领域,应尽可能避免。

需要离线操作的客户端

多主复制的另一种适用场景是:应用程序在断网之后仍然需要继续工作。比如:日历应用

在这种情况下,每个设备都有一个充当主库的本地数据库,在所有的设备的日志副本之间同步。

协同编辑

实时协作编辑应用程序允许多个人同时编辑文档

当一个用户编辑文档时,所做的更改将立即应用到其本地副本并异步复制到服务器。

如果不发生编辑冲突,则应用程序必须对文档加锁,为了加速协作,尽可能将加锁的单位设置的非常小。

处理写入冲突

多主复制最大的问题:写入冲突

image-20240222002907115

假如两个人同时更改一个页面

  • 用户 1 将页面标题从 A 更改为 B
  • 用户 2 将页面标题从 A 更改为 C

当异步复制时,就会出现冲突。

同步与异步冲突检测

如果在单主数据库中,两个操作是串行的,不会发生冲突

但多主数据库中,两个分别写入不同的主库,后续异步复制,必然出现冲突问题

避免冲突

处理冲突的最简单的策略就是避免它们:如果应用程序可以确保特定记录的所有写入都通过同一个主库,那么冲突就不会发生。

例如:一个用户编辑自己数据的应用程序,确保来自特定用户的请求始终路由到同一数据中心并使用该数据中心的主库进行读写。

收敛至一致的状态

我们上述的例子中,在多个主库的情况下,我们的写入顺序是不确定的

数据库必须以一种收敛的方式解决冲突,所有副本必须在变更复制完成时收敛到一个相同的最终值。

解决方案:

  • 给每个写入分配唯一ID(时间戳、长随机数、UUID),挑选最高 ID 的写入作为胜利者
  • 给每个副本分配唯一ID,ID更高的写入具有更高的优先级
  • 将这些值链接在一起,比如:B/C
  • 将冲突显式的暴露出来,交于用户决定,比如:GIT冲突

多主复制拓扑

复制拓扑用来描述写入操作从一个节点传播到另一个节点的通信路径。

image-20240222004135809

无主复制

客户端直接写入几个副本中,另一种情况,由一个 协调者 代表客户端写入。

节点故障

无主配置中,发生节点故障,不需要故障转移

如果有三个副本,两个副本写入成功,一个副本写入失败

image-20240222005455126

当我们不可用的副本重新上线,存的是落后的数据

解决方案:当一个客户端从数据库中读取数据时,它不仅仅把它的请求发送到一个副本,而是将读请求将被并行地发送到多个节点,通过版本号来确定哪个值是最近更新的。

读修复和反熵

复制方案应确保最终将所有数据复制到每个副本。在一个不可用的节点重新联机之后,它如何赶上它错过的写入?

  • 读修复:当客户端并行读取多个节点时,检测落后节点的回应,并将最新值写会落后节点。适用于频繁读取的值
  • 反熵过程:数据存储具有后台进程,进程不断查找副本之间的数据差并进行相关的复制追齐。

总结

鲁迅先生曾说:独行难,众行易,和志同道合的人一起进步。彼此毫无保留的分享经验,才是对抗互联网寒冬的最佳选择。

其实很多时候,并不是我们不够努力,很可能就是自己努力的方向不对,如果有一个人能稍微指点你一下,你真的可能会少走几年弯路。

如果你也对 后端架构中间件源码 有兴趣,欢迎添加博主微信:smallyellow521,一起学习,一起成长

我是爱敲代码的小黄,阿里巴巴淘天集团Java开发工程师,双非二本,培训班出身

通过两年努力,成功拿下阿里、百度、美团、滴滴等大厂,想通过自己的事迹告诉大家,努力是会有收获的!

双非本两年经验,我是如何拿下阿里、百度、美团、滴滴、快手、拼多多等大厂offer的?

我们下期再见。

从清晨走过,也拥抱夜晚的星辰,人生没有捷径,你我皆平凡,你好,陌生人,一起共勉。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1498169.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nginx 使用记录

使用&#xff1a; 去官网下载指定版本1.24.0&#xff0c;直接将压缩包解压到指定目录&#xff0c;打开cmd即可启动 启动服务器&#xff1a; 方法一&#xff1a;打开cmd命令窗口&#xff0c;切换到nginx解压目录下&#xff0c;输入命令start nginx &#xff0c;回车即可&…

数据结构:AVL树

目录 1、AVL树的概念 2、二叉搜索树的功能与实现 1、AVL树节点定义 2、AVL树的插入 3、AVL树的旋转操作 1、左旋 2、右旋 3、左右旋 4、右左旋 3、AVL树完整代码实现 1、AVL树的概念 在前面的文章中&#xff0c;我们学过了二叉搜索树&#xff0c;二叉搜索树虽可以缩短查…

智能控制:物联网智能插座对接文档

介绍 一开始买的某米的插座&#xff0c;但是好像接口不开放&#xff0c;所以找到了这个插座&#xff0c;然后自己开发了下&#xff0c;用接口控制插座开关。wifi的连接方式&#xff0c;通电后一般几秒后就会连接上wifi&#xff0c;这个时候通过接口发送命令给他。 产品图片 通…

cesium-天际线

主要是两个着色器 let postProccessStage new Cesium.PostProcessStage({//unform着色器对象 textureScalefragmentShader:// 声明一个纹理采样器 colorTexture 用于读取纹理颜色uniform sampler2D colorTexture; // 声明一个纹理采样器 depthTexture 用于读取深度纹理unifor…

windows安装程序无法将windows配置为此计算机

目录 问题描述 问题原因 解决办法 方法一 方法二 方法三&#xff1a; 问题描述 重装系统时显示windows安装程序无法将windows配置在此计算机硬件上. 问题原因 安装介质已损坏 如果可引导的安装介质&#xff08;如DVD或USB驱动器&#xff09;损坏或损坏&#xff0c;安装过…

XXE-XML实体注入漏洞

目录 1.xml基础 1.1什么是xml 1.2xml文档结构 1.3 什么是DTD 1.4 什么是实体 1.5 什么是外部实体 2.xxe漏洞 2.1xxe漏洞基本介绍 2.2xxe漏洞的危害 经典漏洞案例分析 3.xxe漏洞挖掘和利用 3.1. 识别潜在的XML入口 3.2. 检查XML处理逻辑 3.3. 构造试探Payload 常…

CVE-2024-25600 WordPress Bricks Builder RCE-漏洞分析研究

本次代码审计项目为PHP语言&#xff0c;我将继续以漏洞挖掘者的视角来分析漏洞的产生&#xff0c;调用与利用..... 前方高能&#xff0c;小伙伴们要真正仔细看咯..... 漏洞简介 CVE-2024-25600 是一个严重的&#xff08;CVSS 评分 9.8&#xff09;远程代码执行 (RCE) 漏洞&am…

软件设计师13--进程调度

软件设计师13--进程调度 考点1&#xff1a;PV操作的概念进程的同步与互斥PV操作例题&#xff1a; 考点2&#xff1a;信号量与PV操作进程管理 - PV操作与互斥模型进程管理 - PV操作与同步模型进程管理 - 互斥与同步模型结合例题&#xff1a; 考点3&#xff1a;前趋图与PV操作进程…

爬虫(四)

1.图片验证码 import requestsres requests.get(https://www.gushiwen.cn/RandCode.ashx)with open("code.png", "wb") as f:f.write(res.content)2.打码平台 网址&#xff1a;http://www.ttshitu.com/&#xff0c;找到开发文档点击Python,没有钱了要用我…

如何在Linux中安装ARM交叉环境编译链

安装ARM交叉环境编译链过程如下&#xff1a; 首先创建一个文件夹如下&#xff1a; mkdir -p Linux_ALPHA/toolcahin然后将arm交叉编译工具链安装包拖到Linux中如下&#xff1a; 先输入mv 拖入的安装包即可 mv /var/run/vmblock-fuse/blockdir/pXeysK/gcc-4.6.4.tar.xz .直接…

-bash: unzip: 未找到命令的解决方案

遇到 -bash: unzip: 未找到命令 这样的错误信息&#xff0c;表示你的系统中没有安装 unzip 工具。unzip 是一个常用的解压工具&#xff0c;用于解压缩 .zip 文件。你可以通过系统的包管理器安装它。 根据你使用的 Linux 发行版&#xff0c;安装 unzip 的命令会有所不同。下面是…

动态内存管理-c语言

目录 1.为什么要有动态内存分配 2.malloc函数和free函数 malloc 函数原型 栗子 free 函数原型 栗子 3.calloc和***realloc*** 3.1calloc函数 原型如下&#xff1a; 栗子 3.2***recalloc*** 第一种情况 第二种情况 第三种情况 recalloc模拟实现calloc函数 4.六…

基于springboot+vue的球队训练信息管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

“揭秘网络握手与挥别:TCP三次握手和四次挥手全解析“

前言 在计算机网络中&#xff0c;TCP&#xff08;传输控制协议&#xff09;是一种重要的通信协议&#xff0c;用于在网络中的两台计算机之间建立可靠的连接并交换数据。TCP协议通过“三次握手”和“四次挥手”的过程来建立和终止连接&#xff0c;确保数据的准确传输。 一、三…

2024年腾讯云优惠政策_腾讯云服务器特价购买活动入口

腾讯云优惠活动2024新春采购节活动上线&#xff0c;云服务器价格已经出来了&#xff0c;云服务器61元一年起&#xff0c;配置和价格基本上和上个月没什么变化&#xff0c;但是新增了8888元代金券和会员续费优惠&#xff0c;腾讯云百科txybk.com整理腾讯云最新优惠活动云服务器配…

数据结构(八)——初识单链表

&#x1f600;前言 单链表是数据结构中最基本的一种链表结构&#xff0c;它由一系列节点组成&#xff0c;每个节点包含数据和指向下一个节点的指针。单链表具有灵活性和动态性&#xff0c;可以根据需要插入、删除和查找元素&#xff0c;适用于各种场景和问题的解决。 在本篇文章…

网络编程 · 代码笔记1

目录 前言1、编程环境2、编译命令3、标题名前缀解释4、注意事项 0011客户端读取服务端字符_服务端0012客户端读取服务端字符_客户端0021回声测试_服务端0022回声测试_客户端0030启动端口复用解决端口绑定失败问题0041服务器不间断进行侦听通信_服务端0042服务器不间断进行侦听通…

liunx操作系统 环境变量

环境变量 main函数参数 命令行参数环境变量 环境变量的查看环境变量的获取 main函数参数 命令行参数 main函数是有参数的&#xff0c;只是我们一般不适用 这是main函数从bash中读取进程数据使用的一个基本入口。 下面进行简单演示。 o 好oo都是我们输入的命令行参数。其实&a…

如何查看前端的vue项目是vue2还是vue3项目

1. 检查package.json文件 在项目的根目录下&#xff0c;打开package.json文件&#xff0c;查找dependencies或devDependencies部分中的vue条目。版本号将告诉你是Vue 2还是Vue 3。例如&#xff1a; Vue 2.x: "vue": "^2.x.x"Vue 3.x: "vue": &…

【Linux基础(二)】进程管理

学习分享 1、程序和进程1.1、程序1.2、进程和进程ID 2、Linux下的进程结构3、init进程4、获取进程标识5、fork系统调用5.1、fork函数实例分析 6、进程的特性7、在Linux下进程指令7.1、终止进程指令7.2、查看进程指令&#xff1a;7.3、以树状图列出进程 8、多进程运行异常情况8.…