惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
B
Blog RSS Feed
云风的 BLOG
云风的 BLOG
G
Google Developers Blog
Recent Announcements
Recent Announcements
A
About on SuperTechFans
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
Google DeepMind News
Google DeepMind News
S
Schneier on Security
S
Secure Thoughts
T
The Exploit Database - CXSecurity.com
Martin Fowler
Martin Fowler
P
Proofpoint News Feed
Security Latest
Security Latest
Jina AI
Jina AI
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Recorded Future
Recorded Future
T
Tor Project blog
有赞技术团队
有赞技术团队
H
Hackread – Cybersecurity News, Data Breaches, AI and More
N
News | PayPal Newsroom
博客园 - 三生石上(FineUI控件)
MyScale Blog
MyScale Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
Forbes - Security
Forbes - Security
D
DataBreaches.Net
人人都是产品经理
人人都是产品经理
NISL@THU
NISL@THU
C
Cisco Blogs
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Google DeepMind News
Google DeepMind News
Project Zero
Project Zero
IT之家
IT之家
T
Threatpost
Cyberwarzone
Cyberwarzone
O
OpenAI News
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
J
Java Code Geeks
P
Proofpoint News Feed
The Last Watchdog
The Last Watchdog
月光博客
月光博客
Latest news
Latest news
MongoDB | Blog
MongoDB | Blog
Apple Machine Learning Research
Apple Machine Learning Research

Mobility

从薅 token 到管 skill:我的 pks 工具落地实践 把笔记、微信读书、知乎装进 Obsidian:我基于llm-wiki知识中枢搭建实录 免费AI视频生成器:我如何用零成本做出带旁白字幕的多场景AI视频 Agnes免费模型真能白嫖视频?我改造了ViMax来试试 教你薅token(二):构建agent无关的skills管理工作流 教你薅token:构建agent无关的AI工作流 用 AI Agent 完成 Hexo 主题迁移:从 Next 到 Butterfly 的全自动化实践 Vercel封禁163邮箱后,我是怎么恢复博客的 用LLM管理安全开发规范:一次llm-wiki实践 Vaadin框架教程:Java工程师的前端开发秘籍 hexo多语言方案总结及最佳实践 知乎增强工具-评论时间精确到秒 怎么理解数据库的四个隔离级别 kubernetes是什么-实用向教程 怎么更科学的用知乎摸鱼 读书笔记《系统之美》,如何面对现实中的复杂问题 分布式系统设计中的通用方法 高并发解决方案很难吗?轻松聊清楚高并发设计 SSP,DSP,RTB,ADX都是什么? 讲讲互联网广告的概念与发展 从redolog,undolog到隔离级别,刨根问底,讲清楚事务和ACID java项目低学习成本使用kubernetes的实践经验 剧变中的2021-一个中年工程师的年终总结 kubernetes环境下做金丝雀发布的一种思路 prometheus教程: 一篇文章讲懂prometheus 实现一个简单的java版本高性能获取ip地址所属国家工具 iterm2配置ssh书签, 实现记住密码和自动登录 怎样做一个好的技术分享 云原生究竟是什么 读书笔记 稻盛和夫《干法》-思考应该怎样去工作 review的个人价值 户口?大厂?高薪?生活?聊聊应届程序员的职业选择 RPC接口将所有输入输出封装成类是合理设计吗 程序员做业务开发的价值 设计模式的原则,设计模式究竟是什么 我提升开发效率的经验 通过合理的设计降低软件开发复杂度 信息传播过程中的衰减 看房小记-2020北京学区 读书感悟:文明、现代化、价值投资与中国 读书笔记-我曾走在崩溃的边缘 redis的对象 redis里的数据结构 设计模式备忘录 聊聊程序员的职业生涯,我对程序员这个职业的理解 通过mysql批量操作不生效问题聊聊java里mysql的batch 【实践经验】单元测试怎么写 关于rocketmq的readQueue和writeQueue 数据分析的利器-clickhouse介绍 通过位运算转换大小写 activemq多线程消费的不同处理方式 高并发下作余额扣减的一些经验 java细节:三目运算符和自动拆箱 设计一个开源的北京地铁路线规划小工具 java版本 redis cluster的数据迁移 jstorm源码解析之循环任务AsyncLoopThread activemq特性之持久化 activemq的安装及基本使用 activemq系列-概述 hexo教程:博客系统搭建及部署到github jstorm的监控metrics数据输出到第三方存储介质 camel系列之camel debugger的使用 jstorm源码解析之bolt异常处理 log4j动态添加appender 【翻译】java里编写基准测试的一些经验 java线程池:获取运行线程数并控制线程启动速度 maven里的mirror和repository: 配置多repository 使用maven shade plugin 打可执行Jar包 activemq plugin开发指南及示例 通过加入classpath的形式实现命令行运行java程序时引入第三方jar包 解决fatjar的 “java.lang.SecurityException: Invalid signature file digest for Manifest main attributes” 问题 通过实际操作理解redis cluster原理 一种实现在hbase中存储set的思路 log4j2.xml配置示例及与log4j的区别 不实现equals方法的情况下比较java list 使用lua脚本和jedis实现redis的hmsetnx命令,操作hash表时不覆盖原有数据 vitualbox虚拟机安装centos 7 及ssh访问、自启动等配置 在java独立进程(standalone app)中嵌入hawtio监控 java日志系统简介: 从tomcat大量打印debug日志说起 Java kryo/protobuf/protostuff序列化 or Json 性能对比 java分布式锁入门实战 leetcode第三题: 输出不包含重复字母的最长子串 java多线程实现三个字母顺序输出 一次kafka空间激增排查:kafka的数据压缩、批量发送等 java里128有何魔力? 聊聊Integer的缓存 storm/jstorm生态与周边工具,storm连接activemq,kafka,hdfs等 jstorm UI 介绍 五分钟学会写storm代码: jstorm/storm编码原理与普通java程序的区别 activemq web console的权限配置 storm ui 中一些关键属性的含义 activemq 5.6 连接池的内存泄露问题 关于apache camel的消息转发效率 一篇不错的lda模型入门文档 wordcount代码 hadoop基本的学习资料
[翻译][关于分布式架构和系统设计]分布式系统的模式-综述
流沙 · 2020-08-10 · via Mobility

(最近把这篇文章重新整理了下,欢迎阅读最新版 https://lichuanyang.top/posts/45718/)

本文翻译自https://martinfowler.com/articles/patterns-of-distributed-systems/ ,原作者对目前各类企业级架构中使用的多种分布式系统进行了总结,从中提取出了一些通用的“模式”(pattern)。本文作为系列文章的第一篇,介绍了分布式系统的特点和一些常见问题。 建议好好阅读一下本文以及英文原文,对于分布式系统设计和分布式架构理念,会有非常大的帮助。

What this is about

分布式系统给程序设计带来了特殊的挑战。 它们通常要求我们拥有多个数据副本,这些副本需要保持同步。 但是我们无法期望各节点能永远可靠地工作,同时,网络延迟也很容易导致不一致的现象出现。 尽管如此,许多组织仍依赖一系列核心的分布式系统来处理数据存储,消息传递,系统管理和计算等。 这些系统面临很多共同的问题,这些问题也可以通过类似的方案来解决。 本文将这些解决方案定义为模式,通过这些模式,我们对于如何更好地理解,交流和教授分布式系统,将建立起更好的认知。

在过去的几个月中,我一直在ThoughtWorks进行有关分布式系统的研讨会。研讨会中面临的主要挑战之一是如何将分布式系统的理论映射到诸如Kafka、Cassandra之类的开源项目中,同时还要保持讨论足够通用,能涵盖更广泛的解决方案。模式的概念提供了一个不错的出路。

“模式”这个结构,本质上使我们能够让我们专注于特定问题,从而很清楚地说明为什么需要特定的解决方案。然后,对解决方案的描述允许我们给出一个代码结构,这个结构足以具体到能够表示出实际解决方案的程度,但同时又足够通用以涵盖各种变化。模式还允许我们将各种模式链接在一起以构建一个完整的系统。这样,我们就有足够的词汇表,来讨论分布式系统的实现。

接下来是在主流开源分布式系统中观察到的第一组模式。我希望这些模式集对所有开发人员都有用。

分布式系统-实现角度

现在的企业架构中有很多天然分布式的平台和框架。如果我们在当前典型的架构抽样查看平台、框架,会看到下面这么一些东西。

Type of platform/framework Example
Databases Cassandra, HBase, Riak
Message Brokers Kafka, Pulsar
Infrastructure Kubernetes, Mesos, Zookeeper, etcd, Consul
In Memory Data/Compute Grids Hazlecast, Pivotal Gemfire
Stateful Microservices Akka Actors, Axon
File Systems HDFS, Ceph

这些系统都天然是分布式的。关于什么样的系统叫“分布式”系统,包括两个方面:

  • 运行在多台服务器上。集群内服务器的数量差别可以非常大,从三台到几千台都可能。
  • 要处理数据,所以它们是内在“有状态”的系统。

当多个服务器参与存储数据时,有几种出错的可能。 上述所有系统都需要解决这些问题。 对这些问题,这些系统的实现方式中有一些重复的解决方案。 以更通用的形式理解这些解决方案,有助于理解这些系统的广泛实现方式,并且在需要构建新系统时也可以作为很好的指导。

模式,是Christopher Alexander提出的,在软件社区中被广泛接受的概念,用于在软件系统设计时记录设计架构。 模式为解决问题提供了一种结构化的方式,可以通过多次查看和验证来解决问题。 使用模式的一种有趣方式是能够以模式序列或模式语言的形式将多个模式链接在一起,这为实现“整个”或完整的系统提供了一些指导。 将分布式系统视为一系列模式,是深入了解其实现方式的有效方法。

问题及其反复出现的解决方案

当用多台服务器存储数据时,会有几种出问题的方式。

进程崩溃

由于硬件或软件因素,进程在任何时刻都可能崩溃。有若干种进程崩溃的方式。

  • 系统管理员进行常规的系统维护,进程会被关闭
  • 进行IO操作,但磁盘空间不足,且异常没有被正确处理时,会导致进程被杀掉
  • 在云环境下,可能会更复杂,一些无关的原因也可能导致系统宕机。

最重要的是,如果进程负责存储数据,则必须将它们设计为能够对存储在服务器上的数据提供持久性保证。 即使进程突然崩溃,它也应保留所有成功给过用户ack确认消息的数据。 根据访问模式,不同的存储引擎具有不同的存储结构,范围从简单的hash表到复杂的图结构都有。 将数据刷新到磁盘是最耗时的操作之一,因此无法将每次插入或更新都立即刷新到磁盘。 因此,大多数数据库具有内存存储结构,内存中的数据定期刷新到磁盘。 如果进程突然崩溃,可能会丢失所有这些数据。

一种叫做Write-Ahead Log的技术就是用来解决这个问题的。服务器将每个状态更改作为命令存储在硬盘上的仅附加(append-only)文件中。 append操作通常是非常快的,因此可以在不影响性能的情况下完成。 顺序写单个日志文件,以存储每个更新。 在服务器启动时,可以重播日志以再次建立内存状态。

这提供了持久性的保证。 即使服务器突然崩溃,然后重新启动,数据也不会丢失。 但是,在服务器恢复之前,客户端将无法获取或存储任何数据。 因此,如果服务器发生故障,我们会缺乏可用性。

一种显而易见的解决方案是将数据存储在多个服务器上。 因此,我们可以在多个服务器上复制预写日志。

当涉及多个服务器时,还有更多的故障情况需要考虑。

网络延迟

在TCP / IP协议栈中,通过网络传输消息时所引起的延迟没有上限。 它会根据网络上的负载而变化。 例如,一个1 Gbps的网络连接可能会被定时触发的大数据作业淹没,从而填满网络缓冲区,并且可能导致某些消息在不确定的延迟后才到达服务器。

在典型的数据中心中,服务器打包在机架中,并且通过机架式交换机连接多个机架。 可能会有一棵交换机树将数据中心的一部分连接到另一部分。 在某些情况下,一组服务器可以相互通信,但与另一组服务器的连接是断开的。 这种情况称为网络分区。 服务器通过网络进行通信的基本问题之一是,何时能知道特定服务器发生了故障。

这里有两个问题要解决。

  • 一台特定的服务器不能通过无限期的等待,去知道另一台服务器已经宕机。
  • 不应有两套服务器,每套服务器都认为另一套服务器发生了故障,因此继续为不同的客户端提供服务。 这称为脑裂(split brain)。

为了解决第一个问题,每台服务器都会定期向其他服务器发送心跳消息。如果没有收到心跳,则将对应的服务器视为已崩溃。心跳间隔足够短,能够确保不需要花费很长时间就能检测服务器故障。在最坏的情况下,服务器可能在正常运行,但是被集群整体认为已经宕机,并继续运行。心跳这种方式可以确保提供给客户端的服务不会中断。

第二个问题是脑裂。在脑裂的情况下,如果两组服务器独立接受更新,则不同的客户端可以获取和设置不同的数据,当脑裂的问题被解决后,是不可能自动解决冲突的。

为了解决脑裂的问题,我们必须确保彼此断开连接的两组服务器不能独立地正常运行下去。为确保这一点,服务器执行动作时,只有大多数服务器可以确认这个动作,该才将动作视为成功。如果服务器无法选出来一个”大多数“,则它们将无法提供服务,并且某些客户端组可能无法接收该服务。但是集群中的服务器将始终处于一致状态。占多数的服务器数量称为Quorum。如何确定Quorum?这是根据集群可以容忍的故障数决定的。比如,我们有五个节点的群集,则需要三个quorum。通常,如果我们要容忍f个故障,则需要2f + 1的集群大小。

Quorum确保我们有足够的数据副本以承受某些服务器故障。但是,仅向客户提供强大的一致性保证是不够的。假设客户端在quorum上启动了写操作,但是该写操作仅在一台服务器上成功。Quorum中的其他服务器仍具有旧值。当客户端从Quorum读取值时,如果具有最新值的服务器可用,则它可能会获得最新值。但是,如果仅当客户端开始读取值时,具有最新值的服务器不可用,它就可以获得旧值。为了避免这种情况,需要有人跟踪判断quorum是否同意特定的操作,并且仅将值发送给保证在所有服务器上都可用的客户端。在这种情况下使用主从模式(master&slave)。其中一台服务器当选为master,其他服务器充当slave。Master控制并协调对slave的复制。Master需要确定哪些更改应对客户可见。高水位标记(High-water mark)用于跟踪预写日志中已成功复制到足够的slave中的条目。客户端可以看到所有高水位之前的条目。Master还将高水位标记发送给slave。因此,如果Master失败并且slave之一成为新master,那么客户看到的内容就不会出现不一致之处。

进程暂停

但这还不是全部,即使有了Quorums和Master and Slave,仍然需要解决一个棘手的问题。 Master进程随时可能暂停。 进程暂停的原因很多。 对于支持垃圾回收的语言来说,可能会有很长的垃圾回收暂停。 具有较长垃圾收集暂停时间的Master可能会与slave断开连接,并在暂停结束后继续向slave发送消息。 同时,如果slave没有收到master的任何心跳信号,他们可能选择了新的master并接受了客户端的更新。 如果旧master的请求按原样处理,则它们可能会覆盖某些更新。 因此,我们需要一种机制来检测过时master的请求。 Generation Clock用于标记和检测来自老master的请求。 世代(generation)是单调增加的数字。

时钟不同步及顺序消息

从较新的消息中检测较旧的master消息的问题是如何保证消息顺序。看起来我们可以使用系统时间来给一组消息排序,但实际上,是不行的。主要原因是我们无法保证跨服务器的系统时钟是同步的。计算机中的一天中的时钟由石英晶体管理,并根据晶体的振荡来测量时间。

这种机制容易出错,因为晶体可以更快或更慢地振荡,因此不同的服务器可能具有截然不同的时间。一组服务器上的时钟通过称为NTP的服务进行同步。该服务会定期检查一组全局时间服务器,并相应地调整计算机时钟。

由于这是通过网络上的通信发生的,并且网络延迟可能会如以上各节中所述发生变化,所以由于网络问题,时钟同步可能会延迟。这可能导致服务器时钟彼此之间漂移,并且在NTP同步发生后甚至会倒退。由于计算机时钟存在这些问题,因此通常不将一天中的时间用于顺序事件。取而代之的是使用一种称为Lamport’s timestamp的简单技术。Generation Clock就是一个例子。

整合-一个分布式系统的例子

我们可以看到,从头开始理解这些模式是如何帮助我们建立一个完整系统的。 我们将以一致性为例。 分布式一致性是分布式系统实现的一种特例,它提供了最强的一致性保证。 比如流行的企业架构中常见的Zookeeper,etcd和Consul。 他们实现了zab和Raft等一致性算法,以提供复制和强大的一致性。 还有其他流行的算法可以实现一致性,Google的Chubby中用于锁定服务的Paxos,考虑stamp replication and virtual-synchrony。 用非常简单的术语来说,一致性是指在一组服务器中,在存储的数据,存储的顺序以及何时使该数据对客户端可见,这些方面达成一致。

实现一致性的模式列表

一致性的实现中,使用 state machine replication来实现容错。在state machine replication中,存储服务,比如键值存储,在所有服务器上复制,而且用户的输入也会在每个服务器上以相同顺序执行。用于实现此目的的关键实现技术是在所有服务器上复制Write-Ahead log以具有“ Replicated Wal”。

我们可以将这些模式放在一起以实现Replicated Wal,如下所示。

为了提供持久性保证,使用Write-Ahead log。使用Segmented Log将预写日志分为多个段。这有助于Low-Water Mark进行日志清理。通过在多个服务器上复制预写日志来提供容错能力。服务器之间的复制通过使用主从模式进行管理。更新High-Water Mark时,使用Quorum,以确定哪些值对客户可见。通过使用Single Update Quest,使所有请求均按严格顺序处理。使用Single Socket Channel, 将master的请求发送给slave时,事件将得到维护。为了优化Single Socket Channel上的吞吐量和延迟,使用了Request Pipeline。Slavet通过HeartBeat确定Master的可用性。如果Master由于网络分区而暂时从集群断开连接,则可以使用“Generation Clock”来检测它。

paterns

通过这种方式,理解这些问题,和它们的通用解决方式,帮助我们理解构建复杂系统的方式。

下一步

分布式系统是一个巨大的话题。 这里涵盖的模式集只是一小部分,涵盖了不同的类别,以展示模式方法如何帮助理解和设计分布式系统。 我将继续向这个合集添加下边这些问题。

  • Group Membership and Failure Detection
  • Partitioning
  • Replication and Consistency
  • Storage
  • Processing

原文地址: https://lichuanyang.top/posts/3914/