微服务系列(一) 我们的WMS单体应用终于扛不住了

news2026/4/17 1:42:54
我们的 WMS 单体应用终于扛不住了副标题从一个 200 万行代码的 Spring Boot 项目说起一、那个让人崩溃的周五你有没有经历过这种周五去年双十一前夜我们团队还在加班。产品经理急匆匆地跑来“出库规则要改客户临时要求把优先发货仓库从 A 仓换成 B 仓”我心想这不就是改个配置嘛分分钟的事。结果一翻代码傻眼了——出库规则散落在七八个类里有的写在Service里有的埋在Mapper的 SQL 里还有一段祖传逻辑躲在某个叫OutStockUtilV2的工具类中。改完一处IDE 的引用分析显示还有 23 处调用。更可怕的是其中 3 处是反射调用的IDE 根本搜不到。“全量回归测一下吧。” 测试同学淡淡地说。3 天。就为了一个仓库优先级的调整我们测了整整 3 天。期间还顺手修了两个因为改一行崩三处引发的 Bug。那天晚上我坐在工位上看着 Jenkins 上那个跑了 2 小时 17 分钟的发布流水线陷入了沉思这系统是不是该动大手术了二、我们的 WMS 长什么样先给不熟悉 WMS 的朋友科普一下WMS 就是仓库管理系统Warehouse Management System。咱们这套系统服务了公司 20 多个仓库日均 10 万单大促峰值能冲到 50 万单。说白了它的核心工作就这几件事入库货来了验收入库上架出库订单来了拣货、打包、发运库存实时算库存别让超卖把老板坑了库内作业盘点、移库、补货这些脏活累活基础资料商品、仓位、客户信息报表给老板看的各种数据大屏那它的技术架构长啥样呢我用文字给你画一张简图┌─────────────────────────────────────┐ │ 前端页面JSP jQuery │ │ 前后端还没分离呢 │ └─────────────┬───────────────────────┘ │ ┌─────────────▼───────────────────────┐ │ 单体 Spring Boot 应用 │ │ 200 万行代码一个 fat jar │ │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ 入库模块 │ │ 出库模块 │ │ 库存模块 │ │ │ └────────┘ └────────┘ └────────┘ │ │ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ 库内作业 │ │ 基础资料 │ │ 报表模块 │ │ │ └────────┘ └────────┘ └────────┘ │ └─────────────┬───────────────────────┘ │ ┌─────────────▼───────────────────────┐ │ 单库 MySQL主从复制 │ │ CPU 常年 80%磁盘快满了 │ └─────────────────────────────────────┘对你没看错。200 万行代码打成一个 jar 包30 多个前端 JSP 页面直接塞在src/main/webapp里数据库就一台主库扛所有读写从库只用来跑报表。这套架构在创业早期是功臣——开发快、部署简单、出了问题翻日志就行。但五年过去它已经从功臣变成了功臣沉重地。三、为什么现在必须拆说实话拆微服务这件事我们管理层吵了快一年。有人觉得能跑就别动有人觉得再不动就晚了。最后促成决策的其实是三个维度的压力一起爆发了。3.1 业务维度新渠道需求互相打架公司这两年业务扩张得厉害原来只服务自营电商现在又接了跨境电商、B2B 批发、线下门店。每个渠道的出库逻辑都不一样自营电商优先发离用户近的仓求快跨境电商要报关、要合单流程复杂B2B一单单量巨大要按批次先进先出门店得支持到店自提和门店调拨这些需求塞进同一个代码库结果就是if-else满天飞。最夸张的一个方法我数过127 行代码里面嵌了 9 层 if-else。每次加新渠道都得小心翼翼地问“我这段逻辑会不会把老渠道搞坏”3.2 技术维度数据库真的加不动索引了我们的核心库存表数据量已经飙到 3 亿多条。为了支撑查询这张表上的索引多达 17 个。DBA 老哥有一次在群里发了一张截图主库 CPU 飙到 97%慢查询日志一分钟刷了 2000 多条。他我说“兄弟这表不能再加索引了再加快写操作要崩。”我回他“那怎么办”他回了我一个表情包一只猫在键盘上躺平。其实问题很清晰——单库单表扛不住了。但单体应用里所有模块共享同一个数据库连接池。报表模块跑一个复杂统计查询能把连接池占满导致出库接口超时。这就是典型的一颗老鼠屎坏了一锅粥。3.3 团队维度30 个人抢一个代码库我们后端团队从 5 个人扩张到 30 个人代码库还是那一个。每天早上第一件事是什么不是写代码是解决合并冲突。你改StockService.java他也改StockService.javaGit 冲突解决到怀疑人生。更魔幻的是发布。原来 10 分钟就能发完后来变成了 2 小时——因为要等所有模块的测试都通过要协调各个团队的发布窗口。有一次报表团队的功能已经测好了但因为入库团队发现了一个 Bug 要修整个发布被推迟到第二天。30 个人被一个 jar 包绑在了一起。这效率想想都心酸。四、微服务是不是银弹聊到这估计有读者要说了“你们这不就是要上微服务嘛直接干啊”别急。作为一个踩过坑的老司机我得诚实地说一句微服务不是银弹它甚至可能是新的坑。拆完之后复杂度一定会上升。原来一个方法调用就能搞定的事现在可能要跨服务调 HTTP 或 RPC原来本地事务就能保证的一致性现在得考虑分布式事务原来只有一个日志文件要翻现在得在十几个服务的日志里排查问题。所以咱们不能为了拆而拆。我画了个简单的判断标准供你参考维度我们的现状是否适合拆团队规模30 后端分 5 个业务小组✅ 适合按团队边界拆分业务复杂度多渠道、多仓库、规则差异大✅ 适合按业务领域拆分运维能力有 3 人 DevOps 小组玩过 K8s⚠️ 勉强需要补基础设施系统稳定性要求电商系统 downtime 成本极高⚠️ 拆分过程必须平滑过渡结论是什么可以拆但要拆得慢、拆得稳不能一刀切。我们最终决定走绞杀者模式——新功能用微服务写老功能逐步迁移而不是直接把 200 万行代码一把推翻重写。这个决策后来证明救了我们好几次。五、本系列要讲什么既然决定拆了那怎么拆拆成什么样拆的过程中会遇到哪些坑这些问题我会用接下来 8 篇文章一步一步跟你分享我们的真实经历。不是教科书式的理论而是有血有肉的实战记录。先给你剧透一下后续内容第 2 篇DDD 领域拆分实战—— 我们是怎么用领域驱动设计把 6 大模块拆成 12 个服务的第 3 篇数据库拆分与分库分表—— 3 亿条库存表怎么平滑迁移不停机、不丢数据第 4 篇服务间通信选型—— 同步 or 异步HTTP or gRPC消息队列怎么兜底第 5 篇库存服务设计—— 超卖问题怎么解预占、冻结、释放的完整状态机第 6 篇Saga 分布式事务落地—— 出库失败怎么回滚我们用 Saga 模式踩过的坑第 7 篇基础设施搭建—— K8s、Nacos、Gateway、CI/CD 流水线的搭建实录第 8 篇监控与排障体系—— 链路追踪、日志聚合、告警规则出问题 5 分钟定位第 9 篇一年后的复盘—— 哪些决策做对了哪些坑其实可以避开六、写在最后写这篇文章的时候我翻了一下去年的项目文档看到那个双十一前夜的发布记录2 小时 17 分钟全量回归 3 天合并冲突 47 处。现在呢同样的改动15 分钟就能上线回归测试只覆盖对应服务合并冲突基本没有了。当然这一路上我们也付出了代价基础设施投入增加了团队学习成本提高了第一次做分布式事务的时候差点把测试环境搞崩。但回头看值。如果你也正在经历类似的困境——单体应用越来越重改不动、发不动、扛不住——希望这个系列能给你一些参考。不敢说我们的方案是最优的但至少是真实的、踩过坑的。你们公司现在是什么架构有没有遇到过改一行怕崩三处的恐惧欢迎在评论区聊聊咱们一起交流本文是 WMS 微服务改造系列第 1 篇下篇预告《DDD 领域拆分实战——6 大模块怎么拆成 12 个服务》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2521649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…