fix: refactor text format

This commit is contained in:
ZhengLin Li
2023-01-28 13:44:02 +08:00
committed by qtmuniao
parent 25480f9a9f
commit 33a7a994c7
11 changed files with 517 additions and 678 deletions

106
ch01.md
View File

@@ -8,7 +8,6 @@
因此,作为 IT 从业人员,有必要系统性的了解一下现代的、分布式的数据系统。学习本书,能够学习到数据系统的背后的原理、了解其常见的实践、进而将其应用到我们工作的系统设计中。
## 常见的数据系统有哪些
- 存储数据,以便之后再次使用——**数据库**
@@ -49,16 +48,12 @@
如何衡量可靠性?
- **功能上**
1. 正常情况下,应用行为满足 API 给出的行为
2. 在用户误输入/误操作时,能够正常处理
1. 正常情况下,应用行为满足 API 给出的行为
2. 在用户误输入/误操作时,能够正常处理
- **性能上**
在给定硬件和数据量下,能够满足承诺的性能指标。
在给定硬件和数据量下,能够满足承诺的性能指标。
- **安全上**
能够阻止未授权、恶意破坏。
能够阻止未授权、恶意破坏。
可用性也是可靠性的一个侧面,云服务通常以多少个 9 来衡量可用性。
@@ -83,9 +78,7 @@
数据系统中常见的需要考虑的硬件指标:
- **MTTF mean time to failure**
单块盘 平均故障时间 5 ~10 年,如果你有 1w+ 硬盘,则均匀期望下,每天都有坏盘出现。当然事实是硬盘会一波一波坏。
单块盘 平均故障时间 5 ~10 年,如果你有 1w+ 硬盘,则均匀期望下,每天都有坏盘出现。当然事实是硬盘会一波一波坏。
解决办法,增加冗余度:
@@ -93,9 +86,9 @@
对于数据:
**单机**可以做RAID 冗余。如EC 编码。
**单机**:可以做 RAID 冗余。如EC 编码。
**多机**:多副本 or EC 编码。
**多机**:多副本 or EC 编码。
## 软件错误
@@ -113,21 +106,19 @@
系统中最不稳定的是人,因此要在设计层面尽可能消除人对系统影响。依据软件的生命周期,分几个阶段来考虑:
- **设计编码**
1. 尽可能消除所有不必要的假设,提供合理的抽象,仔细设计 API
2. 进程间进行隔离,对尤其容易出错的模块使用沙箱机制
3. 对服务依赖进行熔断设计
1. 尽可能消除所有不必要的假设,提供合理的抽象,仔细设计 API
2. 进程间进行隔离,对尤其容易出错的模块使用沙箱机制
3. 对服务依赖进行熔断设计
- **测试阶段**
1. 尽可能引入第三方成员测试,尽量将测试平台自动化
2. 单元测试、集成测试、e2e 测试、混沌测试
1. 尽可能引入第三方成员测试,尽量将测试平台自动化
2. 单元测试、集成测试、e2e 测试、混沌测试
- **运行阶段**
1. 详细的仪表盘
2. 持续自检
3. 报警机制
4. 问题预案
1. 详细的仪表盘
2. 持续自检
3. 报警机制
4. 问题预案
- **针对组织**
科学的培训和管理
科学的培训和管理
## 可靠性有多重要?
@@ -144,14 +135,14 @@
应对负载之前,要先找到合适的方法来衡量负载,如**负载参数load parameters**
- 应用日活月活
- 每秒向Web服务器发出的请求
- 每秒向 Web 服务器发出的请求
- 数据库中的读写比率
- 聊天室中同时活跃的用户数量
书中以 Twitter 201211 披露的信息为例进行了说明:
书中以 Twitter 201211 披露的信息为例进行了说明:
1. 识别主营业务:发布推文、首页 Feed 流。
2. 确定其请求量级:发布推文(平均 4.6k请求/秒,峰值超过 12k请求/秒查看其他人推文300k请求/秒)
2. 确定其请求量级:发布推文(平均 4.6k 请求/秒,峰值超过 12k 请求/秒查看其他人推文300k 请求/秒)
![twitter-table.png](img/ch01-fig02.png)
@@ -172,29 +163,25 @@
注意和系统负载区分,系统负载是从用户视角来审视系统,是一种**客观指标**。而系统性能则是描述的系统的一种**实际能力**。比如:
1. **吞吐量throughput** 每秒可以处理的单位数据量,通常记为 QPS。
2. **响应时间response time** 从用户侧观察到的发出请求到收到回复的时间。
1. **吞吐量throughput**:每秒可以处理的单位数据量,通常记为 QPS。
2. **响应时间response time**:从用户侧观察到的发出请求到收到回复的时间。
3. **延迟latency**:日常中,延迟经常和响应时间混用指代响应时间;但严格来说,延迟只是只请求过程中排队等休眠时间,虽然其在响应时间中一般占大头;但只有我们把请求真正处理耗时认为是瞬时,延迟才能等同于响应时间。
响应时间通常以百分位点来衡量,比如 p95p99和 p999它们意味着9599或 99.9 的请求都能在该阈值内完成。在实际中,通常使用滑动窗口滚动计算最近一段时间的响应时间分布,并通常以折线图或者柱状图进行呈现。
响应时间通常以百分位点来衡量,比如 p95p99 和 p999它们意味着 9599或 99.9 的请求都能在该阈值内完成。在实际中,通常使用滑动窗口滚动计算最近一段时间的响应时间分布,并通常以折线图或者柱状图进行呈现。
## 应对负载
在有了描述和定义负载、性能的手段之后,终于来到正题,如何应对负载的不断增长,即使系统具有可伸缩性。
1. **纵向伸缩scaling upor 垂直伸缩vertical scaling**换具有更强大性能的机器。e.g. 大型机机器学习训练。
2. **横向伸缩scaling outor 水平伸缩horizontal scaling**:“并联”很多廉价机,分摊负载。 e.g. 马斯克造火箭。
1. **纵向伸缩scaling upor 垂直伸缩vertical scaling**换具有更强大性能的机器。e.g. 大型机机器学习训练。
2. **横向伸缩scaling outor 水平伸缩horizontal scaling**“并联”很多廉价机分摊负载。e.g. 马斯克造火箭。
负载伸缩的两种方式:
- **自动**
如果负载不好预测且多变,则自动较好。坏处在于不易跟踪负载,容易抖动,造成资源浪费。
如果负载不好预测且多变,则自动较好。坏处在于不易跟踪负载,容易抖动,造成资源浪费。
- **手动**
如果负载容易预测且不长变化,最好手动。设计简单,且不容易出错。
如果负载容易预测且不长变化,最好手动。设计简单,且不容易出错。
针对不同应用场景:
@@ -207,15 +194,11 @@
两种服务类型:
- **无状态服务**
比较简单,多台机器,外层罩一个 gateway 就行。
比较简单,多台机器,外层罩一个 gateway 就行。
- **有状态服务**
根据需求场景,如读写负载、存储量级、数据复杂度、响应时间、访问模式,来进行取舍,设计合乎需求的架构。
根据需求场景,如读写负载、存储量级、数据复杂度、响应时间、访问模式,来进行取舍,设计合乎需求的架构。
**不可能啥都要,没有万金油架构** 但同时:万变不离其宗,组成不同架构的原子设计模式是有限的,这也是本书稍后要论述的重点。
**不可能啥都要,没有万金油架构**!但同时:万变不离其宗,组成不同架构的原子设计模式是有限的,这也是本书稍后要论述的重点。
# 可维护性
@@ -223,18 +206,12 @@
但大部分人都喜欢挖坑,不喜欢填坑。因此有必要,在刚开就把坑开的足够好。有三个原则:
- ***可维护性Operability***
便于运维团队无痛接手。
- ***简洁性Simplicity***
便于新手开发平滑上手:这需要一个合理的抽象,并尽量消除各种复杂度。如,层次化抽象。
- ***可演化性Evolvability***
便于后面需求快速适配:避免耦合过紧,将代码绑定到某种实现上。也称为**可扩展性extensibility****可修改性modifiability** 或**可塑性plasticity**。
- **_可维护性Operability_**
便于运维团队无痛接手。
- **_简洁性Simplicity_**
便于新手开发平滑上手:这需要一个合理的抽象,并尽量消除各种复杂度。如,层次化抽象。
- **_可演化性Evolvability_**
便于后面需求快速适配:避免耦合过紧,将代码绑定到某种实现上。也称为**可扩展性extensibility****可修改性modifiability**  或**可塑性plasticity**。
## **可运维性Operability人生苦短关爱运维**
@@ -269,9 +246,9 @@
2. 组件间的强耦合。
3. 不一致的术语和[命名](https://www.qtmuniao.com/2021/12/12/how-to-write-code-scrutinize-names/)。
4. 为了提升性能的 hack。
5. 随处可见的补丁( workaround
5. 随处可见的补丁workaround
需求很简单,但不妨碍你实现的很复杂 😉:过多的引入了**额外复杂度***accidental* complexity
需求很简单,但不妨碍你实现的很复杂 😉:过多的引入了**额外复杂度**_accidental_ complexity
)——非问题本身决定的,而由实现所引入的复杂度。
通常是问题理解的不够本质,写出了“**流水账**”(没有任何**抽象abstraction**)式的代码。
@@ -307,9 +284,6 @@
应对之道:
- 项目管理上
敏捷开发
敏捷开发
- 系统设计上
依赖前两点。合理抽象,合理封装,对修改关闭,对扩展开放。
依赖前两点。合理抽象,合理封装,对修改关闭,对扩展开放。