Skip to content

Commit

Permalink
fix typo
Browse files Browse the repository at this point in the history
  • Loading branch information
isno committed Jan 26, 2025
1 parent c055c8b commit b65cb95
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 64 deletions.
2 changes: 1 addition & 1 deletion .vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
2 changes: 1 addition & 1 deletion Observability/OpenTelemetry.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 9.4 可观测标准项目的演进
# 9.4 可观测标准的演进

Dapper 论文发布后,市场上涌现出大量追踪系统,如 Jaeger、Pinpoint、Zipkin 等。这些系统都基于 Dapper 论文实现,功能上无本质差异,但实现方式和技术栈不同,导致它们难以兼容或协同使用。

Expand Down
4 changes: 2 additions & 2 deletions Observability/logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 FROMWHERE ProductId=90329509958
```

接下来,我们来看列式数据库,ClickHouse 的数据组织如表 9-3 所示,数据按列而非按行存储。我们继续以上面的统计销售额的 SQL 为例,列式数据库只读取与查询相关的列(如 sales 列),不会读取不相关列,从而减少不必要的磁盘 I/O 操作。
接下来,我们来看列式数据库,ClickHouse 的数据组织如表 9-3 所示,数据按列而非按行存储,一列数据在物理存储介质中紧密相邻。我们继续以上面的统计销售额的 SQL 为例,列式数据库只读取与查询相关的列(如 sales 列),不会读取不相关列,从而减少不必要的磁盘 I/O 操作。

<center >表 9-3 列式数据库存储结构</center>

Expand Down
57 changes: 21 additions & 36 deletions Observability/metrics.md

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions ServiceMesh/conclusion.md
Original file line number Diff line number Diff line change
@@ -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 等多种模式。

无论通信治理逻辑下沉至哪里、服务网格以何种形态存在,核心把非业务逻辑从应用程序中剥离,让业务开发更简单。这正是业内常提到的“以应用为中心”的软件设计核心理念。
2 changes: 1 addition & 1 deletion application-centric/Kustomize.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 10.3.1 Kustomize

Kubernetes 官方对应用的定义是一组具有相同目标资源合集。这种设定下,只要应用规模稍大,资源配置文件就开始泛滥。尤其是当不同环境(如开发和生产环境)之间的差异较小时,你就会发现通过 kubectl 管理应用十分“蛋疼”。
Kubernetes 官方对应用的定义是一组具有相同目标资源合集。这种设定下,只要应用规模稍大,尤其是不同环境(如开发和生产环境)之间的差异较小时,资源配置文件就开始泛滥。尤其是当不同环境(如开发和生产环境)之间的差异较小时,你就会发现通过 kubectl 管理应用十分“蛋疼”。

Kubernetes 对此的观点是,如果逐一配置和部署资源文件过于繁琐,那就将应用中的稳定信息与可变信息分离,并自动生成一个多合一(All-in-One)的配置包。完成这一任务的工具名为 Kustomize。

Expand Down
22 changes: 8 additions & 14 deletions container/borg-omega-k8s.md
Original file line number Diff line number Diff line change
@@ -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
![](../assets/borg-arch.png)<br/>
Expand Down Expand Up @@ -89,16 +87,12 @@ Google 开发的第三套容器管理系统是 Kubernetes,其背景如下:

## 7.1.4 以应用为中心的转变

容器化技术从最初的 Borg 到 Kubernetes,其收益早已超越了单纯提高资源利用率的范畴。更大的变化在于,系统开发和运维理念从“以机器为中心”转向“以应用为中心”。

- 容器封装了应用程序运行的环境,屏蔽了操作系统和机器的细节,使业务开发者和基础设施管理者不再关注底层细节;
- 每个设计良好的容器或容器镜像通常对应一个应用,管理容器即是管理应用,而非管理机器。

正是以应用为中心,云原生技术体系才会无限强调让基础设施能更好的配合应用、以更高效方式为应用输送基础设施能力:
从最初的 Borg 到 Kubernetes,容器化技术的价值早已超越了单纯提升资源利用率。更深远的变化在于,系统开发和运维理念从“以机器为中心”转向“以应用为中心”。

- 开发者和运维团队无需再关心机器、操作系统等底层细节;
- 基础设施团队引入新硬件和升级操作系统更加灵活,最大限度减少对线上应用和应用开发者的影响;
- 将收集到的各类关键性能指标(如 CPU 使用率、内存用量、每秒查询率 QPS 等)与应用程序而非物理机器关联,显著提高了应用监控的精确度和可观测性,尤其是在系统垂直扩容、机器故障或主动运维等场景。这直接促使软件可观测性领域应运而生。
- 容器封装了应用程序的运行环境,屏蔽了操作系统和硬件的细节,使得业务开发者和基础设施管理者不再需要关注底层实现。
- 基础设施团队可以更灵活地引入新硬件或升级操作系统,最大限度减少对线上应用和开发者的影响。
- 每个设计良好的容器通常代表一个应用,因此管理容器就等于管理应用,而非管理机器。
- 将收集的性能指标(如 CPU 使用率、内存用量、每秒查询率 QPS 等)与应用程序而非物理机器关联,显著提高了应用监控的精确度和可观测性,尤其是在系统垂直扩容、机器故障或主动运维等场景。


[^1]: 在 Kubernetes 中的 Workload 资源包括多种类型,例如 Deployment、StatefulSet、DaemonSet、ReplicaSet 等等
8 changes: 2 additions & 6 deletions container/kube-scheduler.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 等。
Expand Down Expand Up @@ -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 调度生命周期宣告结束。

0 comments on commit b65cb95

Please sign in to comment.