<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>分布式 on 易哥</title>
		<link>https://yeecode.top/tags/%E5%88%86%E5%B8%83%E5%BC%8F/</link>
		<description>Recent content in 分布式 on 易哥</description>
		<generator>Hugo</generator>
		<language>zh-cn</language>
		
		
		
		
			<lastBuildDate>Sun, 22 Jan 2023 00:00:00 +0000</lastBuildDate>
		
			<atom:link href="https://yeecode.top/tags/%E5%88%86%E5%B8%83%E5%BC%8F/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>怎么理解3PC解决了2PC的阻塞问题？</title>
				<link>https://yeecode.top/blog/121/</link>
				<pubDate>Sun, 22 Jan 2023 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/121/</guid>
				<description>&lt;p&gt;正如题目所说，三阶段提交（Three-phase Commit，简称3PC）相比于两阶段提交（Two-phase Commit，简称2PC）的一个重大进步就是，前者解决了后者的阻塞问题。（或者说是部分解决，这个我们后面详细分析）&lt;/p&gt;&#xA;&lt;p&gt;那如何详细解释这一点，还得从两阶段提交算法说起。&lt;strong&gt;先分析下两阶段提交哪里存在阻塞。然后，再看三阶段提交算法如何避免了这个阻塞。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;好，我们开始介绍。&lt;/p&gt;&#xA;&lt;p&gt;我尽量写的简单生动些。&lt;/p&gt;&#xA;&lt;p&gt;而且，你没看错。虽然像是&lt;strong&gt;知乎十年前&lt;/strong&gt;才有的答案，但确实是新回答……&lt;/p&gt;&#xA;&lt;p&gt;哎……&lt;/p&gt;&#xA;&lt;h2 id=&#34;1-两阶段提交&#34;&gt;1 两阶段提交&lt;/h2&gt;&#xA;&lt;p&gt;两阶段提交（Two-phase Commit，简称2PC）是一种比较简单的一致性算法（或者说协议）。它将整个提交过程分成了&lt;strong&gt;准备阶段（Prepare）&lt;/strong&gt;、**提交阶段（Commit）**这两个阶段。&lt;/p&gt;&#xA;&lt;h2 id=&#34;11-具体实现&#34;&gt;1.1 具体实现&lt;/h2&gt;&#xA;&lt;p&gt;在准备阶段中，可以细分成如下的操作步骤：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者给参与者发送“Prepare”消息，“Prepare”消息中包含了此次更新要进行的所有操作。然后协调者等待各个参与者的响应。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Prepare”消息后将消息中的操作封装为一个事务并执行，但不要提交。&lt;/li&gt;&#xA;&lt;li&gt;参与者在执行事务的过程中如果遇到任何问题导致事务中的操作无法完成，则向协调者回应“No”消息；如果事务中的全部操作能够完成，则向协调者回应“Yes”消息。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;经过准备阶段，所有的参与者已经尝试完成了所有的操作，但是没有把这些操作提交。并且，根据将自身能否完成操作的结果回应给了协调者。接下来，便进入了第二个阶段：提交阶段。&lt;/p&gt;&#xA;&lt;p&gt;在提交阶段中，协调者会根据收集到的各个参与者的回应执行不同的操作。&lt;/p&gt;&#xA;&lt;p&gt;如果协调者收到了所有参与者的“Yes”消息，则进行如下操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“Commit”消息。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Commit”消息后，提交在准备阶段已经完成但尚未提交的事务。&lt;/li&gt;&#xA;&lt;li&gt;参与者向协调者发送“Done”消息。&lt;/li&gt;&#xA;&lt;li&gt;协调者收到所有参与者的“Done”消息，表明该一致性操作以成功的形式结束。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;如果协调者在一定时间内没有收齐所有参与者的消息，或者收到的消息中有“No”消息，则进行如下操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“Rollback”消息。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Rollback”消息后，回滚在准备阶段已经完成但尚未提交的事务。&lt;/li&gt;&#xA;&lt;li&gt;参与者向协调者发送“Done”消息。&lt;/li&gt;&#xA;&lt;li&gt;协调者收到所有参与者节点的“Done”消息，表明该一致性操作以回滚的形式结束。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;可见在提交阶段，无论是决定要“Commit”还是“Rollback”，整个一致性操作都能结束。&lt;/p&gt;&#xA;&lt;p&gt;下图展示了两阶段提交的消息流。其中图的左侧部分表示一致性操作成功情况下的消息流；图的右侧部分表示因部分参与者不回应导致的一致性操作失败情况下的消息流。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/121/pic/2p_hu_8d8f95cb519f9750.webp&#34; alt=&#34;两阶段提交的消息流&#34; width=&#34;900&#34; height=&#34;673&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;上述过程中，协调者可以是一个专门起到协调作用而不参与一致性操作的节点，也可以是一个参与一致性操作的节点。如果它是后者，那它不仅要完成协调者的工作，还要作为参与者完成所有参与者要进行的工作，即它也要将操作封装成事务执行、回应“No”消息或“Yes”消息、提交或回滚事务等。&lt;/p&gt;&#xA;&lt;h2 id=&#34;12-阻塞在哪里&#34;&gt;1.2 阻塞在哪里？&lt;/h2&gt;&#xA;&lt;p&gt;通过了解两阶段提交的工作过程，我们其实已经可以看出明确阻塞点。&lt;/p&gt;&#xA;&lt;p&gt;参与者收到协调者发出的“Prepare”消息后，会开启事务完成消息中的操作。事务的开启意味着参与者的并发处理能力将受到很大的影响。而且，参与者不是一个节点而是一群节点，所以&lt;strong&gt;整个系统中的节点都会因为事务的开启而阻塞&lt;/strong&gt;。这个过程可能很长，要等待协调者收集完参与者的消息并发布进一步的消息后，该过程才能结束。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;那如果协调者在这个阶段宕机，则所有参与者会一直阻塞下去。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;这就是两阶段提交存在的&lt;strong&gt;同步阻塞问题&lt;/strong&gt;。显然极大地影响了分布式系统的工作效率。&lt;/p&gt;&#xA;&lt;p&gt;好，接下来我们看一下三阶段提交，看它如何解决这一阻塞问题。&lt;/p&gt;&#xA;&lt;h2 id=&#34;2-三阶段提交&#34;&gt;2 三阶段提交&lt;/h2&gt;&#xA;&lt;p&gt;三阶段提交（Three-phase Commit，简称3PC）是二阶段提交的改进，它修复了二阶段提交的一些缺陷，但也使得整个一致性操作过程多出了一个阶段，更为复杂。此外，三阶段提交还引入了一些超时机制，以便于节点在失去或者部分失去与外界联系时做出一些操作。&lt;/p&gt;&#xA;&lt;p&gt;三阶段提交一共分为三个阶段：&lt;strong&gt;CanCommit阶段&lt;/strong&gt;、&lt;strong&gt;PreCommit阶段&lt;/strong&gt;、&lt;strong&gt;DoCommit阶段&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;21-具体实现&#34;&gt;2.1 具体实现&lt;/h2&gt;&#xA;&lt;p&gt;CanCommit阶段可以细分为以下步骤：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“CanCommit”消息，询问参与者能否完成消息中的操作。然后协调者等待各个参与者的响应。&lt;/li&gt;&#xA;&lt;li&gt;参与者接收到“CanCommit”消息后，判断自身是否能够顺利完成操作。如果自身可以，则向协调者回应“Yes”消息；如果自身不可以，则向协调者回应“No”消息。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;在CanCommit阶段，协调者和参与者只是就能否完成操作进行了交流，并没有进行实际的工作。接下来进入PreCommit阶段。&lt;/p&gt;&#xA;&lt;p&gt;PreCommit阶段则根据协调者收到的参与者的反馈不同而不同。&lt;/p&gt;&#xA;&lt;p&gt;如果协调者收到了所有参与者的“Yes”消息，则进行如下操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“PreCommit”消息。然后协调者等待各个参与者的响应。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“PreCommit”消息后，将此次要进行的操作封装成事务执行，但不要提交。&lt;/li&gt;&#xA;&lt;li&gt;如果参与者完成了各项操作，则向协调者回应“ACK”消息。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;在这种情况下，一致性操作则会进入DoCommit阶段。&lt;/p&gt;&#xA;&lt;p&gt;如果协调者在一定时间内没有收齐所有参与者的消息，或者收到的消息中有“No”消息，则进行如下操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向所有参与者发送“Abort”消息，表明此次一致性操作取消。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Abort”后，中止当前的操作。如果参与者在一定时间内没有收到协调者发来的操作消息，也中止当前的操作。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;这种情况下一致性操作结束，无需再进入DoCommit阶段，&lt;/p&gt;&#xA;&lt;p&gt;在DoCommit阶段中，协调者会根据参与者的回应采取不同的操作。&lt;/p&gt;&#xA;&lt;p&gt;如果协调者收到了所有参与者的“ACK”消息，则进行如下的操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“Commit”消息。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Commit”消息后，提交在准备阶段已经完成但尚未提交的事务。&lt;/li&gt;&#xA;&lt;li&gt;参与者向协调者发送“Done”消息。&lt;/li&gt;&#xA;&lt;li&gt;协调者收到所有参与者的“Done”消息，表明该一致性操作以成功的形式结束。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;如果协调者在一定时间内没有收齐参与者的“ACK”消息，则进行如下的操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“Rollback”消息。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Rollback”消息后，回滚在准备阶段已经完成但尚未提交的事务。&lt;/li&gt;&#xA;&lt;li&gt;参与者向协调者发送“Done”消息。&lt;/li&gt;&#xA;&lt;li&gt;协调者收到所有参与者的“Done”消息，表明该一致性操作以失败的形式结束。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;下图展示了三阶段提交的消息流。其中图的左侧部分表示一致性操作成功情况下的消息流；图的右侧部分表示因部分参与者在CanCommit阶段回应“No”消息导致的一致性操作失败情况下的消息流。&lt;/p&gt;</description>
			</item>
			<item>
				<title>别搞错了！Paxos不是一致性算法！</title>
				<link>https://yeecode.top/blog/120/</link>
				<pubDate>Sat, 21 Jan 2023 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/120/</guid>
				<description>&lt;p&gt;说到一致性，大家都不陌生。随着分布式系统、微服务系统、区块链等技术的发展，“一致性”一词出现的频率也越来越高。&lt;/p&gt;&#xA;&lt;p&gt;再说起一致性时，有人会联想到一个“一致性”算法——Paxos算法。&lt;/p&gt;&#xA;&lt;p&gt;然而，这是错误的，因为：&lt;strong&gt;Paxos并不是一个一致性算法！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;而正是上述误解，使得很多分布式的学习者陷入了混乱之中。给分布式的学习带来了很大的麻烦。&lt;/p&gt;&#xA;&lt;p&gt;为了让大家明确这些概念，我们先温习下分布式一致性的概念。&lt;/p&gt;&#xA;&lt;p&gt;分布式系统中的一致性是说，**用户在分布式系统的某个节点上进行了变更操作，则在一定时间后，用户能从系统的任意节点上读取到这个变更结果。**并且，一致性有强弱之分，如顺序一致性、线性一致性、最终一致性等等，都代表了特定的一致性级别。&lt;/p&gt;&#xA;&lt;p&gt;而熟悉Paxos算法的同学知道，Paxos并不能够帮助系统实现一致性，更不用说帮助系统达到具体的哪种一致性级别了。所以，Paxos算法，并不是一致性算法。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Paxos算法，是个共识算法！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;要想理清这一切，我们需要了解共识这一概念。&lt;/p&gt;&#xA;&lt;p&gt;共识与一致性是两个紧密关联但又彼此独立的概念，然而，在日常的讨论中我们常将两者混淆。这在理解和使用上带来了许多麻烦。&lt;/p&gt;&#xA;&lt;p&gt;**共识（Consensus）是指分布式系统中各个节点对某个提议达成一致的过程。**共识中提议的含义很广泛，可以是某个变量的值，可以某个节点的角色，等等。&lt;/p&gt;&#xA;&lt;p&gt;一致性是指系统各个节点对外表现一致，而共识则是各个节点就某个提议达成一致的内部过程。因此，一致性（Consistency）和共识（Consensus）并不是同一个概念，它们&lt;strong&gt;在英文中也完全不是一个单词&lt;/strong&gt;。但是两者却在很多工程领域的文章、书籍中被混淆，这一点我们要特别注意。&lt;/p&gt;&#xA;&lt;p&gt;共识和一致性也有一定的关系。在一个分布式系统中，数据副本存放在不同节点上。用户修改了某个节点的数据后，经过一定时间，如果用户能从系统任意节点读取到修改后的数据，那我们就说该分布式系统实现了一致性。既然用户能从系统中读到修改后的数据，则说明分布式系统中所有节点对这次的数据修改提议达成了共识。因此，&lt;strong&gt;一致性是目的，而共识是实现一致性这一目的所要经历的一个过程。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;此外一致性有强弱之分，而共识则没有。共识需要所有节点对某个提议达成一致，只要达成一致，就是实现了共识；只要达不成一致，就没有实现共识。&lt;/p&gt;&#xA;&lt;p&gt;我们可以通过组织班级春游的例子来理解共识和一致性这两个概念的区别。&lt;/p&gt;&#xA;&lt;p&gt;几个班委会成员在会议室讨论班级要去哪春游，讨论的过程就是一个共识过程。可能有的班委提议去西湖，有的班委提议去西溪湿地，有的班委提议去太子湾，最终大家不断讨论得出一个确定结果的过程就是共识。期间可能会涉及多轮的提议、投票等，这个过程和本节将要讨论的共识算法的实现流程也十分相似。&lt;/p&gt;&#xA;&lt;p&gt;当班委会讨论并确定春游的地点之后，需要向全班同学公布这一结果。如何公布这一结果就是一个一致性问题。如果选择张贴班级公告栏，则同学们看到公告的时间有先后（这时其他班级的同学询问起来，可能有人会回答“不知道”，有人会回答“公告说了，我们班春游去西湖”），那这就不满足线性一致性；如果选择群发短信，则所有同学会同时收到通知（这时其他班级的同学询问起来，大家都会回答“短信通知过了，我们班春游去西湖”），那这就满足线性一致性。&lt;/p&gt;&#xA;&lt;p&gt;可见，共识是一致性的基础。毕竟如果班委会无法就春游地点达成共识，那就无法向全班同学公布结果。但是，这两个概念并不相同，不能混为一谈。&lt;/p&gt;&#xA;&lt;p&gt;Paxos算法提出者Leslie Lamport描述Paxos算法的论文《Paxos Made Simple》中写道“ At its heart is a consensus algorithm—the “synod” algorithm of.”而论文第二章的名字就叫“The Consensus Algorithm”&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;。甚至，论文通篇都没有出现过“consistency（一致性）”这一单词。&lt;/p&gt;&#xA;&lt;p&gt;Paxos算法是一个比较完美的共识算法，以至于有人这样称赞它：“世上只有一种共识（consensus）算法，那就是Paxos”。它可以在存在故障节点但没有恶意节点的前提下保证系统中节点达成共识，这是一个完备的共识算法。Multi-Paxos算法、Fast-Paxos算法、Raft算法都是由Paxos演化来的。&lt;/p&gt;&#xA;&lt;p&gt;关于共识算法、一致性算法的区别，以及共识算法（包括Paxos算法、Raft算法）的详解，大家可以参考下面的书籍。会帮助大家对分布式系统的一致性建立更全面系统的认识。&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;&lt;img src=&#34;https://yeecode.top/img/promo/dsbook.jpg&#34; width=&#34;680&#34; height=&#34;453&#34; loading=&#34;lazy&#34;  alt=&#34;分布式系统原理与工程实践&#34; /&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;《分布式系统原理与工程实践》&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;书中对各种一致性算法都进行了详细的介绍。还详细阐述了共识算法，给出了&lt;strong&gt;Paxos算法的推导过程、理解分析、具体示例&lt;/strong&gt;。应该是最&lt;strong&gt;简单易懂&lt;/strong&gt;的Paxos讲解书籍了。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;../pic/dsbook_list01.jpg&#34; alt=&#34;书籍部分目录&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;另外这本书对分布式系统相关的理论、实践、工程知识均进行了详细的介绍，层层递进，有助于大家建立完整的分布式系统知识体系。涉及&lt;strong&gt;一致性、共识、Paxos、分布式事务、服务治理、微服务、幂等、消息系统、Zookeeper&lt;/strong&gt;等。并且还发行了&lt;strong&gt;繁体版&lt;/strong&gt;！&lt;/p&gt;&#xA;&lt;p&gt;再次提醒大家，在学习分布式系统时，因为涉及到的理论、框架很多。所以大家一定要理清知识脉络，否则容易学得越多越混乱。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;最后，我是高级架构师&lt;strong&gt;易哥&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;真心希望本文能让大家有所收获，纠正大家的一些错误认知。&lt;/p&gt;&#xA;&lt;p&gt;欢迎&lt;strong&gt;关注&lt;/strong&gt;我们，我会偶尔出没分享&lt;strong&gt;软件架构&lt;/strong&gt;和&lt;strong&gt;编程&lt;/strong&gt;相关的干货知识。&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;Lamport L. Paxos made simple[J]. ACM SIGACT News (Distributed Computing Column) 32, 4 (Whole Number 121, December 2001), 2001: 51-58.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;</description>
			</item>
			<item>
				<title>两阶段、三阶段提交算法，真的可靠吗？</title>
				<link>https://yeecode.top/blog/119/</link>
				<pubDate>Fri, 20 Jan 2023 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/119/</guid>
				<description>&lt;p&gt;在前面的文章中，我们已经详细介绍了两阶段提交算法、三阶段提交算法。包括它们的具体实现流程、优劣等等。如果对这方面不了解的同学，可以再去温习以前的文章。&lt;/p&gt;&#xA;&lt;p&gt;关于两阶段提交，我们知道它可能会出现提交不一致的情况。这种情况有两种：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;假设前面各次通信均正常，但因为网络抖动导致部分参与者无法收到“Commit”消息，则会出现部分参与者提交了事务，部分参与者未提交事务这种不一致情况的发生。&lt;/li&gt;&#xA;&lt;li&gt;假设前面各次通信均正常，如果协调者在发出“Commit”消息或者“Rollback”消息后宕机，部分参与者收到了这条消息后提交或者回滚了事务，部分参与者没有收到这条消息。则也会出现提交不一致的情况。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;而三阶段提交，则出现提交不一致的情况更低。但是仍然存在：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;假设前面各次通信均正常，如果协调者在发送“Rollback”消息后宕机，部分参与者收到了“Rollback”消息回滚了事务；部分参与者因为没有收到“Rollback”消息便会默认提交事务。此时便出现提交不一致的情况。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;可见，两阶段提交、三阶段提交均不可靠。都可能会出现提交不一致的情况。&lt;/p&gt;&#xA;&lt;p&gt;但我们也发现：三阶段提交算法则比两阶段提交算法要好，出现不一致提交的概率更低。这里不仅仅是说出现异常的情况少了一种。而是说三阶段提交的通信次数更多，那&lt;strong&gt;前面各次通信均正常且最后一次通信异常&lt;/strong&gt;的事件，其出现概率也更低。&lt;/p&gt;&#xA;&lt;p&gt;顺着这个思路走下去，阶段越多，则提交越可靠。&lt;strong&gt;那是不是说，继续引入更多的阶段，就可以实现可靠的一致性提交呢？&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;接下来，我们就来讨论这个问题。&lt;/p&gt;&#xA;&lt;p&gt;要回答上述疑问，我们可以先了解&lt;strong&gt;两军问题（Two Generals&amp;rsquo; Problem）&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;如下图所示，山顶的两支蓝军将白军左右围困在山谷。两支蓝军必须派信使跨过白军驻守的山谷才能通信。信使在跨过山谷时，可能被白军俘虏导致信息丢失。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/119/pic/2jun_hu_1e3b43513f9f818.webp&#34; alt=&#34;两军问题示意图&#34; width=&#34;884&#34; height=&#34;264&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;假设两支蓝军必须在同一天从两侧夹击白军才能成功，而任意一支蓝军单独发起进攻都会失败。那请问，蓝军能必胜吗？&lt;/p&gt;&#xA;&lt;p&gt;我们现在思考蓝军怎样通信才能商定出一个进攻日期。&lt;/p&gt;&#xA;&lt;p&gt;假设蓝军1派出信使，传递信息“第五天发起进攻！”&lt;/p&gt;&#xA;&lt;p&gt;然后，第五天时，蓝军1能放心地发起进攻吗？&lt;/p&gt;&#xA;&lt;p&gt;不能，因为蓝军1并不能确定蓝军2收到了自己的消息。&lt;/p&gt;&#xA;&lt;p&gt;于是，需要蓝军2在收到消息后，派出一个信使告知蓝军1自己收到了消息。&lt;/p&gt;&#xA;&lt;p&gt;这样，第五天时，蓝军2能放心地发起进攻吗？&lt;/p&gt;&#xA;&lt;p&gt;不能，因为蓝军2并不能确定蓝军1收到了自己的确认消息。&lt;/p&gt;&#xA;&lt;p&gt;于是，需要蓝军1在收到了蓝军2的确认消息后，再派出一个信使告诉蓝军2自己已经收到了蓝军2的确认消息。&lt;/p&gt;&#xA;&lt;p&gt;这样，第五天时，蓝军1能放心地发起进攻吗？&lt;/p&gt;&#xA;&lt;p&gt;不能，因为蓝军1并不能确定蓝军2收到了自己的确认消息。&lt;/p&gt;&#xA;&lt;p&gt;于是，需要蓝军2在收到蓝军1的确认消息后，再派出一个信使告诉蓝军1……&lt;/p&gt;&#xA;&lt;p&gt;这时我们发现，要想可靠地传递包含进攻日期的信息，互派信使的过程似乎要无穷无尽地进行下去。这意味着，两支蓝军无法实现信息的可靠传递。&lt;/p&gt;&#xA;&lt;p&gt;我们可以使用反证法证明这个结论。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;假设双方共派出n个必要的信使后，能够可靠地传递信息。双方在不派信使的情况下，显然无法可靠传递信息，故n≥1。由于信使可能会被俘，则第n个信使可能会被俘。而n个信使都是必要的，这意味着，信息无法可靠传递。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;两军问题讨论的是在信道不可靠的情况下，能否可靠传递信息的问题。结论是：&lt;strong&gt;如果信道不可靠，则无法可靠传递信息&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;举一反三，我们可以将两军算法的思路和结论迁移到一致性提交算法中，讨论能否在网络、节点均不稳定的分布式系统中实现可靠的一致性提交。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;假设经过n个必要的阶段后，能够实现可靠的一致性提交。不经过任何阶段，显然无法完成提交，故n≥1。由于分布式系统的通信、节点均不稳定，则第n个阶段可能因为通信故障或节点宕机无法顺利完成。而n个阶段都是必要的，这意味着，无法实现可靠的一致性提交。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;可见，&lt;strong&gt;即使引入更多的阶段，也无法在网络、节点均不稳定的分布式系统中实现可靠的一致性提交&lt;/strong&gt;。无论我们增加再多的阶段，都不可能完全避免。&lt;/p&gt;&#xA;&lt;p&gt;但是，确实，&lt;strong&gt;随着阶段的增加，出现不一致提交的概率降低&lt;/strong&gt;。因为在前n-1次无异常且在第n次恰好异常的情况，会随着n的增加逐渐降低。&lt;/p&gt;&#xA;&lt;p&gt;所以，一般来说，三阶段提交就够用了。已经可以将不一致提交降到一个极低的水平（因为通信异常本身就是一个小概率实践）。&lt;/p&gt;&#xA;&lt;p&gt;说到这里，可能有人会说，还有一个重要的一致性算法——Paxos算法——我们没有讲！听说它是一个很棒的算法，能不能实现可靠地一致性提交？&lt;/p&gt;&#xA;&lt;p&gt;如果问出这个问题，则说明他对一致性的概念是混乱的。因为：&lt;strong&gt;Paxos算法是一个共识算法，而不是一致性算法&lt;/strong&gt;。虽然，确实很多网上的资料都讲Paxos算法当做一致性算法。这种错误的认识，应该就是大家在学习分布式系统时容易感到混乱的原因。&lt;/p&gt;&#xA;&lt;p&gt;关于共识算法、一致性算法的区别，以及共识算法（包括Paxos算法、Raft算法）的详解，大家可以参考下面的书籍。会帮助大家对分布式系统的一致性建立更全面系统的认识。&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;&lt;img src=&#34;https://yeecode.top/img/promo/dsbook.jpg&#34; width=&#34;680&#34; height=&#34;453&#34; loading=&#34;lazy&#34;  alt=&#34;分布式系统原理与工程实践&#34; /&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;《分布式系统原理与工程实践》&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;书中对各种一致性算法都进行了详细的介绍。还详细阐述了共识算法，给出了&lt;strong&gt;Paxos算法的推导过程、理解分析、具体示例&lt;/strong&gt;。应该是最&lt;strong&gt;简单易懂&lt;/strong&gt;的Paxos讲解书籍了。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;../pic/dsbook_list01.jpg&#34; alt=&#34;书籍部分目录&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;另外这本书对分布式系统相关的理论、实践、工程知识均进行了详细的介绍，层层递进，有助于大家建立完整的分布式系统知识体系。涉及&lt;strong&gt;一致性、共识、Paxos、分布式事务、服务治理、微服务、幂等、消息系统、Zookeeper&lt;/strong&gt;等。并且还发行了&lt;strong&gt;繁体版&lt;/strong&gt;！&lt;/p&gt;&#xA;&lt;p&gt;再次提醒大家，在学习分布式系统时，因为涉及到的理论、框架很多。所以大家一定要理清知识脉络，否则容易学得越多越混乱。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;别忘了&lt;strong&gt;点赞&lt;/strong&gt;……&lt;/p&gt;&#xA;&lt;p&gt;也欢迎&lt;strong&gt;关注&lt;/strong&gt;我！&lt;/p&gt;&#xA;&lt;p&gt;我是程序员易哥。&lt;/p&gt;</description>
			</item>
			<item>
				<title>从两阶段提交算法到三阶段提交算法</title>
				<link>https://yeecode.top/blog/118/</link>
				<pubDate>Thu, 12 Jan 2023 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/118/</guid>
				<description>&lt;p&gt;现在，分布式系统越来越多。不理解分布式系统，都不好意思说自己会编程。而说起分布式系统，则绕不开各种一致性问题。&lt;/p&gt;&#xA;&lt;p&gt;假设我们要在一个分布式系统中实现一致性，应该怎样做？&lt;/p&gt;&#xA;&lt;p&gt;大家可能脱口而出：用&lt;strong&gt;两阶段提交算法&lt;/strong&gt;或者&lt;strong&gt;三阶段提交算法&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;那大家对这些算法的细节了解的清楚吗？知道两者的区别么？为什么它们可以满足顺序一致性？&lt;/p&gt;&#xA;&lt;p&gt;本文将会解答这些问题。接下来，带大家详细了解这两个算法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;p&gt;假设一个分布式系统中存在多个节点，如下图所示，其中的节点A收到了数据变更请求。如果系统要满足一致性，那节点A在完成自身数据变更的同时必须协调其他节点完成数据变更。这种情况下，我们将发起操作的节点称为协调者(Coordinator)，而将接受操作的节点称为参与者(Participants)。在图中，节点A是协调者，节点B和节点C都是参与者。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/118/pic/yizhi_hu_2b0528f93e111d31.webp&#34; alt=&#34;一致性操作中的角色划分&#34; width=&#34;694&#34; height=&#34;414&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;具体实现似乎很简单，作为协调者的节点A只要在更新自身数据的同时将变更操作通知各个参与者，参与者收到协调者的变更通知后各自完成自身变更即可,如下图所示。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/118/pic/yizhi01_hu_b07e475c62b2769c.webp&#34; alt=&#34;节点间的一致性操作&#34; width=&#34;900&#34; height=&#34;524&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这样，用户再从系统中读取该数据时，无论读请求落在哪个节点上，读取到的结果都是一致的。系统便满足了一致性。&lt;/p&gt;&#xA;&lt;p&gt;可在实际中并没有这么理想：协调者和参与者之间的通讯可能不可靠，参与者也可能因为各种内部原因导致更新失败。&lt;/p&gt;&#xA;&lt;p&gt;协调者更新了自身状态后通知参与者，假设某个参与者因为&lt;strong&gt;通讯原因&lt;/strong&gt;或者&lt;strong&gt;节点自身原因&lt;/strong&gt;更新失败，则那用户便可能从集群中读取到&lt;strong&gt;不一致的结果&lt;/strong&gt;。这时系统的一致性便被打破。&lt;/p&gt;&#xA;&lt;p&gt;发生这种不一致的根源是每个节点都能知道自身是否操作成功，但却无法知道其他节点是否更新成功。&lt;/p&gt;&#xA;&lt;p&gt;类比后面要介绍的两阶段提交和三阶段提交，我们可以将上图所示的操作称为“一阶段提交”，因为整个一致性操作过程中只有一个“提交”阶段。显然我们的“一阶段提交”并不能够很好地实现一致性操作。&lt;/p&gt;&#xA;&lt;p&gt;接下来我们要学习的就是一些更好的也更为实用的一致性算法。也就是两阶段提交算法和三阶段提交算法。&lt;/p&gt;&#xA;&lt;p&gt;两阶段提交算法和三阶段提交算法能够实现的一致性是指线性一致性。而弱一致性算法，例如我们常听说的最终一致性算法，都是在线性一致性的基础上放宽约束实现的。所以，实现线性一致性的算法十分重要，例如各种分布式事务就要用到它！&lt;/p&gt;&#xA;&lt;h2 id=&#34;两阶段提交&#34;&gt;两阶段提交&lt;/h2&gt;&#xA;&lt;p&gt;两阶段提交（Two-phase Commit，简称2PC）是一种比较简单的一致性算法（或者说协议）。它将整个提交过程分成了&lt;strong&gt;准备阶段（Prepare）&lt;/strong&gt;、**提交阶段（Commit）**这两个阶段。&lt;/p&gt;&#xA;&lt;h2 id=&#34;具体实现&#34;&gt;具体实现&lt;/h2&gt;&#xA;&lt;p&gt;在准备阶段中，可以细分成如下的操作步骤：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者给参与者发送“Prepare”消息，“Prepare”消息中包含了此次更新要进行的所有操作。然后协调者等待各个参与者的响应。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Prepare”消息后将消息中的操作封装为一个事务并执行，但不要提交。&lt;/li&gt;&#xA;&lt;li&gt;参与者在执行事务的过程中如果遇到任何问题导致事务中的操作无法完成，则向协调者回应“No”消息；如果事务中的全部操作能够完成，则向协调者回应“Yes”消息。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;经过准备阶段，所有的参与者已经尝试完成了所有的操作，但是没有把这些操作提交。并且，根据将自身能否完成操作的结果回应给了协调者。接下来，便进入了第二个阶段：提交阶段。&lt;/p&gt;&#xA;&lt;p&gt;在提交阶段中，协调者会根据收集到的各个参与者的回应执行不同的操作。&lt;/p&gt;&#xA;&lt;p&gt;如果协调者收到了所有参与者的“Yes”消息，则进行如下操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“Commit”消息。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Commit”消息后，提交在准备阶段已经完成但尚未提交的事务。&lt;/li&gt;&#xA;&lt;li&gt;参与者向协调者发送“Done”消息。&lt;/li&gt;&#xA;&lt;li&gt;协调者收到所有参与者的“Done”消息，表明该一致性操作以成功的形式结束。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;如果协调者在一定时间内没有收齐所有参与者的消息，或者收到的消息中有“No”消息，则进行如下操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“Rollback”消息。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Rollback”消息后，回滚在准备阶段已经完成但尚未提交的事务。&lt;/li&gt;&#xA;&lt;li&gt;参与者向协调者发送“Done”消息。&lt;/li&gt;&#xA;&lt;li&gt;协调者收到所有参与者节点的“Done”消息，表明该一致性操作以回滚的形式结束。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;可见在提交阶段，无论是决定要“Commit”还是“Rollback”，整个一致性操作都能结束。&lt;/p&gt;&#xA;&lt;p&gt;下图展示了两阶段提交的消息流。其中图的左侧部分表示一致性操作成功情况下的消息流；图的右侧部分表示因部分参与者不回应导致的一致性操作失败情况下的消息流。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/118/pic/2p_hu_8d8f95cb519f9750.webp&#34; alt=&#34;两阶段提交的消息流&#34; width=&#34;900&#34; height=&#34;673&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;上述过程中，协调者可以是一个专门起到协调作用而不参与一致性操作的节点，也可以是一个参与一致性操作的节点。如果它是后者，那它不仅要完成协调者的工作，还要作为参与者完成所有参与者要进行的工作，即它也要将操作封装成事务执行、回应“No”消息或“Yes”消息、提交或回滚事务等。&lt;/p&gt;&#xA;&lt;h2 id=&#34;优劣&#34;&gt;优劣&lt;/h2&gt;&#xA;&lt;p&gt;两阶段提交的操作步骤比较简单，但也有几个明显的问题。&lt;/p&gt;&#xA;&lt;p&gt;首先，两阶段提交存在&lt;strong&gt;同步阻塞问题&lt;/strong&gt;。参与者收到协调者发出的“Prepare”消息后，会开启事务完成消息中的操作。事务的开启意味着参与者的并发处理能力将受到很大的影响。而且，参与者不是一个节点而是一群节点，所以整个系统中的节点都会因为事务的开启而阻塞。这个过程可能很长，要等待协调者收集完参与者的消息并发布进一步的消息后，该过程才能结束。&lt;/p&gt;&#xA;&lt;p&gt;其次，两阶段提交&lt;strong&gt;高度依赖协调者发出的消息&lt;/strong&gt;，因此存在&lt;strong&gt;单点故障&lt;/strong&gt;。如果协调者在两阶段提交的过程中出现问题，则会导致系统失控。尤其是在准备阶段和提交阶段之间，如果此时协调者宕机，则会导致已经开启了事务的各个参与者既不能收到“Commit”消息，也不能收到“Rollback”消息。这样事务会一直开启，导致系统全局阻塞。&lt;/p&gt;&#xA;&lt;p&gt;第三，两阶段提交其实设置了一个假设：如果参与者能够收到和正常回应“Prepare”消息，那它应该也能正常收到“Commit”消息或者“Rollback”消息。通常，这个假设是成立的。因为参与者在准备阶段和提交阶段之间宕机的概率很小。但是，再小的概率也有可能发生，尤其是在高并发和多节点的情况下。一旦因为网络抖动导致部分参与者无法收到“Commit”消息，则会出现部分参与者提交了事务，部分参与者未提交事务这种&lt;strong&gt;不一致情况的发生&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;第四，两阶段提交存在&lt;strong&gt;状态丢失问题&lt;/strong&gt;。如果协调者在发出“Commit”消息或者“Rollback”消息后宕机，部分参与者收到了这条消息后提交或者回滚了事务，部分参与者没有收到这条消息。那即使重新选举出一个新的协调者，新的协调者也无法确定各个参与者到底处在哪个状态。&lt;/p&gt;&#xA;&lt;p&gt;为了解决两阶段提交的缺陷，出现了三阶段提交。&lt;/p&gt;&#xA;&lt;h2 id=&#34;三阶段提交&#34;&gt;三阶段提交&lt;/h2&gt;&#xA;&lt;p&gt;三阶段提交（Three-phase Commit，简称3PC）是二阶段提交的改进，它修复了二阶段提交的一些缺陷，但也使得整个一致性操作过程多出了一个阶段，更为复杂。此外，三阶段提交还引入了一些超时机制，以便于节点在失去或者部分失去与外界联系时做出一些操作。&lt;/p&gt;&#xA;&lt;p&gt;三阶段提交一共分为三个阶段：&lt;strong&gt;CanCommit阶段&lt;/strong&gt;、&lt;strong&gt;PreCommit阶段&lt;/strong&gt;、&lt;strong&gt;DoCommit阶段&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;具体实现-1&#34;&gt;具体实现&lt;/h2&gt;&#xA;&lt;p&gt;CanCommit阶段可以细分为以下步骤：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“CanCommit”消息，询问参与者能否完成消息中的操作。然后协调者等待各个参与者的响应。&lt;/li&gt;&#xA;&lt;li&gt;参与者接收到“CanCommit”消息后，判断自身是否能够顺利完成操作。如果自身可以，则向协调者回应“Yes”消息；如果自身不可以，则向协调者回应“No”消息。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;在CanCommit阶段，协调者和参与者只是就能否完成操作进行了交流，并没有进行实际的工作。接下来进入PreCommit阶段。&lt;/p&gt;&#xA;&lt;p&gt;PreCommit阶段则根据协调者收到的参与者的反馈不同而不同。&lt;/p&gt;&#xA;&lt;p&gt;如果协调者收到了所有参与者的“Yes”消息，则进行如下操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“PreCommit”消息。然后协调者等待各个参与者的响应。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“PreCommit”消息后，将此次要进行的操作封装成事务执行，但不要提交。&lt;/li&gt;&#xA;&lt;li&gt;如果参与者完成了各项操作，则向协调者回应“ACK”消息。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;在这种情况下，一致性操作则会进入DoCommit阶段。&lt;/p&gt;&#xA;&lt;p&gt;如果协调者在一定时间内没有收齐所有参与者的消息，或者收到的消息中有“No”消息，则进行如下操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向所有参与者发送“Abort”消息，表明此次一致性操作取消。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Abort”后，中止当前的操作。如果参与者在一定时间内没有收到协调者发来的操作消息，也中止当前的操作。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;这种情况下一致性操作结束，无需再进入DoCommit阶段，&lt;/p&gt;&#xA;&lt;p&gt;在DoCommit阶段中，协调者会根据参与者的回应采取不同的操作。&lt;/p&gt;&#xA;&lt;p&gt;如果协调者收到了所有参与者的“ACK”消息，则进行如下的操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“Commit”消息。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Commit”消息后，提交在准备阶段已经完成但尚未提交的事务。&lt;/li&gt;&#xA;&lt;li&gt;参与者向协调者发送“Done”消息。&lt;/li&gt;&#xA;&lt;li&gt;协调者收到所有参与者的“Done”消息，表明该一致性操作以成功的形式结束。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;如果协调者在一定时间内没有收齐参与者的“ACK”消息，则进行如下的操作：&lt;/p&gt;</description>
			</item>
			<item>
				<title>三阶段提交算法详解</title>
				<link>https://yeecode.top/blog/117/</link>
				<pubDate>Wed, 11 Jan 2023 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/117/</guid>
				<description>&lt;p&gt;通过本文，我们将对三阶段提交（Three-phase Commit，简称3PC）算法进行详细的介绍。在阅读本文之前，需要大家对两阶段提交（Two-phase Commit，简称2PC）算法十分了解。不了解的同学可以翻看我之前的文章。&lt;/p&gt;&#xA;&lt;p&gt;我们从两阶段提交算法的缺点说起，然后引出三阶段提交算法，并分析三阶段提交算法如何克服了这些缺点。&lt;/p&gt;&#xA;&lt;h2 id=&#34;两阶段提交算法的缺点&#34;&gt;两阶段提交算法的缺点&lt;/h2&gt;&#xA;&lt;p&gt;两阶段提交的操作步骤比较简单，但也有几个明显的问题。&lt;/p&gt;&#xA;&lt;p&gt;首先，两阶段提交存在&lt;strong&gt;同步阻塞问题&lt;/strong&gt;。参与者收到协调者发出的“Prepare”消息后，会开启事务完成消息中的操作。事务的开启意味着参与者的并发处理能力将受到很大的影响。而且，参与者不是一个节点而是一群节点，所以整个系统中的节点都会因为事务的开启而阻塞。这个过程可能很长，要等待协调者收集完参与者的消息并发布进一步的消息后，该过程才能结束。&lt;/p&gt;&#xA;&lt;p&gt;其次，两阶段提交&lt;strong&gt;高度依赖协调者发出的消息&lt;/strong&gt;，因此存在&lt;strong&gt;单点故障&lt;/strong&gt;。如果协调者在两阶段提交的过程中出现问题，则会导致系统失控。尤其是在准备阶段和提交阶段之间，如果此时协调者宕机，则会导致已经开启了事务的各个参与者既不能收到“Commit”消息，也不能收到“Rollback”消息。这样事务会一直开启，导致系统全局阻塞。&lt;/p&gt;&#xA;&lt;p&gt;第三，两阶段提交其实设置了一个假设：如果参与者能够收到和正常回应“Prepare”消息，那它应该也能正常收到“Commit”消息或者“Rollback”消息。通常，这个假设是成立的。因为参与者在准备阶段和提交阶段之间宕机的概率很小。但是，再小的概率也有可能发生，尤其是在高并发和多节点的情况下。一旦因为网络抖动导致部分参与者无法收到“Commit”消息，则会出现部分参与者提交了事务，部分参与者未提交事务这种&lt;strong&gt;不一致情况的发生&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;第四，两阶段提交存在&lt;strong&gt;状态丢失问题&lt;/strong&gt;。如果协调者在发出“Commit”消息或者“Rollback”消息后宕机，部分参与者收到了这条消息后提交或者回滚了事务，部分参与者没有收到这条消息。那即使重新选举出一个新的协调者，新的协调者也无法确定各个参与者到底处在哪个状态。&lt;/p&gt;&#xA;&lt;p&gt;为了解决两阶段提交的缺陷，出现了三阶段提交。&lt;/p&gt;&#xA;&lt;h2 id=&#34;三阶段提交详解&#34;&gt;三阶段提交详解&lt;/h2&gt;&#xA;&lt;p&gt;三阶段提交（Three-phase Commit，简称3PC）是二阶段提交的改进，它修复了二阶段提交的一些缺陷，但也使得整个一致性操作过程多出了一个阶段，更为复杂。此外，三阶段提交还引入了一些超时机制，以便于节点在失去或者部分失去与外界联系时做出一些操作。&lt;/p&gt;&#xA;&lt;p&gt;三阶段提交一共分为三个阶段：&lt;strong&gt;CanCommit阶段&lt;/strong&gt;、&lt;strong&gt;PreCommit阶段&lt;/strong&gt;、&lt;strong&gt;DoCommit阶段&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;CanCommit阶段可以细分为以下步骤：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“CanCommit”消息，询问参与者能否完成消息中的操作。然后协调者等待各个参与者的响应。&lt;/li&gt;&#xA;&lt;li&gt;参与者接收到“CanCommit”消息后，判断自身是否能够顺利完成操作。如果自身可以，则向协调者回应“Yes”消息；如果自身不可以，则向协调者回应“No”消息。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;在CanCommit阶段，协调者和参与者只是就能否完成操作进行了交流，并没有进行实际的工作。接下来进入PreCommit阶段。&lt;/p&gt;&#xA;&lt;p&gt;PreCommit阶段则根据协调者收到的参与者的反馈不同而不同。&lt;/p&gt;&#xA;&lt;p&gt;如果协调者收到了所有参与者的“Yes”消息，则进行如下操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“PreCommit”消息。然后协调者等待各个参与者的响应。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“PreCommit”消息后，将此次要进行的操作封装成事务执行，但不要提交。&lt;/li&gt;&#xA;&lt;li&gt;如果参与者完成了各项操作，则向协调者回应“ACK”消息。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;在这种情况下，一致性操作则会进入DoCommit阶段。&lt;/p&gt;&#xA;&lt;p&gt;如果协调者在一定时间内没有收齐所有参与者的消息，或者收到的消息中有“No”消息，则进行如下操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向所有参与者发送“Abort”消息，表明此次一致性操作取消。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Abort”后，中止当前的操作。如果参与者在一定时间内没有收到协调者发来的操作消息，也中止当前的操作。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;这种情况下一致性操作结束，无需再进入DoCommit阶段，&lt;/p&gt;&#xA;&lt;p&gt;在DoCommit阶段中，协调者会根据参与者的回应采取不同的操作。&lt;/p&gt;&#xA;&lt;p&gt;如果协调者收到了所有参与者的“ACK”消息，则进行如下的操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“Commit”消息。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Commit”消息后，提交在准备阶段已经完成但尚未提交的事务。&lt;/li&gt;&#xA;&lt;li&gt;参与者向协调者发送“Done”消息。&lt;/li&gt;&#xA;&lt;li&gt;协调者收到所有参与者的“Done”消息，表明该一致性操作以成功的形式结束。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;如果协调者在一定时间内没有收齐参与者的“ACK”消息，则进行如下的操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“Rollback”消息。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Rollback”消息后，回滚在准备阶段已经完成但尚未提交的事务。&lt;/li&gt;&#xA;&lt;li&gt;参与者向协调者发送“Done”消息。&lt;/li&gt;&#xA;&lt;li&gt;协调者收到所有参与者的“Done”消息，表明该一致性操作以失败的形式结束。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;图{@fig:251san}展示了三阶段提交的消息流。其中图的左侧部分表示一致性操作成功情况下的消息流；图的右侧部分表示因部分参与者在CanCommit阶段回应“No”消息导致的一致性操作失败情况下的消息流。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/117/pic/3p_hu_f0bb324cbf553453.webp&#34; alt=&#34;三阶段提交的消息流&#34; width=&#34;900&#34; height=&#34;813&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;{#fig:251san}&lt;/p&gt;&#xA;&lt;p&gt;在DoCommit阶段中，如果参与者在一定时间内没有收到“Commit”消息或者“Rollback”消息，则参与者会提交事务。这是因为既然能够进入DoCommit阶段，说明所有的参与者在CanCommit都回应了“Yes”。此时，所有的参与者都应该可以正确地提交事务，从而完成该一致性操作。&lt;/p&gt;&#xA;&lt;p&gt;DoCommit阶段中参与者会在无法收到“Commit”消息或者“Rollback”消息时提交事务，这解决了两个问题。首先，整个一致性操作不会因为协调者的突然宕机而导致参与者开启的事务无法关闭，从而阻塞整个系统。其次，如果协调者在发送“Commit”指令前后宕机，则整个系统的状态是确定的，因为各个参与者都会默认提交事务。&lt;/p&gt;&#xA;&lt;h2 id=&#34;三阶段提交的优劣&#34;&gt;三阶段提交的优劣&lt;/h2&gt;&#xA;&lt;p&gt;当然，这个机制&lt;strong&gt;仍然存在漏洞&lt;/strong&gt;。如果协调者在发送“Rollback”消息后宕机，部分参与者收到了“Rollback”消息回滚了事务；部分参与者因为没有收到“Rollback”消息便会默认提交事务。这将导致系统的一致性被打破。而且即使选举出新的协调者，新协调者也无法判断哪些参与者回滚了事务，哪些参与者提交了事务。&lt;/p&gt;&#xA;&lt;p&gt;不过，这种&lt;strong&gt;漏洞的发生概率极小&lt;/strong&gt;。“Rollback”消息在DoCommit阶段发出，既然能够进入该阶段，说明所有参与者在CanCommit阶段都回复了“Yes”消息，则大概率会在PreCommit阶段正常回复“ACK”消息。因此，协调者因为无法收起“ACK”消息而发出“Rollback”消息的概率很低，而在发出“Rollback”消息后恰好宕机的概率则更低。&lt;/p&gt;&#xA;&lt;p&gt;因此，三阶段提交通过加入一个新的阶段和引入超时机制&lt;strong&gt;减少了两阶段提交的同步阻塞问题&lt;/strong&gt;，&lt;strong&gt;减弱了对协调者的依赖&lt;/strong&gt;，&lt;strong&gt;降低了系统状态丢失的概率&lt;/strong&gt;。然而，正如我们上面所分析的，三阶段提交依然存在漏洞，并&lt;strong&gt;不完美&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;总体而言，两阶段提交和三阶段提交的实现比较简单，且能够实现线性一致性。尤其是三阶段提交，其故障概率很低，在实践中应用十分广泛。&lt;/p&gt;&#xA;&lt;p&gt;好，本文就介绍到这里。如果想对分布式系统的一致性有更全面系统的认识，可以参考下面的书籍。&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;&lt;img src=&#34;https://yeecode.top/img/promo/dsbook.jpg&#34; width=&#34;680&#34; height=&#34;453&#34; loading=&#34;lazy&#34;  alt=&#34;分布式系统原理与工程实践&#34; /&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;《分布式系统原理与工程实践》&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;书籍对各种一致性算法都进行了详细的介绍。对大家体系化地掌握这些知识很有帮助。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;../pic/dsbook_list01.jpg&#34; alt=&#34;书籍部分目录&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;另外这本书对分布式系统相关的理论、实践、工程知识均进行了详细的介绍，层层递进，有助于大家建立完整的分布式系统知识体系。涉及一致性、共识、Paxos、分布式事务、服务治理、微服务、幂等、消息系统、Zookeeper等。并且还发行了繁体版。&lt;/p&gt;&#xA;&lt;p&gt;再次提醒大家，在学习分布式系统时，因为涉及到的理论、框架很多。所以大家一定要理清知识脉络，否则容易学得越多越混乱。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;好了，我是程序员易哥。&lt;/p&gt;&#xA;&lt;p&gt;别忘了&lt;strong&gt;点赞&lt;/strong&gt;……&lt;/p&gt;&#xA;&lt;p&gt;这回就说这么多！&lt;/p&gt;&#xA;&lt;p&gt;可以&lt;strong&gt;关注&lt;/strong&gt;我！等我下回接着说！&lt;/p&gt;</description>
			</item>
			<item>
				<title>两阶段提交算法为什么满足线性一致性？</title>
				<link>https://yeecode.top/blog/116/</link>
				<pubDate>Mon, 09 Jan 2023 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/116/</guid>
				<description>&lt;p&gt;两阶段提交（Two-phase Commit，简称2PC）算法我们都熟悉，我们也知道两阶段提交是一个常用的满足&lt;strong&gt;线性一致性&lt;/strong&gt;的算法。&lt;/p&gt;&#xA;&lt;p&gt;那它为什么满足线性一致性呢？我们今天就来证明这一点。&lt;/p&gt;&#xA;&lt;p&gt;提前说明一下，阅读本文需要大家对下面的两点有详细的了解：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;线性一致性的定义及约束&lt;/li&gt;&#xA;&lt;li&gt;两阶段提交算法的实现逻辑&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;对这块概念不清晰的同学，可以阅读我们之前的文章。&lt;/p&gt;&#xA;&lt;p&gt;在证明之前，我们首先确认两点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;考虑到网络延迟、节点处理速度等的不同，各个节点收到“Prepare”消息并创建事务是有先后的。&lt;/li&gt;&#xA;&lt;li&gt;考虑到网络延迟、节点处理速度等的不同，各个节点收到“Commit”消息并提交事务是有先后的。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;在一次成功的二阶段提交操作中一定存在一个全局锁时段。这一时段从准备阶段的最后一个“Yes”消息发出开始，到提交阶段的第一个“Commit”消息被接收结束。在这一时段中，所有的节点都已经创建事务但未提交事务。&lt;/p&gt;&#xA;&lt;p&gt;在全局锁时段之后，是提交时段。这一时段从提交阶段的第一个“Commit”消息被接收开始，到提交阶段的最后一个“Done”消息发出为止。在这一时段中，各个节点陆续完成事务提交，如下图所示。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/116/pic/2pcZ0_hu_abaf03929c35be50.webp&#34; alt=&#34;全局锁时段与全局更新时段示意图&#34; width=&#34;900&#34; height=&#34;774&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这里我们假设参与者开启事务和发出Yes消息是同时进行的，参与者收到Commit消息和提交事务是同时进行的。这两个假设都&lt;strong&gt;不会&lt;/strong&gt;影响最终的结论。&lt;/p&gt;&#xA;&lt;p&gt;在全局锁时段和提交时段之间存在一个&lt;strong&gt;同步时刻&lt;/strong&gt;。同步时刻在&lt;strong&gt;全局历史中是唯一确定的&lt;/strong&gt;，且这一时刻具有以下特点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;除当前的2PC操作外，没有其他操作正在集群中开展。全局锁时段中在各个节点创建的锁可以共同保证这一点。&lt;/li&gt;&#xA;&lt;li&gt;对于任何一个节点而言，该时刻之后进行的第一个操作都是当前2PC的提交操作。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;那我们可以等价地认为2PC操作引发的变更就是在&lt;strong&gt;同步时刻&lt;/strong&gt;发生的。这样，2PC提交操作在全局历史中的位置就被确定了下来。因此，任何通过2PC操作开展的事件都可以唯一地映射到&lt;strong&gt;全局历史&lt;/strong&gt;中，就像是在全局历史中开展的事件一样，那这样的操作自然可以保证线性一致性。&lt;/p&gt;&#xA;&lt;p&gt;接下来，我们再用一个更为宏观视角的示例来理解这一过程。&lt;/p&gt;&#xA;&lt;p&gt;在下图中，节点A作为协调者发起了一次两阶段提交操作A2，并触发了参与者节点B和节点C的B2和C1操作。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/116/pic/2pcZ_hu_2768abb71f07d06e.webp&#34; alt=&#34;两阶段提交操作示例&#34; width=&#34;900&#34; height=&#34;943&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;可以看出，两阶段提交事件A2和另外的B1、B3事件是并发的。我们可以给出线性一致性要求的全局历史：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A1-A2、B1、B3并发- C2&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;根据线性一致性的约束，A1事件发生在A2事件之前，读到的变量x必须为旧值；C2事件发生在A2事件之后，读到的变量x必须为新值。显然在二阶段提交中这两者都是满足的。&lt;/p&gt;&#xA;&lt;p&gt;线性一致性要求单个节点的事件历史在全局历史上符合程序的先后顺序，但是对于并发事件没有约束。因此，关于B1、B2读取变量x的操作存在以下几种情况，且都满足线性一致性的所有约束。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;B1和B3都读取到A2变更前的旧值&lt;/li&gt;&#xA;&lt;li&gt;B1读取到A2变更前的旧值、B3读取到A2变更后的新值&lt;/li&gt;&#xA;&lt;li&gt;B1和B3都读取到A2变更后的新值&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;进一步地，我们可以把A2操作的两阶段提交细节步骤标注出来，如下图所示。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/116/pic/2pcZ1_hu_6fceefeae0d9705d.webp&#34; alt=&#34;两阶段提交操作细节示例&#34; width=&#34;900&#34; height=&#34;951&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这时我们可以得出结论：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;在同步时刻，一定不会发生读取变量x的操作&lt;/li&gt;&#xA;&lt;li&gt;在同步时刻之前，读变量x一定会读取到旧值&lt;/li&gt;&#xA;&lt;li&gt;在同步时刻之后，读变量x一定会读取到新值&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;上述A2操作的两阶段提交细节步骤是我们臆想绘制出来的。在实际的2PC操作中，同步时刻在2PC中的具体位置是难以确定。&lt;/p&gt;&#xA;&lt;p&gt;可见，两阶段提交不对并发事件给出保证。但我们知道，&lt;strong&gt;一定存在一个同步时刻，将两阶段提交映射到全局历史上&lt;/strong&gt;。这个时刻可能在B1之前，可能在B1和B3之间，可能在B3之后，如图所示。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/116/pic/2pcZ3_hu_c9a39b129bc8d655.webp&#34; alt=&#34;同步时刻可能所处的位置示意图&#34; width=&#34;900&#34; height=&#34;791&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;本质上，&lt;strong&gt;两阶段提交是通过给各个节点同时加锁来实现了一个全局同步的时钟&lt;/strong&gt;，这个时钟并不能够用来记录时间的长短，但足以标定出两阶段提交在全局历史中的位置，借此实现了线性一致性。&lt;/p&gt;&#xA;&lt;p&gt;到这里，我们就论证了两阶段提交满足线性一致性。&lt;/p&gt;&#xA;&lt;p&gt;当然，实现这一全局同步的时钟的代价也是很高的，它直接&lt;strong&gt;导致了所有节点的阻塞&lt;/strong&gt;，影响了分布式系统的并发性能。&lt;/p&gt;&#xA;&lt;p&gt;好，本文就介绍到这里。如果想对分布式系统的一致性有更全面系统的认识，可以参考下面的书籍。&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;&lt;img src=&#34;https://yeecode.top/img/promo/dsbook.jpg&#34; width=&#34;680&#34; height=&#34;453&#34; loading=&#34;lazy&#34;  alt=&#34;分布式系统原理与工程实践&#34; /&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;《分布式系统原理与工程实践》&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;书籍对各种一致性算法都进行了介绍，包括两阶段提交算法、三阶段提交算法等，并进行了详细分析。对大家体系化地掌握这些知识很有帮助。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;../pic/dsbook_list01.jpg&#34; alt=&#34;书籍部分目录&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;另外这本书对分布式系统相关的理论、实践、工程知识均进行了详细的介绍，层层递进，有助于大家建立完整的分布式系统知识体系。涉及&lt;strong&gt;一致性、共识、Paxos、分布式事务、服务治理、微服务、幂等、消息系统、Zookeeper&lt;/strong&gt;等。并且还发行了繁体版。&lt;/p&gt;&#xA;&lt;p&gt;再次提醒大家，在学习分布式系统时，因为涉及到的理论、框架很多。所以大家一定要理清知识脉络，否则容易学得越多越混乱。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;好了，我是程序员易哥。&lt;/p&gt;&#xA;&lt;p&gt;别忘了&lt;strong&gt;点赞&lt;/strong&gt;……&lt;/p&gt;&#xA;&lt;p&gt;这回就说这么多！&lt;/p&gt;&#xA;&lt;p&gt;可以&lt;strong&gt;关注&lt;/strong&gt;我！等我下回接着说！&lt;/p&gt;</description>
			</item>
			<item>
				<title>两阶段提交算法详解</title>
				<link>https://yeecode.top/blog/115/</link>
				<pubDate>Sun, 08 Jan 2023 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/115/</guid>
				<description>&lt;p&gt;前面的文章中我们详细介绍了线性一致性，包括线性一致性的约束等。并且，我们说两阶段提交就是一个常用的满足线性一致性的算法。&lt;/p&gt;&#xA;&lt;p&gt;接下来我们介绍下两阶段提交算法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1-背景&#34;&gt;1、 背景&lt;/h2&gt;&#xA;&lt;p&gt;假设一个分布式系统中存在多个节点，如下图所示，其中的节点A收到了数据变更请求。如果系统要满足一致性，那节点A在完成自身数据变更的同时必须协调其他节点完成数据变更。这种情况下，我们将发起操作的节点称为协调者(Coordinator)，而将接受操作的节点称为参与者(Participants)。在图中，节点A是协调者，节点B和节点C都是参与者。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/115/pic/yizhi_hu_2b0528f93e111d31.webp&#34; alt=&#34;一致性操作中的角色划分&#34; width=&#34;694&#34; height=&#34;414&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;具体实现似乎很简单，作为协调者的节点A只要在更新自身数据的同时将变更操作通知各个参与者，参与者收到协调者的变更通知后各自完成自身变更即可,如下图所示。这样，用户再从系统中读取该数据时，无论读请求落在哪个节点上，读取到的结果都是一致的。系统便满足了一致性。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/115/pic/yizhi01_hu_b07e475c62b2769c.webp&#34; alt=&#34;节点间的一致性操作&#34; width=&#34;900&#34; height=&#34;524&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;可在实际中并没有这么理想：协调者和参与者之间的&lt;strong&gt;通讯&lt;/strong&gt;可能不可靠，参与者也可能因为各种&lt;strong&gt;内部原因&lt;/strong&gt;导致更新失败。&lt;/p&gt;&#xA;&lt;p&gt;协调者更新了自身状态后通知参与者，假设某个参与者因为通讯原因或者节点自身原因更新失败，则那用户便可能从集群中读取到&lt;strong&gt;不一致的结果&lt;/strong&gt;。这时系统的一致性便被打破。&lt;/p&gt;&#xA;&lt;p&gt;发生这种不一致的根源是每个节点都能知道自身是否操作成功，但却无法知道其他节点是否更新成功。&lt;/p&gt;&#xA;&lt;p&gt;类比后面要介绍的两阶段提交和三阶段提交，我们可以将上图所示的操作称为“一阶段提交”，因为整个一致性操作过程中只有一个“提交”阶段。&lt;/p&gt;&#xA;&lt;p&gt;显然我们的“一阶段提交”并不能够很好地实现一致性操作。接下来我们要学习的就是更好的也更为实用的一致性算法：两阶段提交算法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;2-2pc的实现&#34;&gt;2、 2PC的实现&lt;/h2&gt;&#xA;&lt;p&gt;两阶段提交（Two-phase Commit，简称2PC）是一种比较简单的一致性算法（或者说协议）。它将整个提交过程分成了&lt;strong&gt;准备阶段（Prepare）&lt;/strong&gt;、**提交阶段（Commit）**这两个阶段。&lt;/p&gt;&#xA;&lt;p&gt;在准备阶段中，可以细分成如下的操作步骤：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者给参与者发送“Prepare”消息，“Prepare”消息中包含了此次更新要进行的所有操作。然后协调者等待各个参与者的响应。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Prepare”消息后将消息中的操作封装为一个事务并执行，但不要提交。&lt;/li&gt;&#xA;&lt;li&gt;参与者在执行事务的过程中如果遇到任何问题导致事务中的操作无法完成，则向协调者回应“No”消息；如果事务中的全部操作能够完成，则向协调者回应“Yes”消息。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;经过准备阶段，所有的参与者已经尝试完成了所有的操作，但是没有把这些操作提交。并且，根据将自身能否完成操作的结果回应给了协调者。接下来，便进入了第二个阶段：提交阶段。&lt;/p&gt;&#xA;&lt;p&gt;在提交阶段中，协调者会根据收集到的各个参与者的回应执行不同的操作。&lt;/p&gt;&#xA;&lt;p&gt;如果协调者收到了所有参与者的“Yes”消息，则进行如下操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“Commit”消息。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Commit”消息后，提交在准备阶段已经完成但尚未提交的事务。&lt;/li&gt;&#xA;&lt;li&gt;参与者向协调者发送“Done”消息。&lt;/li&gt;&#xA;&lt;li&gt;协调者收到所有参与者的“Done”消息，表明该一致性操作以成功的形式结束。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;如果协调者在一定时间内没有收齐所有参与者的消息，或者收到的消息中有“No”消息，则进行如下操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;协调者向参与者发送“Rollback”消息。&lt;/li&gt;&#xA;&lt;li&gt;参与者收到“Rollback”消息后，回滚在准备阶段已经完成但尚未提交的事务。&lt;/li&gt;&#xA;&lt;li&gt;参与者向协调者发送“Done”消息。&lt;/li&gt;&#xA;&lt;li&gt;协调者收到所有参与者节点的“Done”消息，表明该一致性操作以回滚的形式结束。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;可见在提交阶段，无论是决定要“Commit”还是“Rollback”，整个一致性操作都能结束。&lt;/p&gt;&#xA;&lt;p&gt;下图展示了两阶段提交的消息流。其中图的左侧部分表示一致性操作成功情况下的消息流；图的右侧部分表示因部分参与者不回应导致的一致性操作失败情况下的消息流。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/115/pic/2p_hu_8d8f95cb519f9750.webp&#34; alt=&#34;两阶段提交的消息流&#34; width=&#34;900&#34; height=&#34;673&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;上述过程中，协调者可以是一个专门起到协调作用而不参与一致性操作的节点，也可以是一个参与一致性操作的节点。如果它是后者，那它不仅要完成协调者的工作，还要作为参与者完成所有参与者要进行的工作，即它也要将操作封装成事务执行、回应“No”消息或“Yes”消息、提交或回滚事务等。&lt;/p&gt;&#xA;&lt;p&gt;上面就是两阶段提交算法的实现过程，还是十分简单的。我们可以方便地实现它。&lt;/p&gt;&#xA;&lt;h2 id=&#34;3-缺点&#34;&gt;3、 缺点&lt;/h2&gt;&#xA;&lt;p&gt;两阶段提交的操作步骤比较简单，但也有几个明显的问题。&lt;/p&gt;&#xA;&lt;p&gt;首先，两阶段提交存在&lt;strong&gt;同步阻塞问题&lt;/strong&gt;。参与者收到协调者发出的“Prepare”消息后，会开启事务完成消息中的操作。事务的开启意味着参与者的并发处理能力将受到很大的影响。而且，参与者不是一个节点而是一群节点，所以整个系统中的节点都会因为事务的开启而阻塞。这个过程可能很长，要等待协调者收集完参与者的消息并发布进一步的消息后，该过程才能结束。&lt;/p&gt;&#xA;&lt;p&gt;其次，两阶段提交&lt;strong&gt;高度依赖协调者发出的消息&lt;/strong&gt;，因此存在&lt;strong&gt;单点故障&lt;/strong&gt;。如果协调者在两阶段提交的过程中出现问题，则会导致系统失控。尤其是在准备阶段和提交阶段之间，如果此时协调者宕机，则会导致已经开启了事务的各个参与者既不能收到“Commit”消息，也不能收到“Rollback”消息。这样事务会一直开启，导致系统全局阻塞。&lt;/p&gt;&#xA;&lt;p&gt;第三，两阶段提交其实设置了一个假设：如果参与者能够收到和正常回应“Prepare”消息，那它应该也能正常收到“Commit”消息或者“Rollback”消息。通常，这个假设是成立的。因为参与者在准备阶段和提交阶段之间宕机的概率很小。但是，再小的概率也有可能发生，尤其是在高并发和多节点的情况下。一旦因为网络抖动导致部分参与者无法收到“Commit”消息，则会出现部分参与者提交了事务，部分参与者未提交事务这种&lt;strong&gt;不一致情况的发生&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;第四，两阶段提交&lt;strong&gt;存在状态丢失问题&lt;/strong&gt;。如果协调者在发出“Commit”消息或者“Rollback”消息后宕机，部分参与者收到了这条消息后提交或者回滚了事务，部分参与者没有收到这条消息。那即使重新选举出一个新的协调者，新的协调者也无法确定各个参与者到底处在哪个状态。&lt;/p&gt;&#xA;&lt;p&gt;为了解决两阶段提交的缺陷，出现了三阶段提交。&lt;/p&gt;&#xA;&lt;h2 id=&#34;4-展望&#34;&gt;4、 展望&lt;/h2&gt;&#xA;&lt;p&gt;两阶段提交算法是满足线性一致性的，《分布式系统原理与工程实践》一书给出了证明。想要详细了解的同学可以翻看该书的相关章节。&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;&lt;img src=&#34;https://yeecode.top/img/promo/dsbook.jpg&#34; width=&#34;680&#34; height=&#34;453&#34; loading=&#34;lazy&#34;  alt=&#34;分布式系统原理与工程实践&#34; /&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;《分布式系统原理与工程实践》&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;书籍对各种一致性算法都进行了介绍，包括两阶段提交算法、三阶段提交算法等，并进行了详细分析。对大家体系化地掌握这些知识很有帮助。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;../pic/dsbook_list01.jpg&#34; alt=&#34;书籍部分目录&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;另外这本书对分布式系统相关的理论、实践、工程知识均进行了详细的介绍，层层递进，有助于大家建立完整的分布式系统知识体系。涉及&lt;strong&gt;一致性、共识、Paxos、分布式事务、服务治理、微服务、幂等、消息系统、Zookeeper&lt;/strong&gt;等。并且还发行了&lt;strong&gt;繁体版&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;再次提醒大家，在学习分布式系统时，因为涉及到的理论、框架很多。所以大家一定要理清知识脉络，否则容易学得越多越混乱。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;好了，我是程序员易哥。&lt;/p&gt;&#xA;&lt;p&gt;这回就说这么多！&lt;/p&gt;&#xA;&lt;p&gt;可以&lt;strong&gt;关注&lt;/strong&gt;我！等我下回接着说！&lt;/p&gt;</description>
			</item>
			<item>
				<title>什么是线性一致性？</title>
				<link>https://yeecode.top/blog/114/</link>
				<pubDate>Sun, 08 Jan 2023 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/114/</guid>
				<description>&lt;p&gt;线性一致性（Linearizability）又叫原子一致性（Atomic Consistency)这是现实中能实现的最高级的一致性级别，当然也是分布式系统的最高追求。&lt;/p&gt;&#xA;&lt;p&gt;然而要理解线性一致性（Linearizability），则必须先要理解顺序一致性（Sequential Consistency）。对于顺序一致性不是很理解的同学，可以翻看我之前的文章。&lt;/p&gt;&#xA;&lt;p&gt;我们这里就直接给出顺序一致性的两个约束：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;单个节点的事件历史在全局历史上符合程序的先后顺序&lt;/li&gt;&#xA;&lt;li&gt;全局事件历史在各个节点上一致&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;线性一致性在顺序一致性的基础上增加了一个约束：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;如果事件A的开始时间晚于事件B的结束时间，则在全局历史中，B在A之前&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;于是，线性一致性的约束变为了三个，即：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;单个节点的事件历史在全局历史上符合程序的先后顺序&lt;/li&gt;&#xA;&lt;li&gt;全局事件历史在各个节点上一致&lt;/li&gt;&#xA;&lt;li&gt;如果事件A的开始时间晚于事件B的结束时间，则在全局历史中，B在A之前&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;有了新增的这一个约束之后，我们就可以发现满足顺序一致性的下图（这就是我们在讨论顺序一致性时用过的图）不满足线性一致性。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/114/pic/lc_hu_31bdc441edbda9b7.webp&#34; alt=&#34;满足顺序一致性的事件&#34; width=&#34;898&#34; height=&#34;970&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;因为根据线性一致性新增的约束，B1的开始时间晚于A1的结束时间，那么在全局历史中，A1要在B1之前。但是B1却没有读到A1的操作结果，这显然是相悖的。&lt;/p&gt;&#xA;&lt;p&gt;同样的，A2要在B2之前，两者的结果是相悖的；C1要在B1之前，C1读到了A1的结果但B1却没有，这两个结果也是相悖的。&lt;/p&gt;&#xA;&lt;p&gt;于是上图中的事件顺序无法同时满足线性一致性的三个约束。&lt;/p&gt;&#xA;&lt;p&gt;在时序图中，越往下代表时间越晚。通过时序图我们可以清楚地知道各个节点中事件在全局的先后顺序。&lt;/p&gt;&#xA;&lt;p&gt;然而我们要明确，时序图实际是全局上帝视角。在计算机系统看来，每一个节点都只知道自身时间的先后顺序（例如A1在A2之前），但是却不知道节点间的先后顺序（例如A1到底是在B2之前还是B2之后）。&lt;/p&gt;&#xA;&lt;p&gt;但是线性一致性要求节点间事件满足全局先后顺序的约束，这就要求分布式系统必须协调出一个&lt;strong&gt;全局同步的时钟&lt;/strong&gt;。这一全局时钟不要求绝对精准，只要求能区分出事件的&lt;strong&gt;先后顺序&lt;/strong&gt;即可。但即便如此，这也是一个成本很高的工作。因此，线性一致性新增加的约束是一个&lt;strong&gt;很强的约束&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;这就是为什么我们说线性一致性是分布式系统的最高追求。因为，它极为严格。&lt;/p&gt;&#xA;&lt;p&gt;全局锁就是一个常用的全局同步时钟。全局锁将全局时间分割为锁存在前、锁存在期间、锁释放后三段。这三段的先后关系是绝对成立的。基于此，便可以实现事件先后顺序的区分。&lt;/p&gt;&#xA;&lt;p&gt;如下图中，假设我们为B1事件增加全局的锁，则A1、A2、C1事件发生在锁存在前，一定在在B1事件之前；C2时间发生在锁释放后，一定在B1事件之后。这样，便确定了B1事件在全局中的位置为晚于A1、A2、C1，且早于C2。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/114/pic/lcs_hu_5573a9e94cfb5f72.webp&#34; alt=&#34;全局锁的作用&#34; width=&#34;900&#34; height=&#34;773&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;线性一致性通过“事件A的开始时间晚于事件B的结束时间”这样的描述增加了对节点间先后事件的限制，但&lt;strong&gt;没有对并发事件进行限制&lt;/strong&gt;。下图中，A1和C1是并发的。事件C1无论读出的是x=5还是x=0都不违反线性一致性约束，因为这两个事件是并发的。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/114/pic/lcxx_hu_20eefdfe8c65846e.webp&#34; alt=&#34;事件的并发示意图&#34; width=&#34;898&#34; height=&#34;970&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;可什么样的系统能做到线性一致性呢？&lt;/p&gt;&#xA;&lt;p&gt;为了实现线性一致性，可以将数据的变更和同步看作一个整体，不能允许外界读取一个已经变更但尚未完全同步的数据。&lt;/p&gt;&#xA;&lt;p&gt;最简单的，我们可以给每个操作都增加锁，从而使得&lt;strong&gt;全局串行化&lt;/strong&gt;，保证系统满足线性一致性要求，如下图所示。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/114/pic/lcsqu_hu_a96dcba0c3593f2a.webp&#34; alt=&#34;系统内部节点同步示意图&#34; width=&#34;900&#34; height=&#34;1538&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;但全局串行化对系统并发性能的损耗太大，因此很少被实际使用。在具体实施过程中，存在许多效率更高的满足线性一致性的算法，两阶段提交算法、三阶段提交算法。&lt;/p&gt;&#xA;&lt;p&gt;对于上述这些算法，我们就不再展开讲了。感兴趣的读者可以阅读《分布式系统原理与工程实践》一书。&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;&lt;img src=&#34;https://yeecode.top/img/promo/dsbook.jpg&#34; width=&#34;680&#34; height=&#34;453&#34; loading=&#34;lazy&#34;  alt=&#34;分布式系统原理与工程实践&#34; /&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;《分布式系统原理与工程实践》&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;书中对上述算法的原理和使用进行了明确的剖析，并且对上述这些算法满足线性一致性进行了证明。对大家体系化地掌握这些知识很有帮助。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;../pic/dsbook_list01.jpg&#34; alt=&#34;书籍部分目录&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;另外这本书对分布式系统相关的理论、实践、工程知识均进行了详细的介绍，层层递进，有助于大家建立完整的分布式系统知识体系。涉及&lt;strong&gt;一致性、共识、Paxos、分布式事务、服务治理、微服务、幂等、消息系统、Zookeeper&lt;/strong&gt;等。并且还发行了繁体版。&lt;/p&gt;&#xA;&lt;p&gt;另外，在学习分布式系统时，因为涉及到的理论、框架很多。所以大家更要理清知识脉络，否则容易学得越多越混乱。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;好了，我是程序员易哥。&lt;/p&gt;&#xA;&lt;p&gt;这回就说这么多！&lt;/p&gt;&#xA;&lt;p&gt;可以&lt;strong&gt;关注&lt;/strong&gt;我！等我下回接着说！&lt;/p&gt;</description>
			</item>
			<item>
				<title>什么是顺序一致性？</title>
				<link>https://yeecode.top/blog/113/</link>
				<pubDate>Sat, 07 Jan 2023 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/113/</guid>
				<description>&lt;p&gt;在学习分布式系统时，我们需要清晰理解“&lt;strong&gt;一致性（Consistency）&lt;/strong&gt;”这一概念。&lt;/p&gt;&#xA;&lt;p&gt;分布式系统中的“一致性（Consistency）”是说数据副本存放在分布式系统中的不同节点上，如果用户修改了系统中的数据，则在一定时间后，用户能从系统中读取到修改后的数据。&lt;/p&gt;&#xA;&lt;p&gt;或者换一种说法，&lt;strong&gt;用户在分布式系统的某个节点上进行了变更操作，则在一定时间后，用户能从系统的任意节点上读取到这个变更结果。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;而一致性有强弱之分，这就是总要强调“&lt;strong&gt;经过一定时间后&lt;/strong&gt;”的原因。&lt;/p&gt;&#xA;&lt;p&gt;那这个时间到底要多长呢？在这个时间之前读取又会得到怎样的结果呢？回答这个问题便涉及到一致性的强弱概念。也正是根据一致性强弱的不同，我们把一致性分为了很多类。&lt;/p&gt;&#xA;&lt;p&gt;而其中，顺序一致性（Sequential Consistency）是非常重要且基础的一类。&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;    &lt;p&gt;线性一致性就是以顺序一致性为基础定义的。&#xA;顺序一致性在1979年提出，线性一致性则是1987年在顺序一致性的基础上增加了约束得来的。&lt;/p&gt;&#xA;&#xA;  &lt;/blockquote&gt;&lt;p&gt;顺序一致性（Sequential Consistency）提出了两个约束：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;单个节点的事件历史在全局历史上符合程序的先后顺序&lt;/li&gt;&#xA;&lt;li&gt;全局事件历史在各个节点上一致&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;我们可以根据这两个约束来判断一个系统是否满足顺序一致性：如果在系统中找不到任何一个符合上述两个约束的&lt;strong&gt;全局事件历史&lt;/strong&gt;，则说明该系统一定不满足顺序一致性；如果能找到一个符合上述两个约束的全局事件历史，这说明系统在这段过程内是满足顺序一致性的。&lt;/p&gt;&#xA;&lt;p&gt;这个约束描述起来可能稍有拗口，我们通过示例来解释说明。&lt;/p&gt;&#xA;&lt;p&gt;假设分布式系统存在A、B、C三个节点，初始值x=0、y=0，各个节点上发生的事件如图所示。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/113/pic/sc_hu_50ef14fae9a390a4.webp&#34; alt=&#34;不满足顺序一致性的事件&#34; width=&#34;898&#34; height=&#34;970&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;B2读出y=3意味着在全局历史中A2在B2之前（记作A2-B2），B3读出x=0意味着全局历史中B3在A1之前（记作A2-B2，且B3-A1），而节点A的历史决定了A1在A2之前（记作B3-A1-A2-B2），节点B的历史决定了B2在B3之前（记作B3-A1-A2-B2，且B2-B3）。显然不存在一个全局历史能够将A1、A2、B2、B3排列起来，且满足上面的各个排序要求。&lt;/p&gt;&#xA;&lt;p&gt;而下图所示的事件是满足顺序一致性的。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/113/pic/lc_hu_31bdc441edbda9b7.webp&#34; alt=&#34;满足顺序一致性的事件&#34; width=&#34;898&#34; height=&#34;970&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;在上图中，我们能够找到满足以上约束的全局历史，例如：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;B1-B2-A1-B3-A2-C1-C2&lt;/li&gt;&#xA;&lt;li&gt;B1-A1-B2-B3-A2-C1-C2&lt;/li&gt;&#xA;&lt;li&gt;B1-A1-C1-B2-A2-C2-B3&lt;/li&gt;&#xA;&lt;li&gt;……&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这样的全局历史还可以找出很多，这意味着目前的这些片段是满足顺序一致性的。而如果一个系统的工作中，其全部事件都能满足顺序一致性，那这个系统就满足顺序一致性。&lt;/p&gt;&#xA;&lt;p&gt;可见，明确顺序一致性的两个约束是十分重要的。基于这两个约束，我们就可以判断一个分布式系统是否满足顺序一致性。&lt;/p&gt;&#xA;&lt;p&gt;在后面的文章中，我们会在顺序一致性的基础上，介绍线性一致性。这也是一个十分常用的一致性。&lt;/p&gt;&#xA;&lt;p&gt;关于更多一致性的内容，以及分布式系统的知识，大家可以参照下面的书籍。&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;&lt;img src=&#34;https://yeecode.top/img/promo/dsbook.jpg&#34; width=&#34;680&#34; height=&#34;453&#34; loading=&#34;lazy&#34;  alt=&#34;分布式系统原理与工程实践&#34; /&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;《分布式系统原理与工程实践》&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;书籍对常用的一致性进行了详细的介绍，还介绍了一致性相关算法等。对大家体系化地掌握这些知识很有帮助。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;../pic/dsbook_list01.jpg&#34; alt=&#34;书籍部分目录&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这本书对分布式系统相关的&lt;strong&gt;理论、实践、工程&lt;/strong&gt;知识均进行了详细的介绍，层层递进，有助于大家建立完整的分布式系统知识体系。当然，书中也对各种“一致性”级别也进行分析，还分析了&lt;strong&gt;Paxos算法、Zookeeper&lt;/strong&gt;等。并且还发行了&lt;strong&gt;繁体版&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;好了，我是程序员易哥。&lt;/p&gt;&#xA;&lt;p&gt;这回就说这么多！&lt;/p&gt;&#xA;&lt;p&gt;可以&lt;strong&gt;关注&lt;/strong&gt;我！等我下回接着说！&lt;/p&gt;</description>
			</item>
			<item>
				<title>事务的“一致性”和分布式“一致性”完全不是同一个概念！</title>
				<link>https://yeecode.top/blog/112/</link>
				<pubDate>Sun, 25 Dec 2022 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/112/</guid>
				<description>&lt;p&gt;在前面的文章中，我们已经讲了：分布式系统中所说的一致性（CAP一致性）和数据库事务中所说的一致性（ACID一致性）完全不是同一个概念。&lt;/p&gt;&#xA;&lt;p&gt;CAP一致性是说：&lt;strong&gt;用户在分布式系统的某个节点上进行了变更操作，则在一定时间后，用户能从系统的任意节点上读取到这个变更结果。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;ACID一致性是说：&lt;strong&gt;事务的执行不会破坏数据库的完整性约束&lt;/strong&gt;，所谓的完整性约束包括数据关系的完整性和业务逻辑的完整性。因此，这里的“一致性”指的是完整性约束不会破坏。&lt;/p&gt;&#xA;&lt;p&gt;哪有人会问，两者之间有没有什么关联呢？&lt;/p&gt;&#xA;&lt;p&gt;如果真要找，也能找到。只发生在一些很特殊的场景下。&lt;/p&gt;&#xA;&lt;p&gt;我们已经知道ACID一致性讨论的是事务，CAP一致性讨论的是分布式。那在分布式事务中，这两种一致性会存在交集。如图所示。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/112/pic/2yizhix_hu_626e2339dfb2ef0b.webp&#34; alt=&#34;分布式事务示意图&#34; width=&#34;646&#34; height=&#34;476&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;假设存在一个支持事务操作的分布式数据库。&lt;/p&gt;&#xA;&lt;p&gt;那作为数据库，它应该满足CAP一致性，否则数据库中的值没有意义。例如你从数据库的某个节点中读取到变量的值为1，而从数据库的另一个节点中读取到同一变量的值为3，则无法判断哪一个值是正确的。这样无论值1还是值3都没有意义。&lt;/p&gt;&#xA;&lt;p&gt;又因为这个分布式数据库支持事务，则它应该满足ACID一致性。&lt;/p&gt;&#xA;&lt;p&gt;这时候我们发现，CAP一致性是ACID一致性的基础。即如果CAP一致性不成立，则分布式数据库各个节点的数据不一致且没有意义，那么ACID一致性要求的完整性约束便断然无法满足。&lt;/p&gt;&#xA;&lt;p&gt;除了上图所示的情况外，CAP一致性和ACID一致性少有交集。在平时的理论学习和工程实践中，区分好这两种一致性概念非常重要，否则很容易陷入疑惑和混沌。&lt;/p&gt;&#xA;&lt;p&gt;所以，还是建议大家将这些概念理清楚，避免学的越多混的越乱……。推荐大家一本书：&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;&lt;img src=&#34;https://yeecode.top/img/promo/dsbook.jpg&#34; width=&#34;680&#34; height=&#34;453&#34; loading=&#34;lazy&#34;  alt=&#34;分布式系统原理与工程实践&#34; /&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;《分布式系统原理与工程实践》&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;书籍对常用的一致性进行了详细的介绍，包括分布式系统中的一致性级别，还介绍了一致性相关算法等。对大家体系化地掌握这些知识很有帮助。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;../pic/dsbook_list01.jpg&#34; alt=&#34;书籍部分目录&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这本书对分布式系统相关的&lt;strong&gt;理论、实践、工程&lt;/strong&gt;知识均进行了详细的介绍，层层递进，有助于大家建立完整的分布式系统知识体系。当然，书中也对各种“一致性”进行了分析。并且本书备受好评，以至于还发行了&lt;strong&gt;繁体版&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;好了，我是程序员易哥。&lt;/p&gt;&#xA;&lt;p&gt;这回就说这么多！&lt;/p&gt;&#xA;&lt;p&gt;可以&lt;strong&gt;关注&lt;/strong&gt;我！等我下回接着说！&lt;/p&gt;</description>
			</item>
			<item>
				<title>分布式中的“一致性”，到底指的是什么？</title>
				<link>https://yeecode.top/blog/111/</link>
				<pubDate>Sun, 20 Nov 2022 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/111/</guid>
				<description>&lt;h2 id=&#34;众多的一致性&#34;&gt;众多的“一致性”&lt;/h2&gt;&#xA;&lt;p&gt;说到一致性，大家都不陌生。随着分布式系统、微服务系统、区块链等技术的发展，“一致性”一词出现的频率也越来越高。&lt;/p&gt;&#xA;&lt;p&gt;然而，“一致性”这一词语所代表的概念却并不唯一。例如我们常听到“事务的一致性”、“最终一致性”、“一致性哈希”等，它们表述的&lt;strong&gt;并不是同一个概念&lt;/strong&gt;。理解这点十分重要。如果错误地认为以上几个“一致性”都指同一个概念，那就搞混了。&lt;/p&gt;&#xA;&lt;p&gt;在明确以上概念各不相同的基础上，我们介绍下&lt;strong&gt;分布式系统中的“一致性”&lt;/strong&gt;（例如“最终一致性”中的“一致性”）到底指的是什么。&lt;/p&gt;&#xA;&lt;h2 id=&#34;cap一致性&#34;&gt;CAP一致性&lt;/h2&gt;&#xA;&lt;p&gt;我们所说的“最终一致性”中的“一致性（Consistency）”是说数据副本存放在分布式系统中的不同节点上，如果用户修改了系统中的数据，则在一定时间后，用户能从系统中读取到修改后的数据。&lt;/p&gt;&#xA;&lt;p&gt;或者换一种说法，&lt;strong&gt;用户在分布式系统的某个节点上进行了变更操作，则在一定时间后，用户能从系统的任意节点上读取到这个变更结果。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;因此，这里的“一致性”指的是针对分布式系统的各个节点对外的表现是一致的，就像是一个节点一样。&lt;/p&gt;&#xA;&lt;p&gt;例如在图所示的分布式系统中存在大量的节点。我们设置a=5，这一操作可能落在任意一个节点上（图中所示写请求落在了节点A上），则在一定时间之后，访问系统一定能读到a=5（图中所示读请求落在了节点H上），则说明这个分布式系统满足一致性。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/111/pic/capC1_hu_d67cf953fe535081.webp&#34; alt=&#34;分布式系统的一致性示意图&#34; width=&#34;900&#34; height=&#34;475&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;为了便于表述，我们将这种一致性称为“CAP一致性”。&lt;/p&gt;&#xA;&lt;p&gt;要注意的是，我们虽然以同质节点（指这些节点运行同样的代码）进行了举例，但是CAP一致性对于异质节点同样也是成立的。例如分布式应用中存在异质的订单处理节点A和库存管理节点B。如果该分布式应用满足CAP一致性，则当我们向订单处理节点A发送生成新订单的请求一定时间后，能从库存管理节点B上读取到新订单引发的库存变化。&lt;/p&gt;&#xA;&lt;h2 id=&#34;cap一致性的强弱&#34;&gt;CAP一致性的强弱&lt;/h2&gt;&#xA;&lt;p&gt;在介绍一致性的概念时，我们说分布式系统满足一致性意味着用户通过某一个节点修改了数据，经过一定时间后，用户可以在任意节点上读取到修改后的数据。&lt;/p&gt;&#xA;&lt;p&gt;为什么总要强调“&lt;strong&gt;经过一定时间后&lt;/strong&gt;”呢？这个时间到底要多长呢？在这个时间之前读取又会得到怎样的结果呢？&lt;/p&gt;&#xA;&lt;p&gt;解答上述一连串的问题便涉及到&lt;strong&gt;一致性的强弱&lt;/strong&gt;概念。也正是根据一致性强弱的不同，我们把一致性分为了很多类。我们常见的，也是经常会用到的有：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;严格一致性&lt;/li&gt;&#xA;&lt;li&gt;顺序一致性&lt;/li&gt;&#xA;&lt;li&gt;线性一致性&lt;/li&gt;&#xA;&lt;li&gt;最终一致性&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;当然，还有很多的一致性级别，例如因果一致性、会话一致性、单调读一致性、单调写一致性等。&lt;/p&gt;&#xA;&lt;p&gt;对于以上各个一致性级别的判别和证明，一句话说不明白。如果大家有兴趣可以参考下面的书籍。&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;&lt;img src=&#34;https://yeecode.top/img/promo/dsbook.jpg&#34; width=&#34;680&#34; height=&#34;453&#34; loading=&#34;lazy&#34;  alt=&#34;分布式系统原理与工程实践&#34; /&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;《分布式系统原理与工程实践》&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;书籍对各种一致性都进行了详细的介绍。对大家体系化地掌握这些知识很有帮助。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;../pic/dsbook_list01.jpg&#34; alt=&#34;书籍部分目录&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这本书对分布式系统相关的理论、实践、工程知识均进行了详细的介绍，层层递进，有助于大家建立完整的分布式系统知识体系。当然，书中也对各种“一致性”进行了分析。并且本书备受好评，以至于还发行了繁体版。&lt;/p&gt;&#xA;&lt;p&gt;此外，一致性也有强弱之分。但要注意，这只是一个相对的概念。并不能明确地说明那些一致性属于强一致性，那些一致性属于弱一致性。网上确实有一些将某某一致性归为强一致性还是弱一致性的争论，则是没有太大意义的。因为强、弱是倾向性的概念，而没有确切的定义。&lt;/p&gt;&#xA;&lt;h2 id=&#34;其他的一致性&#34;&gt;其他的一致性&lt;/h2&gt;&#xA;&lt;p&gt;以上我们们所述的都是CAP一致性。&lt;/p&gt;&#xA;&lt;p&gt;而我们还会在其他场合见到“一致性”这个词语，如“事务的一致性”、“一致性哈希”。这个都和CAP一致性（也就是分布式系统中的一致性）不是一个概念，别搞混了。如果大家想要了解其他的一致性，并且对这些概念进行梳理，可以参考《分布式系统原理与工程实践》这本书籍。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;好了，我是程序员易哥。&lt;/p&gt;&#xA;&lt;p&gt;这回就说这么多！&lt;/p&gt;&#xA;&lt;p&gt;可以&lt;strong&gt;关注&lt;/strong&gt;我！等我下回接着说！&lt;/p&gt;</description>
			</item>
			<item>
				<title>RPC原理详解与实现</title>
				<link>https://yeecode.top/blog/109/</link>
				<pubDate>Sun, 05 Jun 2022 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/109/</guid>
				<description>&lt;h2 id=&#34;概述&#34;&gt;概述&lt;/h2&gt;&#xA;&lt;p&gt;初看起来，远程过程调用（Remote Procedure Call，简称RPC）是一个比较复杂的名字。但是这个名字起得真的确实好，功能如其名：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;远程&lt;/strong&gt;：指的是需要经过网络的，而不是应用内部、机器内部进行的。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;过程&lt;/strong&gt;：也就是方法。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;那“远程过程调用”，就是：&lt;strong&gt;可以跨过一段网络，调用另外一个网络节点上的方法&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;以上就是对远程过程调用的简单理解。&lt;/p&gt;&#xA;&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;p&gt;远程过程调用的广泛使用，是伴随着分布式系统的普及发生的。要了解它的背景，我们需要从这里开始讲起。&lt;/p&gt;&#xA;&lt;p&gt;单体应用内部存在&lt;strong&gt;模块间的调用&lt;/strong&gt;，这种调用发生在应用内。通常，一个模块可以直接调用另一个模块中的类、对象、方法，十分方便。并且这种调用发生在同一个机器内，甚至是同一个进程、线程内，&lt;strong&gt;十分高效&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;应用之间也会存在调用&lt;/strong&gt;，常基于接口实现。调用过程中会涉及到序列化、反序列化、网络传输、参数校验等多个环节，但因为其发生&lt;strong&gt;频率很低&lt;/strong&gt;，也是可以接受的。&lt;/p&gt;&#xA;&lt;p&gt;分布式应用内部的节点之间也会存在调用。这种调用由单体应用的模块间调用演化而来，其&lt;strong&gt;调用频率是相对较高的&lt;/strong&gt;。但是，他们之间的调用已经&lt;strong&gt;无法通过应用的内部调用来实现&lt;/strong&gt;，基于接口的调用则成本太高、效率太低。这时需要一种能够跨节点的、相对低成本和高效的方式来解决节点间的调用问题，这个问题如下图所示。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/109/pic/diaoyongpinlv_hu_17133fed9a1a7e05.webp&#34; alt=&#34;节点调用问题&#34; width=&#34;900&#34; height=&#34;307&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;“高内聚、低耦合”是软件设计尤其是面向对象设计中的一个重要原则。依据此原则设计的软件系统，由下到上的每一层级都会提升自身的内聚性，降低与外界的耦合。最终使得整个系统中，层级越低的组织间耦合越高，层级越高的组织间耦合越低。&lt;/p&gt;&#xA;&lt;p&gt;“高内聚、低耦合”这一原则最终会反映在组织间的互相调用上。最终，&lt;strong&gt;层级越低的组织间互相调用的频率越高，层级越高的组织间互相调用的频率越低&lt;/strong&gt;。如上图所示。以上图所示的应用、节点、模块组成的三层的软件结构为例。应用处在最高层，应用间的耦合是很低的，它们间的调用是低频的。节点处在中间层，它们间的耦合居中，其调用频率也是居中的。模块处在最底层，它们之间的耦合最高，模块之间的调用频率也最高。&lt;/p&gt;&#xA;&lt;p&gt;节点间的调用，也常被称为服务调用，是需要跨机器的，而其发生频率介于应用间调用和模块间调用之间，是相对高频的。因此&lt;strong&gt;需要一种相对简单高效的、支持跨机器的调用方式，这就是服务调用要解决的问题&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;那显然这种调用方式要满足如下几点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;能够跨机器&lt;/strong&gt;。因为分布式系统的节点往往部署在不同的机器上。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;运行效率高&lt;/strong&gt;。要能够简化各种不必要的包装环节，提升有效信息的比例。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;使用方便&lt;/strong&gt;。用户能够无感知地使用，降低进行调用时候的使用成本。这里主要包括透明性&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;，尤其是其中的访问透明性。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;而远程过程调用则是满足上述要求的不错选择。&lt;/p&gt;&#xA;&lt;h2 id=&#34;原理&#34;&gt;原理&lt;/h2&gt;&#xA;&lt;p&gt;远程过程调用使得服务可以像调用本地方法一样调用网络上另一个服务中的方法。可这一切是怎么实现的呢？接下来，我们介绍下它的具体原理。&lt;/p&gt;&#xA;&lt;p&gt;在使用远程过程调用前，服务提供方需要将自身服务的接口文件导出。而服务调用方则要引入这些接口文件。&lt;/p&gt;&#xA;&lt;p&gt;进行远程过程调用时，服务提供方只需要&lt;strong&gt;调用接口文件中的接口&lt;/strong&gt;，便&lt;strong&gt;相当于调用了服务提供方中的具体实现方法&lt;/strong&gt;，并得到服务提供方给出的执行结果。调用其他服务中的方法就像调用本地方法一样方便。如图所示。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/109/pic/jyjk00_hu_f2cae20302f36bc1.webp&#34; alt=&#34;远程过程调用的流程&#34; width=&#34;900&#34; height=&#34;395&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;接下来我们从服务调用方、通信、服务提供方三部分介绍远程过程调用的具体实现过程。&lt;/p&gt;&#xA;&lt;h2 id=&#34;服务调用方&#34;&gt;服务调用方&lt;/h2&gt;&#xA;&lt;p&gt;服务调用方在本地调用服务提供方给出的接口后，相当于远程调用了该接口的具体实现。这主要用到了&lt;strong&gt;动态代理&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;动态代理能够为原本的空接口注入一个代理实现。于是，服务调用方对接口的调用便转化为了对代理实现的调用。&lt;/p&gt;&#xA;&lt;p&gt;在代理实现中，会向服务注册中心查询服务提供方的具体地址、端口，并将调用参数序列化，然后向服务提供方发送调用请求。之后，代理实现还会接收请求的回应，并通过接口返回给服务调用方的业务逻辑。&lt;/p&gt;&#xA;&lt;h2 id=&#34;通信&#34;&gt;通信&lt;/h2&gt;&#xA;&lt;p&gt;根据OSI（Open System Interconnect，开放式系统互联）模型，将网络通信的工作划分为图所示的七层。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/109/pic/osi_hu_dd63328acf90af6.webp&#34; alt=&#34;图&#34; width=&#34;900&#34; height=&#34;552&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;RPC在工作时，通常使用第七层的HTTP协议或者第四层的TCP协议、UDP协议在两个节点之间进行通信。&lt;/p&gt;&#xA;&lt;p&gt;相比而言，HTTP协议工作在第七层，对传输的信息进行了多层的封装，因此有用信息占比低，效率比较低，但使用更为简单；TCP协议、UDP协议工作在第四层，减少了封装的次数，因此有用信息占比高，效率比较高，但使用略为复杂。&lt;/p&gt;&#xA;&lt;h2 id=&#34;服务提供方&#34;&gt;服务提供方&lt;/h2&gt;&#xA;&lt;p&gt;服务提供方在接受到调用请求后，需要定位到请求所要调用的具体方法。然后将请求中的参数反序列化后展开对方法的实际调用。并在调用结束后将执行结果返回。&lt;/p&gt;&#xA;&lt;h2 id=&#34;实践&#34;&gt;实践&lt;/h2&gt;&#xA;&lt;p&gt;那要想实现这个过程该怎么办呢？别急，咱们一步一步来。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;首先&lt;/strong&gt;，调用方调用的是接口，必须得为接口构造一个假的实现。显然，要使用动态代理。这样，调用方的调用就被动态代理接收到了。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;第二&lt;/strong&gt;，动态代理接收到调用后，应该想办法调用远程的实际实现。这包括下面几步：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;识别具体要调用的远程方法的IP、端口&lt;/li&gt;&#xA;&lt;li&gt;将调用方法的入参进行序列化&lt;/li&gt;&#xA;&lt;li&gt;通过通信将请求发送到远程的方法中&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;strong&gt;第三&lt;/strong&gt;，远程的服务接收到了调用方的请求后，它应该：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;反序列化各个调用参数&lt;/li&gt;&#xA;&lt;li&gt;定位到实际要调用的方法，然后输入参数，执行方法&lt;/li&gt;&#xA;&lt;li&gt;按照调用的路径返回调用的结果&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;整个过程如下所示，虚线框内的部分是RPC框架实现的功能。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/109/pic/jyjk01_hu_17ad4af6307ab0c1.webp&#34; alt=&#34;远程过程调用的实现过程&#34; width=&#34;900&#34; height=&#34;607&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;当然在具体实现中，还需要解决一些细节问题。例如，如何具体定位要调用的方法，如何确定参数的类型等等。而至于成熟的框架，则更为复杂了。&lt;/p&gt;&#xA;&lt;p&gt;为了让大家更好地理解RPC的实现，我们直接编写了一个极简（可能是最简单的了）的RPC示例项目。该实例只用少量的几个类便实现了RPC功能，并且配有服务调用方和服务提供方的展示示例。成熟的框架要比我们的项目复杂的多，但越是简单的项目，越能让大家理解其基本原理。项目地址为：https://github.com/yeecode/EasyRPC&lt;/p&gt;&#xA;&lt;p&gt;下面是&lt;strong&gt;客户端的代码结构&lt;/strong&gt;，看着类有点多，其实代码不长。其中的RPC代码完成完成动态代理、远程调用参数序列化、远程调用发起、远程调用结果反序列化的工作。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/109/pic/z01_hu_4af3050f9f722797.webp&#34; alt=&#34;图&#34; width=&#34;478&#34; height=&#34;347&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;下面是&lt;strong&gt;服务端的代码结构&lt;/strong&gt;，代码更少，完成远程调用接收、调用参数反序列化、调用实际触发、调用结果序列化的工作。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/109/pic/z02_hu_5da7357446db5521.webp&#34; alt=&#34;图&#34; width=&#34;466&#34; height=&#34;242&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这样，一个RPC小框架就做完了，并不复杂。&lt;/p&gt;&#xA;&lt;p&gt;大家可以查看代码，了解其具体实现。&lt;/p&gt;&#xA;&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;RPC是易用的&lt;/strong&gt;。它是一个涉及动态代理、序列化、通信、反序列化的复杂过程，但是，以上&lt;strong&gt;这些过程都被RPC框架隐藏了起来&lt;/strong&gt;。在使用RPC框架时，我们只需要调用服务提供方的接口便可以调用到服务提供方的具体实现，而不用关心其实现细节。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;RPC是高效的&lt;/strong&gt;。它通过将底层的通信协议封装了起来，RPC可以基于第四层的协议来&lt;strong&gt;提升信息传输的效率&lt;/strong&gt;，并可以自由设计通信格式。&lt;/p&gt;&#xA;&lt;p&gt;但是，RPC也有副作用。RPC的使用使得服务提供方不需要给出HTTP接口。这对非RPC的调用是不友好的，可见，&lt;strong&gt;RPC调用损失了服务的通用性、可读性&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;该回答参考了书籍《分布式系统原理与工程实践》。书中还介绍了RPC如何结合注册中心模型使用，如何在服务调用方的代理实现中完成服务提供方的地址查询等内容。想了解的同学可以自行阅读。&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;&lt;img src=&#34;https://yeecode.top/img/promo/dsbook.jpg&#34; width=&#34;680&#34; height=&#34;453&#34; loading=&#34;lazy&#34;  alt=&#34;分布式系统原理与工程实践&#34; /&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;amp;p=JF8BAMYJK1olXDYCVl9YAEkUBV9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksVAmoAGVgTQl9HCANtb05yfSYIcEV3CVJgMgctdStjWGwSa1cZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCk0UBWoMHFwQXDYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAIWBgRC2YLTFMWDQQHUVkKWx4SBDsNHVMdDwQLB1YPCnsVAm4MEms&#34;&gt;《分布式系统原理与工程实践》&lt;/a&gt;&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
