From 5ee0b5baa433053db07da9f97dd627ba1f93c219 Mon Sep 17 00:00:00 2001 From: isno Date: Sat, 28 Dec 2024 18:19:51 +0800 Subject: [PATCH] fix typo --- Observability/profiles.md | 2 +- ServiceMesh/control-plane.md | 4 ++-- consensus/raft-ConfChange.md | 14 +++++++------- container/borg-omega-k8s.md | 24 ++++++++++-------------- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/Observability/profiles.md b/Observability/profiles.md index 403324c3..524d8049 100644 --- a/Observability/profiles.md +++ b/Observability/profiles.md @@ -2,7 +2,7 @@ 熟悉 Golang 的工程师对 pprof 工具一定不陌生。借助 pprof 提供的 CPU 和内存分析功能,工程师能够深入了解 Golang 函数的执行时间、内存使用情况,从而分析、优化应用性能。 -可观测性领域内的性能剖析(Profiling)和 Golang 中的 pprof 目标一致,两者皆是对运行中应用动态分析、生成详细的运行数据(Profiles),帮助工程师全面了解应用资源使用情况,确定代码和性能瓶颈之间的关联。 +可观测性领域内的性能剖析(Profiling)和 Golang 中的 pprof 目标一致,两者皆是对运行中应用进行分析、生成详细的运行数据(Profiles),帮助工程师全面了解应用运行时的行为、资源使用全貌,从而确定代码和性能瓶颈之间的关联。 Profiles 数据通常以火焰图、堆栈图或内存分析图等形式呈现,是从“是什么”到“为什么”这一过程中重要的依据。例如,通过链路追踪识别出延迟(是什么)的位置,然后根据火焰图进一步定位到具体的代码行(为什么)。2021 年,国内某网站崩溃,工程师分析火焰图发现 Lua 代码存在异常,最终成功定位到问题源头[^1]。 diff --git a/ServiceMesh/control-plane.md b/ServiceMesh/control-plane.md index 981ded7e..ec01ecfd 100644 --- a/ServiceMesh/control-plane.md +++ b/ServiceMesh/control-plane.md @@ -12,7 +12,7 @@ Istio 自发布首个版本以来,有着一套“堪称优雅”的架构设 服务网格被誉为下一代微服务架构,用来解决微服务间的运维管理问题。但在服务网格的设计过程中,又引入了一套新的微服务架构。这岂不是“用一种微服务架构设计的系统来解决另一种微服务架构的治理问题”?那么,谁来解决 Istio 系统本身的微服务架构问题呢? -在 Istio 推出三年后,即 Istio 1.5 版本,开发团队对控制面架构进行了重大调整,摒弃了之前的设计,转而采用了“复古”的单体架构。新的统一组件 istiod 整合了 Pilot、Citadel 和 Galley 的功能,并以单个二进制文件的形式进行部署。Istio 1.5 版本的架构变化,实际上是将原有的多进程设计转换为单进程模式,因此,istiod 需要承担之前各个组件的所有职责: +在 Istio 推出三年后,即 Istio 1.5 版本,开发团队对控制面架构进行了重大调整,摒弃了之前的设计,转而采用了“复古”的单体架构。新的统一组件 istiod 整合了 Pilot、Citadel 和 Galley 的功能,并以单个二进制文件的形式进行部署,承担起之前各个组件的所有职责: - **服务发现与配置分发**:从 Kubernetes 等平台获取服务信息,将路由规则和策略转换为 xDS 协议下发至 Envoy 代理。 - **流量管理**:管理流量路由规则,包括负载均衡、分流、镜像、熔断、超时与重试等功能。 @@ -25,7 +25,7 @@ Istio 自发布首个版本以来,有着一套“堪称优雅”的架构设 图 8-12 Istio 架构及各个组件 ::: -通过将架构从多进程转为单进程,Istio 的开发团队以最小的成本显著提高了运维收益。 +Istio 1.5 版本的架构变化,实际上是将原有的多进程设计转换为单进程模式,以最小的成本实现最高的运维收益。 - 运维配置变得更加简单,用户只需要部署或升级一个单独的服务组件; - 更加容易排查错误,因为不需要再横跨多个组件去排查各种错误; diff --git a/consensus/raft-ConfChange.md b/consensus/raft-ConfChange.md index 37acded7..50475053 100644 --- a/consensus/raft-ConfChange.md +++ b/consensus/raft-ConfChange.md @@ -3,22 +3,22 @@ 前面的讨论中,我们假设集群节点数是固定的,也就是集群的 Quorum 是固定的。在生产环境中,集群常常需要进行节点变更,比如因故障移除节点或扩容增加节点等。你或许会想到关闭集群、更新配置后再重启系统,但这种做法对于一个本应具备容错能力的系统来说,未免过于“抽象”。 -讨论如何实现成员变更之前,我们先理解 Raft 中“配置”(configuration)的概念。 +讨论如何实现成员变更之前,我们先弄清楚 Raft 集群中“配置”(configuration)的概念。 :::tip 配置 配置说明集群由哪些节点组成。例如,一个集群有三个节点(Server 1、Server 2、Server 3),该集群的配置就是 [Server1、Server2、Server3]。 ::: -如果把“配置”当成 Raft 中的“特殊日志”。这样一来,成员的动态变更就可以转化为“配置日志”的一致性问题。但注意的是,各个节点中的日志“应用”(apply)到状态机是异步的,不可能同时操作。这种情况下,成员变更就会出现问题。 +如果把“配置”当成 Raft 中的“特殊日志”。这样一来,成员动态变更需求就可以转化为“配置日志”的一致性问题。但需要注意的是,各个节点中的日志“应用”(apply)到状态机是异步的,不可能同时操作。粗暴的 apply “配置日志”很容易导致“脑裂”问题。 -举个具体例子,假设当前有一个由三个节点 [Server1、Server2 和 Server3] 组成的 Raft 集群,当前集群配置为 C~old~。现在,我们计划增加两个节点 [Server1、Server2、Server3、Server4、Server5],新的集群配置为 C~new~。 +举个具体例子,假设有一个由三个节点 [Server1、Server2 和 Server3] 组成的 Raft 集群,当前的配置为 C~old~。现在,我们计划增加两个节点 [Server1、Server2、Server3、Server4、Server5],新的配置为 C~new~。 -由于日志提交是异步进行的,假设 Server1 和 Server2 比较迟钝,仍在使用老配置 C~old~,而 Server3、Server4、Server5 的状态机已经应用了新配置 C~new~: +由于日志提交是异步处理的,假设 Server1 和 Server2 比较迟钝,仍在使用老配置 C~old~,而 Server3、Server4、Server5 的状态机已经应用了新配置 C~new~: - 假设 Server5 触发选举并赢得 Server3、Server4、Server5 的投票(满足 C~new~ 配置下的 Quorum 3 要求),成为领导者; - 同时,假设 Server1 也触发选举并赢得 Server1、Server2 的投票(满足 C~old ~配置下的 Quorum 2 要求),成为领导者。 -在一个集群中,如果存在两个领导者,那么同一个日志索引可能会对应不同的日志条目,导致日志冲突和不一致。 +一个集群存在两个领导者也就是“脑裂”,同一个日志索引可能会对应不同的日志条目,最终导致集群数据不一致。 :::center ![](../assets/raft-ConfChange.png)
@@ -27,9 +27,9 @@ 上述问题的根本原因在于,成员变更过程中形成了两个没有交集的 Quorum,即 [Server1, Server2] 和 [Server3, Server4, Server5] 各自为营。 -最初,Diego Ongaro 在论文中提出了一种基于两阶段的“联合共识”(Joint Consensus)成员变更方案,但这种方案实现较为复杂。随后,Diego Ongaro 又提出一种更为简化的方案 — “单成员变更”(Single Server Changes)。该方案的核心思路是,既然同时提交多个成员变更可能会引发问题,那么每次只提交一个成员变更。如果需要添加多个成员,就执行多次单成员变更操作。 +Raft 的论文中,对此提出过一种基于两阶段的“联合共识”(Joint Consensus)成员变更方案,但这种方案实现较为复杂,Diego Ongaro 后来又提出一种更为简化的方案 — “单成员变更”(Single Server Changes)。该方案思想的核心是,既然同时提交多个成员变更可能引发问题,那么每次只提交一个成员变更,需要添加多个成员,就执行多次单成员变更操作。这样不就没有问题了么! -单成员变更方案能够有效穷举所有情况,如图 6-22 所示,穷举奇/偶数集群下节点添加/删除情况,如果每次只操作一个节点,C~old~ 的 Quorum 和 C~new~ 的 Quorum 一定存在交集。交集节点只会进行一次投票,要么投票给 C~old~,要么投票给 C~new~。因此,不可能出现两个符合条件的 Quorum,也就不会出现两个领导者。 +单成员变更方案很容易穷举所有情况,如图 6-22 所示,穷举奇/偶数集群下节点添加/删除情况。如果每次只操作一个节点,C~old~ 的 Quorum 和 C~new~ 的 Quorum 一定存在交集。交集节点只会进行一次投票,要么投票给 C~old~,要么投票给 C~new~。因此,不可能出现两个符合条件的 Quorum,也就不会出现两个领导者。 以图 6-16 第二种情况为例,C~old~ 为 [Server1、Server2、Server3],该配置的 Quorum 为 2,C~new~ 为 [Server1、Server2、Server3、Server4],该配置的 Quorum 为 3。假设 Server1、Server2 比较迟钝,还在用 C~old~ ,其他节点的状态机已经应用 C~new~: - 假设 Server1 触发选举,赢得 Server1,Server2 的投票,满足 C~old~ Quorum 要求,当选领导者; diff --git a/container/borg-omega-k8s.md b/container/borg-omega-k8s.md index e8fc7135..5b7e8524 100644 --- a/container/borg-omega-k8s.md +++ b/container/borg-omega-k8s.md @@ -17,28 +17,25 @@ Borg 的架构如图 7-1 所示,是典型的 Master(图中 BorgMaster) + Age ::: 开发 Borg 的过程中,Google 的工程师为 Borg 设计了两种工作负载(Workload)[^1]: -- **长期运行的服务(Long-Running Service)**:通常是对请求延迟敏感的在线业务,例如 Gmail、Google Docs 和 Web 搜索以及内部基础设施服务; -- **批处理任务(Batch Job)**:通常用于一次性地、按批次处理一大批数据或执行一系列任务,涉及大量数据处理,需要较长的运行时间和较多的计算资源。典型的 Batch Job 为 Apache Hadoop 或 Spark 等框架进行的各类离线计算任务。 - +- **长期运行服务(Long-Running Service)**:通常是对请求延迟敏感的在线业务,例如 Gmail、Google Docs 和 Web 搜索以及内部基础设施服务; +- **批处理任务(Batch Job)**:用于一次性处理大量数据、需要较长的运行时间和较多的计算资源的“批处理任务”(Batch Job)。典型如 Apache Hadoop 或 Spark 框架执行的各类离线计算任务。 区分 2 种不同类型工作负载的原因在于: -- **两者运行状态不同**:Long-Running Service 存在“环境准备ok,但进程没有启动”、“健康检查失败”等状态,这些状态 Batch Job 是没有的。运行状态不同,决定了两类应用程序生命周期管理、监控、资源分配操作的不同; -- **关注点与优化方向不一样**:一般而言,Long-Running Service 关注的是服务的“可用性”,而 Batch Job 关注的是系统的整体吞吐。关注点的不同,会进一步导致内部实现的分化。 +- **两者运行状态不同**:长期运行服务存在“环境准备ok,但进程没有启动”、“健康检查失败”等状态,这些状态是批处理任务没有的。运行状态不同,决定了两类应用程序生命周期管理、监控、资源分配操作的机制不同; +- **关注点与优化方向不一样**:一般而言,长期运行服务关注的是“可用性”,批处理任务关注的是“吞吐量”(Throughput),即单位时间内系统能够处理的任务数量或数据量。两者关注点不同,进一步导致内部实现机制的分化。 在 Borg 系统中,大多数长期运行的服务(Long-Running Service)被赋予高优先级(此类任务在 Borg 中称为 "prod"),而批处理任务(Batch Job)则被赋予低优先级(此类任务在 Borg 中称为 "non-prod")。Borg 的任务优先级设计基于“资源抢占”模型,即高优先级的 prod 任务可以抢占低优先级的 non-prod 任务所占用的资源。 -这一设计的底层技术由 Google 贡献给 Linux 内核的 cgroups 支撑。cgroups 是容器技术的基础之一,提供了对网络、计算、存储等各类资源的隔离(7.2 节,笔者将详细介绍 cgroups 技术)。Borg 通过 cgroups 技术,实现了不同类型工作负载的混合部署,使其能够共享主机资源而互不干扰。Google 的运维结果表明,Borg 系统显著提升了资源利用率,降低了硬件成本。 +这一设计的底层技术由 Google 贡献给 Linux 内核的 cgroups 支撑。cgroups 是容器技术的基础之一,提供了对网络、计算、存储等各类资源的隔离(7.2 节,笔者将详细介绍 cgroups 技术)。Borg 通过 cgroups 技术,实现了不同类型工作负载的混合部署,共享主机资源同时互不干扰。 随着 Google 内部越来越多的应用程序被部署到 Borg 上,业务团队与基础架构团队开发了大量围绕 Borg 的管理工具和服务,如资源需求预测、自动扩缩容、服务发现与负载均衡、监控系统(Brogmon,Prometheus 的前身,笔者将在第九章详细介绍)等,并逐渐形成了基于 Borg 的内部生态系统。 ## 7.1.2 Omega 系统 -Borg 生态的发展由 Google 内部不同团队推动。 - -从迭代结果来看,Borg 生态是一系列异构且自发形成的工具和系统,而不是一个精心设计的整体架构。为使 Borg 生态更符合软件工程规范,Google 在汲取 Borg 设计与运维经验的基础上开发了 Omega 系统。 +Borg 生态的发展由 Google 内部不同团队推动。从迭代结果来看,Borg 生态是一系列异构且自发形成的工具和系统,而不是一个精心设计的整体架构。 -相比 Borg,Omega 的最大改进是将 BorgMaster 的功能拆分为多个交互组件,而不再是一个单体、中心化的 Master。此外,Omega 还显著提升了大规模集群的任务调度效率: +为使 Borg 生态更符合软件工程规范,Google 在汲取 Borg 设计与运维经验的基础上开发了 Omega 系统。相比 Borg,Omega 的最大改进是将 BorgMaster 的功能拆分为多个交互组件,而不再是一个单体、中心化的 Master。此外,Omega 还显著提升了大规模集群的任务调度效率: - Omega 基于 Paxos 算法实现了一套分布式一致性和高可用的键值存储(内部称为 Store),集群的所有状态都保存在 Store 中; - 拆分后的组件(如容器编排调度器、中央控制器)可以直接访问 Store; @@ -73,8 +70,7 @@ Google 开发的第三套容器管理系统是 Kubernetes,其背景如下: 图 7-3 Kubernetes 架构以及组件概览 [图片来源](https://link.medium.com/oWobLWzCQJb) ::: - -出于降低用户使用的门槛,并最终达成 Google 从底层进军云计算市场意图,Kubernetes 定下的设计目标是**享受容器带来的资源利用率提升的同时,让部署和管理复杂分布式系统的基础设施标准化且更简单**。 +出于降低用户使用的门槛,并最终达成 Google 从底层进军云计算市场意图,Kubernetes 定下的设计目标是**享受容器带来的资源利用率提升的同时,让支撑分布式系统的基础设施标准化、操作更简单**。 为了进一步理解基础设施的标准化,来看 Kubernetes 从一开始就提供的东西 —— 用于描述各种资源需求的标准 API: @@ -85,11 +81,11 @@ Google 开发的第三套容器管理系统是 Kubernetes,其背景如下: 各云厂商已经将 Kubernetes 结构和语义对接到它们各自的原生 API 上。所以,Kubernetes 描述资源需求的 API 是跨公有云、私有云和各家云厂商的,也就是说只要基于 Kubernetes 的规范管理应用程序,那么应用程序就能无缝迁移到任何云中。 -**提供一套跨厂商的标准结构和语义来声明核心基础设施(Pod、Service、Volume...)是 Kubernetes 设计的关键。在此基础上,它又通过 CRD(Custom Resource Define,自定义资源定义)将这个设计扩展到几乎所有的基础设施资源**。 +**提供一套跨厂商的标准结构和语义来声明核心基础设施是 Kubernetes 设计的关键。在此基础上,它又通过 CRD(Custom Resource Define,自定义资源定义)将这个设计扩展到几乎所有的基础设施资源**。 有了 CRD,用户不仅能声明 Kubernetes API 预定义的计算、存储、网络服务,还能声明数据库、Task Runner、消息总线、数字证书等等任何云厂商能想到的东西!随着 Kubernetes 资源模型越来越广泛的传播,现在已经能够用一组 Kubernetes 资源来描述一整个软件定义计算环境。 -就像用 docker run 可以启动单个程序一样,现在用 kubectl apply -f 就能部署和运行一个分布式应用程序,而无需关心是在私有云、公有云或者具体哪家云厂商上。 +就像用 docker run 可以启动单个程序一样,现在用 kubectl apply -f 就能部署和运行一个分布式应用程序,无需关心是在私有云、公有云或者具体哪家云厂商上。 ## 7.1.4 以应用为中心的转变