我在公司用Spring Cloud重构老项目的那些事

Data开发者
2026-11-13 20:31
阅读 786

在这家公司待了三年多,手上的单体项目从两万行膨胀到十几万行,每次改订单模块都要重新打包部署。最近动了跳槽心思,刷招聘JD发现微服务几乎成了标配,索性跟leader提了重构方案,拿老项目练手。

先交代背景。我们做电商中台,订单、库存、用户、支付全塞在一个Spring Boot单体里,单库打天下。大促期间库存扣减接口响应飙到4秒多,数据库连接池被打满,用户直接超时。那晚盯着Grafana监控面板,CPU曲线跟心电图似的,就一个念头:这玩意儿不改,下次大促还得通宵救火。

为什么选Spring Cloud

Dubbo、gRPC各有各的好,但Spring Cloud胜在生态全。团队Java栈为主,Spring Boot本来就熟,上Spring Cloud几乎是零学习成本。版本选了Spring Cloud 2023.0.x对应Spring Boot 3.2.x,JDK升到17。生产环境求稳,不追最新版。

拆服务思路很朴素:按业务域切。订单、库存、用户、支付四个服务先拆出来,每个服务独立数据库。数据库拆分最痛苦,原来十几张表外键关系错综复杂,跨服务数据一致性只能靠最终一致性方案扛。能异步的绝不同步。订单创建先落本地库,发消息通知库存服务扣减,处理完再回写订单状态。中间态靠状态机驱动,配合定时任务补偿。

核心组件落地

网关选了Spring Cloud Gateway,没用Zuul。Gateway基于WebFlux,吞吐量确实能打。路由配置写在Nacos里,动态刷新不用重启。不过断言和过滤器链写起来真啰嗦,一个鉴权过滤器写了一百多行,大部分在处理异常分支。

服务注册发现用Nacos,没选Eureka。Eureka 2.0停止开发后社区活跃度明显下降。但Nacos客户端有时会抽风,服务下线后要十几秒才能感知,期间请求打过去就报连接超时。后来在Spring Cloud LoadBalancer配置里加了重试机制,配合Nacos主动下线接口,勉强把影响控制在可接受范围。

配置中心也用的Nacos,原来散落在各application.yml里的配置全迁过去,改配置不用重新发版。但配置文件多了之后也乱,建议从一开始就定好命名规则,不然找配置跟大海捞针一样。

性能优化是重头戏

拆服务后进程内调用变成RPC,网络开销实打实。订单创建链路变成网关→订单服务→库存服务→订单服务→网关,来回四跳。压测TPS从800掉到500多,当时心里凉了半截。后来做了几件事把性能拉回来:

第一,库存扣减从同步调用改成异步消息驱动。用户下单先返回"处理中",扣减结果通过WebSocket或轮询通知前端。订单服务响应时间从800ms降到200ms以内,用户体验反而好了。当然这要求前端配合改交互,跟产品经理沟通了好几轮才同意。

第二,数据库层面下功夫。拆库后每个服务一个库,MySQL连接数成了新瓶颈。后来把订单和库存两个高频服务的数据库换成TiDB,兼容MySQL协议,水平扩展能力好。迁移踩了坑:TiDB对某些SQL的优化器和MySQL不完全一致,一个用了FOR UPDATE的库存扣减SQL在TiDB上死锁概率明显升高。改成乐观锁加版本号重试后问题解决。

第三,缓存该上的都上。Redis Cluster部署,商品信息、用户基础信息全缓存。注意缓存穿透和雪崩,空值缓存和随机过期时间都用上了。Redis Cluster运维比单机复杂太多,节点故障转移逻辑必须搞清楚。

扯点题外话:AI在微服务里的角色

公司内部在推AI能力落地,说两个方向。一个是vLLM部署的私有化大模型,用来做智能客服和订单异常诊断。vLLM推理吞吐比HuggingFace原生推理快一个量级,PagedAttention的显存管理确实有一手。但部署在Kubernetes里对GPU资源调度要求高,搞了快两周才把显存碎片问题压下去。

另一个是AI Agent,用大模型驱动自动处理运维告警。比如慢查询告警来了,Agent自动拉取日志分析,给出优化建议甚至直接提PR。实际用下来Agent经常给出看似合理实则离谱的建议,比如建议把整个表删了重建。所以目前只让它做告警归类和初步分析,动手的事还是人来。

踩坑记录

Feign超时配置。默认超时时间很短,稍慢的接口就报Read timed out。记得显式设置connectTimeout和readTimeout。之前有个报表接口查询要两三秒,Feign默认1秒超时,线上疯狂报错,排查半天才发现。

服务间调用的事务问题。千万别以为@Transactional能跨服务生效。库存扣减失败回滚了,订单服务的事务不会跟着回滚。必须自己设计补偿机制或用Seata。我们选了最终一致性加补偿,比Seata轻,但代码复杂度上去了。

数据库连接池配小了。HikariCP默认最大连接数10,微服务场景根本不够用。压测发现连接池等待时间占比很高,后来把maximumPoolSize调到50,配合数据库连接数上限合理分配。每个服务根据QPS调,别拍脑袋。

日志链路追踪。服务拆多后一个请求跨好几个服务,定位问题极其痛苦。SkyWalking或Zipkin必须上。我们用SkyWalking,接入成本低,链路图直观。

总结

整个重构从方案设计到上线跑稳定花了大概三个月,经历两次大促考验,订单接口P99从2.8秒降到600ms左右,数据库压力也分散了。微服务不是银弹,复杂度从代码层转移到了运维层。服务多了之后部署、监控、日志、链路追踪必须跟上,否则就是给自己挖坑。

给想入坑的朋友几个建议:别一上来拆太细,按业务域粗粒度拆就够;基础设施先搭好再动代码;数据库拆分最难,提前想清楚数据一致性问题。Spring Cloud学起来不难,难的是在生产环境把它玩明白。共勉。

评论 0

最热最新
暂无评论
Data开发者Lv.1
0
影响力
0
文章
0
粉丝
聊天室