分布式与云原生复习笔记
从 CAP 定理到 Kubernetes,从负载均衡到 Service Mesh,整理分布式系统与云原生的常见主题。
目录 · 35 节
- 1. 分布式系统基础
- 1.1 CAP 定理
- 1.2 BASE 理论
- 1.3 分布式事务
- 1.4 幂等性
- 1.5 分布式 ID
- 1.6 分布式锁
- 2. 一致性算法
- 2.1 Paxos
- 2.2 Raft
- 2.3 Paxos vs Raft
- 2.4 补充:ZAB / Gossip 与脑裂
- 3. 负载均衡
- 3.1 四层 vs 七层
- 3.2 LVS / Nginx / Envoy
- 3.3 常用负载均衡算法
- 4. 高可用与容灾
- 4.1 多活架构
- 4.2 熔断 / 降级
- 4.3 限流
- 4.4 灾备方案
- 5. 微服务架构
- 5.1 拆分策略
- 5.2 服务发现
- 5.3 网关
- 5.4 链路追踪
- 5.5 Service Mesh
- 6. Kubernetes
- 6.1 架构组件
- 6.2 Pod 与生命周期
- 6.3 Deployment 与工作负载
- 6.4 Service
- 6.5 Ingress
- 6.6 调度原理
- 7. 常见问题整理
分布式与云原生复习笔记
这份笔记整理分布式系统与云原生的常见主题,覆盖从单机到集群的演进路径:CAP / BASE、分布式事务、幂等性、分布式 ID,到 Raft / Paxos 一致性算法,再到负载均衡、高可用与容灾、微服务架构,最后是 Kubernetes 容器编排与服务网格。
主要模块:
- 分布式系统基础:CAP、BASE、分布式事务、幂等性、分布式 ID
- 一致性算法:Raft 与 Paxos 的对比
- 负载均衡:四层 vs 七层、LVS / Nginx / Envoy
- 高可用与容灾:多活架构、熔断降级、限流、灾备方案
- 微服务架构:拆分策略、服务发现、网关、链路追踪、Service Mesh
- Kubernetes:Pod、Deployment、Service、Ingress、调度原理
- 常见问题整理
1. 分布式系统基础
1.1 CAP 定理
CAP(Eric Brewer 2000 年提出,2002 年由 Gilbert & Lynch 证明)说的是:分布式系统在**网络分区(Partition Tolerance)**发生时,**一致性(Consistency)和可用性(Availability)**只能二选一,三者无法同时满足。
三个字母:
- 一致性 C:所有节点在同一时刻读到相同数据,读请求能拿到最近一次写入(线性一致性)。
- 可用性 A:每个请求(在非故障节点上)都能在有限时间内得到非错误响应,不保证是最新数据。
- 分区容错 P:系统在任意网络分区(节点间通信中断)下仍能继续工作。
最容易答歪的一点:P 是前提,不是选项。分布式环境里网络分区一定会发生(网线拔了、交换机挂了、GC 停顿导致心跳超时),所以系统必须选 P,剩下的 C 和 A 二选一。于是 CAP 实际是「CP 还是 AP」的选择:
- 选 CP:分区期间牺牲可用性,写入被拒绝直到多数派恢复。代表 ZooKeeper、etcd、HBase。
- 选 AP:分区两侧都能读写,事后合并冲突,牺牲强一致性。代表 Cassandra、Eureka。
所谓「CA」在真实分布式系统里不存在——不分区才有 CA,那是单机事务的语义。另一个常见误解是把「放弃一致性」理解成「数据会错」:AP 系统放弃的是强一致性,靠最终一致性兜底。
1.2 BASE 理论
BASE 是 AP 系统的落地策略:
- Basically Available(基本可用):出故障时损失部分可用性,但核心功能仍可用。双十一降级:下单不实时查库存、返回「稍后确认」,而不是直接报错。
- Soft State(软状态):允许数据存在中间状态,不同副本之间可以短暂不一致。
- Eventually Consistent(最终一致性):不要求实时一致,但保证没有新更新后,数据最终收敛到一致。
BASE 和 ACID 不是对立,而是两个场景的两套取舍:ACID 是强一致事务(转账、订单金额),BASE 是可用性优先的最终一致(点赞数、浏览计数、库存展示)。一句话:ACID 保证「对」,BASE 保证「能用」,最终一致保证「迟早会对」。
1.3 分布式事务
单机事务靠数据库 ACID 和本地锁搞定;拆成微服务后一笔业务要跨多个服务、多个数据库,需要分布式事务协调。常考四类方案:
2PC(两阶段提交)——强一致、同步阻塞:
- 准备阶段:协调者向所有参与者发 prepare,各参与者执行事务但不提交,undo/redo 日志落盘,返回 ready 或 no。
- 提交阶段:全部 ready 就发 commit;任一 no 或超时就发 rollback。
优点:强一致、原理简单。缺点:同步阻塞(参与者锁资源等协调者)、协调者单点(挂了全员卡住)、第二阶段只发到一半会造成数据不一致。XA 协议就是 2PC 的标准实现。改进版 3PC 加了 canCommit 预询问和参与者超时自动提交,缓解阻塞但引入新的一致性问题,生产用得少。
TCC(Try-Confirm-Cancel)——业务层补偿、柔性事务:
- Try:预留资源(冻结库存、预占额度)。
- Confirm:全部 Try 成功后真正执行业务,只允许成功。
- Cancel:任一 Try 失败,撤销已预留资源。
特点是把事务拆成业务代码自己实现,每个操作都要写正向和反向两个接口,侵入性强、开发量大,但不长时间占锁、性能好。适合资金、库存这类需要强业务控制的场景(Seata 的 TCC 模式)。
Saga——长事务的补偿链:
把长事务拆成一系列本地事务 T1, T2, ..., Tn,每个 Ti 配一个补偿 Ci。失败时反向执行补偿:T1 T2 T3 里 T3 失败,就依次执行 C2 C1 回滚。两种编排:
- 编排式(choreography):事件驱动,各服务自己监听事件决定下一步,无中心协调器,但流程散落难维护。
- 控制式(orchestration):一个编排器统一调度,流程清晰但引入单点。
优点:不阻塞、支持长流程(秒杀后的下单、出行订单)。缺点:补偿逻辑要自己写,且没有隔离性,中间态对其他事务可见。
本地消息表 / 事务消息——最终一致的经典落地:
本地业务和「写消息表」放在同一个本地事务里,保证业务数据与待发消息原子落库;后台定时任务扫表重试投递 MQ;消费方保证幂等。核心思想:不追求跨库强一致,而是靠「本地事务 + 可靠消息 + 幂等消费」最终收敛。RocketMQ 的事务消息(半消息)是这个模式的成熟实现。
选型顺序:强一致、短事务用 2PC;资金库存用 TCC;长流程、弱隔离用 Saga;能接受最终一致就优先消息表,最简单、最不容易出 bug。
1.4 幂等性
幂等指同一操作执行一次和执行多次的效果相同。分布式里重试无处不在(网络超时重发、MQ 重复投递、客户端双击),写接口都要做幂等。常见方案:
- 唯一约束 / 唯一索引:靠数据库唯一键兜底,重复插入直接冲突(
order_id唯一索引)。 - token 机制:请求先拿 token,提交时 token 与业务一起校验删除,token 没了就是重复请求。
- 状态机:只有
待支付 → 已支付才允许推进,重复的「已支付」请求被状态挡掉。 - 乐观锁(版本号):
UPDATE ... SET status=1, version=version+1 WHERE version=?,条件不命中说明已更新过。 - MQ 消费侧:用消息 ID 去重,或业务键做唯一约束。
关键区分:幂等 ≠ 只返回成功。幂等要保证副作用只发生一次(钱只扣一次),不是简单地把重复请求吞掉。
1.5 分布式 ID
分库分表后单库自增 ID 会撞车,需要全局唯一 ID。高频考这几个:
- UUID:本地生成、无中心依赖,但无序、字符串长,作为主键会导致 B+ 树页分裂、索引膨胀,一般不适合直接当主键。
- 数据库号段模式:单表集中发号或按业务分段,简单但单点、有性能瓶颈。
- Redis INCR:快,但依赖 Redis 持久化,重启可能重复。
- 雪花算法(Snowflake):64 位长整型,
1 符号位 + 41 时间戳 + 10 机器位 + 12 序列位。趋势递增、可本地生成,但依赖时钟——时钟回拨会导致 ID 重复,通常用「回拨时等待或借位」解决。美团 Leaf、百度 UidGenerator 都是它的变体。
选型看三点:是否趋势递增(利于索引)、是否依赖中心组件、时钟回拨怎么处理。
1.6 分布式锁
多个进程抢同一份资源(扣库存、发号),单机锁失效,需要跨进程锁。基本要求:互斥(同一时刻只有一个持有者)、不会死锁(超时释放)、释放锁的必须是持锁人(否则 A 超时释放了 B 的锁)。主流实现:
- Redis:
SET key value NX PX 30000原子加锁,value 存唯一 token,释放时 Lua 脚本校验 token 再删,防止误删。问题在于主从切换时锁可能丢(主挂了、从没同步到锁,另一个客户端又加上了)。Redlock 用多实例多数派缓解,但存在争议(GC 停顿、时钟跳跃下仍可能失效)。 - etcd / ZooKeeper:临时顺序节点 + watch 实现,节点故障自动释放,强一致但性能低于 Redis。对锁的正确性要求高(选主、全局唯一资源)时优先 etcd/ZK;追求吞吐、能容忍极小概率失效(防重复提交)用 Redis。
延伸概念:租约(lease)与 fencing——持有锁后执行的写要带一个单调递增的 token,存储侧拒绝旧 token 的写,防止「持锁期间卡顿、锁已过期、别人拿到锁后旧持有者又写回来」的脑裂。
2. 一致性算法
共识问题:一组节点就某个值达成一致,即使部分节点宕机、消息丢失或乱序。它是复制状态机的基础——所有节点按相同顺序执行相同命令,状态就一致。Paxos 和 Raft 是两大代表。
2.1 Paxos
Lamport 1990 年提出,用角色(proposer 提议者 / acceptor 接受者 / learner 学习者)和两阶段描述:
- Prepare:proposer 发带编号 n 的 prepare,acceptor 承诺不再接受编号小于 n 的提案,并返回它已接受的最高编号提案。
- Accept:proposer 收到多数派响应后,选「已被接受的最高编号值」或「自己的值」,发 accept;acceptor 只接受编号最大的提案。
核心结论:一旦某个值被多数派 accept,后续任何被多数派接受的提案都只能是这个值(值不变,编号递增)。这个多数派(quorum)机制保证了任意两个多数派必有交集,是 Paxos 正确性的关键。
优点:证明严格、容错性强,最早的分布式一致性算法。缺点:难理解、难实现,Basic Paxos 一次共识要两轮通信、性能差;工程上常用 Multi-Paxos——选出一个 leader 后,只对 leader 的提案做一轮 accept,省掉重复 prepare。
2.2 Raft
Raft(Ongaro 2014)把共识拆成三个可独立理解的子问题,工程上比 Paxos 友好得多:
- Leader 选举:三种角色 Follower / Candidate / Leader,任期(term)单调递增。Follower 收不到心跳就超时变 Candidate、term+1、给自己投票并请求别人投票,拿到多数派票就当选。随机选举超时(150–300ms)降低分裂投票概率。
- 日志复制:leader 把命令追加到本地日志,并行发给 follower,多数派落盘即提交(committed),再把结果返回客户端。提交靠「任期 + 索引」唯一定位日志,follower 落后会被 leader 覆盖对齐。
- 安全性:投票约束保证「leader 一定包含所有已提交日志」——candidate 日志至少和投票者一样新(任期更大,或任期相同索引更大)才给票;leader 不能靠提交旧任期的日志间接提交新日志。
etcd、TiKV、Consul、Kafka(KRaft 模式)都用 Raft。
2.3 Paxos vs Raft
| 维度 | Paxos | Raft |
|---|---|---|
| 可理解性 | 难,角色状态多 | 好,拆成三个子问题 |
| 领导者 | Multi-Paxos 才有稳定 leader | 天然强 leader |
| 日志 | 允许乱序、有空洞 | 严格连续、强制顺序 |
| 成员变更 | 复杂 | 联合共识(joint consensus)两步切换 |
| 工程实现 | Chubby、Spanner | etcd、TiKV、Consul、Kafka(KRaft) |
一句话:Paxos 是理论奠基,Raft 是可工程化的 Paxos。讲清 Raft 的选举 + 日志复制 + 多数派提交,就够撑住大多数追问。
2.4 补充:ZAB / Gossip 与脑裂
- ZAB:ZooKeeper 的原子广播协议,也是「选主 + 日志同步」,与 Raft 思想同源、细节不同(epoch 概念、崩溃恢复阶段)。知道它属于「类 Paxos 的 leader 型共识协议」即可。
- Gossip:去中心化传播协议,节点随机挑邻居交换状态,最终全网收敛。没有 leader、不保证强一致,适合传播元数据(Cassandra、Redis Cluster、Consul 的成员关系)。和 Raft 对比:Raft 强一致但中心化,Gossip 去中心化但最终一致。
- 脑裂(split-brain):集群因网络分区裂成两个都能选出 leader 的子集群,双方同时对外写导致冲突。解法两个方向:多数派仲裁(quorum,只有超过半数节点的集群才能继续服务,如 etcd、ZK);fencing(给 leader 发 fencing token,存储/客户端拒绝旧 token 的写)。
3. 负载均衡
3.1 四层 vs 七层
负载均衡把请求分发给后端多台机器,按 OSI 层次分两类:
- 四层(L4,传输层):只看 TCP/UDP 的源/目的 IP 和端口,做连接级转发。不解析应用协议,性能高、能扛大连接量,但无法按 URL、Header 路由。代表:LVS、F5、云厂商 SLB 四层模式、K8s Service(kube-proxy)。
- 七层(L7,应用层):解析 HTTP/HTTPS,能按域名、路径、Header、Cookie 路由,能做 TLS 终止、缓存、限流、重写。灵活但性能略低、延迟略高。代表:Nginx、Envoy、K8s Ingress。
实际架构常叠加:LVS 扛流量做第一层转发 → Nginx 做七层路由和业务策略。一句话:四层管「连到哪台机器」,七层管「这个请求具体到哪个服务/接口」。
3.2 LVS / Nginx / Envoy
- LVS:Linux 内核里的四层负载均衡,工作在网络层,三种模式 NAT / DR(直接路由)/ TUN。DR 模式回程不经过 LVS,性能极高(百万级连接),但要求 LVS 和真实服务器在同一二层网络、且处理 ARP 抑制。
- Nginx:七层反向代理 + 静态资源 + 四层(
stream模块)。配置简单、生态成熟,upstream配后端、proxy_pass转发。epoll 事件驱动,单机扛几万并发,高可用用 keepalived 做 VIP 漂移。 - Envoy:云原生数据面代理,L3/L4/L7 都支持,xDS 动态配置、可观测性强(内置指标/追踪),是 Istio 默认 sidecar。相比 Nginx,面向动态服务发现和细粒度流量管理设计,但学习曲线陡、内存占用大。
3.3 常用负载均衡算法
- 轮询(Round Robin):按顺序轮流,简单,但没考虑机器负载差异。
- 加权轮询(Weighted RR):按机器配置给权重,权重大的多分。Nginx 默认
weight=1。 - 最少连接(Least Connections):发给活跃连接最少的机器,适合长连接、耗时差异大的场景。
- 一致性哈希(Consistent Hashing):把节点和请求都映射到同一个哈希环(0–2^32 区间),请求顺时针找最近节点。增删节点只影响相邻一小段,不像取模那样全量重映射,适合「同一用户固定打到同一台机器」的有状态场景(缓存、会话保持、分布式缓存分片)。可用虚拟节点(每个真实节点映射多个哈希点)缓解环上分布不均。
4. 高可用与容灾
4.1 多活架构
单机房是单点,挂了全站不可用。多活的目标是多个机房同时对外服务、互为备份:
- 同城双活:同城两机房距离近(延迟 <2ms),可做数据强一致同步,业务双写双读,任一机房故障秒级切换。代价是跨机房写放大延迟。
- 异地多活(单元化):跨地域,延迟大无法强一致,通常按用户维度切分——把用户哈希到固定地域单元,每单元数据自治、流量就近、单元内闭环。适合电商、支付这类「大部分请求只在本地单元内完成」的业务。难点在数据同步与路由(保证用户请求和它的数据在同一单元),以及跨单元事务(尽量避免,靠最终一致兜底)。
常考两个指标:RTO(Recovery Time Objective,故障后多久恢复)、RPO(Recovery Point Objective,最多丢多少数据)。同城双活 RPO≈0,异地多活 RPO 取决于同步策略,秒级到分钟级。
4.2 熔断 / 降级
一个慢调用能拖垮整条链路(级联故障、雪崩),两个核心手段:
- 熔断(Circuit Breaker):断路器三态:
- 关闭(Closed):正常放行,统计失败率/慢调用率;
- 打开(Open):失败率超阈值(如 50%),快速失败、直接返回兜底,不再打下游;
- 半开(Half-Open):冷却期后放少量探测请求,成功则关闭,失败则重新打开。
- 代表:Hystrix、Resilience4j、Sentinel、Envoy 的 circuit breaker。
- 降级(Degradation):主动关闭非核心功能保核心。大促时关推荐、关积分查询,只留下单支付。降级是主动的、可控的,熔断是被动的、自动的,两者常配合:熔断触发后返回的就是降级兜底结果。
4.3 限流
限流是保护系统不被突发流量打垮的第一道防线,控制「单位时间允许通过的请求数」。四种算法:
- 固定窗口计数器:时间切固定窗口(1s),窗口内计数超阈值拒绝。最简单,但有边界突刺:1s 前后各来满额请求,瞬间翻倍。
- 滑动窗口:窗口再细分格子,统计滚动时间内的请求数,更平滑更准。Redis 的 ZSET 记时间戳实现滑动窗口很常见。
- 漏桶(Leaky Bucket):请求进桶,桶以固定速率流出。强制恒定输出速率、能平滑突发,桶满即丢弃。
- 令牌桶(Token Bucket):固定速率放令牌,请求拿不到令牌就拒绝或等待。允许一定突发(桶里攒了令牌就能瞬间放行),最灵活,是 Guava RateLimiter、Sentinel 的默认思路。
选型:漏桶削峰、令牌桶允许突发。网关层常用令牌桶或滑动窗口;还有分布式限流(多实例共享全局计数,用 Redis 做)和分层限流(入口 → 服务 → 依赖隔离)。
4.4 灾备方案
- 冷备:备份数据存着,故障后恢复时间长、RTO 大,成本低。
- 温备:备机房有数据但没流量,故障后拉起服务、切 DNS 才接管,分钟级。
- 热备 / 双活:备机房常驻流量,随时接管,秒级切换(见 4.1)。
- 异地备份:定期把备份复制到异地,防机房级灾难(火灾、地震),是 RPO 的最后兜底。
一句话:RTO 决定你多久能活过来,RPO 决定你丢多少数据,灾备方案本质是在成本和这两个指标之间取舍。
5. 微服务架构
5.1 拆分策略
单体拆微服务两个方向:
- 按业务能力(垂直拆分):订单、商品、用户、支付各一个服务,对齐团队边界(康威定律——组织架构决定系统架构),是主流。
- 按技术 / 读写(水平拆分):CQRS 读写分离、冷热数据分离。
代价要认清:微服务不是银弹,它把单体内的「函数调用」变成「跨网络 RPC」,引入分布式事务、网络抖动、链路追踪、部署编排一堆新问题。团队小、业务简单时单体更快。拆分原则:高内聚低耦合、数据自治——每个服务私有自己的数据库,服务间只通过 API 交互,避免共享库,一个服务一个库是标配。
5.2 服务发现
服务实例是动态的(扩缩容、滚动发布、故障),调用方不能写死 IP。服务发现解决「服务名 → 可用实例列表」的映射,两大模式:
- 客户端发现(client-side):调用方自己拉注册表、自己选实例、自己负载均衡。代表 Dubbo、Spring Cloud + Eureka/Consul、gRPC naming resolver。优点少一跳网络;缺点每个客户端都要集成发现逻辑。
- 服务端发现(server-side):调用方只认一个固定入口(LB/网关),由它查注册表转发。代表 K8s Service + kube-proxy、云厂商 SLB。优点客户端零感知;缺点多一跳、中心组件成依赖。
注册中心核心指标:AP 还是 CP。Eureka 是 AP(宁可拿到过期实例也不拒服务,保护可用性);ZooKeeper、etcd、Consul 偏 CP。实践中 AP 更适合服务发现——过期实例列表比「注册中心不可用导致全部调用失败」危害小。健康检查靠心跳或主动探测,摘除不健康实例。
5.3 网关
网关是微服务统一入口,做认证鉴权、路由转发、限流、熔断、日志、协议转换、灰度发布。好处是把横切关注点收口到一处,服务本身不用每个都做鉴权限流。代价是网关成单点和性能瓶颈,要集群化 + 自身无状态。
代表:Spring Cloud Gateway、Kong、APISIX、Nginx/OpenResty。K8s Ingress 可看成一种七层网关。关系别搞混:服务发现找实例,负载均衡选实例,网关在它们之上做七层路由和策略。
5.4 链路追踪
一个请求横跨十几个服务,出错要知道卡在哪。三大块:
- Trace / Span:一次完整请求是一条 trace,其中每个服务调用是一个 span,span 靠 parent-child 串成调用树。
- 上下文传播:把
trace_id、span_id放进请求头(HTTP Header、RPC metadata)逐跳传递,是跨进程串起链路的关键。 - 采样:全量采集成本高,按比例采样(如 1%),异常请求强制采样。
标准是 OpenTelemetry(合并 OpenTracing 和 OpenCensus),概念对应 Dapper 论文。可观测性三支柱要分清:日志(logs)看单点发生了什么、指标(metrics)看整体趋势、链路(traces)看一次请求的完整路径。落地常用 Jaeger、Zipkin、SkyWalking。
5.5 Service Mesh
限流、熔断、重试、灰度、mTLS、可观测如果写进每个服务 SDK,升级一次要所有服务跟发版,语言还不统一。Service Mesh 把这层逻辑下沉到独立于业务的代理层:
- 数据面(Data Plane):每个实例旁跑一个 sidecar 代理(Envoy),拦截进出流量、执行治理策略,业务零侵入。
- 控制面(Control Plane):下发配置、管理证书、收集遥测(Istio 的 istiod)。
- 代表:Istio(最主流,Envoy + istiod)、Linkerd(Rust 写的轻量数据面)。
优点:业务无侵入、语言无关、策略统一。代价:每个请求多一跳 sidecar 带来延迟、资源翻倍、运维复杂度上升。追问「和网关的区别」:网关管南北向(外部进集群)流量,sidecar 管东西向(服务间)流量,两者常共存。还有 eBPF 化方向(Cilium Service Mesh、Istio ambient mode)想省掉 sidecar 的开销。
6. Kubernetes
6.1 架构组件
- 控制平面(Control Plane):
- kube-apiserver:唯一入口,所有组件和 kubectl 都通过它读写集群状态(REST API),无状态。
- etcd:强一致 KV 存储(Raft),保存集群所有状态,唯一有状态组件,集群的「事实来源」。
- kube-scheduler:只做一件事——决定 Pod 调度到哪个节点(不实际启动 Pod)。
- kube-controller-manager:跑一堆控制器(Deployment、ReplicaSet、Node 等),每个是「watch 期望状态 → 对比实际状态 → 调平」的循环。
- 工作节点(Worker Node):
- kubelet:节点管家,按 PodSpec 拉起容器,上报状态。
- kube-proxy:实现 Service 的流量转发(iptables/IPVS)。
- 容器运行时(Container Runtime):真正跑容器,Docker / containerd / CRI-O,通过 CRI 接口接入。
核心思想是声明式 + 控制器调平(reconcile loop):你声明「我要 3 个副本」,控制器不断对比实际和期望,缺了就补、多了就删。这是 K8s 和传统命令式运维的根本区别。
6.2 Pod 与生命周期
- Pod 是 K8s 最小调度单元,一个 Pod 可放一个或多个容器,共享网络命名空间(同一 IP)、共享存储卷、共享生命周期。通常一个主容器 + 若干 sidecar。
- 生命周期:
Pending → Running → Succeeded / Failed,中间有CrashLoopBackOff(反复崩溃重启)、Terminating(删除中)。探针决定何时就绪、何时重启:- livenessProbe(存活探针):失败则重启容器;
- readinessProbe(就绪探针):失败则把 Pod 从 Service 后端摘除,不接流量但不重启;
- startupProbe(启动探针):慢启动容器专用,通过前不执行另外两个探针。
- 高频坑:liveness 和 readiness 别搞反——readiness 失败只是「暂时不接流量」,liveness 失败才「杀掉重启」。探针阈值配太紧会导致容器刚启动就被反复杀掉。
6.3 Deployment 与工作负载
- Deployment:最常用的无状态工作负载,管理 ReplicaSet → Pod 层级,支持滚动更新(
maxSurge多起的副本数、maxUnavailable允许不可用的副本数)、回滚(kubectl rollout undo)。Deployment 只负责副本数和版本,ReplicaSet 才负责维持指定数量的 Pod 在跑。 - StatefulSet:有状态应用(数据库、MQ),给 Pod 稳定网络标识(
pod-name-0不变)、稳定存储(每个 Pod 绑自己的 PVC)、有序扩缩容(逐个启动/删除)。 - DaemonSet:每个节点跑一个 Pod(日志采集、监控 agent、网络插件)。
- Job / CronJob:一次性任务 / 定时任务。
6.4 Service
Pod 的 IP 是临时的(重启就变),Service 提供稳定的虚拟 IP(ClusterIP)和 DNS 名,通过 label selector 把流量转到匹配的 Pod 集合:
- ClusterIP:默认,集群内部访问。
- NodePort:每个节点开一个端口,把外部流量转到 ClusterIP,用于测试或简单暴露。
- LoadBalancer:云厂商分配外部 LB 转发到节点。
- 实现由 kube-proxy 落地:iptables 模式规则线性增长,IPVS 模式用哈希表性能更好。
- 关键机制:Service 只做四层转发,不解析 HTTP;kube-proxy watch Endpoints 感知 Pod 变化,readiness 失败的 Pod 被摘出 Endpoints。
6.5 Ingress
Ingress 是七层入口,按域名/路径把 HTTP 流量路由到不同 Service:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop
spec:
rules:
- host: shop.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
Ingress 本身只是一份路由规则声明,真正干活的是 Ingress Controller(nginx-ingress、Traefik、Istio ingressgateway)。「Ingress 没生效」多半是 controller 没装或没 watch 到规则。Ingress 对应南北向流量,管 L7 路由、TLS 终止、虚拟主机。
6.6 调度原理
kube-scheduler 把 Pod 放到合适节点,两阶段:
- 预选(Filtering):过滤掉不满足硬性条件的节点——资源不足、污点且无容忍(taint/toleration)、nodeSelector/亲和性不匹配、端口冲突、卷不可用。
- 优选(Scoring):给剩余节点打分,选最高的——资源最空闲(LeastRequested)、镜像已在本地(ImageLocality)、Pod 分散(PodAntiAffinity)、拓扑均衡。
约束手段:nodeSelector(硬性指定节点标签)、nodeName(直接指定节点,跳过调度)、亲和性/反亲和性(affinity,软硬两类)、污点与容忍(taint 打在节点上拒绝普通 Pod,toleration 让特定 Pod 能容忍)、资源请求与限制(requests 决定调度预留量,limits 是运行上限)。高频追问「requests 和 limits 的区别」:requests 用于调度和预留,limits 用于运行限制和驱逐,设反了会浪费节点资源或频繁 OOMKilled。
7. 常见问题整理
- 「服务发现用 AP 还是 CP」——优先 AP,可用性比注册信息短暂不一致更重要。
- 「分布式事务到底用哪个」——能最终一致就别上强一致,先消息表,资金库存再 TCC。
- 「Redis 分布式锁真的安全吗」——正确性敏感场景换 etcd,或加 fencing token。
- 「CAP 里 P 是可选的吗」——不是,P 是前提,只能 CP 或 AP。
- 「负载均衡选四层还是七层」——大流量入口用 LVS 四层扛量,业务路由用 Nginx/Envoy 七层。
- 「K8s 为什么能自愈」——声明式 + 控制器 reconcile loop,期望态和实际态不断对齐。