分布式、云原生与架构:从单体到能上线的系统
这篇覆盖 Java 企业级进阶路线 的阶段四、阶段五和阶段六:微服务与分布式、云原生与运维、架构设计与表达。它对应外部 java-full-stack 路线的阶段四到阶段六,是进阶路线的深水区。
先说结论:不要为了微服务而微服务。单体 + 模块化边界能撑到日活几十万;拆服务的理由是团队规模和独立部署需求,不是架构时髦。
服务拆开后多出来的问题
拆服务没有解决任何业务问题,只是新增了一类系统问题。拆之前先确认你能回答:
| 问题 | 单体里 | 拆开后 |
|---|---|---|
| 方法调用 | 进程内函数调用,微秒级 | 变成网络调用,毫秒级且会失败 |
| 事务 | 本地事务 | 分布式事务 / 最终一致性 |
| 配置 | 一个配置文件 | 配置中心 + 多环境 + 动态刷新 |
| 排查 | 一个堆栈 | 跨服务链路追踪 |
| 部署 | 一个包 | 多服务版本矩阵、兼容性问题 |
微服务组件:先懂职责再记名字
Spring Cloud 组件名常变,职责不变:
- 注册中心:服务上下线时谁感知(Nacos / Eureka / Consul)。
- 配置中心:配置集中管理、动态刷新(Nacos / Apollo)。
- 网关:统一入口、路由、鉴权透传、限流(Spring Cloud Gateway)。
- 熔断限流:故障不扩散(Sentinel / Resilience4j)。
分布式理论的最小工作集:CAP 里工程上通常取 CP(注册中心、分布式锁)或 AP(服务发现)不同侧面;BASE 是"基本可用、软状态、最终一致",是大多数业务系统的默认选择;Raft 是共识算法,ZooKeeper/etcd 的底层;分布式锁要考虑持有者宕机后的续期与释放(Redisson 的看门狗机制)。
幂等是分布式第一课:超时重试必然造成重复请求。每个写接口都要设计幂等键(业务唯一 ID + 状态机校验 + 去重表)。分布式事务优先用"本地消息表 / 事务消息 + 补偿"的最终一致方案,Seata 的 AT 模式适合内部低频场景,不要默认上。
DDD 的实用部分
领域驱动设计不必全套照搬,工程上最有用的三件事:
- 限界上下文:先按业务边界划模块(订单、库存、支付),模块间只走接口——即使最后不拆服务,这也是好的单体。
- 实体与值对象:有生命周期的用 Entity(订单),不可变的用值对象(金额、地址),减少可变共享状态。
- 充血 vs 贫血:把关键业务规则从 Service 挪回领域对象(
order.cancel()而不是orderService.cancel(order)),规则有了归属。
服务间通信:同步用 HTTP/OpenFeign(简单直接),异步用 MQ(解耦、削峰)。原则:查询走同步,状态变更通知走异步;调用方必须设超时、有限重试、降级预案。
容器化与部署
- Dockerfile:多阶段构建,基础镜像选 slim,用非 root 用户跑,显式声明 JVM 内存参数(
-XX:MaxRAMPercentage)适配容器配额。 - 健康检查:区分 liveness(进程活着,挂了重启)与 readiness(能接流量,没准备好先摘除)。Spring Boot Actuator 提供现成端点。
- 优雅停机:
server.shutdown=graceful,发布时在途请求处理完再退出。 - K8s 的定位:单机 Docker Compose 能撑到学习和小规模生产;多副本、弹性扩缩、滚动发布的需求出现时再系统学 K8s。资源请求/限制、HPA、滚动更新策略是三个核心概念。
Docker 细节见 Docker 与部署、Dockerfile 进阶、Docker Compose 网络。
可观测性:三根支柱
| 支柱 | 回答什么 | Java 落地 |
|---|---|---|
| 日志 Logs | 发生了什么 | 结构化日志 + trace_id 贯穿 + 集中收集(ELK / Loki) |
| 指标 Metrics | 系统健康趋势 | Micrometer + Prometheus + Grafana:QPS、P99 延迟、线程池、连接池、JVM、GC |
| 链路追踪 Tracing | 一次请求跨了哪些服务、慢在哪 | OpenTelemetry / SkyWalking |
排查线上问题的顺序:先看指标定位异常时间点和范围 → 用 trace_id 找到对应链路日志 → 深入具体服务代码。没有 trace_id 串起来的日志,跨服务排查就是大海捞针。
架构设计与表达
架构能力的核心不是画大图,而是讲清取舍。每个方案都要能回答:
- 性能:QPS 多少?瓶颈在计算、IO 还是外部依赖?缓存怎么加、热点怎么办?
- 可用:单点在哪?依赖挂了会怎样?降级方案是什么?(99.9% 意味着一年停机 8.7 小时。)
- 容量:连接数、线程池、数据库连接池怎么估?压测过吗?
- 安全:认证授权边界、越权防护、敏感数据脱敏、密钥管理。
- 演进:流量涨十倍,先动哪一层?哪些现在不做,触发条件是什么?
多租户(SaaS)场景额外回答数据隔离策略:独立库(隔离最强、成本最高)、独立 schema、共享表 + tenant_id 字段(最常用,但所有查询和索引都要带租户条件,最容易漏检索和后台导出)。
面试表达的最小结构:问题背景(一句话)→ 核心链路(一张图)→ 两个关键取舍及理由 → 一个已知风险和应对。3 分钟讲完,比堆砌技术名词有说服力。
阶段自检
- 你能说出拆服务的两个真实理由和两个不该拆的理由吗?
- 一次请求超时后,你的重试 + 幂等设计能保证状态不错吗?
- 线上接口 P99 突增,你的排查第一步看什么?
- 你能用 3 分钟讲清当前项目的核心链路和两个风险吗?
下一步
- Java 招聘要求怎么判断:反查岗位能力缺口。
- Agent 可观测性:AI 服务的可观测性扩展。
- Java 调用 Python Agent 服务:与 AI 服务集成的跨语言场景。
来源与授权说明
本篇吸收并改写自 umlink/java-full-stack 阶段四(微服务架构与分布式系统)、阶段五(云原生与运维工程)、阶段六(架构设计与服务端思维)的主题结构,已取得作者授权。原项目采用 MIT License。