PHP 微服务架构实战:服务划分、通信与部署模式

PHP 微服务架构实战:微服务适用性评估、服务划分原则(DDD 限界上下文)、服务间通信(同步 REST/gRPC vs 异步 MQ)、API Gateway 与聚合、服务发现与配置中心、分布式事务(Saga/最终一致)、服务部署(Docker/K8s)、可观测性(日志/追踪/指标)与实战案例。

引言

微服务不是银弹——PHP 单体应用改微服务,最常踩的坑是把「服务划分」做成「拆表拆代码」。本文不讲空话,讲落地:什么时候该上微服务、服务怎么划、服务之间怎么通信、分布式事务怎么处理、以及 PHP 生态里微服务的部署与观测。和 /php-microservices-message-queue/ 的消息队列深度互补。

前置:/php-microservices-message-queue/(MQ 与事件驱动)、/php-api-design-rest/(API 设计)、/php-swoole-async/(常驻内存服务)。


目录


1. 什么时候才该上微服务

1.1 微服务的代价

多服务 = 网络延迟 + 部署复杂度 + 一致性难题 + 观测成本
单体 = 简单可靠,但团队大了会「牵一发动全身」

1.2 该上的信号

信号说明
团队 10+ 人独立部署、独立发布
模块频繁独立演进支付/库存/风控各自迭代
不同扩展需求某模块要单独扩容/异步
技术异构某模块需要非 PHP 技术栈

记忆:微服务的代价是分布式复杂性;团队小/模块耦合/演进不独立,先保持单体(可用模块化单体)。上微服务要有明确信号,别为拆而拆。


2. 服务划分:限界上下文原则

2.1 DDD 限界上下文

按业务领域划界,而非按技术/表结构:

订单上下文:订单、支付、发货状态
库存上下文:库存、采购、预警
用户上下文:账号、权限、资料
(不按 user 表拆,按业务能力拆)

2.2 划分自查

✓ 该上下文数据独立变更?
✓ 该上下文有独立业务规则?
✓ 对外暴露清晰接口?
✗ 为「复用表」而拆 → 会拆出分布式泥潭

记忆:按 DDD 限界上下文划分服务——以业务能力为界(订单/库存/用户),不是按表或代码结构拆;每个上下文数据独立、接口清晰。


3. 服务间通信:同步与异步

3.1 同步通信(REST/gRPC)

适合实时需要结果的场景:

// REST 调用(Laravel HTTP Client)
$resp = Http::get('http://inventory-service/api/stock/'.$sku);
$stock = $resp->json()['stock'];

// 或 gRPC(protobuf + Spiral RoadRunner 等)

3.2 异步通信(MQ)

适合解耦、可延迟的场景:

// 订单创建后发事件,库存/通知异步处理
event(new OrderCreated($order));
// listener 里
dispatch(new DeductStock($order))->onQueue('inventory');

3.3 选型表

场景方式
需要即时结果同步 REST/gRPC
可延迟、要解耦异步 MQ
最终一致事件 + MQ
高吞吐流水线MQ 流式处理

记忆:同步(REST/gRPC)拿即时结果、异步(MQ)解耦降耦合;订单这类跨服务流程,尽量事件驱动 + 最终一致。


4. API Gateway:聚合与流量入口

4.1 网关职责

统一入口 → 鉴权/限流/日志 → 路由到各服务 → 聚合返回

4.2 聚合层:BFF 模式

前端需要「订单+商品+用户」组合数据时,网关聚合:

// 网关服务(BFF)
public function orderDetail($orderId) {
    $order = Http::get("orders/{$orderId}")->json();
    $order['items'] = Http::get("inventory/items", ['ids' => $order['item_ids']])->json();
    return $order;
}

4.3 常见网关选型

方案语言场景
KongLua/Go通用 API 网关
TraefikGoK8s 原生入口
Laravel BFFPHP自家聚合服务

记忆:网关 = 统一入口(鉴权/限流/路由);BFF 聚合层把多服务数据组合成前端需要的形状,减少前端请求次数。


5. 服务发现与配置中心

5.1 服务发现

K8s 下服务名即 DNS,天然服务发现;非 K8s 用注册中心:

K8s Service:inventory-service → 自动负载均衡
Consul / etcd:服务注册 + 健康检查

5.2 配置中心

统一管理各服务配置、支持动态刷新:

// 配置放环境变量/K8s ConfigMap/Consul
$dbHost = config('services.inventory.host');   // 从配置中心拉取

记忆:K8s 里服务发现用 Service DNS 即可;非 K8s 用 Consul/etcd 注册中心;配置用配置中心统一管理、动态刷新。


6. 分布式事务:Saga 与最终一致

6.1 为什么不能「本地事务」

跨服务没有统一事务管理器——订单和库存分属不同库,一个本地事务管不了。

6.2 Saga 模式

订单服务:创建订单(事务1)
  → 发事件 → 库存服务:扣库存(事务2)
    → 若失败 → 补偿:库存回滚 + 订单标记失败
// 扣库存失败时发补偿事件
try {
    $inventory->deduct($order);
} catch (DeductFailedException $e) {
    event(new OrderCancelled($order));   // 补偿
}

6.3 实现选择

方式复杂度一致性
本地事务 + 单库低强
事件 + 最终一致中最终一致
Saga 编排/协同高最终一致

记忆:跨服务事务用 Saga——每个服务本地事务 + 失败补偿事件,达到最终一致;多数业务「事件驱动 + 最终一致」够用,别强行两阶段提交。


7. 服务部署:Docker 与 Kubernetes

7.1 容器化 PHP 服务

FROM php:8.3-fpm
COPY . /app
# 多阶段:依赖、Composer install --no-dev
RUN composer install --no-dev --optimize-autoloader

7.2 K8s 部署清单

apiVersion: apps/v1
kind: Deployment
metadata: { name: inventory-service }
spec:
  replicas: 3
  selector: { matchLabels: { app: inventory } }
  template:
    metadata: { labels: { app: inventory } }
    spec:
      containers:
        - name: inventory
          image: registry/inventory:latest
          env:
            - name: DB_HOST
              value: postgres:5432

7.3 扩容与发布

kubectl scale deployment/inventory --replicas=5   # 扩缩容
kubectl rollout status deployment/inventory        # 滚动发布

记忆:服务用多阶段 Docker 镜像打包(–no-dev 精简依赖);K8s 声明 Deployment(副本数/镜像/环境变量)、Service 做发现、滚动发布 rollout。


8. 可观测性:日志、追踪与指标

8.1 三支柱

支柱工具作用
日志ELK / Loki排障细节
追踪Jaeger / Zipkin跨服务调用链
指标Prometheus + Grafana性能与健康

8.2 分布式追踪(PHP)

// 请求头带 trace_id,贯穿所有服务调用
$resp = Http::withHeaders(['X-Trace-Id' => $traceId])
    ->get('http://inventory-service/api/stock/'.$sku);
// Jaeger/Zipkin 按 trace_id 串起整条调用链

8.3 指标

// 关键指标:QPS、P95 延迟、错误率、命中率
Prometheus::inc('http_requests_total', ['route' => 'order.create']);

记忆:观测三支柱——日志排障、追踪串调用链、指标看健康;PHP 服务间用 trace_id 头贯穿,Prometheus 暴露 /metrics。


9. 实战:订单系统微服务改造

9.1 改造前(单体)

单一 Laravel 应用:订单/库存/用户一张库
痛点:促销大促时库存模块要独立扩容,做不到

9.2 改造后

用户服务(auth/user API)
订单服务(order create/query,Saga 编排)
库存服务(扣减/查询,Redis 预扣 + 异步落库)
网关 BFF(订单详情聚合)

通信:下单走事件(OrderCreated → 扣库存/发通知)
事务:Saga 补偿(扣库存失败 → 订单取消)

9.3 落地顺序

先划界 → 先抽库存(最大热点)→ 抽订单 → 网关聚合
每步独立部署、回归验证,别一次全拆

记忆:订单系统改造 = 按界抽服务(先抽热点库存)、事件驱动下单、Saga 补偿、BFF 聚合;逐服务抽离独立部署验证,别一次拆完。


10. 速查表与一句话记忆

维度关键做法
该不该上团队/演进/扩展信号
划分限界上下文
同步REST/gRPC
异步事件 + MQ
入口API Gateway / BFF
事务Saga 最终一致
部署Docker + K8s
观测日志/追踪/指标

一句话记忆:PHP 微服务落地 = 有明确信号才拆(团队 10+/独立演进/独立扩容),按 DDD 限界上下文划分(订单/库存/用户业务界);通信同步 REST/gRPC 拿即时结果、异步事件+MQ 解耦;入口用 API Gateway+BFF 聚合、K8s Service 做发现;跨服务事务用 Saga 补偿到最终一致(别强上两阶段);部署用多阶段 Docker + K8s Deployment 滚动发布;观测三支柱——日志(ELK/Loki)、追踪(Jaeger,trace_id 贯穿)、指标(Prometheus);按「先划界→先抽热点服务→逐步独立部署验证」落地,别一次全拆。


延伸阅读

  • /php-microservices-message-queue/ — RabbitMQ/Kafka 与事件驱动
  • /php-api-design-rest/ — 服务间 API 设计
  • /php-swoole-async/ — 常驻内存服务与协程
  • /php-deployment-nginx/ — 服务部署与运维
  • /php-caching-redis/ — Redis 缓存与锁
  • [[distributed-systems]] — 分布式系统原理
  • [[architecture]] — 系统架构设计
  • [[kubernetes]] — K8s 部署与编排
  • Kong 文档

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「php」更多文章

  1. PHP 面向对象与设计模式:SOLID、常用模式与 Laravel 实践
  2. PHP 静态分析与代码质量:PHPStan、Psalm、Rector 与 CI 门禁
  3. PHP 部署运维实战:Nginx、PHP-FPM、Docker 与 CI/CD