feat: add comprehensive backend topics and fix build issues

## 新增内容

### 附录文档扩展
- 扩展前端项目架构文档 (frontend-project-architecture.md)
- 扩展后端项目架构文档 (backend-project-architecture.md)
- 扩展数据治理文档 (data-governance.md)
- 扩展数据可视化文档 (data-visualization.md)
- 扩展分布式系统文档 (distributed-systems.md)
- 扩展高可用文档 (high-availability.md)
- 扩展单体到微服务文档 (monolith-to-microservices.md)
- 扩展系统设计方法论文档 (system-design-methodology.md)
- 扩展 Docker 容器文档 (docker-containers.md)
- 扩展 Kubernetes 文档 (kubernetes.md)
- 扩展 Linux 基础文档 (linux-basics.md)
- 扩展神经网络文档 (neural-networks.md)

### 新增交互式组件
- 数据治理组件: DataQualityDemo, DataGovernanceFrameworkDemo, DataLineageDemo
- 数据可视化组件: ChartTypeSelectorDemo, DashboardLayoutDemo
- 分布式系统组件: CAPTheoremDemo, ConsistencyModelsDemo, DistributedChallengesDemo
- 高可用组件: AvailabilityCalculatorDemo, FailoverStrategyDemo
- 系统设计组件: SystemDesignStepsDemo, CapacityEstimationDemo
- Docker 容器组件: DockerArchitectureDemo, DockerLifecycleDemo
- Kubernetes 组件: K8sArchitectureDemo, K8sWorkloadsDemo
- Linux 基础组件: LinuxFileSystemDemo, LinuxCommandDemo, LinuxPermissionsDemo
- 神经网络组件: NeuronDemo, NetworkLayersDemo, NetworkArchitectureDemo
- 单体到微服务组件: ArchEvolutionDemo
- 项目架构组件: ProjectArchitectureComparisonDemo
- 附录导航组件: AppendixFlowMap

### 英文版重构
- 将 en-us 目录重命名为 en
- 更新相关配置和组件中的语言代码

## Bug 修复
- 修复 index.js 中重复的组件导入语句导致的 build 失败
- 恢复被注释的 InvertedIndexDemo 和 SearchRelevanceDemo 导入
- 修复 HomeFeatures.vue 中 en-us 与 config.mjs 中 en 不一致导致的语言切换问题

## 其他改进
- 添加构建脚本 (scripts/build.mjs)
- 更新依赖版本
This commit is contained in:
sanbuphy
2026-02-26 04:35:28 +08:00
parent df51f84ab5
commit ef70b1d8e1
84 changed files with 12917 additions and 3477 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+212 -1
View File
@@ -1,3 +1,214 @@
# 数据治理与数据质量
> 待实现
::: tip 前言
**你有没有遇到过这种情况:报表上的数字和实际业务对不上,两个系统里同一个用户的信息不一样,或者分析结果因为脏数据完全不可信?** 数据治理就是解决这些问题的系统性方法。在"数据驱动决策"的时代,数据质量直接决定了决策质量——垃圾进,垃圾出(Garbage In, Garbage Out)。
:::
**这篇文章会带你学什么?**
学完这章后,你将获得:
- **数据质量维度**:理解完整性、准确性、一致性等六大质量维度
- **数据治理体系**:了解从组织、流程到技术的治理框架
- **数据血缘**:掌握数据从源头到消费的全链路追踪
- **元数据管理**:理解"描述数据的数据"的重要性
- **数据分层架构**:掌握 ODS → DWD → DWS → ADS 的数仓分层模型
- **实战能力**:知道如何在项目中落地数据治理
| 章节 | 内容 | 核心概念 |
|-----|------|---------|
| **第 1 章** | 数据质量维度 | 完整性、准确性、一致性、时效性 |
| **第 2 章** | 数据治理框架 | 组织、流程、技术、文化 |
| **第 3 章** | 数据血缘追踪 | 影响分析、问题排查、合规审计 |
| **第 4 章** | 元数据管理 | 技术元数据、业务元数据、操作元数据 |
| **第 5 章** | 数据分层架构 | ODS、DWD、DWS、ADS |
| **第 6 章** | 治理工具与实践 | Great Expectations、dbt、DataHub |
---
## 0. 全景图:为什么需要数据治理?
数据治理不是一个技术问题,而是一个**管理问题**。它回答的核心问题是:**谁对数据负责?数据的标准是什么?如何保证数据持续可信?**
想象一个公司有 100 个数据表,每个表由不同团队维护,没有统一的命名规范、没有数据字典、没有质量检查。结果就是:同一个"月活用户"指标,市场部算出来 500 万,产品部算出来 300 万——因为定义不一样。
::: tip 数据治理的四个支柱
1. **组织**:明确数据 Owner、数据管家(Data Steward)的角色和职责
2. **流程**:建立数据接入、变更、下线的标准流程
3. **技术**:部署数据质量监控、元数据管理、血缘追踪等工具
4. **文化**:让全公司认同"数据是资产",而不是"数据是副产品"
:::
---
## 1. 数据质量的六个维度
数据质量不是一个模糊的概念,而是可以从六个具体维度来衡量的。每个维度都有明确的定义和检测方法。
<DataQualityDemo />
| 维度 | 定义 | 检测方法 | 常见问题 |
|------|------|---------|---------|
| 完整性 | 数据是否存在缺失 | 空值率检查 | 必填字段为空、关联数据缺失 |
| 准确性 | 数据是否正确 | 规则校验、抽样核对 | 金额为负、日期不合法 |
| 一致性 | 多源数据是否一致 | 跨系统比对 | CRM 和订单系统用户名不同 |
| 时效性 | 数据是否及时更新 | 更新时间检查 | 库存数据滞后、价格未同步 |
| 唯一性 | 是否存在重复记录 | 去重检查 | 同一用户注册两次 |
| 有效性 | 是否符合格式规则 | 正则/范围校验 | 邮箱格式错误、年龄为负数 |
::: tip 数据质量的 1-10-100 法则
- **1 元**:在数据入口做校验,预防脏数据进入
- **10 元**:在数据仓库中清洗已有的脏数据
- **100 元**:因为脏数据导致错误决策的损失
越早发现和修复数据质量问题,成本越低。
:::
---
## 2. 数据治理框架:全生命周期管理
数据治理不是一次性项目,而是贯穿数据全生命周期的持续过程。从数据的产生到销毁,每个阶段都需要明确的规范和责任人。
<DataGovernanceFrameworkDemo />
| 阶段 | 核心产出 | 关键角色 |
|------|---------|---------|
| 定义标准 | 数据字典、命名规范、分类分级标准 | 数据架构师 |
| 采集接入 | 接入规范、校验规则、血缘记录 | 数据工程师 |
| 存储管理 | 分层模型、权限矩阵、生命周期策略 | DBA / 平台工程师 |
| 使用消费 | 数据目录、脱敏规则、质量报告 | 数据分析师 / 业务方 |
| 归档销毁 | 归档策略、删除记录、审计日志 | 安全合规团队 |
## 2. 数据治理框架
数据治理不是买一个工具就能解决的,它需要一套完整的框架来支撑。业界最常用的参考框架是 DAMA-DMBOK(数据管理知识体系)。
| 治理领域 | 核心内容 | 关键产出 |
|---------|---------|---------|
| 数据架构 | 定义数据模型、数据流、存储策略 | 数据架构图、ER 图 |
| 数据标准 | 统一命名规范、编码规范、指标定义 | 数据字典、指标库 |
| 数据质量 | 建立质量规则、监控告警、修复流程 | 质量报告、SLA 仪表盘 |
| 数据安全 | 分级分类、访问控制、脱敏加密 | 安全策略、审计日志 |
| 主数据管理 | 统一客户、商品等核心实体的"黄金记录" | 主数据中心 |
| 数据生命周期 | 管理数据从创建到归档到销毁的全过程 | 保留策略、归档规则 |
::: tip 数据治理的成熟度模型
- **Level 1 - 初始级**:没有统一标准,各团队各自为政
- **Level 2 - 可重复级**:有基本的规范文档,但执行不一致
- **Level 3 - 已定义级**:有统一的治理流程和工具,大部分团队遵守
- **Level 4 - 已管理级**:有量化的质量指标和自动化监控
- **Level 5 - 优化级**:持续改进,数据治理融入日常开发流程
:::
---
## 3. 数据血缘:从哪来,到哪去
数据血缘(Data Lineage)记录了数据从源头到最终消费的完整流转路径。它就像数据的"族谱",让你能追溯任何一个数据的来龙去脉。
<DataLineageDemo />
数据血缘在实际工作中有三个核心应用场景:
| 场景 | 问题 | 血缘如何帮助 |
|------|------|------------|
| 影响分析 | 要修改用户表的字段,会影响哪些下游报表? | 沿血缘向下追踪所有依赖 |
| 根因定位 | 今天的 GMV 报表数据异常,问题出在哪一步? | 沿血缘向上回溯每个环节 |
| 合规审计 | 用户的手机号经过了哪些系统?是否都做了脱敏? | 追踪敏感字段的全链路流转 |
::: tip 血缘采集的两种方式
- **主动采集**:解析 SQL 语句、ETL 配置,自动提取表级/字段级血缘关系
- **被动采集**:通过 Hook 拦截查询引擎(如 Hive、Spark)的执行计划,实时记录血缘
主流工具如 Apache Atlas、DataHub、OpenLineage 都支持自动化血缘采集。
:::
---
## 4. 元数据管理:"描述数据的数据"
元数据(Metadata)是关于数据的数据。如果数据是一本书的内容,元数据就是书的目录、作者、出版日期、ISBN 号。没有元数据,数据就是一堆无法理解的数字和字符串。
| 元数据类型 | 描述 | 示例 |
|-----------|------|------|
| 技术元数据 | 数据的物理存储信息 | 表名、字段类型、分区方式、存储位置 |
| 业务元数据 | 数据的业务含义 | 字段中文名、业务定义、计算口径 |
| 操作元数据 | 数据的运行状态 | ETL 执行时间、数据量、更新频率 |
::: tip 数据字典的重要性
数据字典是元数据管理最基础的产出。一个好的数据字典应该包含:
- **字段名**:英文名和中文名
- **数据类型**VARCHAR(50)、INT、DATETIME 等
- **业务定义**:这个字段代表什么?怎么计算的?
- **取值范围**:有效值是什么?空值是否允许?
- **负责人**:谁维护这个字段?有问题找谁?
没有数据字典的团队,新人入职后理解一张表的含义可能需要一周;有数据字典的团队,10 分钟就够了。
:::
---
## 5. 数据分层架构:ODS → DWD → DWS → ADS
数据仓库不是把所有数据堆在一起,而是按照**加工程度**分层存储。每一层有明确的职责,上层依赖下层,逐步从原始数据提炼为业务可用的数据。
| 层级 | 全称 | 职责 | 数据特点 |
|------|------|------|---------|
| ODS | 操作数据层 | 原样同步业务数据库 | 最原始,未经处理 |
| DWD | 明细数据层 | 清洗、标准化、去重 | 干净的明细记录 |
| DWS | 汇总数据层 | 按主题聚合(日/周/月) | 预计算的聚合指标 |
| ADS | 应用数据层 | 面向具体报表/接口 | 直接可用的结果数据 |
::: tip 为什么要分层?
- **复用**:DWD 层清洗一次,所有上层共享,避免重复清洗
- **解耦**:业务库表结构变更只影响 ODS 层,不会波及报表
- **性能**:DWS 层预聚合,报表查询直接读取,不需要实时计算
- **可追溯**:每一层都保留,出问题时可以逐层排查
:::
---
## 6. 治理工具与实践
| 工具 | 定位 | 核心能力 | 适用场景 |
|------|------|---------|---------|
| Great Expectations | 数据质量 | 声明式数据校验规则,自动生成质量报告 | Python 数据管道 |
| dbt | 数据转换 | SQL 模型化开发,内置测试和文档生成 | 数仓建模 |
| DataHub | 元数据管理 | 数据目录、血缘追踪、数据发现 | 企业级数据治理 |
| Apache Atlas | 元数据管理 | Hadoop 生态血缘追踪 | 大数据平台 |
| OpenMetadata | 元数据管理 | 开源数据目录,支持多种数据源 | 中小团队 |
| Amundsen | 数据发现 | 搜索式数据发现平台 | 数据民主化 |
::: tip 从零开始的治理路径
如果你的团队还没有数据治理,建议按这个顺序推进:
1. **先建数据字典**:把现有的表和字段含义记录下来(哪怕用 Excel)
2. **加质量检查**:在关键数据管道中加入基本的空值、范围校验
3. **统一指标定义**:把"日活""月活""GMV"等核心指标的计算口径统一
4. **引入工具**:当手动管理成本太高时,引入 DataHub 或 dbt 等工具
5. **建立流程**:数据变更需要评审,质量问题有 SLA 和告警
:::
---
## 总结
数据治理是让数据从"能用"变成"好用、可信、可追溯"的系统性工程。它不是一次性项目,而是持续运营的过程。
回顾本章的关键要点:
1. **六大质量维度**:完整性、准确性、一致性、时效性、唯一性、有效性
2. **治理四支柱**:组织、流程、技术、文化缺一不可
3. **数据血缘**:追踪数据的来龙去脉,支撑影响分析和问题排查
4. **元数据管理**:数据字典是最基础也最重要的治理产出
5. **分层架构**ODS → DWD → DWS → ADS,逐层提炼数据价值
6. **渐进式落地**:从数据字典开始,逐步引入工具和流程
## 延伸阅读
- [DAMA-DMBOK](https://www.dama.org/cpages/body-of-knowledge) - 数据管理知识体系,数据治理的"圣经"
- [DataHub](https://datahubproject.io/) - LinkedIn 开源的元数据管理平台
- [Great Expectations](https://greatexpectations.io/) - Python 数据质量框架
- [dbt](https://www.getdbt.com/) - 数据转换工具,内置测试和文档
- [Apache Atlas](https://atlas.apache.org/) - Hadoop 生态的元数据治理框架
- [The Data Warehouse Toolkit](https://www.kimballgroup.com/data-warehouse-business-intelligence-resources/books/) - Kimball 数仓建模经典
@@ -1,3 +1,299 @@
# 数据可视化与仪表盘
> 待实现
::: tip 前言
**一张好的图表胜过一千行数据。** 数据可视化是将抽象的数字转化为直观的视觉表达,让人能在几秒内理解数据背后的故事。从 Excel 图表到 Grafana 监控大屏,可视化无处不在。
:::
**这篇文章会带你学什么?**
学完这章后,你将获得:
- **图表选择**:根据数据目的选择最合适的图表类型
- **可视化原则**:掌握数据可视化的核心设计原则
- **仪表盘设计**:了解不同类型仪表盘的布局模式
- **工具生态**:熟悉主流可视化工具的定位和选型
- **常见陷阱**:避免误导性图表和常见的可视化错误
| 章节 | 内容 | 核心概念 |
|-----|------|---------|
| **第 1 章** | 图表类型选择 | 比较、趋势、占比、分布、关系 |
| **第 2 章** | 可视化设计原则 | 数据墨水比、一致性、可读性 |
| **第 3 章** | 仪表盘布局 | 概览型、对比型、下钻型、实时型 |
| **第 4 章** | 工具选型 | ECharts、D3、Grafana、Metabase |
| **第 5 章** | 常见陷阱 | 截断坐标轴、3D 饼图、颜色滥用 |
---
## 0. 全景图:为什么需要可视化?
人类大脑处理视觉信息的速度比处理文字快 6 万倍。一张折线图能让你在 1 秒内看出"上个月销售额在下降",而同样的信息如果用表格呈现,你可能需要 30 秒才能得出结论。
可视化的核心价值:
- **发现模式**:趋势、周期、异常值在图表中一目了然
- **辅助决策**:让非技术人员也能理解数据,参与决策
- **沟通效率**:一图胜千言,减少数据解读的歧义
::: tip 可视化 ≠ 好看
可视化的目标是**传达信息**,不是炫技。一个朴素但准确的柱状图,远比一个花哨但难以理解的 3D 图表更有价值。
:::
---
## 1. 图表类型选择:用对图表讲对故事
选择图表的第一步不是"我喜欢什么图表",而是"我想传达什么信息"。不同的数据目的对应不同的最佳图表类型。
<ChartTypeSelectorDemo />
### 图表选择速查表
| 数据目的 | 推荐图表 | 不推荐 | 原因 |
|---------|---------|--------|------|
| 比较大小 | 柱状图、条形图 | 饼图 | 人眼对长度差异比角度差异更敏感 |
| 展示趋势 | 折线图、面积图 | 柱状图 | 折线的连续性暗示时间的连续性 |
| 展示占比 | 饼图(≤5 类)、堆叠柱状图 | 3D 饼图 | 3D 透视会扭曲面积比例 |
| 展示分布 | 直方图、箱线图 | 折线图 | 分布需要看频率,不是趋势 |
| 展示关系 | 散点图、气泡图 | 柱状图 | 两个连续变量的关系需要二维空间 |
::: tip 一个简单的决策规则
- **一个变量** → 直方图(分布)或数字卡片(KPI)
- **两个变量** → 折线图(时间 vs 数值)或散点图(数值 vs 数值)
- **多个类别** → 柱状图(比较)或饼图(占比,≤5 类)
- **多维度** → 雷达图或平行坐标图
:::
---
## 2. 可视化设计原则
Edward Tufte 在《The Visual Display of Quantitative Information》中提出了数据可视化的核心原则,至今仍是行业标准。
| 原则 | 说明 | 反面案例 |
|------|------|---------|
| 数据墨水比 | 图表中用于展示数据的"墨水"占比应尽量高 | 过多的网格线、装饰性元素 |
| 最小化非数据元素 | 去除不传达信息的视觉元素 | 3D 效果、阴影、渐变背景 |
| 一致的比例尺 | 坐标轴从零开始,刻度均匀 | Y 轴从 95 开始(夸大差异) |
| 合理的颜色使用 | 用颜色编码信息,而非装饰 | 彩虹色(无序)表示有序数据 |
| 清晰的标注 | 标题、轴标签、图例缺一不可 | 没有单位、没有时间范围 |
::: tip 颜色使用的三条规则
1. **同一指标用同一颜色**:收入在所有图表中都用蓝色,不要一会蓝一会绿
2. **有序数据用渐变色**:温度从低到高用蓝→红渐变,不要用离散色
3. **考虑色盲友好**:约 8% 的男性有红绿色盲,避免仅用红绿区分关键信息
:::
---
## 2. 可视化设计原则:让数据说话
好的可视化不是"好看",而是"好懂"。Edward Tufte 在《The Visual Display of Quantitative Information》中提出了几个经典原则,至今仍是可视化设计的黄金标准。
### 2.1 数据墨水比(Data-Ink Ratio
> 图表中用于表达数据的"墨水"占总"墨水"的比例应该尽可能高。
简单说:**删掉一切不传达信息的元素**。
| 应该删掉的 | 应该保留的 |
|-----------|-----------|
| 3D 效果、阴影、渐变 | 数据点、坐标轴标签 |
| 多余的网格线 | 关键参考线(如目标值) |
| 装饰性图标 | 图例(当有多系列时) |
| 花哨的背景色 | 清晰的标题和单位 |
### 2.2 一致性原则
- **颜色一致**:同一个维度在不同图表中用同一种颜色(如"收入"始终用蓝色)
- **比例一致**:坐标轴从 0 开始(除非有充分理由),避免误导
- **时间一致**:时间轴的间隔应该均匀,不要跳跃
### 2.3 可读性原则
- **标题要说结论**:不是"月度销售额",而是"销售额连续 3 个月下降"
- **标注关键点**:在异常值、拐点处加标注,引导读者注意力
- **控制信息密度**:一张图表传达 1-2 个核心信息,不要塞太多
::: tip Tufte 的名言
"Excellence in statistical graphics consists of complex ideas communicated with clarity, precision, and efficiency."(优秀的统计图形,是用清晰、精确、高效的方式传达复杂的想法。)
:::
---
## 3. 仪表盘布局:不同场景,不同模式
仪表盘(Dashboard)是多个图表的有机组合。好的仪表盘不是把图表堆在一起,而是根据使用场景选择合适的布局模式。
<DashboardLayoutDemo />
### 四种常见布局模式
| 布局模式 | 核心结构 | 适用场景 | 设计要点 |
|---------|---------|---------|---------|
| 全局概览型 | KPI 卡片 + 趋势图 + 明细表 | 管理层日报、运营大盘 | 核心指标放最上方,一眼看到关键数字 |
| 对比分析型 | 左右对称布局 | A/B 测试、同环比分析 | 保持对比维度一致,突出差异 |
| 下钻分析型 | 从汇总到明细逐层展开 | 销售分析、用户行为分析 | 支持点击交互,逐层深入 |
| 实时监控型 | 大数字 + 实时曲线 + 告警状态 | 双十一大屏、服务器监控 | 自动刷新,深色背景,适合投屏 |
### 仪表盘设计的 5 个原则
1. **先问"谁在看"**:CEO 看战略指标,运营看过程指标,工程师看技术指标
2. **5 秒规则**:用户应该在 5 秒内理解仪表盘的核心信息
3. **信息层次**:最重要的放左上角(F 型阅读模式),次要的放下方
4. **减少滚动**:一屏展示核心内容,避免用户需要滚动才能看到关键数据
5. **留白**:不要塞满每一寸空间,适当留白让视觉更舒适
::: tip 仪表盘 vs 报表
- **仪表盘**:实时/准实时,交互式,面向监控和快速决策
- **报表**:定期生成(日/周/月),静态,面向详细分析和存档
两者不是替代关系,而是互补关系。仪表盘发现问题,报表深入分析。
:::
---
## 4. 工具选型:从代码到拖拽
| 工具 | 类型 | 特点 | 适用场景 |
|------|------|------|---------|
| ECharts | JS 图表库 | 百度开源,图表类型丰富,中文文档完善 | 前端项目内嵌图表 |
| D3.js | JS 可视化库 | 底层灵活,可定制任意可视化效果 | 高度定制化需求 |
| Chart.js | JS 图表库 | 轻量简单,上手快 | 简单图表需求 |
| Grafana | 监控仪表盘 | 支持多数据源,实时刷新,告警集成 | 服务器/应用监控 |
| Metabase | BI 工具 | 开源,SQL 查询 + 拖拽建图 | 业务数据分析 |
| Superset | BI 工具 | Apache 开源,支持大数据源 | 企业级数据探索 |
| Tableau | 商业 BI | 拖拽式,交互能力强 | 企业级报表 |
::: tip 怎么选?
- **开发者做项目内嵌图表** → ECharts(功能全)或 Chart.js(轻量)
- **需要高度定制的可视化** → D3.js(学习曲线陡但无限可能)
- **运维监控大屏** → Grafana(行业标准)
- **业务团队自助分析** → Metabase(简单)或 Superset(功能强)
:::
---
## 4. 工具选型:从代码库到 BI 平台
可视化工具可以分为三个层次:底层绑定库、高层图表库、BI 平台。选择哪个取决于你的需求复杂度和团队技术能力。
### 4.1 代码级图表库
| 工具 | 语言/平台 | 特点 | 适用场景 |
|------|----------|------|---------|
| ECharts | JavaScript | 开箱即用,图表类型丰富,中文文档完善 | 业务系统内嵌图表 |
| D3.js | JavaScript | 底层灵活,可定制任何可视化效果 | 高度定制化的数据可视化 |
| Chart.js | JavaScript | 轻量简单,上手快 | 简单的图表需求 |
| Matplotlib | Python | 科学计算标准库,静态图表 | 数据分析、论文图表 |
| Plotly | Python/JS | 交互式图表,支持 3D | 数据探索、Jupyter Notebook |
### 4.2 BI 平台(无代码/低代码)
| 工具 | 定位 | 核心优势 | 适用团队 |
|------|------|---------|---------|
| Grafana | 监控可视化 | 时序数据支持好,告警集成 | 运维/SRE 团队 |
| Metabase | 轻量 BI | 开源免费,SQL 即可出图 | 中小团队快速搭建 |
| Apache Superset | 企业 BI | 开源,支持大数据源 | 有数据团队的公司 |
| Tableau | 商业 BI | 拖拽式操作,可视化效果好 | 业务分析师 |
| Power BI | 商业 BI | 与微软生态集成好 | 使用微软技术栈的企业 |
::: tip 选型建议
- **开发者做产品内嵌图表** → ECharts(中文生态好)或 Chart.js(简单场景)
- **数据分析师做探索分析** → Plotly + Jupyter 或 Metabase
- **运维监控大屏** → Grafana(事实标准)
- **业务团队自助分析** → Metabase(开源)或 Tableau(商业)
- **需要高度定制** → D3.js(学习曲线陡峭,但无所不能)
:::
---
## 5. 常见陷阱:这些图表在骗你
数据可视化是一把双刃剑——用得好能揭示真相,用得不好会制造谎言。以下是最常见的可视化陷阱,每个数据从业者都应该能识别。
### 5.1 截断坐标轴
把 Y 轴的起点从 0 改成一个较大的数字,会让微小的差异看起来像巨大的变化。
| 场景 | 真实差异 | 视觉感受 |
|------|---------|---------|
| Y 轴从 0 开始 | A 产品 98 分,B 产品 95 分 | 差距很小 |
| Y 轴从 90 开始 | 同样的数据 | A 看起来是 B 的好几倍 |
**什么时候可以截断?** 当数据的绝对值很大但变化很小时(如股价从 100 到 105),截断是合理的——但必须明确标注。
### 5.2 3D 饼图的透视陷阱
3D 透视会让靠近观察者的扇区看起来更大。一个 25% 的扇区在 3D 视角下可能看起来像 35%。
**解决方案**:永远不要用 3D 饼图。用普通饼图或环形图,或者干脆用柱状图。
### 5.3 颜色滥用
| 错误做法 | 正确做法 |
|---------|---------|
| 用红绿表示数据(色盲不友好) | 用蓝橙等色盲安全配色 |
| 每个类别用不同颜色(彩虹图) | 同一系列用同色系深浅变化 |
| 用颜色编码连续数据但不加图例 | 始终提供颜色图例和数值标注 |
| 背景色和数据色对比度不够 | 确保 WCAG AA 级对比度 |
### 5.4 其他常见错误
| 陷阱 | 问题 | 修复 |
|------|------|------|
| 双 Y 轴 | 两个不相关的指标共享 X 轴,暗示因果关系 | 拆成两张图,或明确说明无因果 |
| 面积误导 | 用圆的半径而非面积表示数值 | 数值翻倍时面积翻倍,不是半径翻倍 |
| 时间轴不均匀 | 1月、3月、12月的间距一样 | 按实际时间比例排列 |
| 过多类别 | 饼图有 15 个扇区 | 超过 5 个类别就用柱状图或合并"其他" |
::: tip 可视化的道德准则
可视化的目的是**帮助理解**,不是**操纵认知**。每次做图表时问自己:
- 如果我是读者,这张图会不会让我产生错误的结论?
- 我是否隐藏了不利的数据?
- 坐标轴、比例、颜色是否公正地呈现了数据?
:::
---
## 总结
数据可视化是数据价值传递的"最后一公里"。选对图表、遵循设计原则、避免常见陷阱,就能让数据真正"说话"。
回顾本章的关键要点:
1. **先问目的再选图表**:比较用柱状图、趋势用折线图、占比用饼图
2. **数据墨水比**:删掉一切不传达信息的视觉元素
3. **仪表盘有模式**:概览型、对比型、下钻型、实时型各有适用场景
4. **工具按需选**ECharts 做产品、Grafana 做监控、Metabase 做分析
5. **警惕视觉陷阱**:截断坐标轴、3D 饼图、颜色滥用都会误导读者
## 延伸阅读
- [ECharts 官方文档](https://echarts.apache.org/zh/index.html) - 最流行的中文图表库
- [D3.js](https://d3js.org/) - 数据驱动的可视化库
- [Grafana](https://grafana.com/) - 开源监控可视化平台
- [The Visual Display of Quantitative Information](https://www.edwardtufte.com/tufte/books_vdqi) - Tufte 的可视化经典
- [From Data to Viz](https://www.data-to-viz.com/) - 图表类型选择指南
---
## 总结
数据可视化是数据价值传递的"最后一公里"。再好的分析,如果不能被正确理解,就等于没有分析。
回顾本章的关键要点:
1. **选对图表**:根据数据目的(比较、趋势、占比、分布、关系)选择图表类型
2. **设计原则**:高数据墨水比、一致性、可读性是三大核心原则
3. **仪表盘布局**:概览型、对比型、下钻型、实时型四种模式覆盖大部分场景
4. **工具选型**:从 ECharts 到 Grafana,根据团队能力和需求复杂度选择
5. **避免陷阱**:截断坐标轴、3D 饼图、颜色滥用是最常见的误导手段
## 延伸阅读
- [The Visual Display of Quantitative Information](https://www.edwardtufte.com/tufte/books_vdqi) - Edward Tufte 的可视化经典
- [ECharts 官方文档](https://echarts.apache.org/zh/index.html) - 最流行的中文图表库
- [D3.js](https://d3js.org/) - 最强大的底层可视化库
- [Grafana](https://grafana.com/) - 监控可视化事实标准
- [From Data to Viz](https://www.data-to-viz.com/) - 图表类型选择决策树
- [ColorBrewer](https://colorbrewer2.org/) - 色盲安全的配色方案工具
@@ -1,3 +1,253 @@
# 分布式系统的挑战
> 待实现
::: tip 前言
**当一台机器不够用时,问题才真正开始。** 分布式系统是现代互联网的基石——从微信消息到淘宝下单,背后都是成百上千台机器协同工作。但"分布式"不是免费的午餐,它带来了一系列单机系统从未遇到的挑战。
:::
**这篇文章会带你学什么?**
学完这章后,你将获得:
- **核心定理**:理解 CAP 定理及其对系统设计的影响
- **一致性模型**:区分强一致性、最终一致性、因果一致性
- **八大挑战**:掌握分布式系统面临的核心难题
- **共识算法**:了解 Paxos、Raft 等分布式共识的基本思想
- **实战模式**:熟悉 2PC、Saga、CRDT 等常用解决方案
| 章节 | 内容 | 核心概念 |
|-----|------|---------|
| **第 1 章** | 为什么需要分布式 | 扩展性、可用性、地理分布 |
| **第 2 章** | CAP 定理 | 一致性、可用性、分区容错 |
| **第 3 章** | 一致性模型 | 强一致、最终一致、因果一致 |
| **第 4 章** | 八大挑战 | 网络、时钟、分区、脑裂等 |
| **第 5 章** | 共识算法 | Paxos、Raft、ZAB |
| **第 6 章** | 分布式事务 | 2PC、Saga、TCC |
---
## 0. 全景图:为什么需要分布式系统?
单机系统简单可靠,但有三个无法逾越的瓶颈:
| 瓶颈 | 说明 | 分布式的解法 |
|------|------|-------------|
| 性能上限 | 单机 CPU、内存、磁盘有物理极限 | 水平扩展:加更多机器分担负载 |
| 单点故障 | 一台机器挂了,整个服务就挂了 | 冗余副本:多台机器互为备份 |
| 地理延迟 | 用户在全球各地,单机只能在一个地方 | 多地部署:就近服务用户 |
::: tip 分布式的代价
分布式系统解决了上面的问题,但引入了新的复杂性:网络不可靠、时钟不同步、部分失败、数据一致性……这些就是本文要讨论的"挑战"。
**Peter Deutsch 的分布式计算八大谬误**告诉我们,以下假设在分布式环境中都是错的:
1. 网络是可靠的
2. 延迟是零
3. 带宽是无限的
4. 网络是安全的
5. 拓扑不会变化
6. 只有一个管理员
7. 传输成本是零
8. 网络是同构的
:::
---
## 1. CAP 定理:分布式系统的"不可能三角"
2000 年,Eric Brewer 提出了 CAP 猜想(后被证明为定理):一个分布式系统最多只能同时满足以下三个属性中的两个。
| 属性 | 含义 | 通俗理解 |
|------|------|---------|
| **C**onsistency(一致性) | 所有节点在同一时刻看到相同的数据 | 你在任何 ATM 查余额,结果都一样 |
| **A**vailability(可用性) | 每个请求都能收到非错误的响应 | 系统永远能回应你,不会说"服务不可用" |
| **P**artition tolerance(分区容错) | 网络分区时系统仍能继续运行 | 即使部分网线断了,系统还能工作 |
<CAPTheoremDemo />
### 为什么只能选两个?
在分布式环境中,网络分区(P)是不可避免的——光纤会被挖断、交换机会故障、数据中心会断网。所以 P 是必选项,实际的选择是在 C 和 A 之间权衡:
- **选 CP**:分区时拒绝不确定的请求,保证数据正确 → 适合金融、库存
- **选 AP**:分区时继续服务,但数据可能暂时不一致 → 适合社交、内容
::: tip CAP 不是非黑即白
现实中的系统不是简单的"CP 或 AP"。很多系统在不同操作上做不同的选择——比如同一个数据库,读操作可以是 AP(允许读旧数据),写操作可以是 CP(要求多数确认)。
:::
---
## 2. 一致性模型:数据同步的"严格程度"
一致性不是一个开关(有或没有),而是一个光谱。不同的一致性模型在"正确性"和"性能"之间做不同的权衡。
<ConsistencyModelsDemo />
### 一致性模型对比
| 模型 | 保证 | 延迟 | 适用场景 |
|------|------|------|---------|
| 强一致性 | 读到的一定是最新写入的值 | 高(需等待同步) | 银行转账、库存扣减 |
| 最终一致性 | 最终所有副本会一致,但中间可能读到旧值 | 低(写入立即返回) | 社交动态、DNS |
| 因果一致性 | 有因果关系的操作保证顺序 | 中等 | 评论回复、协作编辑 |
| 线性一致性 | 所有操作看起来像在单机上按顺序执行 | 最高 | 分布式锁、选主 |
| 会话一致性 | 同一会话内保证读到自己的写入 | 低-中 | 用户个人数据 |
::: tip "读己之写"一致性
最常见的实际需求是:用户修改了自己的数据后,自己能立即看到更新(但其他用户可以稍后看到)。这叫"Read Your Own Writes"一致性,是最终一致性的一个实用增强。
:::
---
## 3. 八大挑战:分布式系统的"地雷阵"
分布式系统的复杂性不是来自某一个问题,而是多个问题交织在一起。以下是最核心的八大挑战。
<DistributedChallengesDemo />
### 挑战之间的关联
这八大挑战不是孤立的,它们相互关联:
- **网络不可靠** → 导致 **网络分区** → 触发 **CAP 权衡**
- **时钟不同步** → 导致 **事件排序困难** → 影响 **数据一致性**
- **部分失败** → 可能导致 **脑裂** → 需要 **共识算法** 来解决
- **数据一致性** → 需要 **分布式事务** → 但事务又受 **网络不可靠** 影响
::: tip 没有银弹
分布式系统没有"完美"的解决方案,只有"合适"的权衡。理解这些挑战的本质,才能在设计系统时做出正确的取舍。
:::
---
## 4. 共识算法:如何让多台机器"达成一致"
共识算法是分布式系统的核心——它解决的问题是:多个节点如何就某个值达成一致?即使部分节点故障或网络延迟。
### 4.1 Paxos
Leslie Lamport 在 1990 年提出,是第一个被严格证明正确的共识算法。
| 角色 | 职责 |
|------|------|
| Proposer | 提出提案(值) |
| Acceptor | 投票接受或拒绝提案 |
| Learner | 学习最终被选定的值 |
**两阶段流程**
1. **Prepare 阶段**Proposer 发送提案编号,Acceptor 承诺不再接受更小编号的提案
2. **Accept 阶段**:Proposer 发送具体值,多数 Acceptor 接受则提案通过
::: tip Paxos 的问题
Paxos 虽然正确,但出了名的难以理解和实现。Lamport 自己的论文用了一个希腊议会的比喻,结果让更多人困惑了。
:::
### 4.2 Raft:为可理解性而生
2014 年 Diego Ongaro 提出 Raft,目标是做一个"容易理解的 Paxos"。它把共识问题分解为三个子问题:
| 子问题 | 说明 |
|--------|------|
| Leader 选举 | 集群中选出一个 Leader,所有写入都经过 Leader |
| 日志复制 | Leader 将操作日志复制到所有 Follower |
| 安全性 | 保证已提交的日志不会被覆盖 |
**Raft 的核心流程**
1. 集群启动时,所有节点都是 Follower
2. 如果 Follower 超时没收到 Leader 心跳,就变成 Candidate 发起选举
3. 获得多数票的 Candidate 成为新 Leader
4. Leader 接收客户端请求,将日志复制到多数节点后提交
### 4.3 共识算法对比
| 算法 | 提出时间 | 可理解性 | 使用系统 |
|------|---------|---------|---------|
| Paxos | 1990 | 困难 | Google Chubby |
| Raft | 2014 | 容易 | etcd、Consul、TiKV |
| ZAB | 2011 | 中等 | ZooKeeper |
| EPaxos | 2013 | 困难 | 学术研究为主 |
---
## 5. 分布式事务:跨节点的"全有或全无"
单机数据库的事务靠本地锁和日志就能实现 ACID。但当一个业务操作涉及多个服务/数据库时,如何保证原子性?
### 5.1 两阶段提交(2PC
最经典的分布式事务协议,分为两个阶段:
| 阶段 | 协调者动作 | 参与者动作 |
|------|-----------|-----------|
| Prepare | 问所有参与者"能提交吗?" | 执行操作但不提交,回复 Yes/No |
| Commit | 如果全部 Yes,发送 Commit | 正式提交;如果有 No,全部回滚 |
**2PC 的问题**
- **阻塞**:Prepare 后如果协调者挂了,参与者会一直等待
- **单点故障**:协调者是单点,挂了整个事务卡住
- **性能差**:需要多次网络往返,锁持有时间长
### 5.2 Saga 模式
Saga 把一个大事务拆成多个本地事务,每个本地事务有对应的补偿操作。如果某一步失败,就逆序执行补偿。
**电商下单的 Saga 示例**
| 步骤 | 正向操作 | 补偿操作 |
|------|---------|---------|
| T1 | 创建订单(待支付) | 取消订单 |
| T2 | 扣减库存 | 恢复库存 |
| T3 | 扣减余额 | 退还余额 |
| T4 | 确认订单(已支付) | — |
如果 T3(扣减余额)失败:执行 C2(恢复库存)→ C1(取消订单)。
**两种编排方式**
- **编排式(Choreography)**:每个服务监听事件,自行决定下一步。简单但难以追踪全局状态
- **协调式(Orchestration)**:有一个中心协调者控制流程。清晰但协调者是单点
### 5.3 TCCTry-Confirm-Cancel
TCC 是 2PC 的业务层实现,把每个操作分为三个阶段:
| 阶段 | 说明 | 示例(扣库存) |
|------|------|---------------|
| Try | 预留资源,但不真正执行 | 冻结 10 件库存(可用库存 -10,冻结库存 +10) |
| Confirm | 确认执行,消耗预留资源 | 冻结库存 -10(真正扣减) |
| Cancel | 取消预留,释放资源 | 冻结库存 -10,可用库存 +10(恢复) |
### 5.4 三种方案对比
| 方案 | 一致性 | 性能 | 复杂度 | 适用场景 |
|------|--------|------|--------|---------|
| 2PC | 强一致 | 低 | 中 | 数据库层面的跨库事务 |
| Saga | 最终一致 | 高 | 高 | 长流程业务(订单、物流) |
| TCC | 最终一致 | 中 | 最高 | 资金类高可靠场景 |
::: tip 实际选择建议
- 能用单库事务就不要用分布式事务
- 大多数业务场景用 Saga + 消息队列就够了
- TCC 适合对一致性要求极高的金融场景,但开发成本很高
- 2PC 适合数据库中间件(如 ShardingSphere)自动处理
:::
---
## 总结
分布式系统是现代互联网的基础设施,但它的复杂性远超单机系统。理解这些挑战不是为了"解决"它们(很多是根本性的),而是为了在设计系统时做出正确的权衡。
回顾本章的关键要点:
1. **CAP 定理**:网络分区不可避免,实际选择是在一致性和可用性之间权衡
2. **一致性模型**:从强一致到最终一致是一个光谱,根据业务需求选择
3. **八大挑战**:网络不可靠、时钟不同步、网络分区、脑裂等相互关联
4. **共识算法**:Raft 是目前最实用的共识算法,etcd/Consul 都基于它
5. **分布式事务**:Saga 适合大多数场景,TCC 适合金融场景,2PC 适合数据库层
## 延伸阅读
- [Designing Data-Intensive Applications](https://dataintensive.net/) - Martin Kleppmann 的分布式系统经典
- [The Raft Consensus Algorithm](https://raft.github.io/) - Raft 官方可视化演示
- [CAP Twelve Years Later](https://www.infoq.com/articles/cap-twelve-years-later-how-the-rules-have-changed/) - Brewer 对 CAP 的重新审视
- [Jepsen](https://jepsen.io/) - 分布式系统正确性测试框架
- [分布式系统模式](https://martinfowler.com/articles/patterns-of-distributed-systems/) - Martin Fowler 的分布式模式合集
@@ -1,3 +1,204 @@
# 高可用与容灾
> 待实现
::: tip 前言
**系统挂了 1 分钟,可能意味着几十万的损失。** 高可用(High Availability)是指系统在面对硬件故障、软件 Bug、网络问题等异常情况时,仍能持续提供服务的能力。容灾(Disaster Recovery)则是在更大范围的灾难发生时,系统能够恢复服务的能力。
:::
**这篇文章会带你学什么?**
学完这章后,你将获得:
- **可用性度量**:理解"几个 9"的含义和对应的停机时间
- **故障转移**:掌握主备、主主、多活等高可用架构
- **容灾策略**:了解 RPO 和 RTO 的概念及设计方法
- **故障检测**:理解心跳、探针、熔断等故障发现机制
- **混沌工程**:了解如何主动注入故障来验证系统韧性
| 章节 | 内容 | 核心概念 |
|-----|------|---------|
| **第 1 章** | 可用性度量 | SLA、几个 9、停机时间 |
| **第 2 章** | 故障转移架构 | 主备、主主、多可用区、异地多活 |
| **第 3 章** | 容灾设计 | RPO、RTO、备份策略 |
| **第 4 章** | 故障检测与恢复 | 心跳、熔断、自动扩缩容 |
| **第 5 章** | 混沌工程 | 故障注入、韧性验证 |
---
## 1. 可用性度量:几个 9 意味着什么?
可用性通常用"几个 9"来衡量,计算公式为:
**可用性 = 正常运行时间 / 总时间 × 100%**
例如一个月(30 天 = 43200 分钟)内停机了 43 分钟,可用性就是 (43200 - 43) / 43200 ≈ 99.9%。每多一个 9,允许的停机时间就少一个数量级,实现难度和成本也指数级增长。
| 可用性等级 | 百分比 | 每月允许停机 | 每年允许停机 | 典型要求 |
|-----------|--------|------------|------------|---------|
| 2 个 9 | 99% | 7.3 小时 | 3.65 天 | 内部工具 |
| 3 个 9 | 99.9% | 43 分钟 | 8.76 小时 | 普通业务系统 |
| 4 个 9 | 99.99% | 4.3 分钟 | 52.6 分钟 | 电商、SaaS |
| 5 个 9 | 99.999% | 26 秒 | 5.26 分钟 | 金融、支付 |
<AvailabilityCalculatorDemo />
::: tip SLA 是什么?
**SLAService Level Agreement,服务等级协议)** 是服务提供方与客户之间的正式承诺。比如 AWS S3 承诺 99.99% 的可用性,如果没达到,会按比例退款。SLA 不只是技术指标,更是商业合同——违反 SLA 意味着赔钱。
:::
::: tip 从 3 个 9 到 4 个 9 的鸿沟
3 个 9(99.9%)意味着每月可以停机 43 分钟——一次部署出问题,回滚一下就用完了。
4 个 9(99.99%)意味着每月只能停机 4 分钟——这要求你必须有自动故障转移、滚动部署、健康检查等完整的高可用体系。
:::
---
## 2. 故障转移架构
故障转移(Failover)是高可用的核心机制:当主节点故障时,自动切换到备用节点继续提供服务。
### 主备模式(Active-Standby
最常见的高可用架构。主节点处理所有请求,备节点实时同步数据但不处理请求。主节点故障时,备节点自动接管。
```
正常状态:
客户端 → 主节点(处理请求)
备节点(同步数据,待命)
故障转移:
客户端 → 备节点(接管为新主节点)
原主节点(故障,等待修复)
```
关键问题是**脑裂(Split Brain)**:网络分区时,主备节点都认为对方挂了,同时对外提供服务,导致数据不一致。解决方案是引入**仲裁节点(Quorum)**——至少 3 个节点投票决定谁是主节点。
### 多可用区(Multi-AZ
将服务部署在同一地域的多个数据中心(可用区)。单个数据中心断电、断网不影响整体服务。云厂商的可用区之间通常有低延迟专线连接(< 2ms)。
### 异地多活(Multi-Region Active-Active
在不同城市甚至不同国家部署完整的服务副本,每个站点都能独立处理请求。这是最高级别的高可用架构,但也最复杂——核心挑战是**跨地域数据同步**的延迟和一致性问题。
<FailoverStrategyDemo />
| 架构 | 可用性级别 | 成本 | 复杂度 | 适用场景 |
|------|-----------|------|--------|---------|
| 单机 | 99%~99.9% | 低 | 低 | 开发测试、内部工具 |
| 主备 | 99.9%~99.99% | 中 | 中 | 中小型业务系统 |
| 多可用区 | 99.99% | 高 | 高 | 电商、SaaS 平台 |
| 异地多活 | 99.999% | 极高 | 极高 | 金融、大型互联网 |
---
## 3. 容灾设计:RPO 与 RTO
容灾设计围绕两个核心指标展开:
| 指标 | 全称 | 含义 | 举例 |
|------|------|------|------|
| RPO | Recovery Point Objective | 能容忍丢失多少数据 | RPO=0 表示不能丢任何数据 |
| RTO | Recovery Time Objective | 能容忍停机多长时间 | RTO=5min 表示 5 分钟内恢复 |
### 备份策略与 RPO 的关系
| 备份方式 | RPO | 成本 | 说明 |
|---------|-----|------|------|
| 每日全量备份 | 24 小时 | 低 | 最多丢一天数据 |
| 实时增量备份 | 分钟级 | 中 | binlog/WAL 持续同步 |
| 同步复制 | 0 | 高 | 写入必须等副本确认 |
::: tip 不是所有数据都需要 RPO=0
用户头像丢了可以重新上传(RPO=24h 够了),但支付记录一条都不能丢(RPO=0)。根据数据的业务价值来决定备份策略,而不是一刀切。
:::
---
## 4. 故障检测与恢复
### 4.1 故障检测机制
| 机制 | 原理 | 检测速度 | 适用场景 |
|------|------|---------|---------|
| 心跳检测 | 定期发送心跳包,超时判定故障 | 秒级 | 节点存活检测 |
| 健康检查 | HTTP/TCP 探针检查服务状态 | 秒级 | 负载均衡器后端检测 |
| 业务探针 | 模拟真实请求检查业务逻辑 | 秒~分钟级 | 端到端可用性监控 |
**心跳检测的工作原理**:节点 A 每隔固定时间(如 5 秒)向监控方发送一个"我还活着"的信号。如果连续 N 次(如 3 次)没收到心跳,就判定节点 A 故障。关键参数是**心跳间隔**和**超时阈值**——间隔太短会增加网络开销,太长会延迟故障发现。
**健康检查的三种级别**
- **存活探针(Liveness)**:进程还在运行吗?不在就重启
- **就绪探针(Readiness)**:服务能接受请求吗?不能就从负载均衡中摘除
- **启动探针(Startup)**:服务启动完成了吗?没完成就等待,不要误判为故障
### 4.2 自动恢复机制
| 机制 | 描述 | 典型工具 |
|------|------|---------|
| 自动重启 | 进程崩溃后自动拉起 | systemd、PM2、K8s |
| 自动扩缩容 | 负载升高时自动增加实例 | K8s HPA、云厂商 Auto Scaling |
| 熔断降级 | 下游故障时快速失败,防止级联故障 | Hystrix、Sentinel、Resilience4j |
| 限流 | 超过容量的请求直接拒绝 | Nginx limit_req、网关限流 |
**熔断器模式(Circuit Breaker)详解**
熔断器的灵感来自电路中的保险丝——当电流过大时自动断开,保护整个电路不被烧毁。在微服务中,当下游服务故障时,熔断器会"断开",让请求快速失败,而不是傻等超时。
```
熔断器三种状态:
关闭(正常)──→ 失败率超过阈值 ──→ 打开(熔断)
↑ │
│ 等待冷却时间
│ ↓
└── 探测请求成功 ←── 半开(试探)
```
- **关闭状态**:正常转发请求,同时统计失败率
- **打开状态**:所有请求直接返回错误(快速失败),不再调用下游
- **半开状态**:冷却时间到后,放行少量探测请求。如果成功,恢复关闭;如果失败,继续打开
**降级(Fallback** 是熔断的配套策略:熔断触发后,不是直接报错,而是返回一个"兜底"结果。比如推荐服务挂了,就返回热门商品列表;用户头像加载失败,就显示默认头像。
---
## 5. 混沌工程:主动找问题
混沌工程的核心理念是:**与其等故障发生,不如主动制造故障**,在可控环境中验证系统的韧性。
| 工具 | 提出者 | 核心能力 |
|------|--------|---------|
| Chaos Monkey | Netflix | 随机终止生产环境的实例 |
| Chaos Mesh | PingCAP | K8s 环境下的故障注入 |
| Litmus | CNCF | 云原生混沌工程框架 |
| ChaosBlade | 阿里巴巴 | 多场景故障注入工具 |
::: tip 混沌工程的实施步骤
1. **定义稳态**:明确系统正常运行的指标(如 P99 延迟 < 200ms
2. **提出假设**:如果某个节点挂了,系统应该在 30 秒内自动恢复
3. **注入故障**:在可控范围内制造故障(先在测试环境,再到生产)
4. **观察结果**:系统是否如预期恢复?有没有级联故障?
5. **修复弱点**:发现问题后改进架构和流程
:::
---
## 总结
高可用不是一个功能,而是一种架构能力。它需要从设计、开发、部署、运维的每个环节去保障。
回顾本章的关键要点:
1. **几个 9**:每多一个 9,停机时间少一个数量级,成本和复杂度指数增长
2. **故障转移**:从主备到异地多活,根据业务需求选择合适的架构
3. **RPO 与 RTO**:根据数据价值和业务容忍度设计备份和恢复策略
4. **自动化**:故障检测、自动重启、熔断降级是高可用的基础设施
5. **混沌工程**:主动制造故障,在可控环境中验证系统韧性
## 延伸阅读
- [Site Reliability Engineering](https://sre.google/sre-book/table-of-contents/) - Google SRE 经典
- [Chaos Monkey](https://netflix.github.io/chaosmonkey/) - Netflix 混沌工程工具
- [Release It!](https://pragprog.com/titles/mnee2/release-it-second-edition/) - 生产环境设计模式
- [Chaos Mesh](https://chaos-mesh.org/) - K8s 混沌工程平台
@@ -1,3 +1,156 @@
# 从单体到微服务的演进
> 待实现
::: tip 前言
**没有哪个架构是"最好的",只有"最适合当前阶段的"。** 从单体到微服务不是一步到位的跳跃,而是随着业务规模和团队规模增长,逐步演进的过程。过早拆分微服务和过晚拆分一样危险。
:::
**这篇文章会带你学什么?**
学完这章后,你将获得:
- **演进路径**:理解从单体到微服务的四个阶段
- **拆分时机**:知道什么时候该拆、什么时候不该拆
- **拆分策略**:掌握按业务域拆分的方法论
- **通信模式**:了解服务间同步和异步通信的选择
- **数据拆分**:理解数据库拆分的挑战和方案
| 章节 | 内容 | 核心概念 |
|-----|------|---------|
| **第 1 章** | 架构演进路径 | 单体→模块化→SOA→微服务 |
| **第 2 章** | 拆分时机与原则 | Conway 定律、团队自治 |
| **第 3 章** | 拆分策略 | DDD 限界上下文、绞杀者模式 |
| **第 4 章** | 服务通信 | REST、gRPC、消息队列 |
| **第 5 章** | 数据拆分 | 数据库拆分、数据同步 |
---
## 1. 架构演进路径
架构演进不是技术驱动的,而是**组织规模驱动的**。当团队从 5 人增长到 500 人时,单体架构的协作效率会急剧下降。
| 阶段 | 架构 | 团队规模 | 特点 |
|------|------|---------|------|
| 起步期 | 单体应用 | 1~10 人 | 所有代码在一个项目中,部署简单 |
| 成长期 | 模块化单体 | 10~50 人 | 代码按模块划分,但仍然一起部署 |
| 扩张期 | SOA(面向服务) | 50~200 人 | 按业务线拆分为粗粒度服务 |
| 规模期 | 微服务 | 200+ 人 | 细粒度服务,每个团队独立开发部署 |
<ArchEvolutionDemo />
::: tip Conway 定律
"设计系统的组织,其产生的架构等同于组织的沟通结构。"——Melvin Conway
简单说:3 个团队做一个系统,最终会变成 3 个服务。架构拆分的本质是**组织拆分**。
**反向 Conway 定律**:既然组织结构决定了系统架构,那么想要什么样的架构,就先调整成什么样的组织结构。比如你想拆出独立的支付服务,就先组建一个独立的支付团队。很多公司微服务拆分失败,不是技术问题,而是组织没有跟着调整。
:::
---
## 2. 什么时候该拆微服务?
不是所有系统都需要微服务。过早拆分会带来不必要的复杂性。
| 信号 | 说明 | 建议 |
|------|------|------|
| 部署冲突频繁 | 多个团队改同一个代码库,经常冲突 | 考虑拆分 |
| 某模块需要独立扩容 | 搜索模块需要 10 倍于其他模块的资源 | 考虑拆分 |
| 技术栈需要差异化 | AI 模块用 Python,主站用 Java | 考虑拆分 |
| 团队 < 10 人 | 沟通成本低,单体足够 | 不要拆 |
| 业务还在探索期 | 需求变化快,边界不清晰 | 不要拆 |
| 没有 DevOps 能力 | 没有 CI/CD、容器化、监控体系 | 不要拆 |
---
## 3. 拆分策略
### 3.1 按业务域拆分(DDD 限界上下文)
DDD(领域驱动设计)的限界上下文(Bounded Context)是拆分微服务的最佳指导原则。每个限界上下文对应一个独立的业务域,有自己的数据模型和业务规则。
**什么是限界上下文?** 同一个词在不同业务域中含义不同。比如"用户"在用户域是指注册信息(姓名、邮箱),在订单域是指下单人(收货地址、支付方式),在推荐域是指行为画像(浏览历史、偏好标签)。限界上下文就是划定一个边界,在这个边界内,术语和模型有明确统一的含义。
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 用户域 │ │ 订单域 │ │ 支付域 │
│ │ │ │ │ │
│ User │ │ Order │ │ Payment │
│ Profile │ │ OrderItem │ │ Refund │
│ Address │ │ Cart │ │ Transaction │
│ │ │ │ │ │
│ 用户服务 │ │ 订单服务 │ │ 支付服务 │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└────── API 调用 / 事件通信 ───────┘
```
| 限界上下文 | 核心实体 | 对应服务 |
|-----------|---------|---------|
| 用户域 | User、Profile、Address | 用户服务 |
| 商品域 | Product、Category、SKU | 商品服务 |
| 订单域 | Order、OrderItem | 订单服务 |
| 支付域 | Payment、Refund | 支付服务 |
| 物流域 | Shipment、Tracking | 物流服务 |
### 3.2 绞杀者模式(Strangler Fig Pattern
不要一次性重写整个单体,而是像绞杀榕一样,逐步用新服务替换旧模块:
1. 在单体外部创建新服务
2. 通过代理层将部分流量路由到新服务
3. 验证新服务稳定后,逐步迁移更多流量
4. 最终完全替换旧模块
---
## 4. 服务通信模式
| 方式 | 协议 | 特点 | 适用场景 |
|------|------|------|---------|
| REST | HTTP/JSON | 简单通用,生态好 | 对外 API、CRUD 操作 |
| gRPC | HTTP/2 + Protobuf | 高性能,强类型 | 内部服务间高频调用 |
| 消息队列 | AMQP/Kafka | 异步解耦,削峰填谷 | 事件通知、异步任务 |
| GraphQL | HTTP/JSON | 客户端按需查询 | BFF 层、移动端 |
::: tip 同步 vs 异步的选择
- **需要立即返回结果** → 同步(REST/gRPC
- **不需要立即返回** → 异步(消息队列)
- **一个事件触发多个动作** → 异步(发布-订阅)
经验法则:能异步就异步,同步调用链越长,系统越脆弱。
:::
---
## 5. 数据拆分:最难的部分
微服务拆分中最痛苦的不是代码拆分,而是数据库拆分。每个服务应该拥有自己的数据库,但这意味着跨服务查询变得困难。
| 挑战 | 描述 | 解决方案 |
|------|------|---------|
| 跨服务 JOIN | 不能直接 JOIN 两个服务的表 | API 组合查询、数据冗余 |
| 分布式事务 | 跨库事务无法用本地事务 | Saga、本地消息表 |
| 数据一致性 | 多个服务的数据可能暂时不一致 | 最终一致性、事件驱动 |
| 数据迁移 | 从共享库迁移到独立库 | 双写过渡、数据同步工具 |
---
## 总结
从单体到微服务是一个渐进的过程,不是一蹴而就的革命。
回顾本章的关键要点:
1. **演进路径**:单体→模块化单体→SOA→微服务,每一步都有明确的驱动力
2. **拆分时机**:团队规模、部署冲突、扩容需求是拆分的信号
3. **拆分策略**:用 DDD 限界上下文指导拆分,用绞杀者模式渐进迁移
4. **通信选择**:能异步就异步,同步调用链越短越好
5. **数据拆分**:最难但最重要,接受最终一致性是关键心态转变
## 延伸阅读
- [Building Microservices](https://www.oreilly.com/library/view/building-microservices-2nd/9781492034018/) - Sam Newman 微服务经典
- [Monolith to Microservices](https://www.oreilly.com/library/view/monolith-to-microservices/9781492047834/) - 渐进式迁移指南
- [Domain-Driven Design](https://www.domainlanguage.com/ddd/) - Eric Evans 的 DDD 经典
- [The Strangler Fig Pattern](https://martinfowler.com/bliki/StranglerFigApplication.html) - Martin Fowler 的绞杀者模式
@@ -1,3 +1,252 @@
# 系统设计方法论
> 待实现
::: tip 前言
**系统设计不是拍脑袋画架构图,而是一套有章可循的方法论。** 无论是面试中的系统设计题,还是实际工作中的架构设计,都遵循相似的思考框架:先搞清楚问题,再估算规模,然后设计方案,最后深入优化。
:::
**这篇文章会带你学什么?**
学完这章后,你将获得:
- **设计流程**:掌握系统设计的四步法框架
- **容量估算**:学会"信封背面估算"的技巧
- **常见模式**:熟悉缓存、分库分表、消息队列等核心模式
- **权衡思维**:理解架构设计中的 trade-off 思维
- **实战案例**:通过短链服务、Feed 流等案例理解设计过程
| 章节 | 内容 | 核心概念 |
|-----|------|---------|
| **第 1 章** | 设计四步法 | 需求澄清、容量估算、架构设计、深入优化 |
| **第 2 章** | 容量估算 | QPS、存储、带宽、信封背面估算 |
| **第 3 章** | 核心设计模式 | 缓存、分库分表、消息队列、CDN |
| **第 4 章** | 权衡思维 | 一致性 vs 可用性、性能 vs 成本 |
| **第 5 章** | 经典案例 | 短链服务、Feed 流、秒杀系统 |
---
## 1. 系统设计四步法
系统设计不是一上来就画架构图。无论是面试还是实战,都应该遵循一个结构化的流程。
<SystemDesignStepsDemo />
::: tip 为什么要先澄清需求?
很多人拿到题目就开始画图,结果设计了一个"正确但不是面试官想要的"系统。花 5 分钟问清楚需求,能避免后面 30 分钟的返工。
常见的澄清问题:
- 系统的核心功能是什么?(不要设计所有功能)
- 用户规模多大?(决定是否需要分布式)
- 读写比例?(决定缓存策略)
- 数据需要保留多久?(决定存储方案)
:::
---
## 2. 容量估算:信封背面的艺术
"信封背面估算"Back-of-envelope estimation)是系统设计中的核心技能。不需要精确计算,只需要知道量级。
<CapacityEstimationDemo />
### 常用换算速查
| 量级 | 换算 | 记忆技巧 |
|------|------|---------|
| 1 天 | 86,400 秒 | ≈ 10 万秒 |
| 1 亿请求/天 | ≈ 1,200 QPS | 除以 10 万 |
| 1 KB × 1 亿 | ≈ 100 GB | 1 亿条小记录 |
| 1 MB × 100 万 | ≈ 1 TB | 100 万张图片 |
### 2-8 法则在估算中的应用
大多数系统遵循 80/20 法则:20% 的数据承载 80% 的请求。这意味着:
- **缓存大小** ≈ 总数据量 × 20%
- **热点 QPS** ≈ 总 QPS × 80% 集中在 20% 的 key 上
- **缓存命中率**目标 ≈ 80%+(低于这个值说明缓存策略有问题)
---
## 3. 核心设计模式
系统设计中反复出现的模式,掌握这些就能应对大多数场景。
### 3.1 缓存模式
| 模式 | 读路径 | 写路径 | 适用场景 |
|------|--------|--------|---------|
| Cache-Aside | 先查缓存,miss 则查 DB 并回填 | 先写 DB,再删缓存 | 通用场景,最常用 |
| Read-Through | 缓存层自动从 DB 加载 | 同 Cache-Aside | 需要缓存框架支持 |
| Write-Behind | 同 Cache-Aside | 先写缓存,异步写 DB | 写密集型,可容忍丢数据 |
::: tip 为什么是"删缓存"而不是"更新缓存"
更新缓存在并发场景下容易出现数据不一致:线程 A 和 B 同时更新,A 先写 DB 但 B 先更新缓存,导致缓存中是 B 的旧值。删除缓存则让下次读请求重新从 DB 加载,天然避免这个问题。
:::
### 3.2 分库分表
当单表数据量超过千万级,或单库 QPS 超过瓶颈时,就需要考虑分库分表。
| 策略 | 做法 | 优点 | 缺点 |
|------|------|------|------|
| 垂直分库 | 按业务域拆分数据库 | 业务解耦,独立扩展 | 跨库 JOIN 困难 |
| 水平分表 | 同一张表按规则拆成多张 | 单表数据量可控 | 分片键选择关键 |
| 垂直分表 | 把大字段拆到独立表 | 减少 IO,提升查询效率 | 需要额外 JOIN |
**分片键选择原则**
- 选择查询最频繁的字段(如 user_id)
- 数据分布要均匀,避免热点
- 尽量让同一用户的数据在同一分片(减少跨分片查询)
### 3.3 消息队列
消息队列是分布式系统的"减震器",核心作用是解耦、异步、削峰。
| 场景 | 不用队列 | 用队列 |
|------|---------|--------|
| 下单后发通知 | 下单接口同步调用通知服务,通知失败导致下单失败 | 下单成功后发消息,通知服务异步消费 |
| 秒杀抢购 | 瞬间流量打爆数据库 | 请求先入队列,后端按能力消费 |
| 数据同步 | 服务 A 直接调用服务 B 的接口 | 服务 A 发事件,服务 B 订阅处理 |
---
## 4. 权衡思维:没有银弹
架构设计的本质是权衡(Trade-off)。每个决策都有代价,关键是理解代价并做出适合当前阶段的选择。
| 权衡维度 | 选项 A | 选项 B | 决策依据 |
|---------|--------|--------|---------|
| 一致性 vs 可用性 | 强一致(CP) | 高可用(AP) | 业务能否容忍短暂不一致? |
| 性能 vs 成本 | 全量缓存 | 按需缓存 | 数据量和预算 |
| 简单 vs 灵活 | 单体架构 | 微服务 | 团队规模和业务复杂度 |
| 实时 vs 批量 | 流式处理 | 批处理 | 数据时效性要求 |
| 自建 vs 托管 | 自己搭 MySQL | 用云数据库 RDS | 运维能力和成本 |
::: tip 架构决策记录(ADR
每个重要的架构决策都应该记录下来:**背景是什么、考虑了哪些方案、为什么选了这个、有什么代价**。这不是为了甩锅,而是为了让后来的人理解"为什么当时这么设计"。
格式很简单:
- **标题**:用 XXX 替代 YYY
- **背景**:我们遇到了什么问题
- **决策**:我们选择了什么方案
- **理由**:为什么选这个
- **代价**:这个决策的缺点和风险
:::
### 常见的错误权衡
| 错误 | 表现 | 正确做法 |
|------|------|---------|
| 过早优化 | 日活 1000 就上分库分表 | 先用单库,遇到瓶颈再拆 |
| 技术驱动 | "我想用 Kafka" 而不是 "我需要异步" | 从问题出发,而非从技术出发 |
| 忽略运维成本 | 选了最优方案但团队维护不了 | 方案要匹配团队能力 |
| 追求完美一致性 | 所有场景都用分布式事务 | 大多数场景最终一致性就够了 |
---
## 5. 经典案例
通过三个经典案例,把前面学到的方法论串起来。
### 5.1 短链服务(TinyURL
短链服务是系统设计面试的经典题目,麻雀虽小五脏俱全。
**需求澄清**
- 核心功能:长链接 → 短链接(写),短链接 → 重定向(读)
- 读写比:约 100:1(读远多于写)
- 日均重定向:1 亿次
- 短链永不过期
**容量估算**
| 指标 | 计算 | 结果 |
|------|------|------|
| 写 QPS | 1 亿 / 100 / 86400 | ≈ 12 QPS |
| 读 QPS | 1 亿 / 86400 | ≈ 1,200 QPS |
| 峰值读 QPS | 1,200 × 3 | ≈ 3,600 QPS |
| 5 年存储 | 100 万/天 × 365 × 5 × 100B | ≈ 18 GB |
| 缓存(20% | 18 GB × 20% | ≈ 3.6 GB |
**架构设计**
```
写路径:客户端 → API Server → ID 生成器 → Base62 编码 → 写入 MySQL + Redis
读路径:客户端 → CDN → API Server → Redis 查询 → 302 重定向
↓ (cache miss)
MySQL 查询 → 回填 Redis
```
**关键设计决策**
- 短码生成:Snowflake 分布式 ID + Base62 编码,避免哈希冲突
- 缓存策略:Cache-Aside,热点短链用 CDN 加速
- 数据库:单表即可(18GB 很小),按短码做索引
### 5.2 Feed 流系统
社交平台的 Feed 流(朋友圈、微博首页)是另一个经典题目。
**核心挑战**:用户发一条动态,如何让所有关注者看到?
| 方案 | 做法 | 优点 | 缺点 |
|------|------|------|------|
| 拉模式(Pull) | 读取时实时聚合关注者的动态 | 写入简单,存储少 | 读取慢,关注多时延迟高 |
| 推模式(Push) | 发布时写入所有粉丝的收件箱 | 读取极快 | 大 V 发动态写扩散严重 |
| 推拉结合 | 普通用户推,大 V 拉 | 平衡读写性能 | 实现复杂 |
**推拉结合方案**
- 粉丝数 < 1 万:发布时推送到所有粉丝的 Feed 缓存(推模式)
- 粉丝数 > 1 万:不推送,粉丝读取时实时拉取(拉模式)
- 用户打开 Feed 时:合并推送的内容 + 实时拉取大 V 的内容,按时间排序
### 5.3 秒杀系统
秒杀的核心挑战:瞬间超高并发 + 库存不能超卖。
**流量特征**
- 活动开始前:大量用户刷新页面等待
- 活动开始瞬间:QPS 可能是平时的 100 倍以上
- 活动结束后:流量迅速回落
**分层削峰策略**
```
用户请求 → CDN(静态页面)→ 网关(限流)→ 消息队列(削峰)→ 库存服务(扣减)
```
| 层级 | 策略 | 效果 |
|------|------|------|
| 前端 | 按钮置灰 + 随机延迟 + 验证码 | 过滤机器人,分散请求 |
| CDN | 静态资源缓存 | 减少 90% 的页面请求 |
| 网关 | 令牌桶限流 | 只放行系统能承受的流量 |
| 消息队列 | 请求入队,异步处理 | 削峰填谷,保护数据库 |
| 库存服务 | Redis 预扣减 + Lua 原子操作 | 防止超卖,毫秒级响应 |
::: tip 秒杀的核心原则
1. **尽量拦截在上游**:能在 CDN 挡住的就不要到应用层
2. **读写分离**:商品详情页走缓存,只有下单走数据库
3. **异步处理**:用户点击"抢购"后立即返回"排队中",后台异步处理
4. **兜底方案**:限流、熔断、降级,任何一层出问题都有 Plan B
:::
---
## 总结
系统设计是一门实践性很强的技能,核心在于结构化思考和权衡取舍。
回顾本章的关键要点:
1. **四步法框架**:需求澄清 → 容量估算 → 架构设计 → 深入优化,每一步都不可跳过
2. **信封背面估算**:不需要精确,只需要知道量级,用于指导架构决策
3. **核心模式**:缓存、分库分表、消息队列、CDN、限流熔断——这些是系统设计的"积木"
4. **权衡思维**:没有完美方案,只有适合当前阶段的方案,记录每个决策的理由和代价
5. **经典案例**:短链服务练基础、Feed 流练推拉模型、秒杀练高并发——掌握这三个就能举一反三
## 延伸阅读
- [System Design Interview](https://www.amazon.com/System-Design-Interview-insiders-Second/dp/B08CMF2CQF) - Alex Xu 系统设计面试经典
- [Designing Data-Intensive Applications](https://dataintensive.net/) - Martin Kleppmann 数据密集型应用设计
- [The System Design Primer](https://github.com/donnemartin/system-design-primer) - GitHub 上最全的系统设计学习资源
- [ByteByteGo](https://bytebytego.com/) - Alex Xu 的系统设计可视化博客
@@ -1,3 +1,221 @@
# Docker 容器化
> 待实现
::: tip 前言
**"在我机器上能跑"是开发者最经典的借口,Docker 让这个借口彻底消失。** 容器化技术将应用及其所有依赖打包成一个标准化的单元,确保在任何环境中都能一致运行。它是现代软件交付的基石。
:::
**这篇文章会带你学什么?**
学完这章后,你将获得:
- **核心概念**:理解镜像、容器、仓库三大核心概念
- **架构对比**:明白容器和虚拟机的本质区别
- **实操能力**:掌握 Dockerfile 编写和常用命令
- **编排基础**:学会用 Docker Compose 管理多服务应用
- **最佳实践**:了解镜像优化、安全加固等生产级实践
| 章节 | 内容 | 核心概念 |
|-----|------|---------|
| **第 1 章** | 为什么需要容器 | 环境一致性、资源效率、标准化交付 |
| **第 2 章** | 核心概念 | 镜像、容器、仓库、Dockerfile |
| **第 3 章** | Docker 生命周期 | 编写、构建、推送、运行、管理 |
| **第 4 章** | Docker Compose | 多服务编排、网络、数据卷 |
| **第 5 章** | 最佳实践 | 镜像优化、安全、多阶段构建 |
---
## 1. 为什么需要容器?
在容器出现之前,部署一个应用需要在服务器上手动安装运行时、配置环境变量、处理依赖冲突。不同环境(开发、测试、生产)之间的差异是 bug 的温床。
<DockerArchitectureDemo />
### 容器解决了什么问题?
| 问题 | 传统方式 | 容器方式 |
|------|---------|---------|
| 环境不一致 | "我本地能跑" | 打包所有依赖,到处一致 |
| 依赖冲突 | App A 要 Node 14App B 要 Node 18 | 每个容器独立环境 |
| 资源浪费 | 每个 VM 一个完整 OS | 共享内核,MB 级开销 |
| 部署慢 | 手动安装配置 | docker run 一条命令 |
| 扩容难 | 新建 VM、装环境、部署 | 秒级启动新容器 |
::: tip 容器的本质
容器不是轻量级虚拟机。它的本质是**被隔离的进程**。Linux 内核通过两个机制实现容器:
- **Namespace**:隔离进程的视野(PID、网络、文件系统等)
- **Cgroups**:限制进程的资源使用(CPU、内存、IO)
容器里的进程和宿主机上的普通进程没有本质区别,只是被"关在了一个看不到外面的房间里"。
:::
---
## 2. 核心概念
Docker 的世界围绕三个核心概念:镜像(Image)、容器(Container)、仓库(Registry)。
| 概念 | 类比 | 说明 |
|------|------|------|
| 镜像(Image) | 类 / 模板 | 只读的应用模板,包含代码、运行时、库、配置 |
| 容器(Container) | 实例 / 对象 | 镜像的运行实例,可读写,有独立的生命周期 |
| 仓库(Registry) | 应用商店 | 存储和分发镜像的服务(Docker Hub、ACR、ECR |
| Dockerfile | 配方 / 蓝图 | 定义如何构建镜像的文本文件 |
| 数据卷(Volume) | 外接硬盘 | 持久化数据,容器删除后数据不丢失 |
### 镜像的分层结构
Docker 镜像由多个只读层(Layer)叠加而成,每条 Dockerfile 指令创建一层:
```
┌─────────────────────────┐
│ CMD ["node", "app.js"] │ ← 启动命令层
├─────────────────────────┤
│ COPY . /app │ ← 应用代码层(经常变)
├─────────────────────────┤
│ RUN npm install │ ← 依赖安装层(偶尔变)
├─────────────────────────┤
│ FROM node:18-alpine │ ← 基础镜像层(很少变)
└─────────────────────────┘
```
::: tip 为什么分层很重要?
Docker 会缓存每一层。如果某一层没有变化,构建时会直接复用缓存。所以 Dockerfile 中应该把**变化频率低的指令放在前面**(如安装依赖),**变化频率高的放在后面**(如复制代码)。这样大部分构建都能命中缓存,速度快很多。
:::
---
## 3. Docker 生命周期
从编写 Dockerfile 到容器运行,Docker 的工作流程是一条清晰的流水线。
<DockerLifecycleDemo />
### Dockerfile 常用指令速查
| 指令 | 作用 | 示例 |
|------|------|------|
| `FROM` | 指定基础镜像 | `FROM node:18-alpine` |
| `WORKDIR` | 设置工作目录 | `WORKDIR /app` |
| `COPY` | 复制文件到镜像 | `COPY package.json ./` |
| `RUN` | 构建时执行命令 | `RUN npm install` |
| `ENV` | 设置环境变量 | `ENV NODE_ENV=production` |
| `EXPOSE` | 声明端口(仅文档作用) | `EXPOSE 3000` |
| `CMD` | 容器启动命令 | `CMD ["node", "app.js"]` |
| `ENTRYPOINT` | 容器入口点(不易被覆盖) | `ENTRYPOINT ["nginx"]` |
---
## 4. Docker Compose:多服务编排
真实项目通常不止一个容器。一个 Web 应用可能需要:应用服务器 + 数据库 + Redis + Nginx。Docker Compose 用一个 YAML 文件定义和管理多个容器。
### docker-compose.yml 示例
```yaml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DB_HOST=db
- REDIS_HOST=redis
depends_on:
- db
- redis
db:
image: postgres:15-alpine
volumes:
- db-data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=secret
redis:
image: redis:7-alpine
volumes:
db-data:
```
### Compose 核心概念
| 概念 | 说明 | 示例 |
|------|------|------|
| services | 定义各个容器服务 | app、db、redis |
| volumes | 持久化数据卷 | db-data 保存数据库文件 |
| networks | 自定义网络(默认自动创建) | 服务间通过服务名互相访问 |
| depends_on | 启动顺序依赖 | app 依赖 db 和 redis |
| environment | 环境变量 | 数据库密码、连接地址 |
::: tip 服务发现
在 Docker Compose 中,服务名就是主机名。app 容器可以直接用 `db:5432` 访问数据库,用 `redis:6379` 访问 Redis,不需要知道 IP 地址。这是 Docker 内置 DNS 的功劳。
:::
---
## 5. 最佳实践
### 5.1 多阶段构建(Multi-stage Build
多阶段构建是优化镜像大小的利器。构建阶段安装所有工具和依赖,最终阶段只保留运行时需要的文件。
```dockerfile
# 构建阶段
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 运行阶段
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]
```
### 5.2 镜像优化清单
| 优化项 | 做法 | 效果 |
|--------|------|------|
| 选择小基础镜像 | 用 `alpine` 而非 `ubuntu` | 镜像从 ~200MB 降到 ~50MB |
| 合并 RUN 指令 | 多个命令用 `&&` 连接 | 减少镜像层数 |
| 使用 .dockerignore | 排除 node_modules、.git 等 | 加速构建,减小上下文 |
| 多阶段构建 | 分离构建和运行环境 | 最终镜像不含构建工具 |
| 固定版本号 | `node:18.17-alpine` 而非 `node:latest` | 构建可重复 |
### 5.3 安全实践
| 实践 | 说明 |
|------|------|
| 不用 root 运行 | `USER node` 指定非 root 用户 |
| 扫描漏洞 | `docker scout` 或 Trivy 扫描镜像 |
| 最小权限 | 只安装必要的包,不装调试工具 |
| 不硬编码密钥 | 用环境变量或 Docker Secrets |
| 定期更新基础镜像 | 及时修复安全漏洞 |
---
## 总结
Docker 容器化是现代软件交付的基础设施,理解它对于任何开发者都至关重要。
回顾本章的关键要点:
1. **容器 vs 虚拟机**:容器共享宿主内核,更轻量、更快,但隔离性略弱于 VM
2. **核心三件套**:镜像(模板)、容器(实例)、仓库(分发)
3. **Dockerfile**:分层构建,利用缓存,变化少的指令放前面
4. **Docker Compose**:用 YAML 定义多服务应用,服务名即主机名
5. **生产实践**:多阶段构建减小镜像、alpine 基础镜像、非 root 运行
## 延伸阅读
- [Docker 官方文档](https://docs.docker.com/) - 最权威的参考资料
- [Docker Getting Started](https://docs.docker.com/get-started/) - 官方入门教程
- [Dockerfile Best Practices](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) - 官方最佳实践指南
- [Docker Compose 文档](https://docs.docker.com/compose/) - Compose 完整参考
@@ -1,3 +1,192 @@
# Kubernetes 编排
> 待实现
::: tip 前言
**Docker 解决了"打包"问题,Kubernetes 解决了"管理"问题。** 当你有几十上百个容器需要部署、扩缩容、故障恢复时,手动管理是不现实的。Kubernetes(K8s)就是容器的"操作系统",它自动化了容器化应用的部署、扩展和运维。
:::
**这篇文章会带你学什么?**
学完这章后,你将获得:
- **架构理解**:掌握 K8s 控制平面和工作节点的组成
- **核心资源**:熟悉 Pod、Deployment、Service 等核心概念
- **声明式管理**:理解"声明期望状态,系统自动收敛"的思想
- **运维能力**:了解滚动更新、自动扩缩容、健康检查等机制
- **实战入门**:能用 kubectl 和 YAML 部署一个完整应用
| 章节 | 内容 | 核心概念 |
|-----|------|---------|
| **第 1 章** | 为什么需要 K8s | 容器编排的挑战 |
| **第 2 章** | K8s 架构 | 控制平面、工作节点、etcd |
| **第 3 章** | 核心资源 | Pod、Deployment、Service、Ingress |
| **第 4 章** | 声明式管理 | YAML、kubectl、控制循环 |
| **第 5 章** | 运维实践 | 滚动更新、HPA、健康检查 |
---
## 1. 为什么需要 Kubernetes
Docker 让单个容器的打包和运行变得简单,但当你面对以下场景时,手动管理就力不从心了:
| 挑战 | 描述 | K8s 的解决方案 |
|------|------|---------------|
| 多实例部署 | 一个服务需要运行 10 个副本 | Deployment 自动管理副本数 |
| 故障恢复 | 某个容器挂了需要自动重启 | 控制器自动检测并重建 Pod |
| 服务发现 | 容器 IP 会变,怎么找到对方? | Service 提供稳定的 DNS 和 IP |
| 滚动更新 | 更新版本时不能停服 | 逐步替换旧 Pod,零停机 |
| 弹性伸缩 | 流量高峰自动扩容 | HPA 根据 CPU/内存自动调整副本数 |
| 资源调度 | 把容器放到最合适的机器上 | Scheduler 智能调度 |
::: tip K8s 的核心思想:声明式
你不需要告诉 K8s "启动 3 个容器"(命令式),而是告诉它 "我要 3 个副本在运行"(声明式)。K8s 会持续监控,确保实际状态与你声明的期望状态一致。如果一个 Pod 挂了,它会自动创建新的来补上。
:::
---
## 2. Kubernetes 架构
K8s 集群由控制平面(Control Plane)和工作节点(Worker Node)组成。
<K8sArchitectureDemo />
### 一次请求的完整路径
```
用户请求 → Ingress Controller → Service → kube-proxy → Pod(容器)
Endpoint 列表(由 Service 维护)
```
---
## 3. 核心资源对象
K8s 通过各种"资源对象"来描述集群的期望状态。
<K8sWorkloadsDemo />
### 资源对象分类
| 类别 | 资源 | 用途 |
|------|------|------|
| 工作负载 | Pod、Deployment、StatefulSet、DaemonSet、Job | 运行应用 |
| 网络 | Service、Ingress、NetworkPolicy | 服务发现和流量管理 |
| 配置 | ConfigMap、Secret | 配置和敏感数据管理 |
| 存储 | PersistentVolume、PersistentVolumeClaim | 持久化存储 |
| 调度 | Node、Namespace、ResourceQuota | 资源隔离和限制 |
---
## 4. 声明式管理与 kubectl
### 控制循环(Reconciliation Loop
K8s 的核心工作机制是控制循环:
```
观察(Observe)→ 比较(Diff)→ 行动(Act)→ 观察...
↓ ↓ ↓
读取实际状态 与期望状态对比 执行修正操作
```
你声明 `replicas: 3`,控制器发现只有 2 个 Pod 在运行,就会创建 1 个新的。这个循环每隔几秒执行一次,确保系统始终向期望状态收敛。
### kubectl 常用命令
| 命令 | 作用 | 示例 |
|------|------|------|
| `kubectl apply -f` | 应用 YAML 配置 | `kubectl apply -f deployment.yaml` |
| `kubectl get` | 查看资源列表 | `kubectl get pods -o wide` |
| `kubectl describe` | 查看资源详情 | `kubectl describe pod my-app-xxx` |
| `kubectl logs` | 查看 Pod 日志 | `kubectl logs -f my-app-xxx` |
| `kubectl exec` | 进入 Pod 终端 | `kubectl exec -it my-app-xxx -- sh` |
| `kubectl delete` | 删除资源 | `kubectl delete -f deployment.yaml` |
| `kubectl scale` | 手动扩缩容 | `kubectl scale deploy my-app --replicas=5` |
::: tip apply vs create
`kubectl create` 是命令式的——"创建这个资源",如果已存在会报错。`kubectl apply` 是声明式的——"确保资源是这个状态",不存在就创建,已存在就更新。生产环境中应该始终使用 `apply`
:::
---
## 5. 运维实践
### 5.1 滚动更新与回滚
Deployment 默认使用滚动更新策略:逐步创建新版本 Pod,同时逐步终止旧版本 Pod。
```yaml
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 最多多创建 1 个 Pod
maxUnavailable: 0 # 不允许有 Pod 不可用
```
| 操作 | 命令 |
|------|------|
| 更新镜像 | `kubectl set image deploy/my-app app=my-app:2.0` |
| 查看更新状态 | `kubectl rollout status deploy/my-app` |
| 查看历史版本 | `kubectl rollout history deploy/my-app` |
| 回滚到上一版本 | `kubectl rollout undo deploy/my-app` |
### 5.2 自动扩缩容(HPA
HPAHorizontal Pod Autoscaler)根据 CPU、内存或自定义指标自动调整 Pod 副本数。
```yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
```
### 5.3 健康检查(Probe
K8s 通过三种探针监控 Pod 的健康状态:
| 探针 | 作用 | 失败后果 |
|------|------|---------|
| livenessProbe | 检测容器是否存活 | 重启容器 |
| readinessProbe | 检测容器是否就绪 | 从 Service 摘除,不接收流量 |
| startupProbe | 检测容器是否启动完成 | 启动期间不执行其他探针 |
::: tip 探针的重要性
没有配置健康检查的 Pod,K8s 只能通过进程是否存在来判断健康状态。但很多时候进程还在,服务已经不响应了(比如死锁、OOM 边缘)。配置 livenessProbe 可以让 K8s 自动重启这些"假死"的容器。
:::
---
## 总结
Kubernetes 是容器编排的事实标准,理解它的核心概念是云原生开发的基础。
回顾本章的关键要点:
1. **声明式管理**:告诉 K8s "我要什么",而不是"怎么做",控制循环自动收敛
2. **架构分层**:控制平面负责决策,工作节点负责执行,etcd 存储状态
3. **核心资源**Pod(最小单元)、Deployment(副本管理)、Service(服务发现)、Ingress(外部入口)
4. **运维自动化**:滚动更新零停机、HPA 弹性伸缩、探针自动故障恢复
5. **配置分离**ConfigMap 和 Secret 让配置与镜像解耦
## 延伸阅读
- [Kubernetes 官方文档](https://kubernetes.io/zh-cn/docs/) - 最权威的中文参考
- [Kubernetes the Hard Way](https://github.com/kelseyhightower/kubernetes-the-hard-way) - 从零手动搭建 K8s 集群
- [The Illustrated Children's Guide to Kubernetes](https://www.cncf.io/phippy/) - CNCF 出品的趣味入门
- [Kubernetes Patterns](https://www.oreilly.com/library/view/kubernetes-patterns-2nd/9781098131678/) - K8s 设计模式
@@ -1,3 +1,397 @@
# Linux 基础
> 待实现
::: tip 前言
**服务器的世界,Linux 是绝对的主角。** 全球超过 90% 的服务器运行 Linux,从你每天用的微信到 Google 搜索,背后都是 Linux 在支撑。作为开发者,掌握 Linux 基础不是可选项,而是必修课。
:::
**这篇文章会带你学什么?**
学完这章后,你将获得:
- **文件系统**:理解 Linux 目录结构和"一切皆文件"的哲学
- **常用命令**:掌握文件操作、文本处理、进程管理等核心命令
- **权限模型**:理解用户、组、权限的概念
- **Shell 基础**:了解管道、重定向、环境变量等 Shell 核心概念
- **实战技能**:学会日志查看、进程排查、网络诊断等运维基本功
| 章节 | 内容 | 核心概念 |
|-----|------|---------|
| **第 1 章** | 文件系统 | 目录结构、一切皆文件 |
| **第 2 章** | 常用命令 | 文件、文本、进程、网络 |
| **第 3 章** | 权限模型 | 用户、组、rwx、sudo |
| **第 4 章** | Shell 基础 | 管道、重定向、变量、脚本 |
| **第 5 章** | 实战场景 | 日志排查、性能诊断 |
---
## 1. 文件系统:一切皆文件
Linux 最核心的哲学之一就是**一切皆文件**。普通文件是文件,目录是文件,硬盘是文件,甚至网络连接、进程信息都是文件。这个统一的抽象让你可以用同一套工具(读、写、权限控制)操作几乎所有系统资源。
<LinuxFileSystemDemo />
### 目录结构速记
把 Linux 文件系统想象成一棵倒过来的树:
```
/ ← 根目录(树根)
├── home/ ← 用户的家(你的文件都在这)
├── etc/ ← 配置文件(系统的"设置面板")
├── var/ ← 变化的数据(日志、缓存)
├── usr/ ← 用户安装的程序
├── tmp/ ← 临时文件(重启就没了)
├── proc/ ← 进程信息(虚拟的,不占磁盘)
├── dev/ ← 设备文件(硬盘、终端)
├── bin/ ← 基础命令(ls、cp、mv)
├── sbin/ ← 系统管理命令(需要 root)
├── opt/ ← 第三方软件
└── root/ ← root 用户的家目录
```
### 路径的两种写法
| 类型 | 格式 | 示例 | 说明 |
|------|------|------|------|
| 绝对路径 | 从 `/` 开始 | `/home/alice/code/app.js` | 从根目录出发,不会歧义 |
| 相对路径 | 从当前目录开始 | `./code/app.js``../config` | `.` 是当前目录,`..` 是上级目录 |
::: tip "一切皆文件"的威力
想知道 CPU 信息?读文件:`cat /proc/cpuinfo`
想知道内存使用?读文件:`cat /proc/meminfo`
想产生随机数?读文件:`cat /dev/urandom`
想丢弃输出?写文件:`echo "no thanks" > /dev/null`
不需要专门的 API,读写文件就够了。这就是 Unix 哲学的优雅之处。
:::
---
## 2. 常用命令
Linux 命令遵循一个统一的格式:`命令 [选项] [参数]`。比如 `ls -la /home` 中,`ls` 是命令,`-la` 是选项,`/home` 是参数。
<LinuxCommandDemo />
### 最常用的 10 个命令
如果只能记住 10 个命令,记这些:
| 命令 | 用途 | 记忆技巧 |
|------|------|----------|
| `ls` | 列出文件 | list |
| `cd` | 切换目录 | change directory |
| `cat` | 查看文件 | concatenate |
| `grep` | 搜索文本 | global regular expression print |
| `find` | 查找文件 | 就是 find |
| `ps` | 查看进程 | process status |
| `tail -f` | 实时看日志 | 看文件"尾巴"-f 是 follow |
| `chmod` | 改权限 | change mode |
| `curl` | 发 HTTP 请求 | client URL |
| `ssh` | 远程登录 | secure shell |
### 命令组合的艺术
Linux 的强大不在于单个命令,而在于**命令组合**。通过管道 `|` 把多个简单命令串起来,解决复杂问题:
```bash
# 找出占用 CPU 最多的 5 个进程
ps aux --sort=-%cpu | head -6
# 统计日志中出现最多的错误类型
grep "ERROR" app.log | awk '{print $4}' | sort | uniq -c | sort -rn | head -10
# 查找大于 100MB 的文件
find / -size +100M -type f 2>/dev/null
# 实时监控日志中的错误
tail -f /var/log/app.log | grep --color "ERROR"
```
::: tip Unix 哲学
"做一件事,做好它。" 每个命令只负责一个功能,通过管道组合实现复杂操作。这就是为什么 Linux 命令都很短小——它们是积木,不是瑞士军刀。
:::
---
## 3. 权限模型
Linux 是多用户系统,权限模型是安全的基石。每个文件都有三组权限,分别控制**所有者(Owner)**、**所属组(Group**、**其他人(Others**能做什么。
### 读懂 `ls -l` 的输出
```bash
$ ls -l app.js
-rwxr-xr-- 1 alice developers 2048 Jan 15 10:30 app.js
│├──┤├──┤├──┤ │ │ │
│ │ │ │ │ │ └── 文件大小
│ │ │ │ │ └── 所属组
│ │ │ │ └── 所有者
│ │ │ └── 其他人权限:r-- (只读)
│ │ └── 组权限:r-x (读+执行)
│ └── 所有者权限:rwx (读+写+执行)
└── 文件类型:- 普通文件,d 目录,l 链接
```
### 权限的三种操作
| 权限 | 字母 | 数字 | 对文件的含义 | 对目录的含义 |
|------|------|------|-------------|-------------|
| 读 | `r` | 4 | 查看文件内容 | 列出目录内容(ls) |
| 写 | `w` | 2 | 修改文件内容 | 创建/删除目录中的文件 |
| 执行 | `x` | 1 | 运行程序/脚本 | 进入目录(cd) |
<LinuxPermissionsDemo />
### 数字权限速算
三个数字分别代表 Owner、Group、Others 的权限,每个数字是 r(4) + w(2) + x(1) 的和:
```
chmod 755 script.sh
7 = rwx (4+2+1) → 所有者:读+写+执行
5 = r-x (4+0+1) → 组:读+执行
5 = r-x (4+0+1) → 其他人:读+执行
```
| 常见权限 | 含义 | 典型用途 |
|---------|------|---------|
| `644` | rw-r--r-- | 普通文件(所有者可写,其他人只读) |
| `755` | rwxr-xr-x | 可执行文件/目录 |
| `600` | rw------- | 私密文件(如 SSH 密钥) |
| `777` | rwxrwxrwx | 所有人可读写执行(危险,避免使用) |
### sudo:临时获取超级权限
普通用户权限有限,有些操作需要 root 权限。`sudo` 让你临时以 root 身份执行命令:
```bash
# 普通用户无法修改系统配置
$ vim /etc/nginx/nginx.conf
# Permission denied
# 用 sudo 临时提权
$ sudo vim /etc/nginx/nginx.conf
# 输入你的密码后可以编辑
# 切换到 root 用户(谨慎使用)
$ sudo su -
```
::: warning 最小权限原则
永远不要用 `chmod 777` 解决权限问题,这等于把门锁拆了。正确做法是搞清楚谁需要什么权限,精确授予。同样,不要长期以 root 身份操作,只在必要时用 `sudo`
:::
---
## 4. Shell 基础
Shell 是你和 Linux 内核之间的"翻译官"。你输入命令,Shell 解释并交给内核执行。最常用的 Shell 是 **Bash**(大多数 Linux 发行版默认)和 **Zsh**macOS 默认)。
### 管道与重定向
这是 Shell 最强大的两个特性:
| 符号 | 名称 | 作用 | 示例 |
|------|------|------|------|
| `|` | 管道 | 把前一个命令的输出作为后一个的输入 | `cat log | grep ERROR` |
| `>` | 输出重定向 | 把输出写入文件(覆盖) | `echo "hello" > file.txt` |
| `>>` | 追加重定向 | 把输出追加到文件末尾 | `echo "world" >> file.txt` |
| `<` | 输入重定向 | 从文件读取输入 | `wc -l < file.txt` |
| `2>` | 错误重定向 | 把错误信息写入文件 | `cmd 2> error.log` |
| `2>&1` | 合并输出 | 把错误和正常输出合并 | `cmd > all.log 2>&1` |
### 环境变量
环境变量是 Shell 中的"全局配置",影响命令的行为:
```bash
# 查看所有环境变量
env
# 查看某个变量
echo $PATH
echo $HOME
# 临时设置(只在当前 Shell 有效)
export API_KEY="abc123"
# 永久设置(写入配置文件)
echo 'export API_KEY="abc123"' >> ~/.bashrc
source ~/.bashrc # 让配置立即生效
```
| 常见变量 | 含义 | 示例值 |
|---------|------|--------|
| `$PATH` | 命令搜索路径 | `/usr/local/bin:/usr/bin:/bin` |
| `$HOME` | 用户主目录 | `/home/alice` |
| `$USER` | 当前用户名 | `alice` |
| `$PWD` | 当前工作目录 | `/var/log` |
| `$SHELL` | 当前使用的 Shell | `/bin/bash` |
### Shell 脚本入门
把多个命令写进一个文件,就是 Shell 脚本。它是自动化运维的起点:
```bash
#!/bin/bash
# deploy.sh - 简单的部署脚本
APP_DIR="/opt/myapp"
LOG_FILE="/var/log/deploy.log"
echo "$(date) - 开始部署..." >> $LOG_FILE
# 拉取最新代码
cd $APP_DIR && git pull origin main
# 安装依赖
npm install --production
# 重启服务
pm2 restart myapp
echo "$(date) - 部署完成" >> $LOG_FILE
```
```bash
# 给脚本执行权限并运行
chmod +x deploy.sh
./deploy.sh
```
::: tip 脚本调试技巧
在脚本开头加 `set -ex``-e` 让脚本遇到错误立即退出(而不是继续执行),`-x` 会打印每条执行的命令(方便排查问题)。这两个选项在生产脚本中几乎是标配。
:::
---
## 5. 实战场景
理论学完了,来看几个开发中最常遇到的实战场景。
### 5.1 日志排查
服务出问题,第一反应就是看日志。以下是日志排查的常用套路:
```bash
# 1. 实时跟踪日志(最常用)
tail -f /var/log/app/error.log
# 2. 搜索特定时间段的错误
grep "2024-01-15 14:" error.log | grep "ERROR"
# 3. 统计每小时的错误数量
grep "ERROR" app.log | awk '{print substr($1,1,13)}' | uniq -c
# 4. 查看最近 100 行日志
tail -100 app.log
# 5. 在多个日志文件中搜索
grep -r "OutOfMemory" /var/log/app/
```
### 5.2 进程排查
应用卡死、CPU 飙高、内存泄漏——这些问题都需要从进程入手:
```bash
# 查看 CPU 占用最高的进程
ps aux --sort=-%cpu | head -10
# 查看内存占用最高的进程
ps aux --sort=-%mem | head -10
# 查找特定进程
ps aux | grep "node"
# 查看进程的详细信息(包括线程)
top -Hp <PID>
# 查看进程打开的文件
lsof -p <PID>
# 优雅终止进程(SIGTERM
kill <PID>
# 强制终止(SIGKILL,最后手段)
kill -9 <PID>
```
### 5.3 网络诊断
服务连不上?先搞清楚是网络问题还是应用问题:
```bash
# 测试目标是否可达
ping -c 4 google.com
# 检查端口是否开放
telnet db-server 3306
# 或者用 nc
nc -zv db-server 3306
# 查看本机监听的端口
ss -tlnp
# 或
netstat -tlnp
# DNS 解析检查
dig api.example.com
nslookup api.example.com
# 测试 HTTP 接口
curl -v http://localhost:3000/health
# 查看网络连接状态统计
ss -s
```
### 5.4 磁盘空间排查
磁盘满了是线上最常见的故障之一:
```bash
# 查看各分区使用情况
df -h
# 找出占用空间最大的目录
du -sh /* 2>/dev/null | sort -rh | head -10
# 进一步定位大目录
du -sh /var/log/* | sort -rh | head -10
# 查找大文件(>100MB
find / -type f -size +100M 2>/dev/null | head -20
# 清理常见的空间占用
# 清理旧日志
sudo journalctl --vacuum-size=500M
# 清理 Docker 无用镜像
docker system prune -a
```
::: tip 线上排查口诀
**"一看日志,二看进程,三看网络,四看磁盘"**。90% 的线上问题都能通过这四步定位到原因。养成习惯后,排查效率会大幅提升。
:::
---
## 总结
Linux 是开发者的必备技能,掌握基础就能应对大部分日常开发和运维场景。
回顾本章的关键要点:
1. **一切皆文件**:Linux 用文件抽象统一了对硬件、进程、网络等资源的访问方式
2. **命令组合**:单个命令功能简单,通过管道 `|` 组合才能发挥真正威力
3. **权限模型**Owner/Group/Others × Read/Write/Execute,用数字(如 755)快速设置
4. **Shell 基础**:管道、重定向、环境变量、脚本是自动化的基石
5. **实战排查**:日志 → 进程 → 网络 → 磁盘,四步定位大部分线上问题
## 延伸阅读
- [Linux 命令大全](https://man7.org/linux/man-pages/) - Linux man pages 官方文档
- [The Linux Command Line](https://linuxcommand.org/tlcl.php) - 免费的 Linux 命令行入门书
- [Linux Journey](https://linuxjourney.com/) - 交互式 Linux 学习网站
- [explainshell.com](https://explainshell.com/) - 输入命令自动解释每个参数的含义
@@ -1,3 +1,315 @@
# 神经网络与深度学习
> 待实现
::: tip 前言
**神经网络是 AI 革命的引擎。** 从 ChatGPT 的语言理解到自动驾驶的图像识别,背后都是神经网络在工作。它不是魔法,而是一套精巧的数学框架——通过大量数据"学习"出输入到输出的映射关系。理解它的基本原理,能帮你更好地使用和调试 AI 工具。
:::
**这篇文章会带你学什么?**
学完这章后,你将获得:
- **核心概念**:理解神经元、层、前向传播、反向传播的基本原理
- **网络类型**:了解 CNN、RNN、Transformer 等主流架构的特点和适用场景
- **训练过程**:明白模型是如何从数据中"学习"的
- **关键技巧**:掌握过拟合、学习率、正则化等实用概念
- **发展脉络**:了解从感知机到大语言模型的演进历程
| 章节 | 内容 | 核心概念 |
|-----|------|---------|
| **第 1 章** | 从神经元到网络 | 感知机、激活函数、前向传播 |
| **第 2 章** | 网络如何学习 | 损失函数、梯度下降、反向传播 |
| **第 3 章** | 主流网络架构 | CNN、RNN、Transformer |
| **第 4 章** | 训练的艺术 | 过拟合、正则化、超参数调优 |
| **第 5 章** | 发展历程与前沿 | 从感知机到 GPT |
---
## 1. 从神经元到网络
### 单个神经元
神经网络的最小单元是**神经元**(Neuron)。它模拟了生物神经元的工作方式:接收多个输入信号,加权求和,通过激活函数产生输出。
```
输入 x1 ──→ ×w1 ──┐
输入 x2 ──→ ×w2 ──┼──→ Σ(加权求和) + b(偏置) ──→ f(激活函数) ──→ 输出
输入 x3 ──→ ×w3 ──┘
```
数学表达:**y = f(w₁x₁ + w₂x₂ + w₃x₃ + b)**
<NeuronDemo />
### 激活函数:为什么需要非线性?
如果没有激活函数,无论多少层神经元叠加,最终都等价于一个线性变换(矩阵乘法)。激活函数引入**非线性**,让网络能学习复杂的模式。
| 激活函数 | 公式 | 特点 | 常用场景 |
|---------|------|------|---------|
| ReLU | max(0, x) | 简单高效,训练快 | 隐藏层的默认选择 |
| Sigmoid | 1/(1+e⁻ˣ) | 输出 0~1 | 二分类输出层 |
| Tanh | (eˣ-e⁻ˣ)/(eˣ+e⁻ˣ) | 输出 -1~1 | RNN 中常用 |
| Softmax | eˣᵢ/Σeˣⱼ | 输出概率分布 | 多分类输出层 |
### 从神经元到网络
把多个神经元组织成**层**,多个层串联起来,就构成了神经网络:
```
输入层 隐藏层1 隐藏层2 输出层
(特征) (提取低级特征) (提取高级特征) (预测结果)
x1 ──→ [○ ○ ○ ○] ──→ [○ ○ ○] ──→ [○ ○]
x2 ──→ [○ ○ ○ ○] ──→ [○ ○ ○] ──→ 猫/狗
x3 ──→ [○ ○ ○ ○] ──→ [○ ○ ○]
```
| 概念 | 说明 |
|------|------|
| 输入层 | 接收原始数据(图片像素、文本向量等) |
| 隐藏层 | 中间处理层,层数越多网络越"深"(深度学习的"深" |
| 输出层 | 产生最终预测(分类概率、回归值等) |
| 前向传播 | 数据从输入层逐层流向输出层的过程 |
::: tip 为什么叫"深度"学习?
传统机器学习通常只有 1-2 层。当隐藏层数量增加到几十甚至上百层时,就叫"深度"学习。更深的网络能学习更抽象的特征:第一层学边缘,第二层学纹理,第三层学部件,更深的层学到"这是一只猫"。
:::
---
## 2. 网络如何学习
神经网络的"学习"本质上是一个**优化问题**:找到一组权重(w)和偏置(b),使得网络的预测尽可能接近真实答案。
### 训练三步曲
```
1. 前向传播:输入数据,得到预测结果
2. 计算损失:用损失函数衡量预测与真实值的差距
3. 反向传播:根据损失,计算每个权重的梯度,更新权重
重复以上步骤,直到损失足够小
```
### 损失函数:衡量"错得有多离谱"
损失函数(Loss Function)量化了预测值和真实值之间的差距。训练的目标就是最小化损失。
| 损失函数 | 公式简述 | 适用场景 |
|---------|---------|---------|
| MSE(均方误差) | 预测值与真实值差的平方的均值 | 回归问题 |
| Cross-Entropy(交叉熵) | -Σ y·log(ŷ) | 分类问题 |
| Binary Cross-Entropy | 交叉熵的二分类版本 | 二分类问题 |
### 梯度下降:找到最低点
想象你站在一座山上,蒙着眼睛要走到最低点。你能做的就是**摸一下脚下的坡度,然后往下坡方向走一步**。这就是梯度下降。
```
损失值
│ ╱╲
│ ╱ ╲ ← 当前位置
│ ╱ ╲ ↙ 沿梯度方向下降
│ ╱ ╲╱ ← 局部最小值
│╱ ╲╱ ← 全局最小值
└──────────────→ 权重值
```
| 概念 | 说明 |
|------|------|
| 梯度 | 损失函数对每个权重的偏导数,指示"往哪个方向调整能减少损失" |
| 学习率 | 每一步走多远。太大会跳过最低点,太小会收敛太慢 |
| 批量大小 | 每次用多少样本计算梯度。全量太慢,单样本太抖,小批量(mini-batch)是折中 |
### 反向传播:链式法则的胜利
反向传播(Backpropagation)是计算梯度的高效算法。它利用微积分的**链式法则**,从输出层开始,逐层向后计算每个权重对损失的贡献。
```
前向传播:输入 → 隐藏层1 → 隐藏层2 → 输出 → 损失
反向传播:损失 → 输出 → 隐藏层2 → 隐藏层1 → 更新所有权重
```
::: tip 直觉理解反向传播
把神经网络想象成一条流水线。产品(预测)出了问题(损失大),你需要从最后一道工序开始往回查,看每道工序(每层权重)对最终问题贡献了多少,然后按贡献大小调整。贡献大的多调,贡献小的少调。
:::
---
## 3. 主流网络架构
不同类型的数据需要不同的网络架构。选对架构,事半功倍。
<NetworkLayersDemo />
### 3.1 CNN(卷积神经网络)
CNN 是处理图像的王者。核心思想:用小的卷积核在图像上滑动,提取局部特征。
```
输入图像 → [卷积层→激活→池化] × N → 全连接层 → 输出
28×28 提取边缘/纹理/形状 分类结果
```
| 特点 | 说明 |
|------|------|
| 局部连接 | 每个神经元只看一小块区域,而非整张图 |
| 参数共享 | 同一个卷积核在整张图上复用,大幅减少参数 |
| 平移不变性 | 猫在图片左边还是右边,都能识别 |
| 层级特征 | 浅层学边缘,深层学语义 |
代表模型:LeNet、AlexNet、VGG、ResNet、EfficientNet
### 3.2 RNN(循环神经网络)
RNN 专为**序列数据**设计。它的隐藏状态会传递到下一个时间步,让网络具有"记忆"能力。
```
时间步 t1 时间步 t2 时间步 t3
"我" ──→ "喜欢" ──→ "猫"
↓ ↓ ↓
[h1] ──→ [h2] ──→ [h3] ──→ 输出
↑ ↑ ↑
隐藏状态在时间步之间传递(记忆)
```
| 变体 | 解决的问题 | 核心机制 |
|------|-----------|---------|
| 原始 RNN | 基础序列建模 | 简单循环连接 |
| LSTM | 长序列梯度消失 | 遗忘门、输入门、输出门 |
| GRU | LSTM 参数太多 | 简化为重置门和更新门 |
| 双向 RNN | 只能看到过去 | 同时从前往后和从后往前处理 |
::: tip LSTM 的门控机制
LSTM 的精妙之处在于三个"门":**遗忘门**决定丢弃哪些旧记忆,**输入门**决定存入哪些新信息,**输出门**决定输出哪些内容。就像你读一本书,会选择性地记住重要情节、忘掉无关细节。
:::
### 3.3 Transformer:注意力就是一切
2017 年 Google 发表的 "Attention Is All You Need" 论文提出了 Transformer,彻底改变了 AI 领域。它用**自注意力机制**替代了循环结构,是 GPT、BERT、Claude 等大模型的基础。
```
输入序列 → 嵌入 + 位置编码 → [多头注意力 → 前馈网络] × N → 输出
每个词都能"看到"所有其他词
```
| 优势 | 说明 |
|------|------|
| 并行计算 | 不像 RNN 必须逐步处理,Transformer 可以并行处理整个序列 |
| 长距离依赖 | 任意两个位置之间直接建立联系,不受距离限制 |
| 可扩展性 | 模型越大、数据越多,效果越好(Scaling Law |
**自注意力的直觉**:读"小猫坐在垫子上,因为**它**很累"这句话时,"它"需要关注"小猫"才能理解含义。自注意力让模型学会这种关联——为序列中的每对词计算一个"相关性分数"。
<NetworkArchitectureDemo />
## 4. 训练的艺术
有了好的架构还不够,训练过程中有很多"坑"需要避开。
### 4.1 过拟合 vs 欠拟合
| 问题 | 表现 | 原因 | 解决方案 |
|------|------|------|---------|
| 过拟合 | 训练集表现好,测试集表现差 | 模型太复杂,"背答案"而非学规律 | 正则化、Dropout、数据增强、早停 |
| 欠拟合 | 训练集和测试集都表现差 | 模型太简单,学不到规律 | 增加模型容量、训练更久、更好的特征 |
```
误差
│ ╲ 训练误差 测试误差 ╱
│ ╲ ╱
│ ╲─────────────────╱
│ 欠拟合 ← 最佳点 → 过拟合
└──────────────────────────→ 模型复杂度
```
### 4.2 关键超参数
超参数是训练前需要人为设定的参数(不是模型自己学的):
| 超参数 | 作用 | 常见范围 | 调优建议 |
|--------|------|---------|---------|
| 学习率 | 每步更新的幅度 | 1e-5 ~ 1e-1 | 最重要的超参数,通常从 1e-3 开始 |
| 批量大小 | 每次训练用多少样本 | 16 ~ 512 | 越大训练越稳定,但需要更多显存 |
| 训练轮数(Epoch) | 遍历整个数据集的次数 | 10 ~ 100+ | 配合早停法,验证集不再提升就停 |
| 优化器 | 梯度更新策略 | Adam、SGD | Adam 是默认选择,SGD+动量适合精调 |
### 4.3 正则化技巧
防止过拟合的常用手段:
| 技巧 | 原理 | 使用方式 |
|------|------|---------|
| Dropout | 训练时随机关闭部分神经元 | 通常 p=0.1~0.5 |
| 权重衰减 | 在损失函数中加入权重大小的惩罚 | L2 正则化,λ=1e-4 |
| 数据增强 | 对训练数据做随机变换(翻转、裁剪、旋转) | 图像任务必备 |
| 早停法 | 验证集损失不再下降时停止训练 | patience=5~10 |
| Batch Normalization | 标准化每层的输入分布 | 加速收敛,有轻微正则化效果 |
::: tip 训练的经验法则
1. 先用小数据集跑通整个流程,确认代码没 bug
2. 从已有的预训练模型开始微调,而非从零训练
3. 学习率是最值得花时间调的超参数
4. 如果训练损失不下降,先检查数据和代码,再怀疑模型
:::
---
## 5. 发展历程与前沿
神经网络的发展经历了几次"寒冬"和"复兴",每次突破都源于关键的技术创新。
| 年代 | 里程碑 | 关键突破 |
|------|--------|---------|
| 1958 | 感知机(Perceptron) | 第一个神经网络模型,只能处理线性问题 |
| 1986 | 反向传播算法 | 让多层网络的训练成为可能 |
| 1998 | LeNetCNN) | 卷积网络在手写数字识别上大获成功 |
| 2012 | AlexNet | 深度 CNN 在 ImageNet 上碾压传统方法,深度学习爆发 |
| 2014 | GAN(生成对抗网络) | 两个网络对抗训练,能生成逼真图像 |
| 2017 | Transformer | "Attention Is All You Need",注意力机制取代 RNN |
| 2018 | BERT | 预训练+微调范式,NLP 全面突破 |
| 2020 | GPT-3 | 1750 亿参数,展示了大模型的涌现能力 |
| 2022 | ChatGPT | RLHF 对齐技术,AI 进入大众视野 |
| 2023+ | 多模态大模型 | GPT-4V、Claude 等,同时理解文本和图像 |
### 当前趋势
| 方向 | 说明 |
|------|------|
| 大模型(LLM) | 参数量从亿级到万亿级,涌现出推理、编程等能力 |
| 多模态 | 同一个模型处理文本、图像、音频、视频 |
| 高效微调 | LoRA、QLoRA 等技术让普通开发者也能微调大模型 |
| AI Agent | 让大模型使用工具、规划任务、自主完成复杂目标 |
| 小模型蒸馏 | 用大模型的知识训练小模型,在端侧部署 |
::: tip 对开发者的启示
你不需要从零训练神经网络。现代 AI 开发更多是**调用 API**(如 OpenAI、Claude API)或**微调预训练模型**(如用 Hugging Face)。但理解底层原理能帮你更好地选择模型、设计 prompt、诊断问题。
:::
---
## 总结
| 核心概念 | 一句话总结 |
|---------|-----------|
| 神经元 | 加权求和 + 激活函数,网络的最小计算单元 |
| 前向传播 | 数据从输入层逐层流向输出层,产生预测 |
| 反向传播 | 从损失出发,逐层计算梯度,更新权重 |
| CNN | 卷积核提取局部特征,图像处理的首选 |
| RNN/LSTM | 循环连接保持记忆,处理序列数据 |
| Transformer | 自注意力并行处理,大模型的基础架构 |
| 过拟合 | 模型"背答案",用正则化、Dropout 等手段防止 |
| 迁移学习 | 站在巨人肩膀上,用预训练模型微调解决新问题 |
---
## 延伸阅读
- [3Blue1Brown - 神经网络系列视频](https://www.3blue1brown.com/topics/neural-networks) — 最直观的可视化讲解
- [Stanford CS231n](http://cs231n.stanford.edu/) — 经典的卷积神经网络课程
- [The Illustrated Transformer](https://jalammar.github.io/illustrated-transformer/) — 图解 Transformer 架构
- [Neural Networks and Deep Learning](http://neuralnetworksanddeeplearning.com/) — 免费在线教材
- [Hugging Face 课程](https://huggingface.co/learn) — 动手实践 Transformer 和大模型
+8
View File
@@ -2,6 +2,14 @@
本附录涵盖从计算机基础到工程素养的完整知识体系,是你学习旅程中的重要参考库。
## 📍 附录知识地图
点击下方的分类卡片,查看每个分类的完整学习路径:
<AppendixFlowMap />
---
## 内容分类
### 一、计算机是怎么回事