
这是老梁。
我在架构圈摸爬滚打十几年,带过几个人捣鼓的创业项目,也救火过日活千万级的庞大系统。见得多了,就发现一个残酷的真相:90%的系统崩盘,不是因为技术太弱,而是因为架构太贪。
很多兄弟在面试时把微服务吹得天花乱坠,一进公司落地就这就是灾难:服务拆得稀碎,一个请求跨十几个服务,延迟爆炸;分布式事务搞不定,账目无论如何对不上;排查一个Bug,日志在ELK里翻半天找不到头绪。
今天咱们不聊虚的,我把压箱底的经验拿出来,给你复盘一下:一个系统从单体到集群,再到微服务的真实演进路径。我会告诉你每个阶段的痛点在哪里,用什么算法和技术去填坑。
这篇文章,建议你收藏,无论是做架构决策、解决生产故障,还是去面大厂的架构岗,都能用得上。
第一阶段:单体架构—— 别看不起它,它是赚钱机器
别一上来就整微服务。如果你的团队不到5个人,日活不到1万,强上微服务就是找死。单体架构是代码在内存中互调,没有网络开销,没有序列化损耗,它是性能的王者。
但单体怎么写,决定了你以后能不能拆得动。
1. 核心痛点与解决:代码腐化
很多单体项目后期变成了“大泥球(Big Ball of Mud)”,Controller调Service,Service之间随意乱调,甚至直接在Controller里写SQL。
架构师策略:模块化单体(Modular Monolith) 在这一阶段,虽然物理上是一个Jar包,但逻辑上必须严格隔离。
- 战术落地:利用Maven多模块(Module)或严格的包结构(Package)隔离。
- 设计原则:严格遵循 DDD(领域驱动设计)的界限上下文(Bounded Context)。
- 比如
OrderService绝对不能直接注入UserMapper去查库。 - 必须通过
UserService暴露的接口获取数据。 - Why? 这样未来拆分时,只需要把
UserService这个接口改成 Feign Client,业务逻辑一行都不用动。
- 比如
2. 这里的技术栈
- 核心:Spring Boot / GoFrame
- 数据库:MySQL(单机)
- 缓存:LocalCache (Guava/Caffeine) + Redis
第二阶段:集群架构(Cluster)—— 流量来了,怎么扛?
当你的单机 CPU 经常飙到 80%,或者单点故障导致半夜被叫醒重启服务时,你就该上集群了。 集群的本质是:水平扩展(Scale-out)。代码不用大改,部署多份,前面挡一层负载均衡。
但这个时候,原本在单机里不是问题的问题,全都冒出来了。
1. 难点一:会话丢失(Session Stickiness)
单机时,用户登录态存在 HttpSession(内存)里。上集群后,用户请求第一次打到机器A,第二次被Nginx分发到机器B,B没有内存数据,用户被迫下线。
技术选型与原理:
| 方案 | 原理 | 评价 |
|---|---|---|
| Session 复制 | Tomcat之间广播Session | 垃圾。节点多了广播风暴会把内网带宽吃光。 |
| Session 粘滞 | Nginx ip_hash 算法 | 鸡肋。由于企业内网出口IP相同,会导致某台服务器流量倾斜;且机器宕机用户必掉线。 |
| 分布式 Session | Spring Session + Redis | 正解。状态下沉到Redis,服务变成无状态(Stateless)。 |
2. 难点二:数据库读写瓶颈
应用能扩展,数据库还是单点。写库如果锁表,读请求全卡死。
技术攻坚:读写分离(Read-Write Splitting)
- 架构:一主(Master)多从(Slave)。写请求走Master,读请求走Slave。
- 底层原理:MySQL Binlog 异步复制。
- 致命坑:主从延迟(Replication Lag)
- 场景:用户刚注册(写Master),立马自动登录(读Slave)。由于Binlog同步有毫秒级延迟,Slave还没数据,提示“用户不存在”。
- 算法/策略:
- 强制路由:对于即时性要求极高的读(如刚写入后的读取),代码层强制路由到主库。
- 缓存标记法:写入后在Redis打个标,读取时发现有标,就走主库,没标走从库。
3. 难点三:缓存一致性(Cache Consistency)
这是一个面试必问、工作必坑的点。数据库改了,缓存怎么删?
架构师铁律:Cache-Aside Pattern(旁路缓存模式)
- 读:先读缓存;命中返回;未命中读DB,回写缓存。
- 写:先更新DB,再删除缓存(注意是删除,不是更新!)。
- Why删除? 更新缓存容易产生脏数据(并发写时顺序不可控)。
- Why先更DB? 保证数据落盘是第一优先级。
- 高级坑:删缓存失败了怎么办?
- 解决方案:Binlog 异步淘汰。订阅MySQL Binlog(使用 Canal),投递到 MQ,由消费者专门负责重试删除Redis,保证最终一致性。
第三阶段:分布式微服务架构(Microservices)—— 治理复杂度的战争
什么时候上微服务? 不是因为QPS高,而是因为人多。 当50个后端开发在一个Git仓库里提交代码,Merge Conflict 就要花半天;当改一个“修改头像”的功能,却要整个系统停机发布;当“订单服务”需要扩容,却被迫连着“后台管理”一起扩容时。 微服务,是为了解决研发效率和独立部署的问题。
进入微服务,你面对的不再是代码逻辑,而是分布式系统的八大谬误。
1. 核心技术选型:Spring Cloud Alibaba 战队
我们要构建的是一套生态,目前国内最稳的选型:
- 注册中心/配置中心:Nacos(CAP理论中支持AP/CP切换,性能吊打Eureka)。
- 流量网关:Spring Cloud Gateway(基于WebFlux,响应式编程)。
- RPC调用:Dubbo(高性能) 或 OpenFeign(Http协议,生态好)。
- 熔断限流:Sentinel。
- 分布式事务:Seata 或 RocketMQ。
2. 难点一:服务发现与负载均衡算法
服务A要调服务B,B有100个实例,IP随时变。
- 底层原理:
- 注册:B启动时把IP:Port写入Nacos。
- 心跳:B每5秒发心跳,Nacos没收到就剔除。
- 拉取:A本地缓存一份B的实例列表(避免每次查Nacos)。
- 负载均衡算法(Load Balancing):
- Round Robin(轮询):简单,但没考虑机器性能差异。
- Least Active(最小活跃数):Dubbo默认。谁处理得快,就多给谁发请求。这在生产环境最实用,能自动平滑慢节点的问题。
- Consistent Hashing(一致性哈希):用于有状态服务,保证同一参数请求打到同一台机器。
3. 难点二:分布式事务(Distributed Transaction)
这是微服务的最大噩梦。单体的 @Transactional 在跨服务调用时失效。
实战流派对比与选择:
| 方案 | 适用场景 | 复杂度 | 性能 |
|---|---|---|---|
| XA / 2PC | 强一致性要求,银行核心 | 极高(锁资源长) | 差 |
| Seata (AT模式) | 业务并发不高,不想改代码 | 低(框架代理) | 中(依赖全局锁) |
| TCC | 高并发,对一致性要求极高 | 高(要写Try/Confirm/Cancel三个方法) | 高 |
| MQ 最终一致性 | 互联网主流选择 | 中 | 极高 |
架构师推荐方案:本地消息表 + MQ(可靠消息最终一致性) 这是大厂处理高并发资金流转的标准姿势,一定要掌握。
- 逻辑分解:
- 上游(订单服务):开启本地事务,插入订单表,同时插入一张“消息发送表”(状态:待发送)。这一步是原子的。
- 异步发送:一个独立线程轮询“消息发送表”,把消息投递到MQ。
- 下游(积分服务):消费MQ,增加积分。
- 幂等性(Idempotency):下游必须要防重!利用Redis或数据库唯一索引,保证同一条消息只处理一次。
- 兜底:如果下游处理失败,MQ会自动重试。如果死信,人工介入。
4. 难点三:雪崩效应与熔断(Circuit Breaker)
服务B挂了,服务A还在疯狂调B,导致A的线程池被耗尽,A也挂了。A的调用方C也就挂了。全线崩溃。
技术解法:Sentinel / Hystrix
- 核心逻辑:
- 熔断:当错误率达到阈值(如50%),断路器打开(Open)。后续请求直接返回失败,不再调B。
- 半开(Half-Open):过5秒,放一个请求过去试探。如果成功,关闭断路器;失败,继续打开。
- 限流算法(Rate Limiting):
- 令牌桶(Token Bucket):以恒定速率放令牌,请求拿令牌。允许突发流量。
- 漏桶(Leaky Bucket):以恒定速率处理请求。平滑流量。
- 实战建议:一般网关层用令牌桶应对突发流量,内部核心服务用漏桶保护数据库。
5. 难点四:全链路追踪(Observability)
微服务上线后,用户报障:“我点不下单”。请求经过了网关->订单->库存->支付。你根本不知道断在哪。
技术栈:SkyWalking / Jaeger
- 原理:TraceID 透传。
- 请求一进网关,生成一个全局唯一的
TraceID。 - 通过 HTTP Header 或 RPC Context,把这个 ID 一层层传下去。
- SkyWalking Agent 字节码增强,自动采集调用耗时、SQL语句、异常栈。
- 最终在 UI 上呈现一个完整的调用链路图(Flame Graph)。
- 请求一进网关,生成一个全局唯一的
架构师总结:如何做决策?
最后,作为架构师,我想给你一个决策矩阵:
- 初创期(0-1):毫不犹豫选单体(Modular Monolith)。活下去比架构完美更重要。别搞微服务,除非你想把公司搞黄。
- 增长期(1-10):集群 + 读写分离 + Redis缓存。这是性价比最高的优化手段,能抗住绝大多数中型互联网公司的流量。
- 爆发期(10-100):当你的团队规模超过20人,或者业务领域(订单、支付、用户)极其复杂且独立时,再考虑微服务。
记住:架构是演进出来的,不是设计出来的。 能用简单的技术解决问题,才是真正的技术大牛。
