Skip to content

Commit

Permalink
fix typo
Browse files Browse the repository at this point in the history
  • Loading branch information
isno committed Dec 28, 2024
1 parent 8c9eec4 commit 5ee0b5b
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 24 deletions.
2 changes: 1 addition & 1 deletion Observability/profiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

熟悉 Golang 的工程师对 pprof 工具一定不陌生。借助 pprof 提供的 CPU 和内存分析功能,工程师能够深入了解 Golang 函数的执行时间、内存使用情况,从而分析、优化应用性能。

可观测性领域内的性能剖析(Profiling)和 Golang 中的 pprof 目标一致,两者皆是对运行中应用动态分析、生成详细的运行数据(Profiles),帮助工程师全面了解应用资源使用情况,确定代码和性能瓶颈之间的关联
可观测性领域内的性能剖析(Profiling)和 Golang 中的 pprof 目标一致,两者皆是对运行中应用进行分析、生成详细的运行数据(Profiles),帮助工程师全面了解应用运行时的行为、资源使用全貌,从而确定代码和性能瓶颈之间的关联

Profiles 数据通常以火焰图、堆栈图或内存分析图等形式呈现,是从“是什么”到“为什么”这一过程中重要的依据。例如,通过链路追踪识别出延迟(是什么)的位置,然后根据火焰图进一步定位到具体的代码行(为什么)。2021 年,国内某网站崩溃,工程师分析火焰图发现 Lua 代码存在异常,最终成功定位到问题源头[^1]

Expand Down
4 changes: 2 additions & 2 deletions ServiceMesh/control-plane.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 代理。
- **流量管理**:管理流量路由规则,包括负载均衡、分流、镜像、熔断、超时与重试等功能。
Expand All @@ -25,7 +25,7 @@ Istio 自发布首个版本以来,有着一套“堪称优雅”的架构设
图 8-12 Istio 架构及各个组件
:::

通过将架构从多进程转为单进程,Istio 的开发团队以最小的成本显著提高了运维收益
Istio 1.5 版本的架构变化,实际上是将原有的多进程设计转换为单进程模式,以最小的成本实现最高的运维收益

- 运维配置变得更加简单,用户只需要部署或升级一个单独的服务组件;
- 更加容易排查错误,因为不需要再横跨多个组件去排查各种错误;
Expand Down
14 changes: 7 additions & 7 deletions consensus/raft-ConfChange.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) <br/>
Expand All @@ -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 要求,当选领导者;
Expand Down
24 changes: 10 additions & 14 deletions container/borg-omega-k8s.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -73,8 +70,7 @@ Google 开发的第三套容器管理系统是 Kubernetes,其背景如下:
图 7-3 Kubernetes 架构以及组件概览 [图片来源](https://link.medium.com/oWobLWzCQJb)
:::


出于降低用户使用的门槛,并最终达成 Google 从底层进军云计算市场意图,Kubernetes 定下的设计目标是**享受容器带来的资源利用率提升的同时,让部署和管理复杂分布式系统的基础设施标准化且更简单**
出于降低用户使用的门槛,并最终达成 Google 从底层进军云计算市场意图,Kubernetes 定下的设计目标是**享受容器带来的资源利用率提升的同时,让支撑分布式系统的基础设施标准化、操作更简单**

为了进一步理解基础设施的标准化,来看 Kubernetes 从一开始就提供的东西 —— 用于描述各种资源需求的标准 API:

Expand All @@ -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 以应用为中心的转变

Expand Down

0 comments on commit 5ee0b5b

Please sign in to comment.