Interview Prep

分布式与云原生复习笔记

从 CAP 定理到 Kubernetes,从负载均衡到 Service Mesh,整理分布式系统与云原生的常见主题。

分布式与云原生复习笔记

这份笔记整理分布式系统与云原生的常见主题,覆盖从单机到集群的演进路径:CAP / BASE、分布式事务、幂等性、分布式 ID,到 Raft / Paxos 一致性算法,再到负载均衡、高可用与容灾、微服务架构,最后是 Kubernetes 容器编排与服务网格。

主要模块:

  • 分布式系统基础:CAP、BASE、分布式事务、幂等性、分布式 ID
  • 一致性算法:Raft 与 Paxos 的对比
  • 负载均衡:四层 vs 七层、LVS / Nginx / Envoy
  • 高可用与容灾:多活架构、熔断降级、限流、灾备方案
  • 微服务架构:拆分策略、服务发现、网关、链路追踪、Service Mesh
  • Kubernetes:Pod、Deployment、Service、Ingress、调度原理
  • 常见问题整理

INTERACTIVE REVIEW

分布式与云原生交互式复习站

把 CAP、Raft/Paxos、负载均衡、微服务、Kubernetes 和容灾链路做成按主题切换的复习台。

打开完整演示
在文中展开演示

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(两阶段提交)——强一致、同步阻塞:

  1. 准备阶段:协调者向所有参与者发 prepare,各参与者执行事务但不提交,undo/redo 日志落盘,返回 ready 或 no。
  2. 提交阶段:全部 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 的锁)。主流实现:

  • RedisSET 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 学习者)和两阶段描述:

  1. Prepare:proposer 发带编号 n 的 prepare,acceptor 承诺不再接受编号小于 n 的提案,并返回它已接受的最高编号提案。
  2. 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

维度PaxosRaft
可理解性难,角色状态多好,拆成三个子问题
领导者Multi-Paxos 才有稳定 leader天然强 leader
日志允许乱序、有空洞严格连续、强制顺序
成员变更复杂联合共识(joint consensus)两步切换
工程实现Chubby、Spanneretcd、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_idspan_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 放到合适节点,两阶段:

  1. 预选(Filtering):过滤掉不满足硬性条件的节点——资源不足、污点且无容忍(taint/toleration)、nodeSelector/亲和性不匹配、端口冲突、卷不可用。
  2. 优选(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,期望态和实际态不断对齐。