从单体到微服务:PHP 服务拆分演进记录

阿乐
阿乐 管理员 年卡会员
发布于 2026-09-03 23:36 ·2 浏览 ·0 回复

2018年那个夏天,我们的支付系统在搞大促压测时炸了。数据库连接数被打满,Redis 缓存穿透,整个单体应用像多米诺骨牌一样倒下。那天晚上,技术群里吵翻了天,有人提议引入微服务,有人坚持优化单体架构就行。作为 PHP 工程师,我们心里都清楚:PHP 单体的天花板,终究是撞上了。

拆分的真实原因,不是技术,是组织

很多人以为拆微服务是技术驱动,其实大部分情况下是组织驱动。当四五个团队同时在一个代码库里开发时,每次发布都要排队,代码合并冲突比业务需求还多。那个三个月没发版的仓库,成了所有人的噩梦——谁都不敢动它,但每个人又都要改它。

我们最初定的拆分原则很简单:按业务域切,不按技术层级切。用户中心、订单中心、支付中心、商品中心,每个都是一个独立的服务。但真正推动拆分的,其实是负责用户中心的那个团队要独立迭代,不想再被主仓库的发布节奏拖死。

第一步:从「不痛不痒」的模块开始

我们犯过的最大错误,就是一上来就想拆最核心的下单链路。结果发现订单服务拆出去后,事务边界糊了,分布式事务处理不了,回滚逻辑写得跟天书一样,线上事故频发。

后来我们学乖了:先拆一个独立的、边界清晰的、对主流程影响最小的服务。我们选了「短信通知」——它只依赖用户表,也不涉及资金安全,即使挂了也只是通知延迟,不影响主链路。

拆分的第一步,永远选那个「挂了也没关系」的服务。这句话后来成了我们架构评审的黄金法则。

公共代码库:一个巨大的暗坑

PHP 微服务化最痛苦的不是服务通信,而是公共代码怎么处理。原来一个 `common.php` 里全是函数,什么 `getUserInfo`、`formatMoney`、`sendSms`,两百多个公共方法,七八个团队都在用。

拆出去之后,问题来了:用户中心改了 `getUserInfo` 的实现,订单中心那边还跑着旧代码,接口参数不兼容了。

后来我们做了一个很务实的决定:把公共代码抽成一个 Composer 包,每次更新走版本控制。所有服务统一依赖同一个 internal-common 包,需要更新就发新 tag,然后各服务自己决定什么时候升级——而不是强行同步所有服务。即便这样,我们还是约定了一个底线:**公共包只放不涉及业务的数据结构、工具函数、SDK,不允许出现任何含业务逻辑的东西**。

到现在,我们的 internal-common 包已有 300 多个版本,每次升级都要看 changelog。麻烦归麻烦,但至少撕逼的时候有个依据。

数据一致性:从「同一库」到「最终一致」

单体时代,一个事务搞定一切。拆完之后,最不适应的其实是业务同学:「我下单失败了,积分余额怎么扣了?」——跨服务的数据一致性,成了最大的坎。

没有搞微服务之前,我们 PHP 都是 `try { commit } catch { rollback }`,异常了直接回滚,干脆利落。拆开之后,没人能保证两个服务同时成功或同时失败。

我们最终选了本地消息表 + 定时任务重试的方案。这个「土办法」在绝大数业务场景下都够用了。每一次调用远端服务前,先在本地写一条状态为 pending 的表记录,调用成功后更新为 done,失败就由定时任务去扫、去补发,直到成功为止。资金相关操作再加对账系统兜底。

不需要什么高大上的分布式事务框架,我们是 PHP 团队,务实比炫技重要。

一套可观测体系,比微服务本身更重要

服务多了之后,排障是最折磨人的事情。下单链路经过网关、订单服务、支付服务、库存服务、消息队列,一共五个节点,某个环节慢了到底是谁的锅?纯靠查日志、在服务器上 tail -f,一台台地翻,简直要命。

后来我们在所有服务接入统一的日志规范 —— 每次 HTTP 请求带上全局 request_id,写入 Kafka 汇聚到 ES 里;再搭了简单的 Grafana + Prometheus,监控每个服务的 QPS、耗时和错误率。这套体系搭建的成本不算高,但带来格局性的变化:你得先用工具看清楚你的服务在干嘛,然后才谈得上治理它。

如果不是为了独立部署和扩缩容,就别拆

微服务不是万能的,恰恰相反,它是成本极高的选择。每个服务都要写 Dockerfile,每个服务都要维护 CI/CD,每个服务都要配置中心、注册中心、熔断降级,还要有人守 ONCALL。如果你的团队只有五个人,拆分十个微服务就是自寻烦恼。

我们最开始拆成了 12 个服务,后来又合并掉了 4 个——真心觉得业务层太薄、独立价值太小的,必然要走回模块化单体。

微服务拆分的本质,不是让代码变得更「微」,而是让团队拥有独立决策和独立交付的能力。每拆一个服务,你都要问自己:它能不能独立部署、独立扩容、独立故障不影响别人?如果三个「独立」有一半以上回答不了,这个服务就不该拆。

回头看这三年,从单体到微服务,真正留下的不是那些 K8s YAML 文件,而是一整套围绕服务化的工程文化和思维方式。PHP 从来不是微服务的障碍,懒惰和想当然才是。

他们都看过 1 人浏览过
断了的弦

全部回复 0

还没有回复,来抢沙发~