Skip to content

中大型互联网企业:全量架构蓝图

这份文档要解决一个问题:一个转行的人,怎么知道"真实互联网公司的那套东西"到底长什么样。

你在网上搜到的架构图,往往只有一张"用户 → Nginx → 应用 → 数据库"的简笔画; 你在公司里接触到的,往往只是自己负责的那一小块。两头都看不到全貌。

本文按一线互联网公司(日活百万到千万级)的真实形态,把一整套架构从外到内、 从业务线到支撑线全部铺开:四大环境、混合云、CDN/WAF、四层七层负载、K8s 与 PaaS、 数据库一主两从与分库分表、缓存链路、消息队列、全链路监控、日志收集、 配置中心、灰度发布、容灾与安全。

读法建议:第 0~2 章先建立"公司里有哪些系统、它们各自干什么"的地图; 第 3~8 章逐层往下钻,每一层都讲清"它解决什么问题、高可用怎么做的、常见坑在哪"; 第 9~11 章讲支撑线(监控/日志/发布)和演进路线。 全文出现的服务器数量、配置档位都给了三档对照表,你可以按自己手头的机器资源选一档照着落地。

先记住一句话

中大型架构的所有复杂度,几乎都来自两个词:高可用(坏了不能停)和可扩展(涨了要能扛)。 你看到任何一个"多出来"的组件,只要问一句"它是在解决高可用还是可扩展",答案通常立刻就有了。


目录导航

章节内容你会得到什么
第 0 章全局地图:一家公司到底有多少套系统先看清森林,再进树林
第 1 章四大环境:dev / test / uat / prod为什么要有四套,怎么隔离
第 2 章服务器规划三档对照表20 台 / 60 台 / 120 台怎么分配
第 3 章混合云与网络分区自建机房 + 公有云怎么连起来
第 4 章流量入口全链路DNS → CDN → WAF → ELB/SLB → 网关
第 5 章应用层:K8s 与 PaaS 平台容器编排、服务网格、发布平台
第 6 章数据层:数据库、缓存、搜索一主两从、分库分表、缓存链路
第 7 章中间件全家桶MQ、配置中心、注册中心、分布式事务
第 8 章存储与文件对象存储、NAS、备份
第 9 章三条支撑线:监控 / 日志 / 发布业务线、监控线、收集线齐备
第 10 章安全、容灾与应急高可用做到什么程度算合格
第 11 章演进路线:小公司怎么长成这个样子别一步到位,按阶段长
第 12 章附录:术语速查与自检清单随时回来查

第 0 章 全局地图:一家公司到底有多少套系统

在进入细节之前,先建立一张鸟瞰图。一家成熟互联网公司的技术资产,可以分成 5 个平面(Plane)。

流量平面DNS/CDN → LB → 网关用户请求打进来的路径业务平面K8s 中的微服务 Pod真正跑业务代码的地方数据平面MySQL/Redis/MQ/ES有状态、最难扩、最怕丢支撑平面GitLab/Jenkins/Harbor开发交付与制品管理观测平面指标/链路/日志出问题时你的眼睛交付线代码提交CI 构建制品入库CD 同步灰度发布前三条线承载真实业务流量;后两条线不承载请求,但没有它们就跑不起来、出了问题也看不见交付线横跨支撑平面与业务平面:把代码变成 Pod 的那条流水线
图 0-1 五大平面 + 一条交付线:一张图理解公司里所有系统的分工

为什么要有这张图? 因为转行的人最容易犯的错,是把"公司技术栈"理解成"一堆软件的列表"。 实际上它们是有层级的:你在第 ② 层改一个配置,可能要在第 ④ 层(配置中心)操作, 观察结果要在第 ⑤ 层(监控)看,出问题回滚要用 ★ 层(发布系统)。 搞清楚"我现在动的这个东西在哪一层、会影响哪一层",是运维最基本的素养。

五个平面里,哪个最容易被新人忽略?

第 ⑤ 观测平面,以及第 ④ 支撑平面。 新人通常能理解"应用要跑在服务器上",但很难意识到: 一个 500 万日活的产品,观测系统的服务器数量往往和业务服务器数量是同一个量级。 日志、指标、链路三类数据每天能产生几十 TB。这不是"辅助功能",而是产线的一部分。

0.1 真实业务线长什么样

技术架构不是凭空来的,它是被业务逼出来的。以一家典型的电商 + 内容社区公司为例:

业务线典型系统技术特征对架构的硬要求
交易商品、购物车、订单、支付、退款强一致、事务、幂等数据库不能丢数据,链路可对账
营销优惠券、秒杀、拼团、积分瞬时高并发、可降级秒杀必须独立集群,不能拖垮主站
内容帖子、视频、评论、Feed 流读多写少、海量存储缓存命中率、CDN 成本、推荐算力
用户登录、注册、实名、账号全局强依赖挂了全站登不上,必须最高可用等级
消息站内信、Push、IM长连接、海量并发长连接网关、消息不丢不乱序
数据报表、BI、风控、推荐特征离线 + 实时计算数仓、实时链路、不影响在线库
基础工单、审批、运营后台内部使用、低并发与生产隔离,避免误操作

一个非常典型的认知误区

新人常以为"公司就一个网站"。 实际上一个电商 App 打开首页,可能同时调用了 20~50 个后端服务: 用户信息、商品详情、库存、价格、推荐、广告、优惠券、风控、统计…… 这也是为什么必须有"服务治理"——服务数量一多,人工管理连接关系就彻底不可行了。


第 1 章 四大环境:dev / test / uat / prod

1.1 为什么必须要四套环境

一句话:因为你不能在"正在为几百万用户服务"的机器上,试自己刚写的代码。

但光有"生产"和"测试"两套,也不够。真实公司要拆四套,是因为不同阶段要验证的东西完全不同

环境全称谁在用主要验证什么数据对外
devDevelopment 开发环境开发自己代码能不能跑通、单元能不能过造的数据(随便改)
testTest / SIT 测试环境测试工程师功能对不对、接口通不通造的测试数据
uatUser Acceptance Test 验收环境产品、业务方、客户像用户一样用一遍,业务逻辑对不对接近生产的数据(脱敏)部分(预发布域名)
prodProduction 生产环境真实用户——(它就是最终效果)真实数据

一个记忆方法

  • dev = 「我写的代码能不能跑」→ 关心编译和启动
  • test = 「这个功能符不符合需求文档」→ 关心功能正确性
  • uat = 「业务方/客户愿不愿意收货」→ 关心业务正确性和体验
  • prod = 「用户在用」→ 关心稳定、性能、数据安全

每往上一层,对"配置的真实度"和"数据的真实度"要求都更高,但"操作的随意度"都更低。 dev 上你可以随手 kubectl delete,prod 上连登录都要走跳板机和审批。

1.2 环境隔离,到底要隔离哪些东西

这是新人最容易想当然的地方:以为"换个数据库地址就叫隔离了"。真实的隔离至少有 7 个维度:

隔离维度devtestuatprod
网络独立 VPC/VLAN独立子网独立子网独立 VPC + 最小权限
K8s 集群共用小集群 或 独立独立集群独立集群(配置贴近 prod)独立集群(多可用区)
数据库单实例、随便重置单实例主从(备库可读)一主两从 + 高可用切换
Redis单实例单实例主从Cluster 集群 / 主从+哨兵
中间件共用一套共用一套独立 Nacos/RocketMQ独立全量高可用集群
域名dev-xxx.公司域名test-xxx.公司域名uat-xxx.公司域名xxx.公司域名
权限开发可自管测试可部署受限最小权限 + 双人复核 + 全程审计
配置硬编码可接受集中管理集中管理配置中心,动态生效,可回滚

关于「数据」的红线

任何环境都不允许把生产数据直接拷到非生产环境。 真实公司要做的是"脱敏":手机号 138****8888、身份证、银行卡、地址全部替换, 库名表结构保持一致,但数据是假的。 原因:生产数据泄露 = 数据安全事件 = 罚款 + 刑责(中国《个人信息保护法》)。 这条线是绝对不能碰的,不是"建议"。

1.3 环境的成本现实:并不是四套都是 1:1

如果四个环境完全 1:1 复制生产,成本会变成 4 倍,没有公司能承受。 真实做法是按需缩容

环境相对生产的规格常见做法
dev5%~10%所有微服务挤在一个小集群,副本数全为 1
test10%~20%副本数 1~2,数据库单实例
uat30%~50%副本数接近生产,但机器规格降一档
prod100%全量高可用,多可用区

但这会导致一个经典问题:uat 压测通过,生产还是炸。 原因是 uat 的机器数、连接数、数据量都和 prod 不同。 所以成熟公司会额外建压测环境(perf/stress),或者在生产做全链路压测(用影子库 + 染色流量, 在不影响真实用户的前提下压测生产集群)。这也是为什么你会在招聘 JD 里看到"全链路压测"这个词。


第 2 章 服务器规划:三档对照表

下面给出的 IP 规划使用 192.168.0.0/24(内网私网段,你可以按自己的环境改)。 注意:这里只列"主要角色服务器",真实环境一台物理机/云主机上会跑多个容器或虚拟机。

2.1 三档规模总览

档位服务器总数适用场景所在环境
精简版约 20 台自建学习环境、创业公司 MVPdev/test 合一、uat/prod 分离
标准版约 60 台日活几十万,中厂标准形态四环境齐全,高可用基本到位
完整版120 台以上日活百万到千万,大厂形态多可用区、混合云、异地容灾

怎么选

  • 你如果只有 3~5 台机器:先照"精简版",并且把 dev/test/uat 三环境合一,只保留 prod 独立。
  • 有 10~20 台:可以直接从精简版完整落地,这是最推荐的学习路径。
  • 标准版和完整版不要一步到位,它们是"演进目标",看懂即可(第 11 章给演进路径)。

2.2 精简版(约 20 台)详细规划

这是最推荐你实际落地的一档。目标:把架构的"形状"完整走通。

编号主机名IP配置角色主要软件
1ops-runner192.168.0.102C4G运维跳板 / 堡垒机Jumpserver 或 sshd + 审计
2gitlab192.168.0.114C8G代码仓库GitLab CE(或 Gitea,见备注)
3jenkins-ci192.168.0.124C8GCI 服务器(dev/test/uat 共用Jenkins + Maven + Node + Docker
4jenkins-prod192.168.0.134C8GCI 服务器(prod 专用Jenkins(独立,权限收紧)
5harbor192.168.0.144C8G镜像仓库Harbor(自带 PostgreSQL + Redis)
6nexus192.168.0.152C4G制品仓库Nexus 3(Maven/npm 私服)
7k8s-master-1192.168.0.214C8GK8s 控制平面kube-apiserver / etcd
8k8s-master-2192.168.0.224C8GK8s 控制平面同上(两master 即最低可用配置
9k8s-master-3192.168.0.234C8GK8s 控制平面同上(3 台才满足 etcd 多数派)
10k8s-node-1192.168.0.248C16G工作节点kubelet / containerd
11k8s-node-2192.168.0.258C16G工作节点同上
12k8s-node-3192.168.0.268C16G工作节点同上(3 节点才谈得上高可用
13mysql-master192.168.0.318C32G数据库主库MySQL 8.0 + 半同步
14mysql-slave-1192.168.0.328C32G数据库从库 1MySQL 8.0(同步复制)
15redis-1192.168.0.414C16G缓存Redis 7(主)+ Sentinel
16redis-2192.168.0.424C16G缓存Redis 7(从)+ Sentinel
17nacos-1192.168.0.514C8G注册/配置中心Nacos 集群节点 1
18nacos-2192.168.0.524C8G注册/配置中心Nacos 集群节点 2
19mq-1192.168.0.614C16G消息队列RocketMQ NameServer + Broker
20monitor192.168.0.718C32G监控 / 日志Prometheus + Grafana + ELK

精简版的取舍(很重要,要明确知道自己省掉了什么)

省掉的组件后果什么时候必须补上
独立的 test/uat 环境测试会污染开发环境,uat 与 prod 配置有差异团队超过 5 人
第二个 Redis 集群Redis 挂了缓存全失效,数据库可能被压垮上线前
Elasticsearch 独立集群日志和监控抢资源;日志查询慢日志量 > 100GB/天
SkyWalking APM出了问题只能靠猜,排查靠 grep 日志微服务数量 > 10
CDN / WAF静态资源全走源站,带宽贵且没有攻击防护有真实用户访问
异地容灾机房整体故障 = 服务全停有 SLA 承诺(≥99.9%)
分库分表单表数据量涨到几千万后查询变慢单表 > 2000 万行

2.3 标准版(约 60 台)详细规划

标准版的关键变化:四环境分离、每环境独立一套、所有核心组件至少双节点

分组数量配置说明
公共基础(跨环境)64C8G ~ 8C16G跳板机、GitLab(主备)、Jenkins 主节点、Harbor(双节点)、Nexus、VPN
dev 环境64C8GK8s 单 master + 2 node(或复用)、MySQL 单实例、Redis 单实例、Nacos 单机
test 环境84C8GK8s 单 master + 2 node、MySQL 主从、Redis 主从、Nacos 双节点
uat 环境108C16GK8s 3 master + 3 node、MySQL 一主一从、Redis 主从+哨兵、Nacos 三节点
prod 应用集群1216C32GK8s 3 master + 9 node(跨 3 可用区)
prod 数据集群916C64GMySQL 一主两从(3)+ Redis Cluster(3)+ MQ(3)
prod 中间件68C16GNacos 三节点 + ES 三节点
prod 网关/入口58C16GNginx/LB 双节点 + API 网关双节点 + 跳板
观测平台88C32G ~ 16C32GPrometheus 双实例、Grafana、SkyWalking OAP×2、ES 日志集群×3、Kibana

合计约 60 台(含虚拟机),全部覆盖高可用最低要求。

2.4 完整版(120 台以上)的关键增量

完整版不是"标准版乘以 2",而是增加了几个维度的能力

增量能力具体做法服务器增量
同城双活同城两个机房都能承接全量流量,任一机房故障用户无感+30 台
异地多活 / 异地容灾异地机房数据同步,主机房灾难时切换(RTO 分钟级)+40 台
单元化(Set 化)按用户 ID 分片,每个单元自成闭环,跨单元调用极少架构级改造
存储与计算分离数据库上云 RDS、缓存上云、对象存储上云自建机器减少,云成本上升
大数据平台Hadoop/Spark/Flink 集群、数据仓库、实时计算+30 台
AI / 推荐平台GPU 服务器、模型服务、特征平台+10 台(GPU 机器昂贵)
安全体系WAF 集群、堡垒机集群、日志审计、态势感知+8 台

一个反直觉的事实

到了完整版这个体量,"服务器数量"这个说法本身就开始失效了。 因为大量算力跑在云上(弹性伸缩的 Pod、Serverless 函数、云数据库), 机器数是动态的。这时运维的核心指标从"机器数"变成了 "成本(单位请求成本)、可用性(SLA 达成率)、变更效率(一天能发多少次版)"


第 3 章 混合云与网络分区

3.1 什么是混合云,为什么大公司都是混合云

混合云 = 自建机房(IDC)+ 公有云(阿里云/腾讯云/AWS)同时使用。

为什么不全用云,或全自建?因为两者各有不可替代的优势:

维度自建 IDC公有云
单位算力成本长期看便宜(3 年以上折旧完更便宜)短期便宜,长期贵
弹性能力差(买机器要几周)极强(分钟级扩容)
运维负担自己负责硬件、电力、网络云厂商负责,你只管道内的
数据合规数据在自己手里需评估合规要求
突发流量扛不住(大促只能提前备机器)完美(弹性伸缩 + 按量付费)
故障域单机房故障影响大多可用区天然隔离

真实公司的典型组合("稳态 + 敏态")

自建 IDC(稳态业务)流量平稳可预测 · 自建成本低 · 数据敏感核心交易数据库核心业务微服务大数据集群长驻中间件公有云(敏态业务)流量波动大 · 需要秒级弹性 · 试错成本低CDN / WAF弹性 Web 层秒杀 / 大促集群开发测试环境专线 / VPN / 云企业网稳态业务放自建(成本可控、数据不出门);敏态业务放公有云(弹性、按量付费)这正是「混合云」的核心:不是全都上云,也不是全都自建,而是按业务特性分层放置
图 3-1 混合云的本质:稳态放自建,敏态放公有云,中间用专线打通

混合云最核心的三个技术问题

  1. 网络怎么通:专线(成本高、延迟低、稳定)vs VPN(便宜、走公网、抖动大)vs 云企业网。 真实场景:核心链路走专线,非核心走 VPN,专线还要做主备双线。
  2. 数据怎么同步:跨云同步要走公网或专线,延迟通常在 1~20ms, 所以跨云的主从复制通常只能做异步,也就意味着有数据丢失窗口。
  3. 服务怎么发现:跨云的服务注册要特别小心,注册中心(Nacos)不能跨云乱注册, 否则一个云上的服务挂了,另一个云上的调用方会一直超时重试。 做法:按可用区/云划分子集群,注册中心做区域隔离

3.2 网络分区规划(真实公司的做法)

真实公司的网络是分层 + 分区的。一个标准的三层网络模型:

公网区Internet Zone· CDN 回源 · WAF· 四层 LB 的 VIP· 堡垒机 SSH 入口能不放就不放,每多一个公网 IP 就多一个攻击面DMZ 区接入区(半公半私)· 反向代理 · 负载均衡· API 网关· 不能直连数据库可以被公网访问,也能访问内网应用应用区App Zone· K8s 集群 · 微服务实例· 消息消费进程· 只能被 DMZ 访问业务代码运行的地方,能访问数据区数据区Data Zone· MySQL / Redis· MQ / ES· 只允许应用区访问最后一道防线:不出网、不给公网 IP从上到下:信任级别递增、访问方向单向(外可进内,内不出外)
图 3-2 网络安全分区:四层分区,越往下越重要、越不该被直接暴露

VPC / 子网划分示例(标准版)

分区网段说明
公网/ LB192.168.0.0/26负载均衡 VIP
DMZ192.168.0.64/26网关、反向代理
应用区192.168.1.0/24K8s Pod 网段
数据区192.168.2.0/24MySQL / Redis / MQ
管理区192.168.0.128/25Jenkins / 监控 / 跳板
K8s Service10.96.0.0/12集群 ClusterIP 段
K8s Pod10.244.0.0/16Calico/Flannel 分配的 Pod IP

三个真实踩过的坑

  1. Pod 网段和办公网段撞了:同事在办公室访问集群里的服务,发现路由到了自己电脑。 原因:Pod 用了 192.168.0.0/16,和公司办公网完全重叠。规划时一定要先问清全公司网段。
  2. K8s Service 网段和 VPC 撞了10.96.0.0/12 和云上 VPC 的 10.0.0.0/8 有重叠, 导致部分 Pod 无法访问云上数据库。规划时必须避开 10.0.0.0/8 里已用的部分。
  3. 节点数超过 110 个后 Pod IP 不够:默认 Pod CIDR 是 /24(每节点 254 个 IP), 一个节点跑 200 个 Pod 就会失败。规划时给每个节点留 /23 或更大。

3.3 混合云的真实落地形态(三层部署结构)

真实公司的混合云不是"机房 + 云"这么笼统,而是按业务特性分三层部署

第一层:公有云(弹性层 / 接入层)CDN · WAF · DDoS 高防四层/七层 LB · API 网关 · BFF弹性 Web 集群(K8s + HPA)秒杀/大促临时集群(用完即销毁)离用户近 · 弹性强 · 按量付费 · 可随时抛弃第二层:自建机房 A(核心层)核心业务微服务(交易/订单/支付)核心数据库(一主两从)· Redis 集群中间件(Nacos / MQ / ES)内部管理后台 · 大数据集群数据不出门 · 性能可控 · 成本稳定第三层:自建机房 B(灾备层)数据库只读副本 · 延迟复制实例中间件冷备 · 镜像仓库副本核心业务最小可用集定时演练(每季度真实切一次)平时不承载流量 · 灾难时接管 · 定期演练保证可用三层之间靠专线互联;越靠上的层越「轻」,越靠下的层越「重」
图 3-3 混合云的三层落地结构:弹性层 / 核心层 / 灾备层

三层结构的核心思想

"把最需要弹性的放云上,把最需要掌控的放机房,把最需要安全的放远端。"

这三个诉求天然冲突,所以必须分层:

  • 弹性 → 云(分钟级扩 100 台)
  • 掌控与成本 → 自建(长期成本低、网络拓扑自己说了算)
  • 安全与合规 → 异地(物理隔离,灾难时还有一份)

转行者最需要建立的认知:混合云不是"落后"或"过渡"状态, 它是互联网公司的长期稳态选择。全云和全自建都有无法解决的短板, 所以头部公司(阿里、腾讯、字节、美团)都是混合云。

3.4 云上资源清单(你会在控制台看到的东西)

新人第一次登录云控制台会懵:几百个云产品。实际常用的就这些

类别云产品自建对应用途
计算ECS/CVM(云主机)、ACK/TKE(托管 K8s)物理机、kubeadm跑服务
网络VPC、子网、安全组、NAT 网关VLAN、iptables网络隔离
CLB/ELB/SLB(负载均衡)LVS/Nginx流量分发
EIP(弹性公网 IP)公网 IP对外访问
专线 / VPN 网关 / 云企业网光纤 / IPsec混合云互联
存储云盘(ESSD/SSD)、NAS、OSS/COSSAS/SAN、NFS、MinIO数据存储
数据库RDS、Redis、MongoDB、PolarDB自建 MySQL/Redis托管数据库
中间件云 MQ、云 ES、微服务引擎 MSE自建 RocketMQ/ES/Nacos托管中间件
安全WAF、DDoS 高防、云防火墙、堡垒机、KMS自建安全防护
观测云监控、SLS(日志服务)、ARMS(APM)Prometheus/ELK/SkyWalking观测
运维OOS(运维编排)、云助手、资源编排 ROSAnsible/Terraform自动化
CDNCDN / 全站加速 DCDN自建(成本极高,基本不做)加速

该自建还是用云产品?(决策表)

场景建议理由
数据库用云 RDS(除非有专门 DBA 团队)高可用、备份、监控都是开箱即用,自建容易出事
Redis用云 Redis同上
K8s自建(大规模)/ 用托管(小规模)自建可控,托管省心
对象存储一定用云自建成本远超收益
CDN一定用云自建无法实现
Nacos/MQ自建云托管版本贵,且公司需要定制
监控告警自建 Prometheus与业务深度耦合,云产品不够灵活

第 4 章 流量入口全链路

这是整份文档最实用的一章。一个用户点击 App,请求经过了多少层? 把它彻底搞清楚,你就能理解为什么需要这么多组件。

4.1 一次请求的完整旅程

① 客户端DNS 解析域名递归查询 → 拿到 VIP / CDN 地址② CDN / WAF静态资源就近返回动态请求穿透,携带真实客户端 IP③ 四层 LBELB / SLB 按连接转发不看 HTTP 内容,只做 TCP 层散列④ Nginx / Ingress七层路由 + TLS 卸载按域名/路径分发到不同 Service⑤ API 网关鉴权 / 限流 / 路由统一入口,挡住非法与超额流量⑥ 业务 Pod真正的业务逻辑调用下游、访问缓存与数据库⑦ 数据层读写最终落地MySQL 主库写、从库读每一跳都是一次「可以失败的点」排查问题的顺序就是从外到内逐跳验证· 4xx 多是七层的问题(网关/Ingress)· 5xx 要看业务日志和链路追踪· 连不上多半是 DNS / LB / 端口 / 安全组· 慢:先在四层看连接数,再到七层看耗时· 每跳都要有用例:curl -v 从最外层往里打
图 4-1 一次请求的七跳旅程:理解它,你就有了排查问题的坐标系

为什么要这么多层?每层删掉会怎样?

删掉后果
DNS 智能解析所有用户都解析到同一个 IP,跨网延迟巨大,单点故障
CDN静态资源全走源站,带宽费用翻 10 倍,海外用户加载 10 秒
WAF直接被刷、被拖库、被 CC 打挂
四层 LB没有入口级负载均衡,Nginx 单机成为瓶颈且是单点
七层 LB无法按域名分流(一台机器上跑多个网站),无法做 TLS 卸载
API 网关鉴权/限流代码写进每个微服务,重复且无法统一治理

关键认知:每层的存在都是为了让上一层"不用管这件事"。 这叫关注点分离(Separation of Concerns), 是整个 IT 架构里最重要的设计思想,没有之一。

4.2 四层负载 vs 七层负载(面试必问,工作必用)

维度四层(L4)七层(L7)
工作在哪层TCP/UDP 传输层HTTP/HTTPS 应用层
代表软件LVS、F5、云 ELB/SLB、HAProxy(mode tcp)Nginx、HAProxy(mode http)、Envoy、Ingress
看得到什么只看 IP 和端口能看到 URL、Header、Cookie、Body
性能极高(十万~百万级 QPS)中等(万级 QPS)
能否按 URL 路由❌ 不能✅ 能
能否改请求内容✅(改 Header、重写 URL)
能否卸载 TLS❌(只透传)
典型用途入口第一层、数据库负载(如 MySQL 代理)业务路由、灰度、限流

真实公司的搭配方式(记住这个组合)

公网 VIP(L4)→ Nginx 集群(L7)→ 业务服务

L4 在前面扛量 + 做 HA,L7 在后面做精细路由。这是 90% 公司的标准答案。

一个常见误解

"我们用了 K8s,是不是就不需要 Nginx 了?" 不是。K8s 的 Ingress 本质就是一个 Nginx/Envoy 控制器, 它只是把 Nginx 的配置从"手写 nginx.conf"变成了"声明式 YAML + 自动重载"。 底层还是七层负载的原理,一点没变。

4.3 CDN:不只是"加速静态资源"

新人常以为 CDN 就是"缓存图片"。真实场景里 CDN 承担了更多职责:

能力说明
静态资源缓存图片/CSS/JS/视频,命中直接返回,回源率通常 < 10%
动态加速通过最优路径回源(走 CDN 厂商的专线骨干网),降低跨地域延迟
边缘计算在边缘节点跑 JS/WASM,做 A/B 测试、鉴权、改写(如 Cloudflare Workers)
视频分发HLS/DASH 切片分发,直播使用 RTMP/WebRTC 推流
下载分发大文件、App 安装包分发(节流、断点续传)
DDoS 缓解海量边缘节点天然分散攻击流量
证书托管HTTPS 证书在 CDN 侧统一管理

CDN 的成本核心是"回源率"。回源率从 10% 降到 5%,带宽成本直接减半。 所以运维要关注的核心指标是:缓存命中率、回源带宽、5xx 率

缓存刷新与预热(生产事故高发区)

  • 刷新(Purge):把 CDN 上的旧文件删掉,下次请求回源拉新的。 发版后前端文件更新但 CDN 还有缓存 → 用户看到旧页面,就是这个原因。
  • 预热(Prefetch):发版前主动把新文件推到 CDN 边缘,避免第一批用户回源慢。
  • 正确做法:前端构建时给文件名加 hash(app.a3f9c2.js), 这样发版后文件名变了,URL 也变了,天然绕过缓存问题,不需要手动刷新。 这就是所谓的**"前端资源指纹"**,是前端工程化的基本要求。

4.4 负载均衡算法:不只是轮询

算法原理适用
轮询 Round Robin依次分发后端性能均匀
加权轮询按权重分配机器配置不同
最少连接给当前连接数最少的节点请求耗时差异大
IP Hash同 IP 固定到同一后端需要会话保持
一致性哈希节点增减时影响最小的 key分布式缓存路由
最短响应时间给响应最快的节点混合部署、性能不均
P2C(Power of Two Choices)随机选两个,挑好的现代服务网格首选

会话保持是个坑

"用户登录后,下一次请求打到了另一台机器,又要求重新登录"——这就是会话问题。 三种解法,优劣分明:

方案做法优点缺点
会话粘滞(Sticky Session)按 Cookie/IP 固定到同一后端改造成本低后端挂掉会话丢失;负载不均
会话复制各节点间互相同步 session无状态节点多了同步开销爆炸
集中存储(推荐)session 存 Redis,所有节点共享无状态、可任意扩缩容多一次 Redis 调用

现代做法一定是第三种。 这就是"应用要无状态(Stateless)"的含义—— 只有无状态,K8s 才能自由地在任何时候把 Pod 杀掉重建、扩容缩容。


第 5 章 应用层:K8s 与 PaaS

5.0 先看一张完整的生产环境全景图

前面四章讲了入口和网络,这一章开始讲"后端真正跑在哪儿"。 先建立一张 prod 环境的完整部署全景(下面这张图把后面第 5~9 章的内容都包含了, 现在看不懂没关系,读完再来回看):

用户App / Web / 小程序DNS 智能解析+ CDN 边缘 + WAF 防护① 边缘接入层就近接入 · 抗 DDoS · 静态资源卸载动态请求回源到四层负载回源四层负载均衡(云 ELB / SLB 双活)VIP + Keepalived / 云原生挂载 · 按连接散列可用区 ANginx / Ingress ×2七层路由 · 灰度分流 · TLS 卸载K8s 节点 ×3(业务命名空间)用户服务 ×3订单服务 ×3商品服务 ×3网 关 ×3可用区 BNginx / Ingress ×2七层路由 · 灰度分流 · TLS 卸载K8s 节点 ×3(业务命名空间)用户服务 ×3订单服务 ×3商品服务 ×3网 关 ×3两个可用区完全对等,任一侧故障由 LB 摘除② 数据层(跨可用区部署,全部主从/集群)MySQL 一主两从主(AZ-A) ──半同步──▶ 从1(AZ-A) · 从2(AZ-B)Redis Cluster3 主 3 从 · 分片 16384 槽 · 跨 AZ 分布RocketMQNameServer ×2 · Broker 主从 ×2 组 · 同步双写Elasticsearch3 节点集群 · 1 主 2 数据 · 跨 AZ · 副本 ≥1Nacos3 节点 Raft · 独立 MySQL 一主一从③ 支撑平面(管理区 · 不对外)GitLab 主备 · Harbor 主备 · NexusJenkins ×4(dev/test/uat/prod 各一套)Argo CD 双副本 · 跳板机双机④ 观测平面Prometheus ×2 · Grafana · AlertmanagerSkyWalking OAP ×2 · Agent 随 Pod 注入Filebeat → Kafka → Logstash ×2 → ES → Kibana
图 5-0 生产环境全景:从用户到数据层,四条平面各司其职

看这张图的正确方式

先只看从用户到数据库的竖线(业务线),那是主线。 然后看两侧的支撑平面和观测平面,它们不是"附加功能",而是产线的一部分。 最后注意每层都是多个方框——这就是"高可用"在图纸上的样子: 任何一个方框消失,服务都还能跑

5.1 从"部署在虚拟机上"到"部署在 K8s 上"

虚拟机时代的问题:一台机器上改了一个环境变量,另一台忘了改,行为不一致; 扩容要在几分钟到几十分钟;一台机器上跑多个应用会互相抢资源。

容器时代解决:把应用和它的运行环境打包成镜像,处处一致;秒级启动。

K8s 时代解决:容器多了以后,谁来调度、谁来重启、谁来负载、谁来滚动升级? K8s 就是"容器的操作系统"。

概念通俗解释运维关心什么
Pod最小调度单位,一个或多个容器的集合重启次数、OOMKilled、就绪探针
Deployment声明"我要 3 个副本、用哪个镜像"副本数、滚动更新状态
StatefulSet有状态应用(如数据库),Pod 有稳定名字和存储启动顺序、PVC 绑定
DaemonSet每个节点都跑一份(如日志采集器)是否所有节点都覆盖到
Service一组 Pod 的固定访问入口 + 负载均衡ClusterIP/NodePort/LB
Ingress七层入口,按域名/路径路由到 Service证书、路由规则
ConfigMap / Secret配置和密码,与镜像解耦改配置不用重新构建镜像
HPA按 CPU/QPS 自动扩缩容阈值设置、扩容上限
PVC / StorageClass持久化存储声明存储类是否可用、容量
Namespace逻辑隔离(按环境/团队/项目)资源配额、网络策略

三个最常被问到的 K8s 问题

  1. 滚动更新怎么保证不中断? K8s 会先起新 Pod,等它就绪(readinessProbe 通过)后,再把旧 Pod 摘掉。 关键配置:maxSurge(可以多起几个)和 maxUnavailable(可以少几个)。 如果 readinessProbe 没配,K8s 会认为 Pod 一起来就可用,结果流量打进来时应用还没初始化完 → 502。
  2. Pod 一直 CrashLoopBackOff 怎么办?kubectl describe pod 看事件 → kubectl logs --previous 看上一次崩溃的日志。 常见原因:配置缺失、连不上数据库、内存不够被 OOMKill、启动命令写错。
  3. liveness 和 readiness 有什么区别? readiness = "我能接流量了吗"(失败则从 Service 端点摘除,不重启); liveness = "我还活着吗"(失败则重启容器)。 混用这两个是新手最常犯的致命错误——把 liveness 配成依赖数据库, 结果数据库抖动一下,全部 Pod 一起被重启,引发雪崩。

5.2 什么是 PaaS 平台

PaaS = Platform as a Service(平台即服务)。 在公司内部语境里,它通常指的是内部研发效能平台 / 发布平台

转行的人容易以为"PaaS 就是阿里云/腾讯云",其实不是。公司内部的 PaaS 长这样:

内部 PaaS 平台(Web 界面 · 面向研发与运维)应用管理创建服务查看拓扑环境管理dev/test/uat/prod发布管理一键发布灰度 / 回滚资源管理配额申请在线扩容配置管理配置中心入口版本 diff监控看板指标 / 告警健康状态日志查询实时 tail按 traceId 查权限审批工单流审批记录底层对接:K8s API · Jenkins API · Argo CD API · Nacos API · 各云厂商 OpenAPIPaaS 平台的价值:把「运维靠命令行、靠记忆、靠人」变成「研发自助、流程内建、过程可审计」它不替代 K8s/Jenkins/Argo CD,而是这些工具的「统一门面」—— 让不懂底层的人也能安全地操作成熟度标志:研发不需要找运维要权限,也能按规范完成一次合规发布
图 5-2 PaaS 平台:八大能力,把底层工具包装成研发能自助使用的门面

PaaS 的价值在于"屏蔽复杂度": 开发同学不需要会写 K8s YAML,点几下就能把服务部署到测试环境; 反过来,运维通过 PaaS 统一收口,所有变更都走平台,天然有审计、有规范、有回滚

PaaS 与运维的关系(很多人搞反了)

新人担心"有了 PaaS 是不是就不需要运维了"。 恰恰相反:PaaS 把重复的、无脑的操作自动化了, 运维的精力被释放去做架构设计、稳定性治理、成本优化、故障处理这些真正难的事。 PaaS 是运维能力的放大器,不是替代品。 而且 PaaS 平台本身就需要运维来维护(它就是一套运行在 K8s 上的微服务)。

5.4 K8s 生产集群的完整组件清单

一个"能上生产"的 K8s 集群,除了 K8s 自身,还要装一堆周边组件。 这张表建议收藏——它同时也是你运维 K8s 时的"责任范围清单"。

类别组件作用没有它会怎样
网络CNI(Calico / Cilium / Flannel)Pod 网络互通Pod 之间无法通信
CoreDNS集群内服务名解析服务间不能用域名调用
Ingress Controller(Nginx/Traefik)七层入口外部流量进不来
MetalLB / 云 LB Controller裸机环境提供 LoadBalancer 类型 Service无法用 LB 类型 Service
存储CSI 驱动(Ceph/NFS/云盘)动态供给 PV有状态应用无法存储
StorageClass定义存储"档位"PVC 无法自动绑定
可观测metrics-server提供 CPU/内存指标(HPA 依赖)HPA 无法工作
Prometheus + Grafana集群监控
Fluent Bit / Filebeat日志采集(DaemonSet)日志丢失
安全RBAC权限控制任何人能做任何事
NetworkPolicyPod 间网络隔离一个 Pod 被攻破可横向移动
Pod Security Standards禁止特权容器容器逃逸风险
OPA Gatekeeper / Kyverno策略引擎(禁止 latest 镜像等)规范无法落地
Trivy / Clair镜像漏洞扫描带着 CVE 上线
发布Argo CD / FluxGitOps 部署手工 kubectl apply
Argo Rollouts金丝雀/蓝绿只能滚动更新
Helm / Kustomize模板化与多环境差异化YAML 复制粘贴
运维Velero集群级备份与恢复集群灾难无法恢复
Cluster Autoscaler节点自动伸缩资源不够要人工加机器
Descheduler重新平衡 Pod 分布资源碎片化
KubeVirt / KubeSphere虚拟化管理/运维平台运维界面简陋

生产 K8s 的 6 条硬性规范(真实公司一定会查)

  1. 必须配 request 和 limit。只配 limit 不配 request 会导致调度不准; 都不配则一个 Pod 可能吃光节点,引发连锁驱逐(节点雪崩的常见原因)。
  2. 必须配探针。readiness 决定流量,liveness 决定重启。 没有它,滚动更新会"假成功",流量打到还没准备好的 Pod。
  3. 必须禁用 :latest 标签。latest 不可复现,回滚时不知道回到哪个版本。 强制用 image@sha256:... 或明确的语义化版本。
  4. 必须配反亲和性。同一服务的 3 个副本要打散到 3 个节点, 否则一个节点挂掉 = 服务全挂("看起来 3 副本,实际是单点")。
  5. 必须配 PDB(PodDisruptionBudget)。保证节点维护驱逐 Pod 时, 服务至少有 N 个副本可用。
  6. 必须配 ResourceQuota / LimitRange。防止某个团队把集群资源吃干。

5.5 一个生产级 Deployment 应该长什么样

下面这份 YAML 是生产规范的最小集合,每一项都标注了"为什么"。 你可以把它当作模板,检查自己的服务有没有漏。

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
  namespace: prod
spec:
  replicas: 3                    # 多副本 = 高可用的前提
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1                # 最多多起 1 个 Pod
      maxUnavailable: 0          # ★ 关键:保证升级期间可用副本不减少
  selector:
    matchLabels: { app: order-service }
  template:
    metadata:
      labels: { app: order-service }
    spec:
      affinity:
        podAntiAffinity:
          # ★ 强制把 3 个副本打散到不同节点,避免"共死"
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchLabels: { app: order-service }
              topologyKey: kubernetes.io/hostname
      containers:
        - name: app
          image: harbor.internal/prod/order-service:1.4.2   # ★ 明确版本,禁用 latest
          ports: [{ containerPort: 8080 }]
          resources:
            requests: { cpu: "500m", memory: "1Gi" }   # ★ request 影响调度
            limits:   { cpu: "2000m", memory: "2Gi" }  # ★ limit 防止吃光节点
          readinessProbe:                # ★ 决定"能否接流量"
            httpGet: { path: /actuator/health/readiness, port: 8080 }
            initialDelaySeconds: 30      # 给应用启动留时间
            periodSeconds: 5
            failureThreshold: 3
          livenessProbe:                 # ★ 决定"是否重启"
            httpGet: { path: /actuator/health/liveness, port: 8080 }
            initialDelaySeconds: 60
            periodSeconds: 10
          env:
            - name: NACOS_ADDR
              value: "nacos-1:8848,nacos-2:8848,nacos-3:8848"
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef: { name: order-db-secret, key: password }  # ★ 密码用 Secret
          lifecycle:
            preStop:
              exec:
                # ★ 优雅停机:先从注册中心摘除,等待长连接排空,再退出
                command: ["sh", "-c", "curl -X POST localhost:8080/actuator/offline; sleep 15"]
      terminationGracePeriodSeconds: 45   # 要大于 preStop 的 sleep 时间
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata: { name: order-service-pdb, namespace: prod }
spec:
  minAvailable: 2                       # ★ 节点维护时至少保留 2 个副本
  selector:
    matchLabels: { app: order-service }

三个最致命的配置错误

错误后果原因
maxUnavailable: 1 且副本数 = 1升级期间服务完全中断唯一副本被删掉了
livenessProbe 检查数据库连通性数据库抖动 → 全部 Pod 被重启 → 雪崩探针不该依赖外部系统
terminationGracePeriodSeconds 小于 preStop sleepPod 被强杀,长连接被切断用户看到"连接中断"

5.6 服务网格(Service Mesh)

微服务多了以后,每个服务都要处理:超时、重试、熔断、限流、链路追踪、mTLS 加密。 如果每个语言各写一套 SDK,升级一次要改几十个仓库,这是灾难。

Service Mesh 的思路:把这些能力从业务代码里"抽出来",放到一个 Sidecar 代理(如 Envoy)里。 业务代码完全无感,所有流量自动经过代理。

方案形态代表优缺点
SDK 模式能力在代码里(jar 包)Spring Cloud Alibaba、Dubbo性能好,但绑定语言,升级难
Sidecar 模式每个 Pod 加一个代理容器Istio、Linkerd语言无关,统一治理;但多一跳,复杂
Node 级代理每个节点一个代理Cilium Service Mesh性能好,但隔离性弱于 Sidecar

中小公司不要盲目上 Istio

Istio 功能强大,但引入的复杂度也很高(控制面组件多、排障链路变长、资源占用增加)。 真实建议:微服务数量 < 50 个、团队 < 20 人时, 用 Spring Cloud Alibaba(Nacos + Sentinel + Seata)+ 网关就够了。 Istio 更适合多语言、超大规模、有专门基础架构团队的公司。 技术选型的第一原则是:用你团队能维护得住的最简单方案。


第 6 章 数据层:数据库、缓存、搜索

数据层是整个架构里最不能出问题的一层。应用挂了可以重启,数据丢了就真没了。

6.1 MySQL 一主两从:到底是什么

"一主两从"= 1 个主库(Master)+ 2 个从库(Slave)。

写请求INSERT/UPDATE/DELETEMySQL 主库192.168.0.31 · 记录 binlog复制异步 / 半同步复制从库 1(读)192.168.0.32从库 2(读 + 备份)192.168.0.33读请求SELECT为什么这样设计写只走主库:避免多写冲突读走从库:分担查询压力从库可随时顶上做主库核心原则:写主读从。应用层的读写分离通常由 ShardingSphere / MyCat 中间件或框架自动完成
图 6-1 MySQL 一主两从:写请求走主库,读请求分摊到从库

为什么要两个从库,不能一个?

从库用途为什么需要独立
从库 1分担读流量大多数业务读:写 = 10:1 甚至 100:1,读库要能扩展
从库 2备份 + 高可用切换在从库上做备份(mysqldump/xtrabackup)不能影响读库性能;主库挂了,从库 2 升主,从库 1 改指向新主

这就是"一主两从"的完整理由一个承载读、一个承接备份与容灾。 如果只有一个从库,备份时读性能下降,主库挂了也没有冗余的切换候选。

复制模式:异步 / 半同步 / 全同步

模式主库什么时候返回成功数据安全性能使用场景
异步复制写完 binlog 立刻返回,不等从库⚠️ 主库宕机可能丢数据最快日志类、可容忍丢失
半同步(推荐)至少一个从库确认收到主库宕机不丢核心交易业务标配
全同步(组复制 MGR)所有从库确认最安全最慢金融级一致性

半同步的关键参数:rpl_semi_sync_master_wait_for_slave_count=1注意:半同步在从库响应超时后会自动降级为异步rpl_semi_sync_master_timeout,默认 10s), 所以部署时要监控这个降级事件,它意味着"此刻数据有丢失风险"。

6.2 主从延迟:一个真实存在的、无法消除的问题

主库写完立刻查从库,可能查不到(因为复制有延迟)。这叫主从延迟,通常在毫秒级, 但在大事务、大批量写入、网络抖动时可能达到秒级甚至分钟级

三个真实场景,三个解法

场景现象解法
下单后立刻查订单刚下单跳到详情页,显示"订单不存在"写后读走主库(同一请求内强制走主),或前端延迟 1 秒再跳转
支付成功回调回调处理了,但状态查不到强制主库读 + 幂等重试
跨机房从库异地从库延迟几百毫秒异地从库只用于只读分析,不承载在线业务

千万别做的事

不要为了"解决主从延迟"而把所有读都打到主库——那会瞬间压垮主库。 正确顺序是:① 接受延迟(UI 上做处理)→ ② 精准地把"写后立刻读"的少数请求路由到主库 → ③ 用缓存兜住

6.3 分库分表:单表撑不住时的必然选择

单表数据量的经验红线(超过就该考虑拆了):

数据量现象
< 500 万行正常,索引好就没问题
500 万 ~ 2000 万查询开始变慢,DDL(改表结构)时间变长
2000 万 ~ 1 亿明显变慢,DDL 可能锁表几小时
> 1 亿必须拆分,否则维护窗口都无法安排

两种拆法

方式做法解决什么不解决什么
垂直拆分按业务拆:用户表、订单表、商品表放不同库单库压力、业务解耦单表数据量
水平拆分按规则拆:order_0000 ~ order_1023单表数据量、单库写入跨分片查询

水平拆分的分片键选择(这是最关键的决策)

分片键优点缺点
用户 ID同一用户的订单在同一分片(查询高效)运营按时间查全量订单要扫所有分片
订单 ID分布均匀用户查自己订单要扫所有分片
用户 ID + 时间(推荐)用户维度高效,冷热可分离需要两级路由,复杂

常用中间件:ShardingSphere(Apache,最主流)、MyCat(老牌)、 或在应用层用 sharding-jdbc 直接做(无代理,性能好,但每个服务要引依赖)。

分库分表的代价,新人一定要知道

  1. 跨分片 JOIN 变成不可能 → 只能改成多次查询在应用层拼,或者做冗余字段。
  2. 分布式事务:跨库写入要保证一致性 → 引入 Seata / 最终一致方案,复杂度陡增。
  3. 全局唯一 ID:自增 ID 不再唯一 → 改用雪花算法(Snowflake)、号段模式(Leaf)。
  4. 扩容困难:从 1024 分片扩到 2048 分片要数据迁移,代价巨大。 → 所以分片数要一次规划到位(如提前分 1024 片,未来几年够用)。
  5. 运维复杂度:DDL 要按分片批量执行、备份要合并、监控要看每个分片。 结论:分库分表是"最后手段",能靠索引优化、读写分离、缓存、归档解决的,绝不上分片。

6.4 缓存:架构里的"性能加速器"

缓存的本质是"用空间换时间",把慢的存储(磁盘数据库)的热数据放到快存储(内存)里。

多级缓存架构(真实公司的做法)

请求 → ① 本地缓存(Caffeine/Guava,进程内,纳秒级,容量小)
        │ 未命中

      ② 分布式缓存(Redis 集群,毫秒级,容量大)
        │ 未命中

      ③ 数据库(MySQL,几十毫秒,容量最大)
层级代表访问速度特点
本地缓存Caffeine、Guava Cache~100ns无网络开销;多实例间不一致
分布式缓存Redis、Tair、Memcached~1ms一致;有网络开销
近端缓存Redis + 客户端本地副本~10μs折中方案(阿里 Tair 的做法)

缓存三大经典问题(必背,工作中必遇)

问题现象原因解法
缓存穿透大量请求打不到缓存,全落到数据库查不存在的数据(缓存里也没有)① 缓存空值(短 TTL);② 布隆过滤器拦截;③ 参数校验
缓存击穿某个热 key 失效瞬间,大量请求涌入数据库热 key 过期① 互斥锁(只让一个线程去加载);② 热 key 永不过期 + 后台更新
缓存雪崩大量 key 同时失效,数据库瞬间被打垮同一时间批量过期① TTL 加随机值(打散);② 多级缓存;③ 熔断降级

还有第四、第五个(进阶)

  • 缓存与数据库一致性:推荐 Cache Aside + 延迟双删,或订阅 binlog(Canal)异步刷新。 绝对不要用"先更新数据库再更新缓存"——并发下必不一致。
  • 热 key / 大 key:单个 key 的 QPS 过高(如秒杀商品)要多副本打散; 单个 key 的 value 过大(如几 MB 的 List)会导致 Redis 阻塞,必须拆分。

Redis 高可用三种形态

形态原理优点缺点适用
主从 + 哨兵哨兵监控主库,故障时自动选一个从库升主部署简单,可用性够单机容量受限于内存,扩容需停机中小规模
Redis Cluster数据分 16384 个槽,分布到多个主节点容量和性能可水平扩展运维复杂,跨槽操作受限中大型标配
Codis / 云 Redis代理层分片客户端无感多一跳,代理可能成瓶颈云上场景

6.5 Elasticsearch:搜索与日志

为什么需要 ES? MySQL 的 LIKE '%关键词%' 无法走索引,几百万行就是全表扫描。 而搜索需要:分词、相关性排序、聚合统计、高亮——这些都不是关系型数据库擅长的。

能力MySQLElasticsearch
精确查询✅ 强✅ 可以
全文检索❌ 慢到不可用✅ 倒排索引,毫秒级
模糊/前缀搜索
聚合统计(类似 GROUP BY 但更灵活)一般✅ 强
相关性排序(匹配度打分)
事务✅ 强❌ 不支持
实时性实时准实时(默认 1 秒刷新)

ES 的两大用途

  1. 业务搜索:商品搜索、站内搜索(配合分词器 IK)。
  2. 日志检索:就是 ELK 里的那个 E(详见第 9 章)。

ES 高可用与两个常见坑

三节点起是 ES 的最低可用配置(集群选主需要多数派)。

  • 坑 1:脑裂(Split Brain)。旧版本在节点分区时会分裂成两个集群,都认为自己是主。 7.x 之后用 cluster.initial_master_nodes + 投票配置基本解决,但节点数要满足过半存活(3 节点最多挂 1 台)。
  • 坑 2:分片数不能改。索引的主分片数在创建时就固定了,事后无法修改。 所以创建索引前必须估算数据量和增长,一般规则:单分片 10~50GB。 分片太少 → 无法水平扩展;分片太多 → 元数据开销大,查询要合并几百个分片的结果,反而变慢。

6.6 数据层的容量规划(真实数字)

很多人问"到底多少数据算多"。下面这张表是基于真实生产经验的经验值,可以直接用来判断风险:

对象健康区间需要关注危险处理方式
MySQL 单表行数< 2000 万2000 万 ~ 5000 万> 5000 万归档 / 分表
MySQL 单库大小< 500 GB500 GB ~ 1 TB> 1 TB垂直拆分
MySQL QPS(单实例)< 50005000 ~ 1 万> 1 万加从库 / 分片
MySQL 连接数< 500500 ~ 1000> 1000连接池调优 / ProxySQL
Redis 单实例内存< 10 GB10 GB ~ 20 GB> 20 GBCluster 分片
Redis 单 key 大小< 10 KB10 KB ~ 100 KB> 1 MB拆分 key
Redis 单实例 QPS< 5 万5 万 ~ 8 万> 8 万主从读 / Cluster
ES 单分片大小10 ~ 50 GB50 ~ 100 GB> 100 GB重新规划分片
ES 集群分片数< 10001000 ~ 3000> 3000合并小分片 / 按天索引
Kafka 单分区吞吐< 10 MB/s10 ~ 50 MB/s> 50 MB/s加分区
Nginx 单机 QPS< 2 万2 万 ~ 5 万> 5 万加节点 / 上 L4

这张表的正确用法

它不是为了让你背数字,而是让你在评审时能提出正确的问题。 比如看到"orders 表已经 8000 万行了",你就知道要问: "做过归档吗?查询有没有走索引?要不要按时间分表?" 这比背下来"分表用 ShardingSphere"有用得多——知道什么时候需要,比知道用什么工具更重要。

6.7 数据库高可用的完整形态(含自动切换)

前面讲了"一主两从",但光有主从还不够:主库挂了,谁来把从库升成主? 应用怎么知道新主的 IP?这一节给出完整的生产方案。

方案对比(从简单到复杂)

方案原理切换耗时复杂度适用
MHAManager 监控主库,故障时提升从库 + 补数据差异 + VIP 漂移10~30 秒传统自建 MySQL
MGR(组复制)MySQL 官方多主/单主复制,Paxos 协议自动选主秒级MySQL 5.7.17+,金融级
Orchestrator + ProxySQL拓扑发现 + 代理层自动改路由秒级大规模 MySQL 集群
云 RDS 高可用版云厂商双节点 + 自动切换30 秒~1 分钟低(托管)推荐,省心
PXC / MGR 三节点强同步多主秒级对一致性要求极高

完整拓扑(MHA 方案,自建最常见)

MHA Manager部署在独立管理机(不与应用同机)MySQL 主库 (Master)AZ-A · 可写 · 承载全部写流量心跳探测从库 1 (Slave)AZ-A · 只读 · 半同步从库 2 (Slave)AZ-B · 只读 · 半同步binlog 复制binlog 复制VIP(虚拟 IP)应用只连 VIP,不写死 IP切换时 VIP 漂移切换流程① 主库宕机 → ② Manager 探测到心跳超时 → ③ 选一个数据最新的从库 → ④ 提升为新主 → ⑤ 其余从库重新指向新主 → ⑥ VIP 漂移整个过程通常 10~30 秒,应用层只需重试即可恢复(前提是:应用连的是 VIP,而不是写死的 IP)
图 6-7 MHA 自动主从切换:主库倒了,从库顶上,VIP 漂移,应用无感

切换过程中会发生什么(这是重点)

  1. MHA Manager 发现主库失联(默认连续 miss 3 次,约 9 秒)。
  2. 从从库中挑一个数据最新的作为候选主。
  3. 尝试从宕机主库拉取最后的 binlog(如果主库只是网络隔离而非彻底宕机,能补回差异数据,不丢数据)。
  4. 提升候选主,其余从库指向新主。
  5. VIP 漂移到新主(Keepalived 完成 ARP 广播)。
  6. 应用侧:连接池报错重连,通常 10~30 秒内恢复。

切换期间的三个真实问题

  1. 应用连接池不会立刻感知。老连接还连着旧 IP,会持续报错直到连接超时。 做法:连接池配置 connectionTestQuery + 合理超时(如 3 秒)+ 重试机制。
  2. 切换过程中"双写"风险。如果旧主库只是网络分区(脑裂),它恢复后会认为自己是主, 造成数据冲突。做法:开启 read_only + MHA 的 master_ip_failover 脚本强制降级
  3. 没做切换演练很多公司的自动切换从来没成功过,因为配置有细节问题。 做法:每季度在预发环境真实演练一次(用 kill -9 模拟主库宕机)。

6.8 Redis 高可用完整拓扑

方案 A:主从 + 哨兵(推荐学习用)Sentinel ×3奇数个才可投票Redis 主可读写Redis 从 1只读 · 全量副本Redis 从 2只读 · 全量副本监控数据全量存在每个节点 → 容量受单机限制故障切换由 Sentinel 投票决定,秒级完成方案 B:Redis Cluster(生产主流)主 1槽 0~从 1副本主 2槽 5461~从 2副本主 3槽 10922~从 3副本16384 个槽均分到 3 个主 → 容量可水平扩槽位固定,迁移期间有 MOVED 重定向怎么选数据量 < 单机内存、并发不高、团队小 → 方案 A(简单、好维护、出问题好查)数据量会持续增长、需要水平扩容、能承受运维复杂度 → 方案 B(生产环境的标准答案)共同点:都不该把 Redis 当唯一存储。重要的数据必须能重建(回源数据库),否则你就是在裸奔。三级缓存:越来越慢、越来越大、越来越远① 本地缓存Caffeine/Guava · 进程内 · 纳秒级 · 容量小② 分布式缓存Redis · 跨进程共享 · 微秒级 · 容量大③ 数据库MySQL · 持久化 · 毫秒级 · 最终真相
图 6-8 Redis 两种高可用方案 + 三级缓存的分工

哨兵方案的两个坑

  1. 应用必须通过哨兵查主地址,不能硬编码 IP。 Java 用 JedisSentinelPool,Spring Boot 配 spring.redis.sentinel.master/nodes硬编码 IP = 主库切换后你的应用还连在旧主库上(这个错很常见)。
  2. 哨兵自身也要 ≥3 个。只有 1 个哨兵 → 哨兵挂了就没法切换; 只有 2 个哨兵 → 网络分区时无法达成多数派判断。

第 7 章 中间件全家桶

"中间件"这个词很多人说不清。通俗定义:中间件 = 不直接实现业务、但业务离不开的通用基础软件。 它夹在操作系统和应用之间,为应用提供通用能力。

7.1 消息队列(MQ):异步、解耦、削峰

为什么需要 MQ? 举个最经典的例子——用户下单:

不用 MQ(同步调用):
  下单 → 扣库存 → 发优惠券 → 发短信 → 加积分 → 更新推荐 → 返回
         ↓        ↓         ↓        ↓         ↓
       每多一个下游,就多一次等待,任何一环慢/挂,下单就失败

用 MQ(异步解耦):
  下单 → 扣库存(同步,必须成功)→ 发消息到 MQ → 返回成功(快!)

                        优惠券/短信/积分/推荐 各自订阅,异步慢慢消费
能力说明通俗理解
异步主流程不等下游点餐后拿到号码牌就走,不用站在窗口等
解耦生产者和消费者互不认识餐厅换了厨师,顾客不用知道
削峰填谷瞬时流量先进队列,后端按能力消费水坝蓄洪
最终一致通过重试 + 幂等实现最终一致通知没送到就再送一次
广播一个消息多个消费者组都收到群发通知

主流选型(重要对比)

产品语言/生态特点适用
KafkaScala/Java吞吐极高(百万/秒)、持久化、可重放日志收集、大数据、流计算
RocketMQJava(阿里开源)事务消息、延迟消息、顺序消息、消息回溯国内电商交易场景首选
RabbitMQErlang协议丰富、路由灵活、社区成熟中小规模、复杂路由
PulsarJava存算分离、多租户、云原生新一代,学习成本高
云 MQ(阿里云/腾讯云)托管免运维不想自维护时

MQ 的四个必须处理的问题

  1. 消息丢失:生产者要确认(confirm)、Broker 要持久化(刷盘)、消费者要手动 ACK。 三处任何一处偷懒都会丢消息。
  2. 消息重复:网络重试必然导致重复投递。解法是消费端幂等—— 用业务唯一键(订单号)+ 去重表 / Redis SETNX 保证"同一消息只处理一次"。 记住:MQ 只能保证"至少一次"(at-least-once),"恰好一次"要靠业务自己实现。
  3. 消息积压:消费者挂了或变慢了,队列堆积几百万条。 应急处理:临时扩容消费者 → 先把积压消费掉 → 再排查根因(千万别直接清队列)。
  4. 顺序消息:同一笔订单的"创建/支付/发货"必须按顺序消费。 做法:按订单号 Hash 到同一队列,一个队列一个消费者串行消费。

7.2 注册中心与配置中心:Nacos 是本项目的核心

两个不同的职责,经常被同一个组件承担

职责解决什么问题不用它会怎样
服务注册(Service Registry)A 服务怎么找到 B 服务的地址地址要硬编码,B 扩容/迁移后 A 全部失效
配置中心(Config Center)配置怎么集中管理、动态生效改一个超时时间要重新打包发版

Nacos 同时提供这两种能力,是国内微服务生态(Spring Cloud Alibaba)的默认选择。

Nacos 集群(3 节点 · Raft 协议)注册中心能力· 服务实例注册· 健康检查(心跳 / 主动探测)· 服务发现(推 + 拉)配置中心能力· 配置的增删改查· 版本管理与灰度发布· 变更推送(长连接)持久化:MySQL(Nacos 自己的库,必须高可用!这是最容易被忽略的单点)注册拉配置接收推送服务 A随 Pod 启动即注册服务 B随 Pod 启动即注册服务 C随 Pod 启动即注册三个硬性要求(踩过坑的都懂)① 必须 3 节点起:Raft 需要过半,2 节点反而比 1 节点更差② Nacos 自己的 MySQL 必须高可用:库挂了 → 全站拿不到配置 → 起不来③ 必须开鉴权(nacos.core.auth.enabled=true):默认无鉴权是重大事故
图 7-2 Nacos 双能力:服务注册发现 + 配置管理,但它的 MySQL 是最隐蔽的单点

Nacos 部署的三个硬性要求

  1. 必须 3 节点起。Nacos 用 Raft 做一致性,2 节点反而比 1 节点更差 (无法过半,任何一台挂都影响可用性)。要么 1 台(开发环境),要么 3 台(生产)。
  2. Nacos 自己的数据库也必须高可用。Nacos 把配置存在 MySQL 里, 这个库挂了 → 所有服务拿不到配置 → 全站起不来。 这是最容易被忽略的单点,很多公司就栽在这里。
  3. 一定要配鉴权nacos.core.auth.enabled=true)。 默认没开鉴权,任何人能进控制台改配置、能注册假服务,是重大安全事故。

配置中心的真实价值(一个具体例子)

场景没有配置中心有配置中心
调大数据库连接池改代码 → 提交 → CI → 构建镜像 → 部署 → 重启,30 分钟控制台改一下 → 秒级推送 → 应用热生效
紧急关闭某功能发版(30 分钟,还可能有风险)改一个开关,秒级生效
不同环境不同配置打包时选 profile,容易打错包namespace + group 隔离,天然不会错
配置变更审计有版本、有 diff、可一键回滚

namespace / group / dataId 三件套(Nacos 的核心概念)

  • namespace:最外层隔离,通常用来隔离环境(dev/test/uat/prod 各一个 namespace)。
  • group:中层分组,通常按业务线或项目分。
  • dataId:具体的一份配置文件(如 ruoyi-gateway-prod.yml)。

定位一份配置 = namespace + group + dataId 三者共同确定。 最常犯的错误是把环境隔离做在 group 而不是 namespace 上—— 这样权限就没法按环境隔离,测试能改到生产的配置。必须用 namespace 隔离环境。

7.3 网关:微服务的统一入口

API 网关(Gateway) 是微服务外的"前台",所有外部请求都从它进。

网关职责说明
路由/api/user/** → 用户服务,/api/order/** → 订单服务
统一鉴权校验 JWT,通过后在 Header 里塞用户 ID 传给下游(下游不用再解 token)
限流按 IP / 用户 / 接口限流(令牌桶、漏桶、滑动窗口)
熔断降级下游服务失败率高时,快速失败,避免雪崩
灰度路由按 Header/用户标签把部分流量导到新版本
日志与链路统一记录入口日志,生成 traceId 贯穿全链路
协议转换外部 HTTP → 内部 Dubbo/gRPC

主流实现:Spring Cloud Gateway(Java 生态最常用)、KongAPISIX(国产,性能好)、Nginx + Lua

网关自身的两个致命问题

  1. 网关是全局单点。它挂了全站不可用 → 必须集群部署 + 前面挂 L4 LB
  2. 网关的降级策略必须明确。当下游服务大面积超时时, 网关要有"快速失败"能力(如 1 秒超时 + 熔断),而不是无限等待, 否则网关线程池被打满,整个网关跟着一起挂(这就是"雪崩"的典型路径)。

7.4 其他常见中间件速查

中间件一句话说明典型场景
ZooKeeper分布式协调(选主、分布式锁、配置)Kafka 旧版依赖;Dubbo 注册中心
Etcd同上的新一代实现,Raft 一致性K8s 的元数据存储就靠它
Apollo携程开源的配置中心配置管理(比 Nacos 更聚焦配置)
Sentinel流量控制、熔断降级限流降级(阿里开源)
Seata分布式事务框架AT/TCC/SAGA 模式解决跨库事务
XXL-JOB分布式任务调度定时任务(替代 Linux crontab)
Canal订阅 MySQL binlog数据同步到 ES/缓存、跨库同步
SkyWalkingAPM 全链路追踪微服务调用链分析(第 9 章详解)
Prometheus指标采集与时序存储系统/业务监控(第 9 章详解)
Kong / APISIXAPI 网关统一入口治理
MinIO自建对象存储,兼容 S3 协议图片/文件/备份存储
SeaweedFS分布式文件系统海量小文件(比 HDFS 更适合)
Hadoop HDFS大数据存储离线数仓
Flink流式计算实时计算、实时风控

7.5 支撑平面:项目里其他不可缺的组件

除了上面几类,一家真实公司的"支撑平面"还有这些组件。 它们平时不起眼,但一挂就是全站级事故,因为它们是"被所有人依赖"的东西。

组件职责部署形态挂了会怎样
统一认证中心(SSO)一次登录,全站通行(CAS/OAuth2/LDAP)双节点 + Redis全站登不上(最高可用等级)
权限中心(RBAC)谁能操作什么(菜单、按钮、数据)双节点 + 数据库后台功能不可用,可能有越权风险
分布式任务调度定时任务统一管理与分片(XXL-JOB)调度中心双节点 + 执行器对账、清算、报表全部不跑
统一文件服务上传下载、图片处理、水印多节点 + 对象存储用户传不了图、看不到图
消息推送中心App Push / 短信 / 邮件 / 站内信多节点 + MQ用户收不到通知(影响留存)
对账中心与支付渠道核对流水定时任务 + 独立库资金差异无法发现
风控中心反欺诈、限流、黑名单多节点 + Redis被刷、被薅羊毛
灰度/AB 平台按用户/设备分流实验双节点 + 配置中心无法做新功能灰度
配置审计/发布平台变更管理与审计双节点变更无记录,出事无法追溯

一个真实的教训

某公司把统一认证中心做了集群,但它的 Redis 是单机。 结果 Redis 一挂,认证中心全挂 → 所有系统登不上 → 全公司停摆 40 分钟。 "被依赖最多的组件,必须用最高规格的高可用",这条原则比任何技术细节都重要。 判断标准很简单:"它挂了,有多少系统不能工作?" 依赖越多,规格越高。


第 8 章 存储与文件

8.1 存储的四种形态

形态全称通俗理解代表用途
块存储Block Storage一块裸硬盘,要自己格式化文件系统云盘、SAN、Ceph RBD、K8s PVC数据库、有状态应用
文件存储File Storage / NAS网络共享文件夹NFS、CephFS、云 NAS多台机器共享读写(如上传目录)
对象存储Object Storage用 HTTP API 存"文件+元数据",无目录层级S3、OSS、COS、MinIO图片、视频、备份、静态资源
分布式文件系统Distributed FS专门为海量文件设计HDFS、FastDFS大数据、海量小文件

怎么选?一句话判断

  • 要跑数据库 → 块存储(要求低延迟、高 IOPS)
  • 多台机器要同时读写同一批文件 → 文件存储(NAS)
  • 存用户上传的图片/视频/附件 → 对象存储(最便宜、最可靠、可 CDN 直连)
  • 存海量日志/大数据文件 → HDFS

8.2 对象存储为什么是现代标配

核心优势

  • 容量无限(分布式,加机器就扩容)
  • 成本极低(比云盘便宜 5~10 倍)
  • 可靠性高(多副本 / 纠删码,标称 11 个 9)
  • 可直接对接 CDN(用户上传图片,CDN 直接回源对象存储,不经过你的应用)
  • 支持生命周期(30 天后自动转低频存储,1 年后归档,自动降本)

真实用法(重要)

❌ 错误做法:用户上传图片 → 应用服务器 → 保存到本地磁盘 → 应用返回 URL
   问题:多台应用服务器磁盘不共享;应用重启磁盘可能丢;无法扩展

✅ 正确做法:用户请求"上传凭证" → 应用返回临时签名 → 
           用户直接上传到对象存储 → 应用只存 URL 到数据库
   优点:不占用应用带宽和磁盘;天然可扩展;可直接接 CDN

对象存储的三个坑

  1. Bucket 权限配错会导致数据泄露。见过太多公司把 Bucket 设成"公共读", 结果全站用户上传的身份证、合同、内部文档被搜索引擎爬到。 默认必须是私有,用临时签名 URL 访问。
  2. 对象存储不是文件系统。没有真正的目录(/ 只是 key 的一部分), rename 实际是"复制 + 删除",代价高。
  3. 最终一致性。虽然 S3 现在标称强一致,但历史上有延迟。 "上传后立刻读"可能 404,业务上要有重试。

第 9 章 三条支撑线:监控 / 日志 / 发布

这一章是整份文档里对运维最核心的部分。 业务线之外,一家公司的技术体系里还有三条"支撑线",它们不直接产生业务价值, 但没有它们,业务线根本不敢上线

业务线(最上层 · 用户直接感知)用户 → 网关 → 微服务 → 数据库① 监控线出问题「多快能发现、多快Prometheus 采集 → Grafana 看板 → Alertmanager 告警SkyWalking 调用链 → 钉钉 / 企微 / 短信 / 电话② 收集线日志「怎么被集中收上来、Filebeat / Fluent Bit 采集 → Kafka 缓冲Logstash 处理 → Elasticsearch 索引 → Kibana 查询③ 发布线代码「怎么安全地变成线上GitLab 代码 → Jenkins 构建 → Harbor 镜像Argo CD 部署 → K8s 运行(Git 为唯一真相来源)三条线围绕业务线运转:没有它们,业务线跑不稳、出了问题也看不见
图 9-0 三条支撑线全览:监控 / 收集 / 发布,各自解决一类问题

9.1 监控线:三根支柱(Metrics / Logging / Tracing)

这是可观测性(Observability)的经典三分法,面试必问,工作必用

支柱回答什么问题数据特征代表工具
指标 Metrics"系统整体健康吗?哪里异常?"数值、可聚合、采样存储、便宜Prometheus、Zabbix、云监控
日志 Logging"具体发生了什么?"文本、离散事件、量大、贵ELK、Loki、SLS
链路 Tracing"这次请求慢在哪一环?"带 traceId 的调用树、采样SkyWalking、Jaeger、Zipkin

一句话记住区别

  • Metrics 告诉你"着火了"(CPU 95%、错误率 8%)
  • Logging 告诉你"烧的是什么"(异常堆栈、报错内容)
  • Tracing 告诉你"从哪儿烧起来的"(哪个服务的哪次调用慢/错)

正确的排查顺序:告警(Metrics)→ 定位服务(Tracing)→ 查具体原因(Logging)。 只有 Metrics 没 Tracing 时会很痛苦:你知道错误率涨了,但不知道是哪个调用链导致的。

9.2 Prometheus + Grafana + Alertmanager(监控线核心)

Prometheus 的工作方式(拉模式 Pull)

业务 Pod/metrics 端点节点/Podkubelet/cAdvisorPrometheus ×2拉取 + 存储 + 告警规则Alertmanager去重/分组/静默Grafana可视化大盘企业微信 / 邮件值班人员手机PagerDuty / 电话P0 升级通道pullpull触发指标线:采集的是「数字」——CPU 用了多少、QPS 多高、P99 多少毫秒适合回答「现在正常吗、趋势如何」;不适合回答「这一个请求为什么慢」
图 9-2 指标线:Prometheus 拉取 → 规则判定 → Alertmanager 分发
组件作用说明
Node Exporter采集主机指标CPU/内存/磁盘/网络
cAdvisor采集容器指标每个容器的 CPU/内存
kube-state-metrics采集 K8s 对象状态Pod 状态、副本数、重启次数
Prometheus Server存储 + 计算告警规则默认保留 15 天,长期存储要接 Thanos/VictoriaMetrics
Alertmanager告警路由分组(同类告警合并)、抑制(A 挂了不报 B)、静默(维护期)
Grafana可视化看板、大屏、告警(也可在 Grafana 配告警)

SRE 的四个黄金指标(记住这四个,监控就有章法了)

指标含义对应 Prometheus 查询示例
延迟 Latency请求耗时(区分成功和失败的)histogram_quantile(0.99, ...) P99
流量 Traffic系统负载(QPS)rate(http_requests_total[5m])
错误 Errors错误率rate(http_requests_total{status=~"5.."}[5m])
饱和度 Saturation资源饱和度(CPU/内存/连接池)container_memory_usage_bytes

三个最容易配错的告警

  1. 告警风暴:一个 Redis 挂了,触发 200 个服务告警。 解法:抑制规则(Infrastructure 层告警抑制 Application 层告警)+ 分组。
  2. 阈值告警太迟钝:CPU > 90% 才报,但你服务慢的时候 CPU 才 60%。 解法:用业务指标(错误率、P99 延迟)而不是只盯资源指标。
  3. 没有告警分级:所有告警都发钉钉,导致没人看。 解法:P0 电话(立刻处理)、P1 电话/短信(15 分钟内)、P2 钉钉(当天处理)、P3 邮件(周会看)

9.3 SkyWalking:全链路追踪(微服务排障的命脉)

没有全链路追踪时,排障是这样的: 用户报"下单失败" → 你看订单服务日志没错误 → 看库存服务日志有超时 → 看库存服务调用的商品服务 → 发现商品服务连接池满了 → 商品服务连接池为什么满? → 因为调用它的推荐服务在疯狂重试…… 靠人肉在 7 个服务的日志里串线索,半小时过去了。

有 SkyWalking 时:打开 SkyWalking UI → 输入 traceId → 看到完整调用树, 一眼看到"商品服务 3.2s 超时",再点进去看它的自己的调用链。

Trace 全景:一次下单请求穿过五个服务,用同一个 traceId 串起来0ms200ms400ms600ms网关620ms订单250ms库存136ms支付84ms通知40ms① 每个服务都要上报 Span(谁调了谁、耗时多少、有没有报错)② Agent 随 Pod 注入,自动埋点,业务代码无需改造③ OAP 聚合 Span 成 Trace,是排查「这一条请求为什么慢」的唯一手段数据流业务 PodAgent 埋点OAP ×2聚合存储ES存 SpanUI按 traceId 查
图 9-3 链路追踪线:一个请求慢在哪一段,一眼看得出

SkyWalking 的核心概念

概念说明
Agent挂在应用上(Java 用 -javaagent,无侵入),采集调用信息
OAP Server接收、分析、存储链路数据
Storage存储(生产用 ES 或 ClickHouse,测试可用 H2)
UI查询界面:追踪、拓扑图、指标、告警
TraceId一次请求的全局唯一 ID,贯穿所有服务(这是灵魂)
Span一次调用(一个服务内的一段)

TraceId 怎么贯穿全链路?三个方案

  1. 网关生成:网关为每个请求生成 traceId,通过 HTTP Header 传给下游。
  2. 自动传播:Agent 自动把 traceId 放进 HTTP Header / RPC 上下文 / MQ 消息头。
  3. 日志打标:把 traceId 打进日志(logback 的 MDC),这样在 ELK 里搜 traceId 就能看到全链路日志。

关键点:日志和链路一定要用同一个 traceId 打通,否则两套系统各自为政,排查效率照样低。

9.4 收集线:ELK 日志平台

为什么需要集中日志?

  • 100 个 Pod,每个 Pod 的日志只在自己容器里,重启就没了 → 必须收走
  • 排查问题要在 10 个服务的日志里关联搜索 → 必须集中
  • 合规要求日志保留 6 个月以上 → 必须归档

ELK 经典架构(Beats → Kafka → Logstash → ES → Kibana)

生产端应用 Pod 标准输出Filebeat / Fluent BitDaemonSet 每节点一份,采集全部容器日志缓冲Kafka 3 副本削峰填谷:ES写不过来时,先积压在 Kafka收集Logstash ×2解析、脱敏、字段提取,分流到不同索引存储ES 日志集群热温冷分层、按天建索引,ILM 滚动删除查询Kibana按 traceId、关键字、时间范围检索日志线回答的是「到底发生了什么」:错误堆栈、业务流水、审计记录它是事后排查的唯一真相来源 —— 指标告诉你「有问题」,日志告诉你「是什么问题」常见故障Kafka 积压(消费跟不上)· ES 磁盘写满(ILM 没配)· Logstash 解析失败(字段类型冲突)
图 9-4 日志线:生产端 → 缓冲 → 收集 → 存储 → 查询

每个组件的职责

组件职责为什么需要它
Filebeat / Fluent Bit采集日志文件,轻量(几十 MB)部署在每个节点,开销必须小
Kafka缓冲ES 抖动/重启时日志不丢;削峰(日志量有波峰)
Logstash解析、清洗、格式化Grok 解析非结构化日志成 JSON;过滤敏感信息
Elasticsearch存储 + 索引 + 检索毫秒级全文检索
Kibana查询界面开发/运维查日志的地方

日志平台的四个工程问题

  1. 成本。日志是最贵的数据(ES 集群磁盘消耗极大)。 必须做的:① 分级(DEBUG 不上生产);② 按天索引 + 生命周期(7 天热、30 天温、180 天冷/归档); ③ 采样(高频重复日志只留样本);④ 字段裁剪(不要整条 JSON 全存)。
  2. ES 写入压力。日志是"写入多、查询少"的场景。 做法:Logstash 批量写(bulk)关闭不必要的字段索引refresh_interval 调大减少段合并
  3. 权限与合规。日志里可能有手机号、密码、token。 做法:Logstash 阶段就做脱敏mutate 替换字段),而不是事后处理。
  4. 日志规范。如果每个服务的日志格式都不一样,什么都搜不出来。 做法:统一 JSON 结构化日志 + 统一字段名traceId / level / service / timestamp)。 这一条是"日志能不能用"的分水岭,比装什么工具重要得多。

什么时候该用 Loki 而不是 ELK?

Loki(Grafana 出品)只索引标签,不索引内容,存储成本比 ES 低 5~10 倍。 代价是全文检索能力弱(只能先按标签筛选,再 grep)。 选择标准:需要复杂检索/聚合 → ELK;只按服务/时间查日志 → Loki 更省钱。 很多公司是两者并存:核心业务日志 ELK,一般日志 Loki。

9.5 发布线:CI/CD 全链路

这条线就是把前面几份文档讲的东西串起来。放在这里的意义是: 让你看到它在整个架构中的位置——它是一条横切的支撑线,服务于所有环境。

GitLab / Gitea① 代码托管feature/* → develop → release/* → master → tagJenkins② CI 构建编译 · 单测 · 代码扫描 · 构建镜像(各环境一套)Harbor③ 镜像仓库Trivy 漏洞扫描 · Cosign 签名 · 只留最近 30 个版本GitOps 清单仓库④ 更新镜像 tagJenkins 只改 Git 里的 tag,不碰集群Argo CD⑤ CD 同步检测到清单变化 → 自动同步到 K8s · 可审计可回滚Kubernetes⑥ 滚动发布滚动更新 · 就绪探针通过才切流量 · 失败自动回滚两条铁律① Jenkins 只写 Git, 不直接操作集群 (否则失败无法回滚)② 集群里的状态必须 能从 Git 完整重建 (否则就是漂移)产物可追溯: 每个镜像 tag 都能定位到提交这条链路的关键转变:构建与发布解耦 —— Jenkins 不再需要集群的写权限
图 9-5 发布线全链路:从代码提交到 Pod 运行,六步,每一步都可审计

四个环境的流水线差异(真实做法)

环境触发方式是否需审批副本数验证手段
dev每次提交自动1冒烟测试
test自动 / 手动1~2自动化测试 + 接口测试
uat手动触发产品确认接近 prod人工验收 + 回归测试
prod手动触发必须审批(双人)全量灰度观测 + 全链路监控

发布线的核心指标(衡量团队工程能力)

指标含义优秀水平
发布频率多久发一次每天多次
变更前置时间从提交到上线< 1 小时
变更失败率发布导致故障的比例< 15%
平均恢复时间 MTTR故障多久恢复< 1 小时

这四个指标就是 DORA 指标(Google DevOps 研究), 面试时能说出来,面试官会认为你真的懂 DevOps,而不只是会敲命令。

9.6 三条线的协同:一次故障的完整还原

讲了那么多组件,最重要的是理解它们怎么协同工作。下面用一次真实故障的全过程, 把三条线串起来(这个例子建议反复看,它比任何架构图都更能说明问题):

时间事件哪条线在起作用你看到什么T+0s用户下单请求打进来流量线网关 QPS 曲线抬头T+2s订单服务响应变慢指标线P99 从 200ms 涨到 800msT+5s告警规则命中指标线Alertmanager 发出告警T+30s值班人打开 Grafana指标线看到慢的是订单服务T+60s按 traceId 查链路链路线定位到是库存服务慢T+90s看库存服务日志日志线发现 Redis 连接池耗尽T+120s扩容连接池 / 重启流量线P99 回落到 200msT+300s写复盘文档交付线下次不会再犯三条线不是三套独立系统,而是同一次故障中「广度 → 精度 → 深度」的三次追问
图 9-6 三条线协同排障时间线:从发现到复盘的完整 5 分钟

反过来,缺了任何一条线会怎样?

缺哪条线后果上面的流程会变成
缺监控线靠用户投诉才发现2 小时后才发现(而不是 2 分钟)
缺链路追踪知道商品服务慢,不知道慢在哪在 7 个服务的日志里人肉搜,30 分钟
缺日志收集只能一台台机器登上去看日志Pod 重启后日志丢失,永远查不到
缺发布线回滚只能手工改 YAML 再重启10 分钟以上,且可能改错

"可观测性"不是锦上添花,它就是生产系统的一部分。 一家公司如果把监控和日志当作"以后再补",那它就是在拿用户的耐心当测试环境。

9.7 告警体系设计(别让告警把你淹死)

告警配得不好比不配更糟——因为人会对告警脱敏(Alert Fatigue), 最后所有告警都被忽略,真故障来了也没人看。

告警分级(真实公司的做法)

级别定义通知方式响应时间例子
P0全站不可用 / 资金损失电话 + 短信 + 企微 + 值班群立即网关全挂、数据库主库不可用
P1核心功能受损电话 + 短信15 分钟支付成功率跌破 90%
P2部分用户受影响企微 / 钉钉2 小时某台机器磁盘 85%
P3潜在风险 / 趋势异常邮件 / 日报当天磁盘周增长 20% 需扩容规划

告警质量的三条铁律

铁律说明反例
每个告警必须可行动收到告警你知道该做什么"CPU 使用率 71%"——然后呢?
每个告警必须有 owner有明确的人负责告警发到群里没人认领,最后没人看
每个告警必须分级不同级别不同处理方式所有告警都发钉钉 → 全部被忽略

最常见的三种"垃圾告警",一定要删掉

  1. 阈值型资源告警CPU > 80%。 CPU 80% 不一定是问题(可能是有用负载),CPU 40% 也可能是问题(可能在等锁)。 应该用业务指标(错误率、延迟、饱和度)替代或补充。
  2. 单点瞬时抖动告警:一次请求超时就告警。 必须加持续时间条件(如"错误率 > 1% 持续 2 分钟"),否则告警风暴。
  3. 没有抑制关系的告警:数据库挂了,触发 50 个服务的连接失败告警。 必须配抑制规则:基础设施告警触发时,抑制上层应用告警。

第 10 章 安全、容灾与应急

10.1 高可用的等级(先搞清楚你在哪一级)

等级可用性年停机时间实现方式成本
单机99%3.65 天一台机器
双机/主备99.9%8.76 小时主备切换(分钟级)2 倍
集群多副本99.95%4.38 小时多节点负载均衡2-3 倍
多可用区99.99%52.6 分钟跨 AZ 部署3-4 倍
同城双活99.995%26.3 分钟两机房同时服务4-6 倍
异地多活99.999%5.26 分钟多地同时服务8 倍以上

一个残酷的成本规律

可用性每提高一个 9,成本大约翻一倍。 所以"我们的系统要做到 5 个 9"这句话,背后必须有业务价值支撑(比如支付、金融)。 一个内部审批系统做到 99.9% 就完全够了。 架构设计的第一原则不是"越高可用越好",而是"可用性匹配业务价值"。

10.2 容灾的两个关键指标

指标全称含义通俗理解
RTORecovery Time Objective恢复时间目标能接受停多久
RPORecovery Point Objective恢复点目标能接受丢多少数据

不同业务的要求差异极大

业务RTORPO说明
支付/交易< 1 分钟0(不能丢)必须同步复制 + 多副本
核心订单< 5 分钟< 1 秒半同步 + 自动切换
商品浏览< 30 分钟可回滚 5 分钟异步复制可接受
日志/报表数小时可丢部分定时备份即可

最容易被忽略的:备份不等于容灾

有备份 ≠ 能恢复。 真实事故中,"备份文件损坏""备份恢复了 8 小时""恢复后发现备份是 3 天前的" 是最常见的情况。所以:

  1. 备份必须定期做恢复演练(每季度至少一次,在隔离环境完整恢复一遍)。
  2. 备份要异地存放(同机房备份,机房烧了备份也没了)。
  3. 要监控备份任务是否成功(很多公司是"备份脚本挂了半年没人知道")。
  4. 备份要防勒索(备份账号不要和业务账号同权限,用不可变存储保留)。

10.3 安全体系的基本盘

层面措施说明
网络安全组最小开放、WAF、DDoS 高防、内网隔离只开必需的端口
主机基线加固、补丁管理、HIDS、防病毒关闭无用服务、禁止 root 直登
应用代码审计、依赖扫描(SCA)、SAST/DAST防 SQL 注入、越权、SSRF
镜像镜像扫描(Trivy)、只允许内网仓库防止引入带漏洞的基础镜像
数据传输加密(TLS)、存储加密、脱敏、分级分类敏感数据必须加密
身份统一认证、最小权限、MFA、堡垒机禁止共享账号
审计操作日志、数据库审计、变更审计出了问题能追责
合规等保 2.0、个人信息保护法、数据出境法律要求,不是可选项

运维最容易犯的 6 个安全错误

  1. 用 root 直接 SSH 登录生产,且密码是弱密码 → 必须用堡垒机 + 密钥 + MFA。
  2. 数据库端口对公网开放 → 只允许应用区访问,且要密码 + IP 白名单。
  3. 密钥、密码写在代码/配置文件里提交到 Git → 用 K8s Secret + Vault,且 Git 提交要有 secret 扫描。
  4. Nacos / Redis / ES / Docker API 没有鉴权 → 这些都是"裸奔"高发区,能被直接接管服务器。
  5. 备份和业务用同一个账号 → 被入侵后备份一起被删(勒索软件最爱)。
  6. 测试环境用生产数据且没有脱敏 → 数据泄露直接违法。

10.4 故障处理的标准动作(SRE 的工作方式)

出故障时,人容易慌。成熟团队有固定流程

① 发现(监控告警 / 用户反馈)
   ↓ 5 分钟内
② 定级(P0 全站不可用 / P1 核心功能受损 / P2 部分影响 / P3 轻微)
   ↓ 立即
③ 止血优先于定位根因 ★★★ 最重要的一条
   · 先回滚、先重启、先扩容、先降级、先切流 —— 让服务先恢复
   · 千万不要在故障中"顺手改点别的"(会把问题搞得更复杂)

④ 定位(用监控→链路→日志三级定位)

⑤ 修复(修复后验证:指标回落、用户可用)

⑥ 复盘(无指责复盘 Blameless Postmortem)
   · 时间线、根因(5 Why)、影响面、改进项(有 owner 有 deadline)
   · 目标不是找人背锅,而是让系统更不容易出错

"止血优先于定位根因"为什么这么重要

新人最常见的错误:出了故障非要"搞清楚为什么"才动手, 结果服务一直在挂,用户一直在骂,10 分钟过去了。 故障处理的第一目标是恢复服务,不是搞明白原理。回滚是最快、最安全的止血手段——这也是为什么 CI/CD 必须支持一键回滚。 (原理可以在事后复盘时慢慢想,那时候服务已经恢复了,你有充足时间。)


第 11 章 演进路线:小公司怎么长成这个样子

不要一步到位。 这篇文章描述的架构是演进的结果,不是起点。 真实公司是按阶段长起来的,把下面这张表看懂,你就理解了"为什么会有这些组件"。

阶段规模架构形态关键技术变化遇到的瓶颈
第 0 阶段0~1000 DAU1 台服务器,Nginx + PHP/Java + MySQL 同机单体应用,手工部署(FTP/scp)单点,挂了就全挂
第 1 阶段1 千~1 万应用与数据库分离;引入 Redis 缓存读写分离;CI 工具(Jenkins)数据库压力、发版靠人
第 2 阶段1 万~10 万应用多实例 + Nginx 负载;主从数据库容器化(Docker);配置中心手工部署易错、环境不一致
第 3 阶段10 万~100 万K8s 集群;微服务拆分;MQ 解耦;ELK 日志GitOps、服务治理、监控体系微服务治理复杂、故障定位难
第 4 阶段100 万~1000 万多可用区、分库分表、Redis 集群、APM 链路追踪灰度发布、全链路压测、容量规划成本飙升、稳定性压力、数据一致性
第 5 阶段1000 万+异地多活、单元化、混合云、Serverless精细化成本治理、混沌工程、SRE 体系组织效率、跨团队协作

每个阶段的"必备项"和"可以没有的"

阶段必须有明确可以没有
0~1备份、监控(哪怕是 Zabbix)K8s、MQ、APM
2~3CI/CD、容器、集中配置、日志分库分表、异地容灾
4APM、自动化容量管理、灰度单元化
5混沌工程、成本平台——

判断标准:当你被某个具体问题反复折磨(比如"发版总要停服"),就引入对应组件解决它。不要为了"架构先进"而引入自己驾驭不了的东西。

11.1 给转行者的学习路径建议

结合这套架构,从哪开始学

顺序学什么对应本文落地方式
1Linux 基础 + 网络基础第 3、4 章本机装 VM,配通网络
2Nginx 反向代理 + 负载均衡第 4 章2 台 VM 做 upstream
3MySQL 主从复制第 6.1 节2 台 VM 搭主从,手动模拟主库宕机
4Redis 主从 + 哨兵第 6.4 节3 台 VM 或 3 个端口
5Docker + K8s 单节点第 5.1 节minikube / kubeadm
6Jenkins CI 流水线第 9.5 节打通"提交代码 → 自动构建 → 自动部署"
7Prometheus + Grafana第 9.2 节监控自己的 K8s 和 MySQL
8ELK 日志平台第 9.4 节收集 K8s 日志
9Nacos + 微服务部署第 7.2 节部署若依微服务(本系列其他文档有完整流程)
10Argo CD GitOps第 9.5 节在本系列《Jenkins CI + Argo CD CD》文档里练
11全链路压测 + 容量规划第 6、10 章用 JMeter 压测自己的服务

配套资源:本系列的《若依微服务上 K8s》《Jenkins CI + Argo CD CD》两份文档, 给出了第 5、6、9 步的完整可执行步骤,可以直接照着搭。


第 12 章 附录:术语速查与自检清单

12.1 架构术语速查表

缩写全称中文一句话解释
IDCInternet Data Center自建机房自己租机柜放服务器的机房
VPCVirtual Private Cloud虚拟私有云云上逻辑隔离的私有网络
AZAvailability Zone可用区同一地域内电力和网络独立的机房
RegionRegion地域地理区域(如华东1、首尔)
ELBElastic Load Balancer弹性负载均衡云上的四层/七层 LB
SLBServer Load Balancer(阿里云叫法)负载均衡同 ELB
CDNContent Delivery Network内容分发网络边缘缓存加速
WAFWeb Application FirewallWeb 应用防火墙防注入/XSS/CC
DNSDomain Name System域名系统域名→IP
VIPVirtual IP虚拟 IP负载均衡对外暴露的浮动 IP
L4 / L7Layer 4 / Layer 7四层/七层传输层/应用层负载
API GWAPI GatewayAPI 网关统一入口、鉴权、限流
BFFBackend For Frontend服务于前端的后端为不同端定制的聚合层
RPCRemote Procedure Call远程过程调用服务间调用(Dubbo/gRPC)
SLAService Level Agreement服务等级协议承诺的可用性(如 99.9%)
SLOService Level Objective服务等级目标内部目标,通常严于 SLA
SLIService Level Indicator服务等级指标衡量 SLO 的具体度量
RTO / RPO恢复时间/恢复点目标能停多久 / 能丢多少
MTTRMean Time To Recovery平均恢复时间故障恢复耗时
MTBFMean Time Between Failures平均无故障时间两次故障间隔
QPS / TPSQueries/Transactions Per Second每秒查询/事务数吞吐量指标
P99 / P95Percentile分位延迟99%/95% 请求快于此值
HAHigh Availability高可用坏了能自动切
DRDisaster Recovery灾难恢复机房级故障的应对
IaCInfrastructure as Code基础设施即代码用代码管理基础设施
GitOpsGit 运维用 Git 作为唯一真相来源驱动部署
PaaSPlatform as a Service平台即服务内部研发效能平台 / 云平台
IaaSInfrastructure as a Service基础设施即服务云主机、云网络
SaaSSoftware as a Service软件即服务直接用的软件

12.2 架构自检清单(评审时逐条问)

流量入口

  • [ ] 有没有 CDN?静态资源命中率多少?回源率多少?
  • [ ] 有没有 WAF?被攻击过吗?防护规则多久更新?
  • [ ] LB 是双节点吗?LB 自己挂了怎么办?
  • [ ] 七层路由规则变更需要重启吗?会中断连接吗?

应用层

  • [ ] 应用是无状态的吗?能不能随时杀掉一个 Pod 不影响用户?
  • [ ] readinessProbe / livenessProbe 配了吗?配置正确吗?
  • [ ] 有没有资源 limit 和 request?会不会一个 Pod 吃光节点内存?
  • [ ] 单点故障有哪些?节点挂了 Pod 能否漂移?

数据层

  • [ ] 数据库是一主两从吗?复制的同步模式是什么?延迟多少?
  • [ ] 主库挂了谁来做切换?切换要多久?切换期间写请求怎么办?
  • [ ] 备份做了吗?恢复演练做过吗? 备份在异地吗?
  • [ ] 分库分表的分片键选对了吗?扩容方案想好了吗?
  • [ ] Redis 是集群还是单机?挂了缓存穿透会不会打垮数据库?

中间件

  • [ ] Nacos 是 3 节点吗?Nacos 自己的数据库高可用吗?开了鉴权吗?
  • [ ] MQ 会丢消息吗?消费端幂等做了吗?积压了怎么处理?
  • [ ] 配置中心的环境隔离是用 namespace 还是 group?(必须 namespace)

观测

  • [ ] 有指标监控吗?告警能到人吗?告警分级了吗?会告警风暴吗?
  • [ ] 有链路追踪吗?traceId 贯穿全链路了吗?
  • [ ] 日志集中了吗?日志里能搜到 traceId 吗?日志成本多少?
  • [ ] 有没有业务监控(而不只是资源监控)?核心接口的成功率知道吗?

发布与应急

  • [ ] 发布能一键回滚吗?回滚需要多久?
  • [ ] 生产发布需要审批吗?有审计记录吗?
  • [ ] 有没有做过故障演练(杀进程、断网、删 Pod)?
  • [ ] 有没有应急预案文档?值班表有吗?半夜告警谁接?

12.3 常见"看起来高可用,实际是单点"的陷阱

这是本文最实用的一节。很多架构图看着很美,实际经不起一次故障。

陷阱为什么是假的正确做法
Nacos 集群了,但 Nacos 用单机 MySQLMySQL 挂 → Nacos 全挂 → 所有服务拿不到配置 → 全站崩Nacos 的库必须一主两从
Redis 主从了,但没配哨兵主库挂了不会自动切换,要人工介入,RTO 几十分钟哨兵 / Cluster 模式
LB 双节点了,但共用一台交换机/一个机柜机柜断电 → 双节点一起挂跨机柜、跨可用区
MySQL 主从了,但 VIP 没有主库挂了切换后,应用不知道新 IPVIP / 中间件(ProxySQL、MHA)
Jenkins 单点挂了就发不了版(虽然不影响线上,但影响抢修)Jenkins 主备 / 用 K8s 部署可自愈
只有一台跳板机跳板挂了无法运维(最要命的时刻)双跳板 + 证书登录
监控只有一台 Prometheus监控挂了,你就是瞎的双实例 + 远程存储
日志只有一台 ES出故障时日志平台自己先挂ES 至少 3 节点
备份和业务同账号同机房被入侵/断电则备份一起没了异地 + 独立账号 + 不可变存储
"我们有多副本"但都在一个节点节点挂 → 副本全没反亲和性(anti-affinity)强制打散

最经典的一幕

故障的时候,恰恰是你最需要监控和跳板机的时候,而它们往往也在这时候挂了。 因为它们和业务系统共享了同一个故障域。 判断一个架构是否真的高可用,有一个非常简单的问题: "如果我现在拔掉任何一个机柜的电源,会发生什么?" 如果答案是"某个支撑系统全挂"——那它就不是高可用。


结语

如果你读到这里,应该已经建立了这样一张地图:

一家中大型互联网公司的技术体系 = 5 个平面(流量/业务/数据/支撑/观测)+ 1 条横切的交付线。

它们的所有复杂度,都在回答两个问题:高可用可扩展

而对你个人来说,最重要的认知是:

三条给转行者的忠告

  1. 别追求背下所有组件。 没有人能靠背记住这些。你要掌握的是**"它解决什么问题"**, 遇到具体需求时能想起来"这个场景应该有现成的方案",然后去查。这才是真正的能力。
  2. 从一条链路完整走通,比看十张架构图有用。 把"用户请求 → 网关 → 服务 → 数据库 → 返回"这一条链路,亲手搭一遍、压一遍、打挂一遍、 恢复一遍。你对架构的理解会超过读一百篇文章。
  3. 遇到不懂的组件,先问"没有它会怎样"。 这个问题能帮你跳过 90% 的细节,直接抓住本质。

配套阅读(本系列其他文档):

文档内容
《计算机基础概念与术语》本文的前置知识:网络、协议、操作系统、中间件的通俗讲解
《若依微服务上 K8s》本文第 5、6 章的完整落地步骤
《Jenkins CI + Argo CD CD》本文第 9.5 章发布线的完整落地步骤
《客户端 / 服务端类软件发布》本文的补充:有独立客户端的软件怎么发布

基于 VitePress 构建 · 内容为个人学习与工程实践笔记