从 Laravel 到 Hyperf:PHP 微服务迁移经验谈
记录将一个成熟的 Laravel 单体应用迁移到 Hyperf 微服务架构的完整历程。
项目背景
2024 年初,我所在团队维护的一个 Laravel 单体应用遇到了严重的性能瓶颈。这是一个电商中台系统,日均 PV 约 200 万,高峰期 QPS 达到 5000+。随着业务增长,单体架构的问题日益凸显:
- 部署一次需要 15 分钟,回滚更慢
- 某个模块的 Bug 可能影响整个系统
- 不同业务线对技术栈的要求互相制约
- 数据库连接池耗尽成为常态
为什么选择 Hyperf?
| 框架 | 性能 | 生态 | 学习成本 |
|---|---|---|---|
| Laravel Octane | 中 | 极丰富 | 低 |
| Hyperf | 极高 | 丰富 | 中 |
| Go + Gin | 极高 | 中 | 高 |
| Node.js + NestJS | 高 | 丰富 | 中 |
选择 Hyperf 的核心原因:协程原生支持、PHP 生态延续、AOP 编程、完善的组件。
迁移策略
第一步:服务拆分规划
将单体应用拆分为:API Gateway、用户服务、商品服务、订单服务,通过 Message Queue 通信。
第二步:数据库拆分
使用事件溯源模式逐步拆分数据库,在 Laravel 侧写入时发布事件,Hyperf 侧消费事件。
第三步:灰度切换
使用 Nginx 的 split_clients 模块实现流量切换,逐步将流量从 Laravel 切换到 Hyperf。
核心代码对比
Laravel 版本(同步阻塞)
class OrderController extends Controller
{
public function store(Request $request)
{
$order = DB::transaction(function () use ($request) {
$order = Order::create($request->validated());
foreach ($request->items as $item) {
$product = Product::find($item['product_id']);
$product->decrement('stock', $item['quantity']);
}
return $order;
});
return new OrderResource($order);
}
}
Hyperf 版本(协程异步)
#[Service]
class OrderService
{
public function create(int $userId, array $items): Order
{
return Db::transaction(function () use ($userId, $items) {
// 并发检查库存
$checks = [];
foreach ($items as $item) {
$checks[] = $this->stockService
->checkAsync($item['product_id'], $item['quantity']);
}
$results = concurrently($checks);
// 创建订单
return Order::create([
'user_id' => $userId,
'items' => $items,
'total' => array_sum(array_column($items, 'subtotal')),
]);
});
}
}
迁移成果
| 指标 | 迁移前 | 迁移后 | 提升 |
|---|---|---|---|
| 平均响应时间 | 280ms | 45ms | 6.2x |
| P99 响应时间 | 1.2s | 120ms | 10x |
| 吞吐量(QPS) | 5,000 | 35,000 | 7x |
| 部署时间 | 15min | 3min | 5x |
| 服务器成本 | 8台 8C16G | 4台 4C8G | 降低75% |
迁移过程中的坑
- 协程环境下的连接管理:多个协程共享连接池,需要使用协程安全的容器
- 全局变量的协程隔离:用
Context::set()替代全局变量 - 第三方库的兼容性:维护兼容层适配 Laravel 包
总结
从 Laravel 到 Hyperf 的迁移是一次成功的技术升级。关键经验:渐进式迁移、事件驱动保证数据一致性、充分测试、监控先行。PHP 在协程领域的进步令人瞩目,Hyperf 已经证明它可以胜任大规模高并发场景。