发布日期:2024年1月18日 | 作者:PHP架构专家
一、微服务架构概述
随着电商业务复杂度的增加,传统的单体架构已无法满足高并发、高可用的需求。基于Swoole和Hyperf的PHP微服务架构,通过协程、异步非阻塞IO等特性,为电商系统提供了全新的解决方案。
架构优势:
- 高性能:Swoole协程支持,QPS提升10倍以上
- 高可用:服务隔离,故障不影响整体系统
- 易扩展:按业务模块独立扩展
- 技术异构:不同服务可使用最适合的技术栈
系统架构图:
用户请求 → API网关 → 服务注册中心
↓
+-------------------------------+
| 用户服务 | 商品服务 | 订单服务 |
+-------------------------------+
↓
+-------------------------------+
| Redis集群 | MySQL集群 | 消息队列 |
+-------------------------------+
二、环境搭建与配置
1. Swoole扩展安装
# 安装Swoole扩展
pecl install swoole
# 或者编译安装
git clone https://github.com/swoole/swoole-src.git
cd swoole-src
phpize
./configure --enable-openssl --enable-http2
make && make install
# php.ini配置
extension=swoole.so
swoole.use_shortname=Off
2. Hyperf框架安装
# 创建项目
composer create-project hyperf/hyperf-skeleton micro-mall
# 项目结构
micro-mall/
├── app/
│ ├── Controller/
│ ├── Service/
│ ├── Model/
│ ├── Listener/
│ └── Process/
├── config/
├── runtime/
├── test/
└── vendor/
3. 配置文件
// config/autoload/server.php
return [
'mode' => SWOOLE_PROCESS,
'servers' => [
[
'name' => 'http',
'type' => Server::SERVER_HTTP,
'host' => '0.0.0.0',
'port' => 9501,
'sock_type' => SWOOLE_SOCK_TCP,
'callbacks' => [
Event::ON_REQUEST => [HyperfHttpServerServer::class, 'onRequest'],
],
],
],
'settings' => [
'enable_coroutine' => true,
'worker_num' => swoole_cpu_num(),
'pid_file' => BASE_PATH . '/runtime/hyperf.pid',
'open_tcp_nodelay' => true,
'max_coroutine' => 100000,
'open_http2_protocol' => true,
'max_request' => 100000,
'socket_buffer_size' => 2 * 1024 * 1024,
'buffer_output_size' => 2 * 1024 * 1024,
],
];
三、核心服务实现
1. 用户服务 (User Service)
<?php
declare(strict_types=1);
namespace AppService;
use HyperfDbConnectionDb;
use HyperfDiAnnotationInject;
use HyperfRedisRedis;
use AppModelUser;
class UserService
{
#[Inject]
private Redis $redis;
/**
* 用户注册
*/
public function register(array $data): array
{
// 开启事务
Db::beginTransaction();
try {
// 检查用户名是否重复
if (User::query()->where('username', $data['username'])->exists()) {
throw new Exception('用户名已存在');
}
// 创建用户
$user = new User();
$user->username = $data['username'];
$user->email = $data['email'];
$user->password = password_hash($data['password'], PASSWORD_DEFAULT);
$user->save();
// 生成访问令牌
$token = $this->generateToken($user->id);
// 缓存用户信息
$this->cacheUserInfo($user, $token);
Db::commit();
return [
'user' => $user->toArray(),
'token' => $token
];
} catch (Exception $e) {
Db::rollBack();
throw $e;
}
}
/**
* 用户登录
*/
public function login(string $username, string $password): array
{
$user = User::query()->where('username', $username)->first();
if (!$user || !password_verify($password, $user->password)) {
throw new Exception('用户名或密码错误');
}
$token = $this->generateToken($user->id);
$this->cacheUserInfo($user, $token);
return [
'user' => $user->toArray(),
'token' => $token
];
}
/**
* 生成访问令牌
*/
private function generateToken(int $userId): string
{
$token = bin2hex(random_bytes(32));
$key = "user:token:{$token}";
$this->redis->setex($key, 3600 * 24, $userId);
return $token;
}
/**
* 缓存用户信息
*/
private function cacheUserInfo(User $user, string $token): void
{
$userKey = "user:info:{$user->id}";
$this->redis->setex($userKey, 3600, json_encode($user->toArray()));
// 设置用户-令牌映射
$this->redis->setex("user:{$user->id}:token", 3600 * 24, $token);
}
}
2. 商品服务 (Product Service)
<?php
declare(strict_types=1);
namespace AppService;
use HyperfDbConnectionDb;
use HyperfDiAnnotationInject;
use HyperfRedisRedis;
use AppModelProduct;
use AppModelProductSku;
class ProductService
{
#[Inject]
private Redis $redis;
/**
* 获取商品列表(带缓存)
*/
public function getProductList(int $categoryId = 0, int $page = 1, int $pageSize = 20): array
{
$cacheKey = "products:list:{$categoryId}:{$page}:{$pageSize}";
// 尝试从缓存获取
$cached = $this->redis->get($cacheKey);
if ($cached) {
return json_decode($cached, true);
}
$query = Product::query()->where('status', 1);
if ($categoryId > 0) {
$query->where('category_id', $categoryId);
}
$products = $query->orderBy('sort', 'desc')
->orderBy('id', 'desc')
->offset(($page - 1) * $pageSize)
->limit($pageSize)
->get()
->toArray();
// 缓存结果,5分钟过期
$this->redis->setex($cacheKey, 300, json_encode($products));
return $products;
}
/**
* 获取商品详情
*/
public function getProductDetail(int $productId): array
{
$cacheKey = "product:detail:{$productId}";
$cached = $this->redis->get($cacheKey);
if ($cached) {
return json_decode($cached, true);
}
$product = Product::with(['skus', 'attributes'])
->where('id', $productId)
->where('status', 1)
->first();
if (!$product) {
throw new Exception('商品不存在');
}
$result = $product->toArray();
// 缓存商品详情,10分钟过期
$this->redis->setex($cacheKey, 600, json_encode($result));
return $result;
}
/**
* 减少库存
*/
public function decreaseStock(int $skuId, int $quantity): bool
{
$key = "product:stock:{$skuId}";
// 使用Redis原子操作减少库存
$remaining = $this->redis->decrby($key, $quantity);
if ($remaining redis->incrby($key, $quantity);
throw new Exception('库存不足');
}
// 异步更新数据库库存
HyperfUtilsCoroutine::create(function () use ($skuId, $quantity) {
ProductSku::query()
->where('id', $skuId)
->where('stock', '>=', $quantity)
->decrement('stock', $quantity);
});
return true;
}
}
3. 订单服务 (Order Service)
<?php
declare(strict_types=1);
namespace AppService;
use HyperfDbConnectionDb;
use HyperfDiAnnotationInject;
use HyperfRedisRedis;
use AppModelOrder;
use AppModelOrderItem;
use AppServiceProductService;
class OrderService
{
#[Inject]
private Redis $redis;
#[Inject]
private ProductService $productService;
/**
* 创建订单
*/
public function createOrder(int $userId, array $items, array $address): array
{
Db::beginTransaction();
try {
// 验证商品和库存
$this->validateOrderItems($items);
// 计算订单总金额
$totalAmount = $this->calculateTotalAmount($items);
// 创建订单
$order = new Order();
$order->user_id = $userId;
$order->order_no = $this->generateOrderNo();
$order->total_amount = $totalAmount;
$order->address = json_encode($address);
$order->status = Order::STATUS_PENDING;
$order->save();
// 创建订单项
foreach ($items as $item) {
$orderItem = new OrderItem();
$orderItem->order_id = $order->id;
$orderItem->product_id = $item['product_id'];
$orderItem->sku_id = $item['sku_id'];
$orderItem->quantity = $item['quantity'];
$orderItem->price = $item['price'];
$orderItem->save();
// 减少库存
$this->productService->decreaseStock($item['sku_id'], $item['quantity']);
}
Db::commit();
// 发送订单创建事件
event(new OrderCreated($order));
return $order->toArray();
} catch (Exception $e) {
Db::rollBack();
throw $e;
}
}
/**
* 验证订单项
*/
private function validateOrderItems(array $items): void
{
foreach ($items as $item) {
$sku = ProductSku::query()
->where('id', $item['sku_id'])
->where('product_id', $item['product_id'])
->first();
if (!$sku) {
throw new Exception("商品SKU不存在");
}
if ($sku->stock name} 库存不足");
}
}
}
/**
* 计算订单总金额
*/
private function calculateTotalAmount(array $items): float
{
$total = 0;
foreach ($items as $item) {
$total += $item['price'] * $item['quantity'];
}
return $total;
}
/**
* 生成订单号
*/
private function generateOrderNo(): string
{
return date('YmdHis') . str_pad((string) mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
}
}
四、服务通信机制
1. JSON-RPC服务通信
// config/autoload/services.php
return [
'consumers' => [
[
'name' => 'UserService',
'service' => AppServiceUserServiceInterface::class,
'nodes' => [
['host' => '127.0.0.1', 'port' => 9502],
],
],
[
'name' => 'ProductService',
'service' => AppServiceProductServiceInterface::class,
'nodes' => [
['host' => '127.0.0.1', 'port' => 9503],
],
],
],
];
// 用户服务接口
interface UserServiceInterface
{
public function register(array $data): array;
public function login(string $username, string $password): array;
public function getUserInfo(int $userId): array;
}
// 在订单服务中调用用户服务
class OrderController
{
#[Inject]
private UserServiceInterface $userService;
public function create()
{
// 调用用户服务验证用户
$userInfo = $this->userService->getUserInfo($userId);
// 创建订单逻辑...
}
}
2. 消息队列异步处理
// 配置Redis队列
// config/autoload/async_queue.php
return [
'default' => 'redis',
'enable' => true,
'connections' => [
'redis' => [
'driver' => HyperfAsyncQueueDriverRedisDriver::class,
'channel' => 'queue',
'timeout' => 2,
'retry_seconds' => 5,
'handle_timeout' => 10,
'processes' => 1,
'concurrent' => [
'limit' => 10,
],
],
],
];
// 订单创建事件监听器
class OrderCreatedListener implements ListenerInterface
{
public function listen(): array
{
return [
OrderCreated::class,
];
}
public function process(object $event)
{
$order = $event->order;
// 发送邮件通知
$this->sendOrderEmail($order);
// 更新统计数据
$this->updateStatistics($order);
// 推送消息到APP
$this->pushNotification($order);
}
private function sendOrderEmail(Order $order)
{
// 异步发送邮件
HyperfAsyncQueueDriverDriverFactory::instance('redis')->push(
new SendEmailJob($order)
);
}
}
// 发送邮件任务
class SendEmailJob extends Job
{
public $order;
public function __construct(Order $order)
{
$this->order = $order;
}
public function handle()
{
// 发送邮件逻辑
$mailer = make(Mailer::class);
$mailer->sendOrderConfirmation($this->order);
}
}
3. 服务发现与注册
// 使用Consul进行服务注册发现
// config/autoload/consul.php
return [
'uri' => 'http://127.0.0.1:8500',
'token' => '',
'check' => [
'deregister_critical_service_after' => '90m',
'interval' => '10s',
],
];
// 服务提供者
class AppServiceProvider extends ServiceProvider
{
public function register()
{
// 注册Consul客户端
$this->app->bind(ClientInterface::class, function () {
return new Client([
'base_uri' => config('consul.uri'),
'headers' => [
'X-Consul-Token' => config('consul.token'),
],
]);
});
// 注册服务发现
$this->app->bind(ServiceDiscoverInterface::class, ConsulAgent::class);
}
public function boot()
{
// 服务启动时注册到Consul
$this->app->get(ConsulAgent::class)->registerService([
'ID' => 'user-service-' . getmypid(),
'Name' => 'user-service',
'Tags' => ['v1.0'],
'Address' => '127.0.0.1',
'Port' => 9502,
'Check' => [
'HTTP' => 'http://127.0.0.1:9502/health',
'Interval' => '10s',
'Timeout' => '5s',
],
]);
}
}
五、部署与监控
1. Docker容器化部署
# Dockerfile
FROM hyperf/hyperf:8.0-alpine-v3.15-swoole
WORKDIR /opt/www
COPY . /opt/www
RUN composer install --no-dev
&& php bin/hyperf.php
EXPOSE 9501
CMD ["php", "bin/hyperf.php", "start"]
# docker-compose.yml
version: '3.8'
services:
user-service:
build: ./user-service
ports:
- "9502:9501"
environment:
- APP_ENV=production
depends_on:
- redis
- mysql
- consul
product-service:
build: ./product-service
ports:
- "9503:9501"
environment:
- APP_ENV=production
order-service:
build: ./order-service
ports:
- "9504:9501"
environment:
- APP_ENV=production
api-gateway:
build: ./api-gateway
ports:
- "9501:9501"
environment:
- APP_ENV=production
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- api-gateway
redis:
image: redis:6-alpine
ports:
- "6379:6379"
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: micro_mall
ports:
- "3306:3306"
consul:
image: consul:1.15
ports:
- "8500:8500"
2. 性能监控配置
// 集成Prometheus监控
// config/autoload/metric.php
return [
'default' => 'prometheus',
'use_standalone_process' => true,
'enable_default_metrics' => true,
'default_metrics_interval' => 5,
];
// 自定义业务指标
class OrderMetrics
{
public static function recordOrderCreated()
{
$counter = make(Counter::class, [
'namespace' => 'app',
'subsystem' => 'order',
'name' => 'created_total',
'help' => '订单创建总数',
]);
$counter->add(1);
}
public static function recordOrderAmount(float $amount)
{
$histogram = make(Histogram::class, [
'namespace' => 'app',
'subsystem' => 'order',
'name' => 'amount_distribution',
'help' => '订单金额分布',
'buckets' => [100, 500, 1000, 5000, 10000],
]);
$histogram->observe($amount);
}
}
// 在订单服务中使用
class OrderService
{
public function createOrder()
{
// 创建订单逻辑...
// 记录指标
OrderMetrics::recordOrderCreated();
OrderMetrics::recordOrderAmount($totalAmount);
}
}
3. 压力测试结果
# 使用wrk进行压力测试
wrk -t12 -c400 -d30s http://localhost:9501/api/products
# 测试结果对比:
# 传统PHP-FPM架构:
# Requests/sec: 1,200
# 平均延迟: 350ms
# Swoole+Hyperf微服务架构:
# Requests/sec: 12,500 (提升10.4倍)
# 平均延迟: 32ms (降低89%)
# 资源占用对比:
# 内存使用:从2GB降低到800MB
# CPU使用率:从90%降低到45%

