Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >聊聊【微服务架构】下【分布式系统的问题】

聊聊【微服务架构】下【分布式系统的问题】

作者头像
田维常
发布于 2020-06-28 09:55:48
发布于 2020-06-28 09:55:48
5080
举报

当前最流行的微服务架构,你知道微服务架构下分布式系统会有哪些问题吗?

前言

无论是 SOA 或者微服务架构,都是必须要面对和解决一些分布式场景下的问题。如果确实用不到微服务,或者勇哥简单的主备就解决了。那么对于程序员来说那真是太幸福了,bug都会少很多。

可惜了,当下最流行的就是微服务架构,然而在分布式系统中,如果想当然的去按照单服务思想编程和架构,那可能会收获很多意想不到的“惊喜”:网络延迟导致的重复提交、数据不一致、部分节点挂掉但是任务处理了一半等。在分布式系统环境下编程和在单机器系统上写软件最大的差别就是,分布式环境下会有很多很“诡异”的方式出错,所以我们需要理解哪些是不能依靠的,以及如何处理分布式系统的各种问题。

SOA架构和微服务架构的区别,首先SOA和微服务架构一个层面的东西,而对于ESB和微服务网关是一个层面的东西,一个谈到是架构风格和方法,一个谈的是实现工具或组件。 1.SOA(Service Oriented Architecture)“面向服务的架构”:他是一种设计方法,其中包含多个服务, 服务之间通过相互依赖最终提供一系列的功能。一个服务 通常以独立的形式存在与操作系统进程中。各个服务之间 通过网络调用。 2.微服务架构:其实和 SOA 架构类似,微服务是在 SOA 上做的升华,微服务架构强调的一个重点是“业务需要彻底的组件化和服务化”,原有的单个业务系统会拆分为多个可以独立开发、设计、运行的小应用。这些小应用之间通过服务完成交互和集成。 微服务架构 = 80%的SOA服务架构思想 + 100%的组件化架构思想 + 80%的领域建模思想

理想和现实

微服务架构跟 SOA 一样,也是服务化的思想。在微服务中,我们倾向于使用 RESTful 风格的接口进行通信,使用 Docker 来管理服务实例。我们的理想是希望分布式系统能像在单个机器中运行一样,就像客户端应用,再坏的情况,用户只要一键重启就可以重新恢复,然而现实是我们必须面对分布式环境下的由网络延迟、节点崩溃等导致的各种突发情况。

在决定使用分布式系统,或者微服务架构的时候,往往是因为我们希望获得更好的伸缩性、更好的性能、高可用性(容错)。虽然分布式系统环境更加复杂,但只要能了解分布式系统的问题以及找到适合自己应用场景的方案,便能更接近理想的开发环境,同时也能获得伸缩性、性能、可用性。

分布式系统的可能问题

分布式系统从结构上来看,是由多台机器节点,以及保证节点间通信的网络组成,所以需要关注节点、网络的特征。

(1)部分失败

在分布式环境下,有可能是节点挂了,或者是网络断了,如下图:

如果系统中的某个节点挂掉了,但是其他节点可以正常提供服务,这种部分失败,不像单台机器或者本地服务那样好处理。单机的多线程对象可以通过机器的资源进行协调和同步,以及决定如何进行错误恢复。但在分布式环境下,没有一个可以来进行协调同步、资源分配以及进行故障恢复的节点,部分失败一般是无法预测的,有时甚至无法知道请求任务是否有被成功处理。

所以在开发需要进行网络通讯的接口时(RPC 或者异步消息),需要考虑到部分失败,让整个系统接受部分失败并做好容错机制,比如在网络传输失败时要能在服务层处理好,并且给用户一个好的反馈。

(2)网络延迟

网络是机器间通信的唯一路径,但这条唯一路径并不是可靠的,而且分布式系统中一定会存在网络延迟,网络延迟会影响系统对于“超时时间”、“心跳机制”的判断。如果是使用异步的系统模型,还会有各种环节可能出错:可能请求没有成功发出去、可能远程节点收到请求但是处理请求的进程突然挂掉、可能请求已经处理了但是在 Response,可能在网络上传输失败(如数据包丢失)或者延迟,而且网络延迟一般无法辨别。

即使是 TCP 能够建立可靠的连接,不丢失数据并且按照顺序传输,但是也处理不了网络延迟。对于网络延迟敏感的应用,使用 UDP 会更好,UDP 不保证可靠传输,也不会丢失重发,但是可以避免一些网络延迟,适合处理音频和视频的应用。

(3)没有共享内存、锁、时钟

分布式系统的节点间没有共享的内存,不应理所当然认为本地对象和远程对象是同一个对象。分布式系统也不像单机器的情况,可以共享同一个 CPU 的信号量以及并发操作的控制;也没有共享的物理时钟,无法保证所有机器的时间是绝对一致的。时间的顺序是很重要的,夸张一点说,假如对于一个人来说,从一个时钟来看是 7 点起床、8 点出门,但可能因为不同时钟的时间不一致,从不同节点上来看可能是 7 点出门、8 点起床。

在分布式环境下开发,需要我们能够有意识地进行问题识别,以上只是举例了一部分场景和问题,不同的接口实现,会在分布式环境下有不同的性能、扩展性、可靠性的表现。下面会继续上述的问题进行探讨,如何实现一个更可靠的系统。

概念和处理模型

对于上述分布式系统中的一些问题,可以针对不同的特征做一些容错和处理,下面主要看一下错误检测以及时间和顺序的处理模型。在实际处理中,一般是综合多个方案以及应用的特点。

错误检测

对于部分失败,需要一分为二的看待。

节点的部分失败,可以通过增加错误检测的机制,自动检测问题节点。在实际的应用中,比如有通过 Load Balancer,自动排除问题节点,只将请求发送给有效的节点。对于需要有 Leader 选举的服务集群来说,可以引入实现 Leader 选举的算法,如果 Leader 节点挂掉了,其余节点能选举出新的 Leader。实现选举算法也属于共识问题,在后续文章中会再涉及到几种算法的实现和应用。

网络问题:由于网络的不确定性,比较难说一个节点是否真正的“在工作”(有可能是网络延迟导致的错误),通过添加一些反馈机制可以在一定程度确定节点是否正常运行,比如:

  • 健康检查机制,一般是通过心跳检测来实现的,比如使用 Docker 的话,Consul、Eureka 都有健康检查机制,当发送心跳请求发现容器实例已经无法回应时,可以认为服务挂掉了,但是却很难确认在这个 Node/Container 中有多少数据被正确的处理了。
  • 如果一个节点的某个进程挂了,但是整个节点还可以正常运行。在使用微服务体系中是比较常见的,一台机器上部署着很多容器实例,其中个容器实例(即相当于刚才描述挂掉的进程)挂掉了,可以有一个方式去通知其他容器来快速接管,而不用等待执行超时。比如 Consul 通过 Gossip 协议进行多播,关于 Consul,可以参考这篇 Docker 容器部署 Consul 集群 内容。在批处理系统中,HBase 也有故障转移机制。

在实际做错误检测处理时,除了需要 节点、容器 做出积极的反馈,还要有一定的重试机制。重试的实现可以基于网络传输协议,如使用 TCP 的 RTT;也可以在应用层实现,如 Kafkaat-least-once 的实现。基于 Docker 体系的应用,可以使用 SpringCloud 的 Retry,结合 Hytrix、Ribbon 等。对于需要给用户反馈的应用,不太建议使用过多重试,根据不同的场景进行判断,更多的时候需要应用做出积极的响应即可,比如用户的“个人中心页面”,当 User 微服务挂了,可以给个默认头像、默认昵称,然后正确展示其他信息,而不是反复请求 User 微服务。

时间和顺序

在分布式系统中,时间可以作为所有执行操作的顺序先后的判定标准,也可以作为一些算法的边界条件。在分布式系统中决定操作的顺序是很重要的,比如对于提供分布式存储服务的系统来说,Repeated Read 以及 Serializable 的隔离级别,需要确定事务的顺序,以及一些事件的因果关系等。

物理时钟

每个机器都有两个不同的时钟,一个是 time-of-day,即常用的关于当前的日期、时间的信息,例如,此时是 2018 年 6 月 23 日 23:08:00,在 Java 中可以用 System.currentTimeMillis() 获取;另一个是 Monotonic 时钟,代表着单调递增的时间,一般是测量时间间距,在 Java 中调用 System.nanoTime() 可以获得 Monotonic 时间,常常用于测量一个本地请求的返回时间,比如 Apache commons 中的 StopWatch 的实现。

在分布式环境中,一般不会使用 Monotonic,测量两台不同的机器的 Monotonic 的时间差是无意义的。

不同机器的 time-of-day 一般也不同,就算使用 NTP 同步所有机器时间,也会存在毫秒级的差,NTP 本身也允许存在前后 0.05% 的误差。如果需要同步所有机器的时间,还需要对所有机器时间值进行监控,如果一个机器的时间和其他的有很大差异,需要移除不一致的节点。因为能改变机器时间的因素比较多,比如无法判断是否有人登上某台机器改变了其本地时间。

虽然全局时钟很难实现,并且有一定的限制,但基于全局时钟的假设还是有一些实践上的应用。比如 Facebook Cassandra 使用 NTP 同步时间来实现 LWW(Last Write Win)。Cassandra 假设有一个全局时钟,并基于这个时钟的值,用最新的写入覆盖旧值。当然时钟上的最新不代表顺序的最新,LWW 区分不了实际顺序;另外还有如 Google Spanner 使用 GPS 和原子时钟进行时间同步,但节点之间还是会存在时间误差。

逻辑时钟

在分布式系统中,因为全局时钟很难实现,并且像 NTP 同步过程,也会受到网络传输时间的影响,一般不会使用刚才所述的全局同步时间,当然也肯定不能使用各个机器的本地时间。对于需要确认操作执行顺序的时候,不能简单依赖一个基于 time-of-day 的 timestamps,所以需要一个逻辑时钟,来标记一些事件顺序、操作顺序的序列号。常见的方式是给所有操作加上递增的计数器。

这种所有操作都添加一个全局唯一的序列号的方式,提供了一种全局顺序的保证,全局顺序也包含了因果顺序一致的概念。关于分布式一致性的概念和实现会在后续文章详细介绍,我们先将关注点回归到时间和顺序上。下面看两种典型的逻辑时钟实现。

(1)Lamport Timestamps

Lamport timestamps 是 Leslie Lamport 在 1978 年提出的一种逻辑时钟的实现方法。Lamport Timestamps 的算法实现,可以理解为基于每个节点的一对值(NodeId,Counter)的全局顺序的同步。在集群中的每个节点(Node)都有一个唯一标识,并且每个 Node 都持有一个本地的对于所有操作顺序的一个 Counter(计数器)。

Lamport 实现的核心思想就是把事件分成三类(节点内处理的事件、发送事件、接收事件):

  • 如果一个节点处理一个事件,节点 counter +1。
  • 如果是发送一个消息事件,则在消息中带上 counter 值。
  • 如果是接收一个消息事件,则更新 counter = max(本地 counter,接收的消息中带的 counter) +1。

简单画了个示例如下图:

初始的 counter 都是 0,在 Node1 接收到请求,处理事件时 counter+1(C:1表示),并且再发送消息带上 C:1。

在 Node1 接受 ClientA 请求时,本地的 Counter=1 > ClientA 请求的值,所以处理事件时 max(1,0)+1=2(C:2),然后再发送消息,带上 Counter 值,ClientA 更新请求的最大 Counter 值 =2,并在下一次对 Node2 的事件发送时会带上这个值。

这种序列号的全局顺序的递增,需要每次 Client 请求持续跟踪 Node 返回的 Counter,并且再下一次请求时带上这个 Counter。lamport 维护了全局顺序,但是却不能更好的处理并发。在并发的情况下,因为网络延迟,可能导致先发生的事件被认为是后发生的事件。如图中红色的两个事件属于并发事件,虽然 ClientB 的事件先发出,但是因为延迟,所以在 Node 1 中会先处理 ClientA,也即在 Lamport 的算法中,认为 Node1(C:4) happens before Node1(C:5)。

Lamport Timestamps 还有另一种并发冲突事件:不同的 NodeId,但 Counter 值相同,这种冲突会通过 Node 的编号的比较进行并发处理。比如 Node2(C:10)、Node1(C:10) 是两个并发事件,则认为 Node2 的时间顺序值 > Node1 的序列值,也就认为 Node1(C:10) happens before Node2(C:10)。

所以可见,Lamport 时间戳是一种逻辑的时间戳,其可以表示全局的执行顺序,但是无法识别并发,以及因果顺序,并发情况无法很好地处理 偏序。

(2)Vector Clock

Vector Clock 又叫向量时钟,跟 Lamport Timestamps 比较类似,也是使用 SequenceNo 实现逻辑时钟,但是最主要的区别是向量时钟有因果关系,可以区分两个并发操作,是否一个操作依赖于另外一个。

Lamport Timestamps 通过不断把本地的 counter 更新成公共的 MaxCounter 来维持事件的全局顺序。Vector Clock 则各个节点维持自己本地的一个递增的 Counter,并且会多记录其他节点事件的 Counter。通过维护了一组 [NodeId,Counter] 值来记录事件的因果顺序,能更好得识别并发事件,也即,Vector Clock 的 [NodeId,Counter] 不仅记录了本地的,还记录了其他 Node 的 Counter 信息。

Vector Clock 的 [NodeId,Counter] 更新规则:

  • 如果一个节点处理一个事件,节点本地的逻辑时钟的 counter +1。
  • 当节点发送一个消息,需要包含所有本地逻辑时钟的一组 [NodeId,Counter] 记录值。
  • 接受一个事件消息时, 更新本地逻辑时钟的这组 [NodeId,Counter] 值:
    • 让这组 [NodeId,Counter] 值中每个值都是 max(本地 counter,接收的消息中的counter)。
    • 本地逻辑时钟 counter+1。

如下图简单示意了 Vector Clock 的时间顺序记录:

三个 Node,初始 counter 都是 0。NodeB 在处理 NodeC 的请求时,记录了 NodeC 的 Counter=1,并且处理事件时,本地逻辑时钟的 counter=0+1,所以 NodeB 处理事件时更新了本地逻辑时钟为 [B:1,C:1]。在事件处理时,通过不断更新本地的这组 Counter,就可以根据一组 [NodeId,Counter] 值来确定请求的因果顺序了,比如对于 NodeB,第二个处理事件 [A:1,B:2,C:1] 早于第三个事件:[A:1,B:3,C:1]。

在数值冲突的时候,如图中红色箭头标记的。NodeC 的 [A:2,B:2,C:3] 和 NodeB[A:3,B:4,C:1]。C:3 > C:1、B:2 < B:4,种情况认为是没有因果关系,属于同时发生。

Vector Clock 可以通过各个节点的时间序列值的一组值,识别两个事件的先后顺序。Vector 提供了发现数据冲突的方式,但是具体怎样解决冲突需要由发现冲突的节点决定,比如可以将并发冲突抛给 Client 决定,或者用 Quorum-NRW 算法进行读取修复(Read Repair)。

Amazon Dynamo 就是通过 Vector Clock 来做并发检测的一个很好的分布式存储系统的例子。对于复制节点的数据冲突使用了 Quorum NRW 决议,以及读修复(Read Repair)处理最新更新数据的丢失,详细实现可以参考这篇论文 Dynamo: Amazon’s Highly Available Key-value Store ,Dynamo 是典型的高可用、可扩展的,提供弱一致性(最终一致性)保证的分布式 K-V 数据存储服务。后续文章再介绍 Quorums 算法时,也会再次提到。Vector Clock 在实际应用中,还会有一些问题需要处理,比如如果一个上千节点的集群,那么随着时间的推移,每个 Node 将需要记录大量 [NodeId,Counter] 数据。Dynamo 的解决方案是通过添加一个 timestamp 记录每个 Node 更新 [NodeId,Counter] 值的时间,以及一个设定好的阈值,比如说阈值是 10,那么本地只保存最新的 10 个 [NodeId,Counter] 组合数据。

小结

本文引出了一些分布式系统的常见问题以及一些基础的分布式系统模型概念,微服务的架构目前已经被更广泛得应用,但微服务面临的问题其实也都是经典的分布式场景的问题。

本文在分布式系统的问题中,主要介绍了关于错误检测以及时间和顺序的处理模型。关于时间和顺序的问题处理中,没有一个绝对最优的方案,Cassandra 使用了全局时钟以及 LWW 处理顺序判定;Dynamo 使用了 Vector clock 发现冲突,加上 Quorum 算法处理事件并发。

OK,关于微服务中分布式的问题就介绍到这里。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java后端技术栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
微服务和分布式的区别
​分布式架构是​分布式计算技术的应用和工具,目前成熟的技术包括J2EE, CORBA和.NET(DCOM),这些技术牵扯的内容非常广,相关的书籍也非常多,也没有涉及这些技术的细节,只是从各种分布式系统平台产生的背景和在软件开发中应用的情况来探讨它们的主要异同。
张哥编程
2024/12/19
2040
微服务和分布式的区别
顺序、时钟与分布式系统
大家可以查看原文:https://mp.weixin.qq.com/s/2JYkT8a-HdJ2LePVJ3Vlag
用户6879030
2024/06/05
1460
分布式系统之道:Lamport 逻辑时钟
分布式系统解决了传统单体架构的单点问题和性能容量问题,另一方面也带来了很多的问题,其中一个问题就是多节点的时间同步问题:
一个会写诗的程序员
2022/06/12
1.6K0
分布式系统之道:Lamport 逻辑时钟
DDIA:分布式系统最重要的事情——“顺序”和“因果”
该定义暗含着:所有操作会形成一个确定的执行顺序。在图 9-4 中,我们就根据读到的结果来推测出了一个服务器端所有操作的看起来的执行顺序。
木鸟杂记
2023/11/27
6330
DDIA:分布式系统最重要的事情——“顺序”和“因果”
分布式系统理论基础3: 时间、时钟和事件顺序
转自:https://www.cnblogs.com/bangerlee/p/5448766.html
Java技术江湖
2019/12/03
8290
谈谈分布式系统
先讲个黑色笑话: 半年前,一个谁也没见过的日本浪人推出的理财产品突然在七侠镇火爆起来,据说买上点屯着,不出几月就能把同福客栈,甚至龙门镖局都盘下。我们家小六的七舅老爷,卖掉祖宅也嚷嚷着要 all in。我觉得这事吧很是蹊跷,好歹也是自家人嘛,不能让老人家上当受骗 —— 所以 … 放着我来。我用我无双的智慧,和堪比丞相的三寸不烂之舌给七舅老爷拦下来,让他打消了念头。没出半年,小六七舅老爷全家就和我们斩了联系,死生不复相见。 – 摘自《无双日记》 2018.1.1 最近一个多月,谈论 blockchain 的人
tyrchen
2018/03/29
9470
谈谈分布式系统
分布式系统不可靠时钟问题
今天我同样结合《设计数据密集系统》来聊分布式系统另外一个话题,即分布式系统的不可靠时钟问题.
小坤探游架构笔记
2025/05/05
1050
分布式系统不可靠时钟问题
袖珍分布式系统(三)
本文是Distributed systems for fun and profit的第三部分,本文是阅读该文后的一些记录。
zhuanxu
2018/08/23
5540
袖珍分布式系统(三)
5分钟学分布式系统理论,从放弃到入门
随承载用户数量的增加和容灾的需要,越来越多互联网后台系统从单机模式切换到分布式集群。回顾自己毕业五年来的工作内容,同样有这样的转变。
Bug开发工程师
2020/03/31
6920
5分钟学分布式系统理论,从放弃到入门
分布式系统中的时钟与一致性解读
世界是处于不断变化中的,佛经上说:“诸行无常”,就是这个意思。只有变化,作为观察者的我们才能感觉到时间,正是变化的世界让我们有了时间的概念。
GreatSQL社区
2023/02/23
1.9K0
分布式系统中如何保证数据一致?
在分布式系统中,保证数据一致性是一个复杂而关键的问题。由于系统的分布性,不同节点上的数据可能会发生变化,而系统需要采取一些机制来确保数据的一致性。以下是一些常见的方法:
孟斯特
2023/12/29
1.2K0
分布式系统中如何保证数据一致?
微服务与分布式系统设计看这篇就够了!
后台分布式架构形形色色,特别是微服务和云原生的兴起,诞生了一批批经典的分布式架构,然而在公司内部,或者其他大型互联网企业,都是抛出自己的架构,从接入层,逻辑层,数据层都各有特点,但这些系统设计中到底是出于何种考量,有没有一些参考的脉络呢,本文将从云原生和微服务,有状态服务,无状态服务以及分布式系统等维度探讨这些脉络。
腾讯云开发者
2024/10/22
2.9K0
微服务与分布式系统设计看这篇就够了!
[源码解析] 并行分布式框架 Celery 之 Lamport 逻辑时钟 & Mingle
Celery是一个简单、灵活且可靠的,处理大量消息的分布式系统,专注于实时处理的异步任务队列,同时也支持任务调度。本文介绍 Celery 的Lamport 逻辑时钟 & Mingle。
罗西的思考
2021/05/24
6310
[源码解析] 并行分布式框架 Celery 之 Lamport 逻辑时钟 & Mingle
分布式架构知识体系
节点,时间,一致性,CAP,ACID,BASE,P2P,机器伸缩,网络变更,负载均衡,限流,鉴权,服务发现,服务编排,降级,熔断,幂等,分库分表,分片分区,自动运维,容错处理,全栈监控,故障恢复,性能调优
Java团长
2019/04/25
7650
分布式架构知识体系
分布式系统是什么
分布式系统奠基者 Leslie Lamport [1] 在其最重要的论文之一 ”Time, Clocks, and the Ordering of Events in a Distributed System“ [2] 中提到:
木鸟杂记
2021/10/14
1.8K0
五分钟学后端技术:分布式系统理论 - 从放弃到入门
本系列文章转自某技术大佬的博客https://www.cnblogs.com/bangerlee/
程序员黄小斜
2020/03/23
6580
如何在分布式系统中确定先后?
在数据系统中,时钟(clocks)和时间(time)都很重要。应用程序会以很多种形式依赖时钟,举例来说:
木鸟杂记
2023/10/30
3090
如何在分布式系统中确定先后?
架构新说之响应式微服务架构-分布式系统设计原则
O’Reilly的电子书《Reactive Microservices Architecture》讲述了微服务/分布式系统的一些设计原则,本文是笔者阅读完此书后的理解。
技术zhai
2019/02/15
8120
分布式系统(微服务架构)的一致性和幂等性问题相关概念解析
前言 什么是分布式系统?关于这点其实并没有明确且统一的定义。在我看来,只要一个系统满足以下几点就可以称之为分布式系统 系统由物理上不同分布的多个机器节点组成 系统的多个节点通过网络进行通信,协调彼此之
java架构师
2019/02/26
5550
简单聊聊分布式系统的一致性问题
记得有人说过,分布式系统的所有问题归根结底都是一致性问题。前面文章提到的数据复制,分区以及事务面临的问题都是如何保证数据一致。而分布式系统不同于单机,它不仅会面临着宕机,他们唯一的交流方式就是网络,而网络是不可靠的,也因此带来了时间的不可靠。在分布式系统里,与一致性类似的是consensus的概念,consensus用大白话来说,就是所有的节点都认可同一件事。
哒呵呵
2018/08/06
3360
简单聊聊分布式系统的一致性问题
相关推荐
微服务和分布式的区别
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档