🎓 总站 🏠 本课目录 01 概论 02 虚拟化 03 云原生 04 K8s基础 05 K8s进阶 06 消息队列 07 分布式存储 08 分布式文件系统 09 并行编程 10 Spark
云计算技术 · 第3章

云原生基础与微服务

从 CNCF 定义与四大要素出发,理解 12 要素应用、单体到微服务的演进、服务拆分/通信/发现/治理,以及熔断、限流、降级等容错模式。

📚 学习进度
0%

🎯学习目标

  • 掌握 CNCF 对云原生的定义及四大核心要素;
  • 了解 12 要素应用(12Factor App)的核心原则;
  • 对比单体架构与微服务架构,理解服务拆分策略与原则;
  • 掌握微服务通信方式(REST / gRPC / 消息队列)及选型;
  • 理解服务注册与发现、负载均衡、API 网关;
  • 掌握熔断器、限流、降级等容错模式与 Docker Compose 编排。

1云原生的定义(CNCF)

CNCF(Cloud Native Computing Foundation)官方定义:云原生技术使组织能够在公有云、私有云和混合云等现代动态环境中,构建和运行可弹性扩展的应用。代表技术包括容器、服务网格、微服务、不可变基础设施和声明式 API。这些技术能够构建容错性好、易于管理和便于观察的松耦合系统,结合可靠的自动化手段,使工程师能够轻松对系统进行频繁且可预测的重大变更。

拆解理解:
Cloud:应用长在云上(具备云计算五大本质:按需自服务、弹性扩展、资源池化、网络访问、按量计费);
Native:应用从写代码第一天起,就是为适应云环境而设计的。

💡 CNCF 简介2015 年成立,托管超过 160+ 个云原生开源项目。代表项目:Kubernetes、Prometheus、Envoy、Helm、Istio。生态分层:应用编排(K8s)→ 微服务通信(Istio/Envoy)→ 可观测性(Prometheus/Grafana/Jaeger)→ CI/CD(ArgoCD/Tekton)→ 容器运行时(Containerd/CRI-O)。

2四大核心要素 ⭐

📦

容器化

Containerization
应用及依赖打包为容器镜像,确保环境一致性。价值:可移植、快速部署
🧩

微服务

Microservices
将应用拆为小型、独立的服务,每个专注单一业务功能。价值:独立开发/部署/扩展
📝

声明式 API

Declarative APIs
用户声明期望状态,系统自动实现和维护。价值:简化运维、自动化管理
🧊

不可变基础设施

Immutable Infra
组件部署后不再修改,更新通过替换而非修补。价值:环境一致、可审计

可变 vs 不可变基础设施

对比可变基础设施不可变基础设施
更新方式SSH 登录服务器手动修改构建新镜像,滚动替换
环境一致性低(易配置漂移、"雪花服务器")高(镜像统一)
回滚困难简单(用旧版本镜像)
可审计性强(镜像版本化管理)

3十二要素应用(12Factor App)

由 Heroku 联合创始人 Adam Wiggins 于 2011 年提出,为构建现代 SaaS 应用提供最佳实践指南。

要素核心思想
基准代码 Codebase一份代码库对应多份部署
依赖 Dependencies显式声明并隔离依赖
配置 Config ⭐将配置存储在环境变量中(K8s ConfigMap / Docker 环境变量)
后端服务 Backing Services把后端服务当作附加资源
构建/发布/运行严格分离构建和运行阶段
进程 Processes ⭐以无状态进程运行(反模式:Session Sticky 会话粘滞)
端口绑定 Port Binding通过端口绑定提供服务
并发 Concurrency通过进程模型横向扩展
易处理 Disposability ⭐快速启动、优雅终止(SIGTERM 后完成当前请求再退出)
开发/生产等价 ⭐尽可能保持各环境一致(Docker + CI/CD)
日志 Logs把日志当作事件流
管理进程后台管理任务作为一次性进程运行

4单体架构 vs 微服务架构 ⭐

单体架构:一个紧密耦合的整体,开发快、部署简单,但难以独立扩展和迭代。
微服务(Martin Fowler & James Lewis, 2014):将应用构建为一组小型、自治的服务,每个围绕特定业务能力构建,独立部署,通过轻量级机制(通常 HTTP API)通信。

单体架构 微服务架构 用户模块 订单模块 商品模块 共享数据库 用户服务DB 订单服务DB 商品服务DB 支付服务DB 库存服务DB API 网关 每服务独立部署·独立数据库(Database per Service)
图1 · 单体(共享库、整体部署)vs 微服务(独立服务、独立数据库、API 网关入口)

核心特征与对比

维度单体架构微服务架构
代码组织所有功能一个代码库每个服务独立代码库
部署整体打包部署各服务独立部署
扩展整体扩展按需扩展特定服务
技术栈统一可混合多语言/框架(技术异构)
数据库共享数据库每服务独立数据库
故障影响一模块故障可能整体崩溃单服务故障不影响整体
开发速度初期快、后期急剧变慢初期慢(基础设施复杂)、后期持续高效

微服务核心特征:单一职责、独立部署、独立扩展、技术异构、轻量级通信、去中心化治理、去中心化数据(Database per Service)、容错设计(熔断/降级/重试)。

5服务拆分策略与原则

如何确定服务边界?

  • ① 按业务领域拆分(DDD):基于领域驱动设计的限界上下文(Bounded Context),每个上下文对应一个微服务。例:电商系统 = 用户服务 + 商品服务 + 订单服务 + 支付服务 + 库存服务。
  • ② 按数据边界拆分:每服务拥有自己的数据库,服务间不直接访问对方数据库,通过 API 或事件交换数据。
  • ③ 按变更频率拆分:变更频率高的功能独立为服务,稳定功能保持在一起。

拆分原则

原则说明
高内聚相关功能放在同一服务内
低耦合服务间依赖最小化
可独立部署改一个服务不需重新部署其他服务
适当粒度既不过粗(变成小单体)也不过细(网络开销大)
💡 拆分后的新痛点① 微服务之间如何通信?② 如何定位到想要的微服务?③ 微服务崩了怎么办?④ 怎么防止微服务崩溃?这引出后续的通信、服务发现、熔断/降级等机制。

6微服务通信方式:REST vs gRPC

前端/客户端 服务 A微服务 服务 B微服务 REST/JSON (对外) gRPC/Protobuf (对内)
图2 · 通信选型:对外用 REST/JSON(人类可读、浏览器友好),对内用 gRPC/Protobuf(高性能)

同步通信

对比RESTgRPC
协议HTTP/1.1(文本)HTTP/2(二进制帧)
数据格式JSON(可读性好)Protobuf(二进制,体积小 3~10 倍)
接口定义OpenAPI/Swagger(可选).proto 文件(强制 IDL)
代码生成可选自动生成多语言客户端/服务端
流式不原生支持支持四种模式(含双向流)
浏览器完美支持需 gRPC-Web 代理
适用对外 API、Web 前端调用内部微服务间高性能通信
syntax = "proto3";
service UserService {
  rpc GetUser (GetUserRequest) returns (User) {}
  rpc ListUsers (ListUsersRequest) returns (stream User) {}   // 服务端流式
}
message GetUserRequest { string user_id = 1; }
message User { string id = 1; string name = 2; string email = 3; }

异步通信:消息队列

以消息队列为核心(Kafka、RabbitMQ),将生产者消息暂存并异步交付给消费者,实现服务解耦。优势:削峰填谷、保障最终一致性。适用于事件通知、异步处理、跨服务数据同步。

7服务发现与注册

微服务实例 IP/端口动态变化(扩缩容、故障重启、迁移),硬编码地址行不通,需动态发现服务位置。

模式核心流程优点缺点
客户端发现服务 A 直接查注册中心拿实例列表,本地负载均衡后调用无额外网络跳转、延迟低客户端需集成发现/负载逻辑,与语言耦合
服务端发现服务 A 请求发给网关/负载均衡器,由其查注册中心并转发客户端逻辑简单、语言无关、策略统一多一跳延迟,网关需高可用

主流服务注册中心

注册中心一致性模型特点
etcd强一致(Raft)K8s 默认使用,键值存储
Consul强一致(Raft)内置服务发现、健康检查、KV
ZooKeeper强一致(ZAB)老牌,配置管理
NacosAP/CP 可切换阿里开源,服务发现 + 配置管理

8负载均衡

将流量/负载分发到多个实例,提高可用性、提升性能、避免单点过载。

算法原理适用场景
轮询 Round Robin按顺序依次分发实例性能相同
加权轮询按权重比例分发实例性能不均
最少连接分发到连接数最少的实例长连接场景
随机随机选择简单场景
一致性哈希相同请求哈希到相同实例缓存命中率优化
IP 哈希按客户端 IP 哈希Session 亲和性
层次层级说明
L4 负载均衡TCP/UDP 层基于 IP+端口转发,速度快
L7 负载均衡HTTP 层基于 URL/Header 智能路由,功能丰富

9容错模式:熔断 / 限流 / 降级 ⭐

问题:级联故障(雪崩效应)

A 调 B、B 调 C,若 C 崩溃 → B 线程阻塞 → 线程池耗尽 → A 也阻塞 → 整条链路崩溃。

熔断器三种状态

关闭Closed 正常 打开Open 熔断 半开HalfOpen 探测 失败率超阈值 超时后试探 探测成功→恢复
图3 · 熔断器状态机:Closed → (失败率超阈值) → Open → (超时) → HalfOpen → (成功) → Closed
状态行为
关闭 Closed正常转发,统计失败率;失败率达阈值切到 Open
打开 Open直接返回降级响应(fast-fail),不调用下游;超时后进入 HalfOpen
半开 HalfOpen放少量探测请求;成功则 Closed,失败则回 Open
⭐ 熔断器关键参数失败率阈值(50%)、统计窗口(10 秒)、最少请求数(20 次)、熔断持续时间(30 秒)、半开允许请求数(5 次)。

配套容错模式

重试 Retry(配合指数退避)、超时 Timeout(防长时间阻塞)、舱壁 Bulkhead(资源隔离,独立线程池/连接池)、降级 Fallback(返回默认值或缓存)。

限流算法

算法原理特点
固定窗口计数器窗口内计数,超阈值拒绝简单,有边界突刺问题
滑动窗口计数器滑动窗口平滑限流更平滑
令牌桶 Token Bucket固定速率生成令牌,请求消耗令牌允许突发流量
漏桶 Leaky Bucket请求入桶,固定速率流出严格平滑流量

降级策略

返回默认值(推荐服务降级→热门商品)、返回缓存(用户画像降级→缓存画像)、功能裁剪(高峰关闭评论/推荐)、流量排队(秒杀排队)。

10API 网关与 Docker Compose

API 网关

微服务架构的统一入口,接收所有客户端请求,进行路由、认证、限流、协议转换后转发到后端微服务。功能:请求路由、认证鉴权、限流熔断、负载均衡、协议转换(外部 REST → 内部 gRPC)、请求聚合、日志监控。

Docker Compose 多容器编排

用于定义和运行多容器 Docker 应用,使用 YAML 描述服务、网络和卷,一次声明、一键拉起整个集群docker-compose up)。五大顶级 key:services、networks、volumes、configs、secrets。

services:
  gateway:
    build: ./gateway
    ports: ["8080:80"]
    depends_on: [userservice]
    networks: [frontend, backend]
  userservice:
    image: user:latest
    environment: [DB_HOST=userdb]
    networks: [backend]
  userdb:
    image: postgres:15
    volumes: [./data:/var/lib/postgresql/data]
    networks: [backend]
networks:
  frontend:            # 外部可访问
    driver: bridge
  backend:             # 内部服务网络
    driver: bridge
    internal: true     # 禁止外部访问
💡 Compose 服务发现Compose 自动创建默认网络(项目名_default),同网络容器可通过服务名直接通信(Docker 内置 DNS)。例:userservice 容器可直接用 userdb:5432 访问数据库。

重点例题

例题1:REST 还是 gRPC? 问:什么场景选 gRPC 而非 REST?反之呢? 答:选 gRPC:微服务内部高性能通信、强类型契约、需要流式传输(Protobuf 体积小、HTTP/2 多路复用)。选 REST:对外 API、Web 前端/浏览器调用、需要人类可读、生态成熟(基于 HTTP/JSON)。
例题2:推荐服务(非核心)崩了,订单服务(核心)怎么办? 问:设计降级策略保证核心下单不受影响。 答:对推荐服务调用加熔断器:当失败率超阈值(如 50%)熔断打开,订单页直接走降级——返回默认的"热门商品"或缓存推荐,不阻塞下单主流程;配合超时舱壁隔离,避免推荐服务拖垮订单线程池。下游恢复后熔断器半开探测,成功则恢复正常调用。
例题3:电商系统微服务拆分 问:基于 DDD 限界上下文,给电商系统拆分至少 5 个微服务。 答:用户服务、商品服务、订单服务、支付服务、库存服务——每个对应一个限界上下文、拥有独立数据库(Database per Service),遵循高内聚、低耦合、可独立部署、适当粒度原则。

🎯自测(点击展开)

云原生的四大核心要素是什么?
容器化、微服务、声明式 API、不可变基础设施。
12 要素中"配置"应该存在哪里?
环境变量中(而非硬编码),实践如 K8s ConfigMap、Docker 环境变量,便于同份代码跑多环境。
微服务为什么要"去中心化数据"?
每服务独立数据库(Database per Service),服务间不直接访问对方数据库,保证解耦与独立演进、避免单点故障扩散。
熔断器三种状态及转换?
Closed(正常,失败率超阈值→Open)、Open(熔断快速失败,超时→HalfOpen)、HalfOpen(探测,成功→Closed,失败→Open)。
限流的令牌桶和漏桶有何区别?
令牌桶固定速率生成令牌、桶满时允许突发流量;漏桶以固定速率流出、严格平滑流量。
Docker Compose 中容器如何互相找到对方?
同一默认网络内通过服务名直接通信(Docker 内置 DNS 自动解析),无需手动配置 IP。

📝强化题库

选择题点选即时判分;填空题输入后"检查"或"显示答案"。

已答 0/0答对 0正确率
已答 0/0答对 0