diff --git a/.vuepress/config.js b/.vuepress/config.js
index 3994139b..33ed7dbf 100644
--- a/.vuepress/config.js
+++ b/.vuepress/config.js
@@ -290,7 +290,7 @@ export default defineUserConfig({
"/observability/What-is-Observability.md",
"/observability/Observability-vs-Monitoring.md",
{
- text: "9.3 可观测数据的分类及处理",
+ text: "9.3 遥测数据的分类与处理",
link: '/observability/signals.md',
children: [
'/observability/metrics.md',
diff --git a/Observability/OpenTelemetry.md b/Observability/OpenTelemetry.md
index 5e1dfb00..17fa1811 100644
--- a/Observability/OpenTelemetry.md
+++ b/Observability/OpenTelemetry.md
@@ -1,4 +1,4 @@
-# 9.4 可观测标准项目的演进
+# 9.4 可观测标准的演进
Dapper 论文发布后,市场上涌现出大量追踪系统,如 Jaeger、Pinpoint、Zipkin 等。这些系统都基于 Dapper 论文实现,功能上无本质差异,但实现方式和技术栈不同,导致它们难以兼容或协同使用。
diff --git a/Observability/logging.md b/Observability/logging.md
index 7c941466..8da1848d 100644
--- a/Observability/logging.md
+++ b/Observability/logging.md
@@ -93,14 +93,14 @@ ClickHouse 是由俄罗斯 Yandex 公司[^2]于 2008 年开发的开源列式数
| #2 | 89953706054 | 78 | Mission| 1 | 2016-05-18 07:38:00| |
| #N | ...| ...| ...| ... | ...
-在行式数据库中,表的一行数据会在物理存储介质中紧密相邻。如果要执行下面的 SQL 来统计某个产品的销售额,行式数据库需要加载整个表的所有行到内存,进行扫描和过滤(检查是否符合 WHERE 条件)。过滤出目标行后,若有聚合函数(如 SUM、MAX、MIN),还需要进行相应的计算和排序,最后才会过滤掉不必要的列,整个过程可能非常耗时。
+在行式数据库中,一行数据会在物理存储介质中紧密相邻。如果要执行下面的 SQL 来统计某个产品的销售额,行式数据库需要加载整个表的所有行到内存,进行扫描和过滤(检查是否符合 WHERE 条件)。过滤出目标行后,若有聚合函数(如 SUM、MAX、MIN),还需要进行相应的计算和排序,最后才会过滤掉不必要的列,整个过程可能非常耗时。
```SQL
// 统计销售额
SELECT sum(sales) AS count FROM 表 WHERE ProductId=90329509958
```
-接下来,我们来看列式数据库,ClickHouse 的数据组织如表 9-3 所示,数据按列而非按行存储。我们继续以上面的统计销售额的 SQL 为例,列式数据库只读取与查询相关的列(如 sales 列),不会读取不相关列,从而减少不必要的磁盘 I/O 操作。
+接下来,我们来看列式数据库,ClickHouse 的数据组织如表 9-3 所示,数据按列而非按行存储,一列数据在物理存储介质中紧密相邻。我们继续以上面的统计销售额的 SQL 为例,列式数据库只读取与查询相关的列(如 sales 列),不会读取不相关列,从而减少不必要的磁盘 I/O 操作。
表 9-3 列式数据库存储结构
diff --git a/Observability/metrics.md b/Observability/metrics.md
index a80cabbc..39044c34 100644
--- a/Observability/metrics.md
+++ b/Observability/metrics.md
@@ -29,17 +29,15 @@ Prometheus 起源可以追溯到 Google 的内部监控系统 BorgMon。2012 年
## 2. 通过 Exporter 收集指标
-定义完指标类型后,接下来的任务是从监控目标中收集这些指标。
-
收集指标看似简单,但实际上复杂得多:首先,应用程序、操作系统和硬件设备的指标获取方式各不相同;其次,它们通常不会以 Prometheus 格式直接暴露。例如:
- Linux 的许多指标信息存储在 /proc 目录下,如 /proc/meminfo 提供内存信息,/proc/stat 提供 CPU 信息。
- Redis 的监控数据通过执行 INFO 命令获取。
- 路由器等硬件设备的监控数据通常通过 SNMP 协议获取。
-为了解决上述问题,Prometheus 设计了 Exporter 作为监控系统与被监控目标之间的“中介”,负责将不同来源的监控数据转换为 Prometheus 支持的格式。Exporter 通过 HTTP 协议将指标暴露在指定的端点(通常是 /metrics)上,供 Prometheus 定期抓取。
+为了解决上述问题,Prometheus 设计了 Exporter 作为监控系统与被监控目标之间的“中介”,负责将不同来源的监控数据转换为 Prometheus 支持的格式。
-如下所示,Prometheus 请求某个 Exporter,获取名称为 http_request_total、类型为 Counter 的指标。Prometheus 定期请求这个接口,从而实现对系统状态的实时监控的目标。
+Exporter 通过 HTTP 协议将指标暴露在指定的端点(通常是 /metrics)上,供 Prometheus 定期抓取。如下所示,Prometheus 定期请求某个 Exporter,获取名称为 http_request_total、类型为 Counter 的指标。
```bash
$ curl http://127.0.0.1:8080/metrics | grep http_request_total
@@ -48,7 +46,7 @@ $ curl http://127.0.0.1:8080/metrics | grep http_request_total
http_request_total 5
```
-现今,Prometheus 社区涌现出大量用于不同场景的 Exporter,涵盖了基础设施、中间件和网络等各个领域。如表 9-1 所示,这些 Exporter 扩展了 Prometheus 的监控范围,几乎覆盖了所有用户关心的监控目标。
+现今,Prometheus 社区涌现出大量用于不同场景的 Exporter,涵盖了基础设施、中间件和网络等各个领域。如表 9-1 所示,这些 Exporter 扩展了 Prometheus 的监控范围,几乎覆盖了用户关心的所有监控目标。
:::center
表 9-1 Prometheus 中常用 Exporter
@@ -60,25 +58,23 @@ http_request_total 5
| 硬件 | Apcupsd Exporter、IoT Edison Exporter、IPMI Exporter、Node Exporter 等 |
| 消息队列 | Beanstalkd Exporter、Kafka Exporter、NSQ Exporter、RabbitMQ Exporter 等 |
| 存储 | Ceph Exporter、Gluster Exporter、HDFS Exporter、ScaleIO Exporter 等 |
- | HTTP服务 | Apache Exporter、HAProxy Exporter、Nginx Exporter 等 |
- | API服务 | AWS ECS Exporter、Docker Cloud Exporter、Docker Hub Exporter、GitHub Exporter 等 |
+ | HTTP 服务 | Apache Exporter、HAProxy Exporter、Nginx Exporter 等 |
+ | API 服务 | AWS ECS Exporter、Docker Cloud Exporter、Docker Hub Exporter、GitHub Exporter 等 |
| 日志 | Fluentd Exporter、Grok Exporter 等 |
| 监控系统 | Collectd Exporter、Graphite Exporter、InfluxDB Exporter、Nagios Exporter、SNMP Exporter 等 |
| 其它 | Blockbox Exporter、JIRA Exporter、Jenkins Exporter、Confluence Exporter 等|
## 3. 存储指标
-存储数据本来是一项常规操作,但当面对存储指标类型的场景来说,必须换一种思路应对。举例来说,假设你负责管理一个小型集群,该集群有 10 个节点,运行着 30 个微服务系统。每个节点需要采集 CPU、内存、磁盘和网络等资源使用情况,而每个服务则需要采集业务相关和中间件相关的指标。假设这些加起来一共有 20 个指标,且按每 5 秒采集一次。那么一天的数据规模将是:
+存储数据本来是一项常规操作,但当面对存储指标类型的场景来说,必须换一种思路应对。举例来说,假设你负责管理一个小型集群,该集群有 10 个节点,运行着 30 个微服务系统。每个节点需要采集 CPU、内存、磁盘和网络等资源使用情况,而每个服务则需要采集业务相关和中间件相关的指标。假设这些加起来一共有 20 个指标,且按每 5 秒采集一次。那么,一天的数据规模将是:
```
10(节点)* 30(服务)* 20 (指标) * (86400/5) (秒) = 103,680,000(记录)
```
-对于一个仅有 10 个节点的小规模业务来说,`7*24` 小时不间断生成的数据可能超过上亿条记录,占用 TB 级别的存储空间。
-
-虽然关系型数据库或 NoSQL 数据库也可以处理时序数据,但它们并未充分利用时序数据的特点。因此,使用这些数据库往往需要不断增加计算和存储资源,导致系统的运维成本急剧上升。如何低成本存储这些海量的指标数据,是个关乎系统可用的重要课题。
+对于一个仅有 10 个节点的小规模业务来说,`7*24` 小时不间断生成的数据可能超过上亿条记录,占用 TB 级别的存储空间。虽然关系型数据库或 NoSQL 数据库也可以处理时序数据,但它们并未充分利用时序数据的特点。因此,使用这些数据库往往需要不断增加计算和存储资源,导致系统的运维成本急剧上升。如何低成本存储这些海量的指标数据,是个关乎系统可用的重要课题。
-根据下面的指标数据思考它们的特征。
+以一个具体的指标数据为例,分析其特征可以发现,指标数据是纯数字型的,具有时间属性,旨在揭示某些事件的趋势和规律。此类数据通常不涉及关系嵌套、主键/外键,也不需要考虑事务处理。针对这一数据特点,业界已发展出专门优化的数据库类型——时序数据库(Time-Series Database,简称 TSDB)。
```json
{
@@ -92,14 +88,10 @@ http_request_total 5
},
```
-观察上述的数据结构,可以看出指标类型的数据是纯数字的、具有时间属性,目的揭示某些事件的趋势和规律。它们肯定没有关系嵌套、不用考虑主键/外键、不用考虑事务处理。对于这种类型的数据,业界也发展出了专门优化的数据库类型 —— 时序数据库(Time-Series Database,简称 TSDB)。
-
-时序数据库并不是一个新概念。最早的专用时序数据库之一是 1999 年问世的 RRDtool。自 2015 年以来,随着对实时数据监控、性能管理和预测分析需求的增加,时序数据库逐渐受到广泛关注,现已成为 DB-engines 排行网站上最受欢迎的数据库类型。
-
与常规数据库(如关系型数据库或 NoSQL 数据库)相比,时序数据库在设计和用途上存在显著区别。笔者介绍数据结构、数据保留策略方面的差异供你参考:
-- 数据结构:时序数据库使用 LSM-Tree(Log-Structured Merge-Tree)来替代常规数据库中的 B+Tree。时序数据库中,所有写入操作首先写入内存存储区(MemTable,通常为跳表或平衡树)。当 MemTable 满时,数据会被批量写入磁盘文件中。虽然磁盘写入延迟较高,但由于批量操作,时序数据库在写入吞吐量上通常优于传统关系数据库(使用 B+Tree)。
-- 数据保留策略:时序数据通常有明确的生命周期,例如监控数据可能只需保留几天或几个月。时序数据库通常具有自动化的数据保留策略(data retention),以防止存储空间无限膨胀。例如,可以设置基于时间的保留策略,保留最近 30 天的数据,超过 30 天的数据将自动删除。
+- **数据结构**:时序数据库使用 LSM-Tree(Log-Structured Merge-Tree)来替代常规数据库中的 B+Tree。时序数据库中,所有写入操作首先写入内存存储区(MemTable,通常为跳表或平衡树)。当 MemTable 满时,数据会被批量写入磁盘文件中。虽然磁盘写入延迟较高,但由于批量操作,时序数据库在写入吞吐量上通常优于传统关系数据库(使用 B+Tree)。
+- **数据保留策略**:时序数据通常有明确的生命周期,例如监控数据可能只需保留几天或几个月。时序数据库通常具有自动化的数据保留策略(data retention),以防止存储空间无限膨胀。例如,可以设置基于时间的保留策略,保留最近 30 天的数据,超过 30 天的数据将自动删除。
Prometheus 服务端内置了一个强大的时序数据库(该时序数据库与 Prometheus 同名)。Prometheus 时序数据库将数据按照时间范围进行“分片”存储,每两小时为一个时间窗口,数据被组织成时间块(chunk)。每个时间块包含该时间段内的所有样本数据、元数据文件以及索引文件。通过时间窗口以及分片的方式存储数据,使得 Prometheus 可以在海量数据规模的情况下,高效地根据特定时间段进行分析/查询指标。
@@ -110,9 +102,9 @@ Prometheus 服务端内置了一个强大的时序数据库(该时序数据库
笔者稍后介绍的 Elastic Stack、ClickHouse 等技术皆是利用了分片技术实现水平可扩展以及并行计算能力。
:::
-Prometheus 时序数据库内置了专用的数据查询语言 PromQL(Prometheus Query Language)。
+Prometheus 时序数据库内置了专用的数据查询语言 PromQL(Prometheus Query Language),这是一种由 Prometheus 定制的查询 DSL,其语法类似于支持函数和运算的 CSS 选择器。
-PromQL 是一种由 Prometheus 定制的查询 DSL,其语法类似于支持函数和运算的 CSS 选择器。举一个例子供你参考,假设有一个名为 http_requests_total 的指标,要计算过去 5 分钟内 host 标签为 server1 的请求速率,该 PromQL 查询如下:
+举个例子,假设有一个名为 http_requests_total 的指标,若要计算过去 5 分钟内 host 标签为 server1 的请求速率,该 PromQL 如下:
```PromQL
rate(http_requests_total{host="server1"}[5m])
@@ -120,20 +112,16 @@ rate(http_requests_total{host="server1"}[5m])
// 返回查询结果
92.0
```
-PromQL 对时间序列数据提供了丰富的查询、聚合和逻辑运算,已广泛应用于 Prometheus 指标查询、可视化和告警处理等日常操作中。掌握 PromQL 语法已成为必备技能,笔者就不再详细介绍语法细节了。
+PromQL 提供了强大的查询、聚合和逻辑运算功能,广泛应用于 Prometheus 的指标查询、可视化和告警处理等日常操作中。掌握 PromQL 语法是使用 Prometheus 的必备技能,笔者就不再详细介绍语法细节了。
## 4. 展示分析/预警
采集/存储指标最终目的要用起来,也就是要“展示分析”以及“预警”。
-在数据分析和可视化领域,Grafana Labs 公司开发的 Grafana 已成为事实上的标准。最初,Grafana 专注于时间序列数据的监控与分析,但随着项目的发展,它已经扩展到所有需要数据可视化和监控的场景,包括 IT 运维、应用性能监控以及物联网、金融、医疗等行业。
+在数据分析和可视化领域,Grafana Labs 公司开发的 Grafana 已成为行业事实标准。图 9-5 展示了一个 Grafana 仪表板(Dashboard),它两个核心概念:
-图 9-5 展示了一个 Grafana 仪表板(Dashboard),它两个核心概念:
-
-- **数据源(Data Source)**:在 Grafana 中,数据源指的是为其提供数据的服务。Grafana 支持多种数据源,包括时序数据库(如 Prometheus、Graphite、InfluxDB)、日志数据库(如 Loki、Elasticsearch)、关系型数据库(如 MySQL、PostgreSQL),以及云监控平台(如 Google Cloud Monitoring、Amazon CloudWatch、Azure Monitor)。Grafana 插件库中提供了多达 165 种数据源。如果找不到某个特定的数据源,那通常意味着该数据源已经被市场淘汰。
-- **面板(Panel)**:面板是仪表板中的基本构建块,用于显示各种可视化图表。Grafana 提供了多种图表类型,如仪表盘、表格、折线图、柱状图、热力图、饼图和直方图等。每个面板可以单独配置,并具备交互选项。通过 Panel 的 Query Editor(查询编辑器),可以为每个面板设置不同的数据源。例如,如果以 Prometheus 作为数据源,那在 Query Editor 中,我们使用 PromQL 查询语言从 Prometheus 中查询出相应的数据,并且将其可视化。Grafana 支持多种数据源,每个面板可配置不同的数据源,这样就可以在一个统一的界面上(仪表板)整合和展示来自多种不同系统的数据。
-
-Grafana 几乎涵盖了所有的数据源和图表类型。正如 Grafana 的宣传语所言“只要你能想到的数据,都能转化为你想要的图表”。
+- **面板**(Panel):仪表板中的基本构建块,用于显示各种可视化图表。Grafana 提供了多种图表类型,如仪表盘、表格、折线图、柱状图、热力图、饼图和直方图等。每个面板可配置不同的数据源,这样就可以在一个统一的界面上(仪表板)整合和展示来自多种不同系统的数据。
+- **数据源**(Data Source):图表背后的数据服务。Grafana 支持多种数据源,包括时序数据库(如 Prometheus、Graphite、InfluxDB)、日志数据库(如 Loki、Elasticsearch)、关系型数据库(如 MySQL、PostgreSQL),以及云监控平台(如 Google Cloud Monitoring、Amazon CloudWatch、Azure Monitor)。Grafana 插件库中提供了多达 165 种数据源。如果找不到某个你想要的数据源,那通常意味着该数据源已经被市场淘汰。
:::center

@@ -157,12 +145,9 @@ groups:
summary: "High QPS detected on instance {{ $labels.instance }}"
description: "Instance {{ $labels.instance }} (job {{ $labels.job }}) has had a QPS greater than 1000 for more than 5 minutes."
```
+上述的配置,定期使用 PromQL 语法检查过去 5 分钟内,某个被监控目标(instance)中指定服务(job)的 QPS 是否超过 1000。如果条件满足,Prometheus 就会触发告警,Alertmanager 负责对告警进一步处理,笔者列举部分操作供你参考:
-这段规则定期通过 PromQL 语法检测过去 5 分钟内某个被监控目标(instance)中的某个具体服务(job)的 QPS 是否大于 1000。如果条件满足,Prometheus 就会触发告警,并将其发送到 Alertmanager。
-
-Alertmanager 负责对告警进一步处理,例如:
-
-- 分组(Grouping):将具有相似标签的告警进行分组,以减少告警冗余。例如,若多个实例的故障告警属于同一服务,Alertmanager 可以将这些告警合并为一个群组发送,而不是发送多个独立的通知。
-- 抑制(Inhibition):定义规则来抑制某些告警的触发。当某个重要告警已触发时,可以避免其他相关但不那么重要的告警再次触发,从而防止告警风暴。例如,当整个服务宕机时,单个实例宕机的告警可以被抑制。
-- 静默(Silencing):在特定时间段内禁用某些告警通知。静默操作可以通过指定标签、持续时间和备注等条件设置,常用于维护期间的告警屏蔽。
-- 路由(Routing):根据告警标签或其他规则将告警路由到不同的接收端。Alertmanager 支持通过标签、优先级等条件进行灵活的路由设置。例如,将高优先级告警发送到短信和电话通知,而将低优先级告警仅通过邮件发送。
+- **分组**(Grouping):将具有相似标签的告警进行分组,以减少告警冗余。例如,若多个实例的故障告警属于同一服务,Alertmanager 可以将这些告警合并为一个群组发送,而不是发送多个独立的通知。
+- **抑制**(Inhibition):定义规则来抑制某些告警的触发。当某个重要告警已触发时,可以避免其他相关但不那么重要的告警再次触发,从而防止告警风暴。例如,当整个服务宕机时,单个实例宕机的告警可以被抑制。
+- **静默**(Silencing):在特定时间段内禁用某些告警通知。静默操作可以通过指定标签、持续时间和备注等条件设置,常用于维护期间的告警屏蔽。
+- **路由**(Routing):根据告警标签或其他规则将告警路由到不同的接收端。Alertmanager 支持通过标签、优先级等条件进行灵活的路由设置。比如高优先级告警短信通知、低优先级告警邮件通知。
diff --git a/ServiceMesh/conclusion.md b/ServiceMesh/conclusion.md
index 5500409e..70fe0791 100644
--- a/ServiceMesh/conclusion.md
+++ b/ServiceMesh/conclusion.md
@@ -1,9 +1,9 @@
# 8.7 小结
-本章第二节,我们回顾了服务间通信的演变,从中解释了服务网格出现的背景、它到底解决了什么问题。服务网格“出圈”的原因,不在于它提供了多少功能(传统的 SDK 框架都有),而是把非业务逻辑从应用程序内剥离的设计思想。
+在本章第二节,我们回顾了服务间通信的演变,并阐述了服务网格出现的背景。相信你已经理解,服务网格之所以受到青睐,关键不在于它提供了多少功能(这些功能传统 SDK 框架也有),而在于其将非业务逻辑从应用程序中剥离的设计思想。
-从最初 TCP/IP 协议的出现,我们看到网络传输相关的逻辑从应用层剥离,下沉至操作系统,成为操作系统的网络层。分布式系统的崛起,又带来了特有的分布式通信语义(服务发现、负载均衡、限流、熔断、加密...)。为了降低治理分布式通信的心智负担,面向微服务架构的 SDK 框架出现了,但这类框架与业务逻辑耦合在一起,带来门槛高、无法跨语言、升级困难三个固有问题。
+从最初 TCP/IP 协议的出现,我们看到网络传输相关的逻辑从应用层剥离,下沉至操作系统,成为操作系统的网络层。分布式系统的崛起,又带来了特有的分布式通信语义(服务发现、负载均衡、限流、熔断、加密...)。为了降低治理分布式通信的心智负担,面向微服务的 SDK 框架出现了,但这类框架与业务逻辑耦合在一起,带来门槛高、无法跨语言、升级困难三个固有问题。
-服务网格为分布式通信治理带来了全新的思路:通信治理逻辑从应用程序内部剥离至边车代理,下沉至 Kubernetes、下沉至各个云平台,在应用层与基础设施层之间衍生出全新的微服务治理层。沿着上述“分离/下沉”的设计思想,服务网格的形态不再与 Sidecar 挂钩,开始多元化,出现了 Proxyless、Sidecarless、Ambient Mesh 等多种模式。
+而服务网格为分布式通信治理带来了全新的解决思路:通信治理逻辑从应用程序内部剥离至边车代理,下沉至 Kubernetes、下沉至各个云平台,在应用层与基础设施层之间衍生出全新的微服务治理层。沿着上述“分离/下沉”的设计理念,服务网格的形态不再局限于 Sidecar,开始多元化,出现了 Proxyless、Sidecarless、Ambient Mesh 等多种模式。
无论通信治理逻辑下沉至哪里、服务网格以何种形态存在,核心把非业务逻辑从应用程序中剥离,让业务开发更简单。这正是业内常提到的“以应用为中心”的软件设计核心理念。
\ No newline at end of file
diff --git a/application-centric/Kustomize.md b/application-centric/Kustomize.md
index fb27f1ea..46f07dcf 100644
--- a/application-centric/Kustomize.md
+++ b/application-centric/Kustomize.md
@@ -1,6 +1,6 @@
# 10.3.1 Kustomize
-Kubernetes 官方对应用的定义是一组具有相同目标资源合集。这种设定下,只要应用规模稍大,资源配置文件就开始泛滥。尤其是当不同环境(如开发和生产环境)之间的差异较小时,你就会发现通过 kubectl 管理应用十分“蛋疼”。
+Kubernetes 官方对应用的定义是一组具有相同目标资源合集。这种设定下,只要应用规模稍大,尤其是不同环境(如开发和生产环境)之间的差异较小时,资源配置文件就开始泛滥。尤其是当不同环境(如开发和生产环境)之间的差异较小时,你就会发现通过 kubectl 管理应用十分“蛋疼”。
Kubernetes 对此的观点是,如果逐一配置和部署资源文件过于繁琐,那就将应用中的稳定信息与可变信息分离,并自动生成一个多合一(All-in-One)的配置包。完成这一任务的工具名为 Kustomize。
diff --git a/container/borg-omega-k8s.md b/container/borg-omega-k8s.md
index 2a111a5a..a36c109b 100644
--- a/container/borg-omega-k8s.md
+++ b/container/borg-omega-k8s.md
@@ -1,15 +1,13 @@
-# 7.1 从 Borg 到 Kubernetes:容器编排系统的演变
+# 7.1 容器编排系统的演变
近几年,业界对容器技术兴趣越来越大,大量的公司开始逐步将虚拟机替换成容器。
-实际上,早在十几年前,Google 内部就已开始大规模的实践容器技术了。实践过程中,Google 先后设计了三套不同的容器管理系统(Borg、Omega 和 Kubernetes),并向外界分享了大量的设计思想、论文和源码,直接促进了容器技术的普及和发展,对整个行业的技术演进产生了深远的影响。
+实际上,早在十几年前,Google 内部就已开始大规模的实践容器技术了。Google 先后设计了三套不同的容器管理系统,Borg、Omega 和 Kubernetes,并向外界分享了大量的设计思想、论文和源码,直接促进了容器技术的普及和发展,对整个行业的技术演进产生了深远的影响。
## 7.1.1 Borg 系统
Google 内部第一代容器管理系统叫 Borg。
-Borg 的架构如图 7-1 所示,是典型的 Master(图中 BorgMaster) + Agent(图中的 Borglet)架构。
-
-用户通过命令行或者浏览器将任务提交给 BorgMaster,BorgMaster 负责记录“某某任务运行在某某节点上”这类元信息,然后节点中的 Borglet 与 BorgMaster 通信,获取分配给自己的任务,在节点操作容器执行具体的任务。
+Borg 的架构如图 7-1 所示,是典型的 Master(图中 BorgMaster) + Agent(图中的 Borglet)架构。用户通过命令行或浏览器将任务提交给 BorgMaster,后者负责记录任务与节点的映射关系(如“任务 A 运行在节点 X 上”)。随后,节点中的 Borglet 与 BorgMaster 进行通信,获取分配给自己的任务,然后启动容器执行。
:::center

@@ -89,16 +87,12 @@ Google 开发的第三套容器管理系统是 Kubernetes,其背景如下:
## 7.1.4 以应用为中心的转变
-容器化技术从最初的 Borg 到 Kubernetes,其收益早已超越了单纯提高资源利用率的范畴。更大的变化在于,系统开发和运维理念从“以机器为中心”转向“以应用为中心”。
-
-- 容器封装了应用程序运行的环境,屏蔽了操作系统和机器的细节,使业务开发者和基础设施管理者不再关注底层细节;
-- 每个设计良好的容器或容器镜像通常对应一个应用,管理容器即是管理应用,而非管理机器。
-
-正是以应用为中心,云原生技术体系才会无限强调让基础设施能更好的配合应用、以更高效方式为应用输送基础设施能力:
+从最初的 Borg 到 Kubernetes,容器化技术的价值早已超越了单纯提升资源利用率。更深远的变化在于,系统开发和运维理念从“以机器为中心”转向“以应用为中心”。
-- 开发者和运维团队无需再关心机器、操作系统等底层细节;
-- 基础设施团队引入新硬件和升级操作系统更加灵活,最大限度减少对线上应用和应用开发者的影响;
-- 将收集到的各类关键性能指标(如 CPU 使用率、内存用量、每秒查询率 QPS 等)与应用程序而非物理机器关联,显著提高了应用监控的精确度和可观测性,尤其是在系统垂直扩容、机器故障或主动运维等场景。这直接促使软件可观测性领域应运而生。
+- 容器封装了应用程序的运行环境,屏蔽了操作系统和硬件的细节,使得业务开发者和基础设施管理者不再需要关注底层实现。
+- 基础设施团队可以更灵活地引入新硬件或升级操作系统,最大限度减少对线上应用和开发者的影响。
+- 每个设计良好的容器通常代表一个应用,因此管理容器就等于管理应用,而非管理机器。
+- 将收集的性能指标(如 CPU 使用率、内存用量、每秒查询率 QPS 等)与应用程序而非物理机器关联,显著提高了应用监控的精确度和可观测性,尤其是在系统垂直扩容、机器故障或主动运维等场景。
[^1]: 在 Kubernetes 中的 Workload 资源包括多种类型,例如 Deployment、StatefulSet、DaemonSet、ReplicaSet 等等
diff --git a/container/kube-scheduler.md b/container/kube-scheduler.md
index 7e9b616d..71cf5f29 100644
--- a/container/kube-scheduler.md
+++ b/container/kube-scheduler.md
@@ -73,9 +73,7 @@ func getDefaultConfig() *schedulerapi.Plugins {
}
```
-上述插件本质上是按照 Scheduling Framework 规范实现 Filter 方法,根据方法内预设的策略筛选节点。
-
-内置筛选插件的筛选策略,可总结为下述三类:
+上述插件本质上是按照 Scheduling Framework 规范实现 Filter 方法,根据方法内预设的策略筛选节点。总结它们的筛选策略为下述三类:
- **通用过滤策略**:负责最基础的筛选策略。例如,检查节点可用资源是否满足 Pod 请求(request),检查 Pod 申请的宿主机端口号(spec.nodeport)是否跟节点中端口号冲突。对应的插件有 noderesources、nodeports 等。
- **节点相关的过滤策略**:与节点相关的筛选策略。例如,检查 Pod 中污点容忍度(tolerations)是否匹配节点的污点(taints);检查待调度 Pod 节点亲和性设置(nodeAffinity)是否和节点匹配;检查待调度 Pod 与节点中已有 Pod 之间亲和性(Affinity)和反亲和性(Anti-Affinity)的关系。对应的插件有 tainttoleration、interpodaffinity、nodeunschedulable 等。
@@ -150,12 +148,10 @@ profiles:
经过优选阶段之后,调度器根据预定的打分策略为每个节点分配一个分数,最终选择出分数最高的节点来运行 Pod。如果存在多个节点分数相同,调度器则随机选择其中一个。
-经过预选阶段筛选,优选阶段的打分之后,调度器选择最终目标节点,最后阶段是通知目标节点内的 Kubelet 创建 Pod 了。
+选择出最终目标节点后,接下来就是通知目标节点内的 Kubelet 创建 Pod 了。
这一阶段中,调度器并不会直接与 Kubelet 通信,而是将 Pod 对象的 nodeName 字段的值,修改为上述选中 Node 的名字即可。Kubelet 会持续监控 Etcd 中 Pod 信息的变化,然后执行一个称为“Admin”的本地操作,确认资源是否可用、端口是否冲突,实际上就是通用过滤策略再执行一遍,二次确认 Pod 是否能在该节点运行。
不过,从调度器更新 Etcd 中的 nodeName,到 Kueblet 检测到变化,再到二次确认是否可调度。这一系列的过程,会持续一段不等的时间。如果等到一切工作都完成,才宣告调度结束,那势必影响整体调度的效率。
调度器采用了“乐观绑定”(Optimistic Binding)策略来解决上述问题。首先,调度器同步更新 Scheduler Cache 里的 Pod 的 nodeName 的信息,并发起异步请求 Etcd 更新 Pod 的 nodeName 信息,该步骤在调度生命周期中称 Bind 步骤。如果调度成功了,Scheduler Cache 和 Etcd 中的信息势必一致。如果调度失败了(也就是异步更新失败),也没有太大关系,Informer 会持续监控 Pod 的变化,将调度成功却没有创建成功的 Pod 清空 nodeName 字段,并重新同步至调度队列。
-
-至此,整个 Pod 调度生命周期宣告结束。