普通视图

系统设计: Fan-out/Fan-in 并发模式

Fan-out / fan-in 指的是一种并发模式:将工作拆分为多个单元并行执行,然后在所有任务完成后进行同步。虽然它经常在无服务器(serverless)函数的语境中被提及,但这一概念并不局限于无服务器架构。 更广义地说,fan-out / fan-in 是一种通用的并发模式,适用于任何可以将任务分解为相互独立部分的场景,例如线程、进程、Actor、微服务,甚至分布式作业,并在之后将结果汇聚起来。其核心思想是在执行阶段将工作并行展开(fan-out),在收敛阶段对各个分支的输出进行协调和聚合(fan-in),而不依赖于具体的执行模型或底层基础设施。 [caption id="attachment_70812" align="alignnone" width="1653"]Fan-out / fan-in 指的是一种并发模式:将工作拆分为多个单元并行执行,然后在所有任务完成后进行同步。 Fan-out / fan-in 指的是一种并发模式:将工作拆分为多个单元并行执行,然后在所有任务完成后进行同步。[/caption] 在实际工程中,fan-out / fan-in 模式常用于提升系统吞吐量和资源利用率,尤其适合 I/O 密集型或可并行计算的场景。通过将一个复杂任务拆分为多个相互独立的子任务并同时执行,可以显著缩短整体处理时间;而在 fan-in 阶段,对各个子任务的结果进行统一汇总、排序或合并,则有助于保持业务逻辑的完整性与一致性。不过,这种模式也需要注意并发控制、错误处理以及超时与重试机制,否则容易在高并发场景下引入资源争用、级联失败或结果不一致等问题。因此,在设计和实现 fan-out / fan-in 架构时,应结合具体场景权衡并发度、系统复杂度与稳定性。 [show_file file="/var/www/wp-post-common/justyy.com/design.php"] 英文:System Design: Fan-out/Fan-in Concurrency Pattern

相关文章:

  1. 第一次私校家长会: 原来家长比孩子还卷 前几天参加了娃的第一次家长会,和几位家长聊下来,真是个个都很厉害。不光孩子们卷,家长也一样卷,一眼望去基本都是 Dr/博士。娃还调侃我一句:“这有什么的,你不也是 Dr 吗?” 我心里默默想:还好没写学校名字,不然我这野鸡大学的头衔真拿不出手 😂。 私校里真是人才济济,乐器过 8 级的太常见了,卷得不得了。我还问过娃,是想当 big fish in a small pond...
  2. 智能手机 HTC One M9 使用测评 虽然我对手机要求不高, 远远没有像追求VPS服务器一样, 但是怎么算来两年内换了四个手机, 先是三星 S4 用了一年多, 然后 Nokia Lumia 635 Windows Phone, 后来又是 BLU, 半年多前换了...
  3. 按揭贷款(房贷,车贷) 每月还贷计算器 去年给银行借了17万英镑 买了20万7500英镑的房子, 25年还清. 前2年是定率 Fix Rate 的合同 (年利率2.49%). 每个月大概是还 700多英镑. 有很多种还贷的计算方式, 定率/每月固定 是比较常用的. 简单来说就是 每个月交的钱是...
  4. 英国房子的EPC节能报告(Energe/Efficiency Performance Certificate) EPC (Energe/Efficiency Performance Certificate) 是英国房子的节能报告, 法律上规定, 每个房子都必须要有一个EPC报告, 报告的有效期为十年. 房东在把房子出租或者想卖房的时候, 这个EPC就必须有效, 在一些情况下 比如出租房子的时候, 这个EPC报告还必须符合一些最低标准, 比如房子必须满足 F档(类似及格线)...
  5. 在英国给孩子换学校的经历: 孩子离开了村里的小学 由于搬了家, 孩子上学得提前半小时出门了, 因为早上堵, 也得开车半小时才能到. 之前在 Fen Drayton 村庄上小学, 早上8:45学校门开, 9点敲钟孩子排队依次进入教室, 我们由于在村里, 只需要提前5分钟出门和孩子一起走路就可以了. 现在一下子早上变得很匆忙, 得叫孩子起床, 做早饭,...
  6. 微信PC端程序占用了1.39 TB的空间! 快速清理微信占用空间 前两天我的 C 盘剩余空间突然变红了,我随手一查,竟然发现微信 PC 端程序居然占用了 1.39 TB 的空间,简直不可思议。在手机上,微信同样是名列前茅的“吞空间大户”,在 设置 → 通用 → 手机存储空间 里几乎稳居第一。 更离谱的是,这些空间大多并不是因为聊天记录,而是各种缓存文件、视频、图片和被动接收的文件所堆积起来的。平时我们只是点开看一眼,就算没保存下来,微信也会悄悄把它们留在本地,占据大量磁盘。尤其是群聊里转发的视频和文件,日积月累就成了一个“隐形黑洞”。...
  7. 同一台服务器上多个WORDPRESS站点的一些设置可以移出去 我自从把所有网站都挪到一处VPS服务器上 就发现很多事情省事很多 可以同时管理多个网站 包括 WORDPRESS博客. 比如我有四个WORDPRESS博客 然后我就把通用的一些资料给移出去 移到 HTTP或者HTTPS都不能直接访问的文件夹里这样就更安全许多. 文件 wp-conn.php 存储了 相同的数据库资料. /** MySQL...
  8. 和孩子到英国Suffolk进行复活节Easter Egg Hunt 去年复活节刚好因为疫情 只能待在家里, 于是在院子里和家里藏好复活节Egg然后孩子找蛋. 前年去了到 Beth Chatto 花园找复活节彩蛋 今年疫情好转, 政府允许在室外活动, 于是驱车到了Suffolk进行复活节Easter Egg Hunt. 地址是: The Rotunda,...

聊一聊分布式系统中的时间

2024年10月21日 08:41

今天聊一下时间的话题。在分布式系统中,“时间” 是一个挺有趣,但是很难处理的东西。我把自己的理解简单整理下来。

不可靠的物理时钟

首先,单一节点的物理时钟是不可靠的。

物理时钟本身就有偏差,可是除此之外,可以引起节点物理时钟不准确的原因太多了,比如 clock jump。考虑到 NTP 协议,它基于 UDP 通信,可以从权威的时钟源获取信息,进行自动的时间同步,这就可能会发生 clock jump,它就是说,时钟始终会不断进行同步,而同步回来的时间,是有可能不等于当前时间的,那么系统就会设置当前时间到这个新同步回来的时间。即便没有这个原因,考虑到数据从网络传输的延迟,处理数据的延迟等等,物理时钟是非常不可靠的。

如果一个分布式系统,多个节点想要仅仅依赖于物理时钟来完成什么操作,那么只能祈祷运气足够好了。在 《从物理时钟到逻辑时钟》这篇文中,我已经介绍了对于物理时钟不可靠的问题,我们有一个解决的办法,就是引入 Lamport 逻辑时钟,或者使用向量时钟,这里就不赘述了。

超时

分布式系统中什么样的执行结果最难处理,成功还是失败?其实都不是,最难处理的结果是超时,因为执行超时了,但是系统却并不知道它:

  • 是没执行,
  • 是执行成功了,
  • 还是执行失败了。

所谓超时,一个显然的问题是,超过多少时间才算超时?往往没有一个公式,更没有一个标准答案,我觉得《Designing Data-Intensive Applications》这本书里面对这一点总结得很好——对于超时时间的定义,其实就是一个 tradeoff,一个基于 failure detection delay 和 risk of premature timeouts 之间抉择的平衡。如果超时时间设置长了,就会减少超时判定的误杀,但是对于系统失败的识别就会延迟;反之,如果超时时间设置过短,那就会触发更多看起来是超时的 case,但是它们本身其实并没有真正超时。

通常来说,对于超时的处理,其实办法也不多。一种是放弃,一种是重试。就像消息投递,如果要保证 “至多投递一次”,那在投递超时后,就直接放弃;如果要保证 “至少投递一次”,那在投递超时后,就重试。如果要重试,那就需要引入保证幂等性的机制。

分布式事务 SAGA 对于超时的处理,其实也是遵照上面的原则,在系统内单步都成为事务的基础上,把流程视作一个状态机,无论单步操作是成功还是失败,都会根据清晰的预定义逻辑,触发相应的正向流程或者反向流程,可是唯独超时,多数情况下最有意义的事情就是重试,也只能重试,因为谁也不知道它究竟实际是成功了还是失败了。

说完操作超时,再来说一下节点超时。很多分布式系统中都会使用一种 lease(租约)的机制,比如一个集群中的 leader,作为 leader 会扮演不同的角色,但是必须要 renew 这个 lease,否则超过一定的时间,无论它给不给响应,它都会被开除出 leader 的角色,而 follower 会重新选举(或者其他方式)一个 leader。

比较难处理的是,如果这个节点本来是被 hang 住了,导致了超时,它也已经被踢下 leader 的角色,但是之后它 “活” 过来了(比如经过了一个超长时间的 GC),它还以为自己是 leader,继续去干 leader 干的事,变成了一个假 leader。这其实就是出现了脑裂,本质上是一个一致性的问题。这种情况比较难处理,因为即便有 heartbeat 不断检测,在每两个 heartbeat 的间隙,可能这种重要的变动就发生了。

要解决这种问题,需要使用 token fence 的方法,即让每次最关键的状态数据的更改,携带一个单调递增的 token,这种情况下这个假 leader 发起更改的 token,已经小于系统中最新的 token 了,接收这个数据更改的子系统应该拒掉这个请求。上面说的节点超时的情况我在《谈谈分布式锁》里面有详细说明。

计算机的两种时钟

有两种时钟是计算机普遍支持的,一种叫做 time-of-day clock,就是我们一般意义上的时钟,代表着相对于 1970 年 1 月 1 日的 epoch 时间,也就是 Java 里面 System.currentTimeMillis() 返回的。网络时间协议 NTP 就是用来同步计算机这个时间的。

不过,其实还有一种时钟,叫做 monotonic clock(单调时钟),在 Java 里面相应的接口是 System.nanoTime()。这个时钟有一个特点,就是它永不回头。对于 time-of-day clock 来说,时间是可能 “回头” 的,对于很多应用来说,时间回头是要命的。不过这个时钟给出的具体时间却是毫无意义,如果在不同的机器上调用 System.nanoTime(),会得到完全随机的结果。API 的名字是纳秒,可是这个时钟并不给出到纳秒的时间精度,它的作用是用来帮助计算间隔时间的:在同一个节点,第二次调用的时间减掉第一次调用的时间,这个结果(时间间隔)是严格递增(不回头)的。从这个意义上说,除去时间这个视角本身,这个时钟更像是一个单调的计数器。既然是单调的计数器,就可以用来帮助产生系统严格自增的 ID。

下面是 System.nanoTime() Javadoc 上面的解释:

Returns the current value of the most precise available system timer, in nanoseconds.
This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time. The value returned represents nanoseconds since some fixed but arbitrary time (perhaps in the future, so values may be negative). This method provides nanosecond precision, but not necessarily nanosecond accuracy. No guarantees are made about how frequently values change. Differences in successive calls that span greater than approximately 292 years (263 nanoseconds) will not accurately compute elapsed time due to numerical overflow.

TrueTime

一般来说,我们都知道计算机的时钟有误差,可是这个误差是多少,差 1 毫秒还是 1 分钟,并没有任何严格保证。绝大多数接触到的时间 API 也是如此,可是,Google 数据库 Spanner 的 TrueTime API 却。它使用了 GPS 时钟和原子钟两种完全独立的机制来冗余某一个机制失败导致的时钟问题,增加 reliability。此外,它还有和 System.nanoTime() 一样的严格递增的特点。

它有三个核心 API,很有意思:

  • TT.now() 它返回 [earliest, latest] 这样一个范围,表示当前时间就在这个范围内;
  • TT.after(t) 它返回当前时间是不是肯定在 t 之后
  • TT.before(t) 它返回当前时间是不是肯定在 t 之前

有了 TrueTime,这让分布式系统中,本来无法通过物理时钟解决的问题也变得可解决了。比如对于操作冲突的问题,现在的新办法就是等一个 buffer 时间,TrueTime 认为已经前一个操作的结束时间肯定已经过去了,再来启动后一个操作。当然,这个方法的缺点是 throughput,因为整个操作周期因为 buffer 时间的关系变长了。

《四火的唠叨》文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接

❌