分布式事务的21种武器 - 7

news2024/11/25 6:56:33

在分布式系统中,事务的处理分布在不同组件、服务中,因此分布式事务的ACID保障面临着一些特殊难点。本系列文章介绍了21种分布式事务设计模式,并分析其实现原理和优缺点,在面对具体分布式事务问题时,可以选择合适的模式进行处理。原文: Exploring Solutions for Distributed Transactions (7)

Duncan Meyer @Unsplash
Duncan Meyer @Unsplash

在不同业务场景下,可以有不同的解决方案,常见方法有:

  1. 阻塞重试(Blocking Retry)
  2. 二阶段和三阶段提交(Two-Phase Commit (2PC) and Three-Phase Commit (3PC))
  3. 基于后台队列的异步处理(Using Queues to Process Asynchronously in the Background)
  4. TCC补偿(TCC Compensation Matters)
  5. 本地消息表(异步保证)/发件箱模式(Local Message Table (Asynchronously Ensured)/Outbox Pattern)
  6. MQ事务(MQ Transaction)
  7. Saga模式(Saga Pattern)
  8. 事件驱动(Event Sourcing)
  9. 命令查询职责分离(Command Query Responsibility Segregation, CQRS)
  10. 原子提交(Atomic Commitment)
  11. 并行提交(Parallel Commits)
  12. 事务复制(Transactional Replication)
  13. 一致性算法(Consensus Algorithms)
  14. 时间戳排序(Timestamp Ordering)
  15. 乐观并发控制(Optimistic Concurrency Control)
  16. 拜占庭容错(Byzantine Fault Tolerance, BFT)
  17. 分布式锁(Distributed Locking)
  18. 分片(Sharding)
  19. 多版本并发控制(Multi-Version Concurrency Control, MVCC)
  20. 分布式快照(Distributed Snapshots)
  21. 主从复制(Leader-Follower Replication)

本文将介绍MVCC、分布式快照以及主从复制三种模式。

19. 多版本并发控制(Multi-Version Concurrency Control, MVCC)
图片来源: https://vladmihalcea.com/how-does-mvcc-multi-version-concurrency-control-work
图片来源: https://vladmihalcea.com/how-does-mvcc-multi-version-concurrency-control-work
  • 允许多个事务并发访问相同的数据,而不会相互干扰。
  • 创建同一数据对象的多个版本,并允许事务同时访问不同的版本。通过这种方式,事务可以在非阻塞的情况下读取数据,并且可以在不产生冲突或不一致的情况下执行写操作。
  • 涉及如下步骤:
    1. 当事务想要读写数据时,首先检查系统事务表,以确定是否可以进行。如果事务可以继续,则为其分配唯一的事务ID。
    2. 当事务写入数据对象时,创建该对象的新版本,并且事务ID与该版本相关联,新版本被添加到系统版本表中。
    3. 当事务读取数据对象时,会在版本表中搜索该对象在事务开始之前创建的最新版本,并从对象的那个版本读取数据。
    4. 数据对象的每个版本都与事务ID、开始时间和结束时间相关联。开始时间为版本创建的时间,结束时间为版本被更新版本取代的时间。
    5. 当事务提交时,结束时间被记录在事务表中。与该事务关联的所有版本的数据对象都被标记为已提交,并且结束时间设置为事务的结束时间。
    6. 事务终止时,其结束时间记录在事务表中。与该事务关联的所有版本的数据对象都被标记为终止,并且结束时间设置为事务的结束时间。
    7. 当新的事务开始时,只能访问在它开始时间之前已经提交的数据对象,确保事务只读取一致的数据。
import sqlite3
import time

# Connect to the database
conn = sqlite3.connect('example.db')

# Create a table for testing MVCC
conn.execute('''CREATE TABLE test (
                 id INTEGER PRIMARY KEY,
                 name TEXT,
                 value INTEGER,
                 version INTEGER
                 )'''
)

# Insert some initial data
conn.execute("INSERT INTO test (name, value, version) VALUES ('foo', 42, 1)")

# Start a transaction
tx = conn.begin()

# Read the current value of 'foo'
cursor = tx.execute("SELECT value, version FROM test WHERE name = 'foo'")
value, version = cursor.fetchone()

# Increment the value of 'foo'
new_value = value + 1

# Insert a new version of the data
new_version = version + 1
tx.execute("INSERT INTO test (name, value, version) VALUES ('foo', ?, ?)", (new_value, new_version))

# Update the version of the original data
tx.execute("UPDATE test SET version = ? WHERE name = 'foo' AND version = ?", (new_version, version))

# Commit the transaction
tx.commit()

# Print the final value of 'foo'
cursor = conn.execute("SELECT value FROM test WHERE name = 'foo'")
value = cursor.fetchone()[0]
print(f"Final value of 'foo': {value}")

# Close the database connection
conn.close()

示例代码

  • 事务可以根据自己的时间戳读取适当版本的数据,而不会影响其他事务。
  • 涉及如下步骤:
    1. 连接数据库SQLite3
    2. 创建测试MVCC的表
    3. 插入初始数据
    4. 启动事务
    5. 读取'foo'的当前值
    6. 将'foo'的值+1
    7. 插入版本号更高的数据新版本
    8. 更新原始数据版本号,使其与新版本相匹配
    9. 提交事务
    10. 输出'foo'的最终值
    11. 关闭数据库连接

优点

  • 允许多个事务同时读写数据
  • 避免使用锁
  • 维护数据的多个版本
  • 在事务之间提供高度隔离

缺点

  • 增加了数据库设计的复杂性
  • 由于需要存储多版本数据,增加了存储开销
  • 由于需要扫描多版本数据,增加了查询执行时间

适用场景

  • 具有高读写比率,并且大多数是只读事务的应用
  • 需要同时执行许多事务
  • 需要高并发性和一致性的联机事务处理(OLTP)系统
  • 事务需要高度隔离的应用,例如金融应用程序

20. 分布式快照(Distributed Snapshots)
图片来源: https://www.semanticscholar.org/paper/Distributed-snapshots%3A-determining-global-states-of-Chandy-Lamport/31814c386a31d27524a086f1f074c015bce08a2b
图片来源: https://www.semanticscholar.org/paper/Distributed-snapshots%3A-determining-global-states-of-Chandy-Lamport/31814c386a31d27524a086f1f074c015bce08a2b
  • 记录分布式系统在特定时间点的状态
  • 可用于多种应用,如分布式数据库、分布式文件系统和分布式消息代理。
  • 涉及如下步骤:
    1. 选择启动快照的进程。该进程向系统中其他进程发送标记消息,当进程接收到标记消息时,获取其当前状态的快照,并将消息发送给相邻进程。
    2. 当进程接收到标记消息时,记录其本地状态,包括进程状态及其通信通道。
    3. 进程记录本地状态后,将标记消息发送给相邻进程,相邻进程启动快照进程。
    4. 进程等待来自相邻进程的所有标记消息完成快照。
    5. 进程接收到所有标记消息后,记录所有用于与其他进程通信的通道状态。
    6. 一旦进程记录了所有通道的状态,就向发起快照的进程发送确认消息。
    7. 发起快照的进程收到所有进程的确认消息后,结合本地状态和通道状态信息,构建分布式系统的快照。
from multiprocessing import Process, Queue

class ProcessNode(Process):
    def __init__(self, pid, processes, markers):
        super().__init__()
        self.pid = pid
        self.processes = processes
        self.markers = markers
        self.state = 0

    def send_message(self, dest):
        self.processes[dest].queue.put(self.pid)

    def run(self):
        while True:
            if not self.queue.empty():
                message = self.queue.get()
                if message == 'marker':
                    self.markers[self.pid] = True
                    for i in range(len(self.processes)):
                        if i != self.pid:
                            self.send_message(i)
                else:
                    self.state += message
                    for i in range(len(self.markers)):
                        if self.markers[i]:
                            self.send_message(i)
                            self.markers[i] = False
            else:
                # do some work
                self.state += 1

示例代码

  • Chandy-Lamport算法是一种常用的分布式快照算法。
图片来源: https://decomposition.al/blog/2019/04/26/an-example-run-of-the-chandy-lamport-snapshot-algorithm
图片来源: https://decomposition.al/blog/2019/04/26/an-example-run-of-the-chandy-lamport-snapshot-algorithm
  • ProcessNode类 —— 扩展 multiprocessing.Process
    • 每个 ProcessNode实例代表分布式系统中的一个进程。
    • send_message方法 —— 将消息发送到另一个进程
    • run方法 —— 定义进程的主逻辑
    • 如果接收到 marker消息,则进程将标记设置为 True,并向所有其他进程发送 marker消息,开始记录其状态。
    • 如果接收到非 marker消息,则该进程将该消息添加到其状态,并向所有设置了标记的其他进程发送 marker消息。
    • 如果队列中没有消息,则进程执行自己的工作并改变其状态。
    • 每个进程获取其本地状态的快照,并向其他进程发送消息以获取一致的全局状态。

优点

  • 实现跨多个节点的数据一致性
  • 实现容错机制,并能从故障中恢复

缺点

  • 实现复杂
  • 引入额外的网络流量和开销
  • 难以调试和诊断问题
  • 要求修改现有系统

适用场景

  • 要求跨多个节点实现数据一致性的金融系统
  • 需要跨多个节点实现数据一致性的库存管理和订单跟踪系统
  • 需要容错性和一致性的可靠消息传递

21. 主从复制(Leader-Follower Replication)
  • 在分布式系统中复制数据
  • 一个节点充当领导者,其他节点充当追随者
  • 领导者节点 —— 更新数据
  • 跟随者节点 —— 复制领导者节点所做的更改
  • 涉及如下步骤:
    1. 领导者节点收到客户端的写请求
    2. 领导者节点更新其本地数据副本,并将更新发送给所有追随者节点
    3. 跟随者节点将更新应用到自己的本地数据副本
    4. 领导者节点向客户端发送写操作成功的确认信息
    5. 如果跟随者节点出现故障,领导者节点将更新信息发送给替代节点,以确保替代节点拥有最新的数据副本
    6. 客户端想要读取数据时,可以向领导者节点或任何跟随者节点请求数据。如果从跟随者节点请求数据,则跟随者节点需要检查是否拥有最新的数据副本。如果没有,则从领导者节点请求数据。
import threading
import time

class LeaderFollowerReplication:
    def __init__(self, data):
        self.data = data
        self.leader_lock = threading.Lock()
        self.follower_lock = threading.Lock()
        self.leader = None
        self.follower = None

    def start_leader(self):
        while True:
            self.leader_lock.acquire()
            self.follower_lock.acquire()
            self.follower = self.data
            time.sleep(0.5)
            self.leader = self.data
            self.follower_lock.release()
            self.leader_lock.release()

    def start_follower(self):
        while True:
            self.follower_lock.acquire()
            if self.follower != self.data:
                self.data = self.follower
            self.follower_lock.release()
            time.sleep(1)

if __name__ == "__main__":
    lfr = LeaderFollowerReplication("original_data")
    leader_thread = threading.Thread(target=lfr.start_leader)
    follower_thread = threading.Thread(target=lfr.start_follower)

    leader_thread.start()
    follower_thread.start()

    leader_thread.join()
    follower_thread.join()

示例代码

  • LeaderFollowerReplication类 —— 存储要复制的数据并管理锁机制
    • 这个类有两个锁, leader_lockfollower_lock,以确保两个线程中一次只有一个可以访问数据。
    • start_leader方法 —— 运行领导者线程,首先获取 leader_lockfollower_lock,以确保跟随者线程没有修改数据。然后将数据设置为与跟随者的数据相等,并在将数据设置为与自己的数据相等之前休眠0.5秒,最后释放锁。
    • start_follower方法 —— 运行跟随者线程,获取 follower_lock并检查跟随者的数据是否与当前数据不同。如果是,将数据设置为等于跟随者的数据,然后释放 follower_lock并休眠1秒。
  • 创建 LeaderFollowerReplication实例,初始数据值为"original_data"。然后创建两个线程,一个用于领导者,一个用于跟随者。

优点

  • 即使跟随者节点出现故障,领导者节点也可以继续处理写请求并保持数据的一致性
  • 随着跟随者节点数量的增加,系统可以在不影响领导者节点性能的情况下处理大量读请求
  • 确保所有节点都有一致的数据副本

缺点

  • 如果领导者节点故障,系统将无法处理写请求,直到选出新的领导者节点
  • 因为每次更新都必须广播到所有跟随者节点,因此会产生更多网络流量

适用场景

  • 需要在多个地点保持一致库存的电子商务网站
  • 需要在多个分支机构之间保持账户余额一致的金融机构
  • 需要在多个服务器上保持用户资料一致的社交媒体平台

挑战

  • 很难确保所有节点在任何时候都有相同的数据副本
  • 如果领导者节点必须处理大量写请求,那么有可能成为瓶颈
  • 系统必须能够检测并从节点故障中恢复,以保持数据一致性

参考文献

How does MVCC (Multi-Version Concurrency Control) work

What is MVCC? How multi-version concurrency control works

Chapter 13. Concurrency Control

Multiversion Concurrency Control (MVCC)

Setting Multi-Version Concurrency Control (MVCC)

Open Source Database (RDBMS) for the Enterprise

Distributed Snapshots

Distributed Snapshots

Distributed Snapshot Problem - Distributed Systems for Practitioners

Distributed Snapshots

Reading Group. Distributed Snapshots: Determining Global States of Distributed Systems

Distributed snapshots for YSQL

An example run of the Chandy-Lamport snapshot algorithm

DB Replication (I): Introduction to database replication

Chapter 5. Replication - Shichao's Notes

Leader and Followers

Understanding Database Replication

Leaders and Followers

Multi-master vs leader-follower

Data Replication - Grokking Modern System Design Interview for Engineers & Managers

Build software better, together


你好,我是俞凡,在Motorola做过研发,现在在Mavenir做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。微信公众号:DeepNoMind

- END -

本文由 mdnice 多平台发布

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

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

相关文章

Rocketmq学习之路(一)从生产上的问题引出MQ

前言: 从来没有真正弄明白mq是什么,只知道他有消峰,异步,解耦的作用。但是在日常开发工作中,就是简单的生产者发送消息,消费者接受消息。所以,从今天开始。我要吃掉这个技术。 一.这该死的订单…

word解决文字与公式mathtype不对齐

修改字体和段落里面的这两个。

每日学术速递5.23

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CL 1.Tree of Thoughts: Deliberate Problem Solving with Large Language Models 标题:思想树:用大型语言模型有意识地解决问题 作者:Shunyu Yao, …

每日学术速递5.24

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Reprompting: Automated Chain-of-Thought Prompt Inference Through Gibbs Sampling 标题:重新提示:通过 Gibbs 采样的自动思维链提示推理 作者&#xff1…

《java核心卷Ⅰ》读书笔记

🛫 JDK和JRE傻傻分不清?🛫 HelloWorld的输出都经历了啥?🛫 Java的三个版本都是啥?🛫 关于main方法你都知道啥?main方法被声明为private会怎样?🛫 强制and自动类型转换都…

数据结构基础内容-----第四章 栈与队列

文章目录 栈栈的定义站的抽象数据类型两栈共享空间栈的作用递归的定义 栈运算 队列循环队列队列链式存储结构及实现 栈 栈的定义 栈(Stack)是计算机科学中的一种抽象数据类型,它是一个只能在一端进行插入和删除操作的线性数据结构。栈按照后…

tomcat what

tomcat是什么 对于tomcat是什么有什么作用。曾经看到一个大神是这样解释tomcat的,现在分享给大家 内容大体是: 我家有一台机器,可以把石头变成金子。你快递给我一箱石头,让我把它们变成一箱金子再快递给你。 这个机器就是web项…

【Python从入门到进阶】21、爬虫相关概念介绍

接上篇《20、HTML页面结构的介绍》 上一篇我们正式进入了Python爬虫的实战教程,主要讲解了要爬取的HTML页面的结构。本篇我们来介绍爬虫的相关概念。 一、什么是互联网爬虫 如果我们把互联网比作一张大的蜘蛛网,那一台计算机上的数据便是蜘蛛网上的一个…

如何自己搭建chatgpt镜像网站

前沿 总所周知,访问以及注册chatgpt都是比较困难的,如何能畅游chatgpt而不受魔法的限制呢?还好openai给出了非常不错的api能使我们快速搭建一个镜像网站 准备工作 首先得准备一台服务器 这里推荐使用海外vps来进行搭建,缺点就是…

java基础入门-16-【阶段项目(综合练习doudizhu游戏)】

Java基础入门-16-【阶段项目(综合练习&doudizhu游戏)】 25、阶段项目(综合练习&doudizhu游戏)斗地主小游戏斗地主游戏1(控制台版)步骤一:准备牌步骤二:洗牌步骤三:发牌步骤四:看牌步骤五:给牌进行排序(两种方式排序)方式一:利用序号进行排序方式二:给每一…

阻焊设计~焊盘阻焊开窗、阻焊桥

阻焊设计 焊盘阻焊开窗 阻焊开窗应比焊盘尺寸大6mils以上(单边3mils),见下图: 阻焊桥 a) 相邻的SMD焊盘,SMD焊盘和插件孔、SMD焊盘和过孔、过孔与过孔之间需要保留阻焊桥;最小阻焊桥宽度2mils &#x…

vue3.0与vue2.0

一、生命周期的变化 1.vue2.响应式架构 2.vue3.0 响应式架构图 Vue3.0响应式框架在设计上,将视图渲染和数据响应式完全分离开来。将响应式核心方法effect从原有的Watcher中抽离。这样,当我们只需要监听数据响应某种逻辑回调(例如监听某个text属性的变化…

每日学术速递5.28

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CL 1.Improving Factuality and Reasoning in Language Models through Multiagent Debate 标题:通过多主体辩论改进语言模型中的事实性和推理 作者:Yilun Du,…

创建型设计模式02-工厂方法模式

✨作者:猫十二懿 ❤️‍🔥账号:CSDN 、掘金 、个人博客 、Github 🎉公众号:猫十二懿 工厂方法模式 1、工厂方法模式介绍 工厂方法模式(Factory Method Pattern)是一种常用的对象创建型设计模式…

MAC中文版 FCPX V10.6.6 专属视频剪辑后期工具安装教程

Final Cut Pro X简介 Final Cut Pro X又名FCPX,是MAC上非常不错的视频非线性剪辑软件,它剪辑速度超凡,具有先进的调色功能、HDR 视频支持,以及 ProRes RAW,让剪辑、音轨、图形特效、整片输出,支持主流的摄像机格式,是专业视频剪辑领域的王者…

Java经典笔试题—day14

Java经典笔试题—day14 🔎选择题🔎编程题🍭计算日期到天数转换🍭幸运的袋子 🔎结尾 🔎选择题 (1)定义学生、教师和课程的关系模式 S (S#,Sn,Sd,Dc,SA )(其属性分别为学号、姓名、所…

【数据湖仓架构】数据湖和仓库:范式简介

是时候将数据分析迁移到云端了——您选择数据仓库还是数据湖解决方案?了解这两种方法的优缺点。 数据分析平台正在转向云环境,例如亚马逊网络服务、微软 Azure 和谷歌云。云环境提供了多种好处,例如可扩展性、可用性和可靠性。此外&#xff0…

SpringMVC bean加载控制 -- SpringMVC入门保姆级教程(二)

文章目录 前言二、SpringMVC bean 加载控制1.bean加载控制2.添加Spring开发环境3.SpringMVC bean加载控制4.SpringMVC bean控制相关知识点 总结 前言 为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能…

丝印设计~丝印内容、大小、距离、排列,位置

丝印设计 丝印的内容包括: a) PCB的名称/PCB的版本号 b) 元器件外形框 c) 元器件的序号 d) 元器件的极性和方向标志 e) 条码框 f) 插入PCB的名称(母板) g) 插针的位置序号 h) 安装孔位置代号 i) 元器件第1脚的位置代号 j) 过板方向 k) 光纤盘…