PHP微服务架构实战:构建分布式电商用户系统 | 容器化部署指南

2025-11-17 0 534

引言:从单体架构到微服务的演进

随着业务规模扩大,传统单体PHP应用面临性能瓶颈和部署困难。本文将深入探讨如何使用PHP构建现代化的微服务架构,通过完整的电商用户系统案例,展示微服务拆分、容器化部署和分布式事务处理的最佳实践。

一、微服务架构设计

我们的电商用户系统将拆分为四个核心微服务:

  • 用户服务(User Service):处理用户注册、登录、信息管理
  • 认证服务(Auth Service):JWT令牌生成与验证
  • 积分服务(Points Service):用户积分管理和消费记录
  • 消息服务(Notification Service):邮件和短信通知

架构拓扑:
客户端 → API网关 → 服务注册中心 → 各微服务 → 独立数据库
        

二、技术栈与环境准备

2.1 核心组件

  • PHP 8.1+ (Swoole扩展)
  • Docker & Docker Compose
  • Redis 7.0 (缓存和会话存储)
  • MySQL 8.0 (分库分表)
  • Consul (服务发现)

2.2 项目结构


microservices/
├── api-gateway/
├── user-service/
├── auth-service/
├── points-service/
├── notification-service/
├── docker-compose.yml
└── consul-config/
        

三、核心微服务实现

3.1 用户服务 (User Service)


<?php
// user-service/src/Controllers/UserController.php

class UserController {
    private $userRepository;
    private $httpClient;
    
    public function __construct() {
        $this->userRepository = new UserRepository();
        $this->httpClient = new HttpClient();
    }
    
    public function register($request) {
        // 数据验证
        $userData = [
            'username' => $request['username'],
            'email' => $request['email'],
            'password' => password_hash($request['password'], PASSWORD_DEFAULT),
            'created_at' => date('Y-m-d H:i:s')
        ];
        
        // 分布式事务开始
        $transactionId = uniqid('tx_');
        
        try {
            // 创建用户
            $userId = $this->userRepository->create($userData);
            
            // 调用积分服务初始化用户积分
            $pointsResponse = $this->httpClient->post('http://points-service/init', [
                'user_id' => $userId,
                'transaction_id' => $transactionId
            ]);
            
            // 调用消息服务发送欢迎邮件
            $notificationResponse = $this->httpClient->post('http://notification-service/welcome', [
                'user_id' => $userId,
                'email' => $userData['email'],
                'transaction_id' => $transactionId
            ]);
            
            // 确认分布式事务
            $this->confirmTransaction($transactionId);
            
            return [
                'success' => true,
                'user_id' => $userId,
                'message' => '用户注册成功'
            ];
            
        } catch (Exception $e) {
            // 回滚分布式事务
            $this->rollbackTransaction($transactionId);
            throw $e;
        }
    }
    
    public function getUserProfile($userId) {
        $user = $this->userRepository->findById($userId);
        
        if (!$user) {
            throw new Exception('用户不存在');
        }
        
        // 并行调用其他服务获取完整用户信息
        $promises = [
            'points' => $this->httpClient->getAsync("http://points-service/users/{$userId}/summary"),
            'preferences' => $this->httpClient->getAsync("http://preference-service/users/{$userId}")
        ];
        
        $results = Promisesettle($promises)->wait();
        
        return [
            'user' => $user,
            'points' => $results['points']['value'] ?? null,
            'preferences' => $results['preferences']['value'] ?? null
        ];
    }
}

// user-service/src/Repositories/UserRepository.php
class UserRepository {
    private $db;
    
    public function __construct() {
        $this->db = new PDO(
            'mysql:host=' . getenv('DB_HOST') . ';dbname=user_service',
            getenv('DB_USER'),
            getenv('DB_PASS')
        );
    }
    
    public function create($userData) {
        $stmt = $this->db->prepare("
            INSERT INTO users (username, email, password, created_at) 
            VALUES (?, ?, ?, ?)
        ");
        
        $stmt->execute([
            $userData['username'],
            $userData['email'],
            $userData['password'],
            $userData['created_at']
        ]);
        
        return $this->db->lastInsertId();
    }
    
    public function findById($userId) {
        $stmt = $this->db->prepare("SELECT * FROM users WHERE id = ?");
        $stmt->execute([$userId]);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }
}
?>
        

3.2 认证服务 (Auth Service)


<?php
// auth-service/src/Services/JwtService.php

class JwtService {
    private $secretKey;
    private $algorithm = 'HS256';
    
    public function __construct() {
        $this->secretKey = getenv('JWT_SECRET');
    }
    
    public function generateToken($payload) {
        $header = json_encode(['typ' => 'JWT', 'alg' => $this->algorithm]);
        $payload['exp'] = time() + 3600; // 1小时过期
        $payload['iat'] = time();
        
        $base64Header = $this->base64UrlEncode($header);
        $base64Payload = $this->base64UrlEncode(json_encode($payload));
        
        $signature = hash_hmac('sha256', 
            "{$base64Header}.{$base64Payload}", 
            $this->secretKey, true
        );
        
        $base64Signature = $this->base64UrlEncode($signature);
        
        return "{$base64Header}.{$base64Payload}.{$base64Signature}";
    }
    
    public function validateToken($token) {
        $parts = explode('.', $token);
        
        if (count($parts) !== 3) {
            return false;
        }
        
        list($base64Header, $base64Payload, $base64Signature) = $parts;
        
        $signature = $this->base64UrlDecode($base64Signature);
        $expectedSignature = hash_hmac('sha256', 
            "{$base64Header}.{$base64Payload}", 
            $this->secretKey, true
        );
        
        if (!hash_equals($expectedSignature, $signature)) {
            return false;
        }
        
        $payload = json_decode($this->base64UrlDecode($base64Payload), true);
        
        if (isset($payload['exp']) && $payload['exp'] jwtService = new JwtService();
        $this->httpClient = new HttpClient();
    }
    
    public function login($credentials) {
        // 调用用户服务验证用户
        $userResponse = $this->httpClient->post('http://user-service/validate', [
            'email' => $credentials['email'],
            'password' => $credentials['password']
        ]);
        
        if ($userResponse['success']) {
            $token = $this->jwtService->generateToken([
                'user_id' => $userResponse['user_id'],
                'email' => $credentials['email'],
                'role' => $userResponse['role']
            ]);
            
            return [
                'success' => true,
                'token' => $token,
                'expires_in' => 3600
            ];
        }
        
        return ['success' => false, 'message' => '认证失败'];
    }
}
?>
        

四、API网关实现

4.1 网关路由配置


<?php
// api-gateway/src/Router.php

class Router {
    private $routes = [
        'POST /api/register' => 'user-service',
        'POST /api/login' => 'auth-service',
        'GET /api/users/{id}' => 'user-service',
        'GET /api/users/{id}/points' => 'points-service',
        'POST /api/notifications' => 'notification-service'
    ];
    
    private $serviceDiscovery;
    
    public function __construct() {
        $this->serviceDiscovery = new ServiceDiscovery();
    }
    
    public function route($method, $path, $headers, $body) {
        $routeKey = "{$method} {$path}";
        
        // 路由匹配
        foreach ($this->routes as $pattern => $serviceName) {
            if ($this->matchRoute($pattern, $routeKey)) {
                $serviceUrl = $this->serviceDiscovery->resolve($serviceName);
                
                // JWT验证(登录注册除外)
                if (!in_array($routeKey, ['POST /api/login', 'POST /api/register'])) {
                    $authResult = $this->validateAuth($headers);
                    if (!$authResult['valid']) {
                        return $this->unauthorizedResponse();
                    }
                    $headers['X-User-ID'] = $authResult['user_id'];
                }
                
                // 转发请求到目标服务
                return $this->forwardRequest($serviceUrl, $method, $path, $headers, $body);
            }
        }
        
        return $this->notFoundResponse();
    }
    
    private function validateAuth($headers) {
        if (!isset($headers['Authorization'])) {
            return ['valid' => false];
        }
        
        $token = str_replace('Bearer ', '', $headers['Authorization']);
        $jwtService = new JwtService();
        
        return [
            'valid' => true,
            'user_id' => $jwtService->validateToken($token)['user_id'] ?? null
        ];
    }
}
?>
        

五、Docker容器化部署

5.1 Docker Compose配置


# docker-compose.yml
version: '3.8'

services:
  consul:
    image: consul:1.15
    ports:
      - "8500:8500"
  
  mysql-user:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: user_service
    ports:
      - "3306:3306"
  
  redis:
    image: redis:7.0-alpine
    ports:
      - "6379:6379"
  
  user-service:
    build: ./user-service
    ports:
      - "8001:8000"
    environment:
      DB_HOST: mysql-user
      DB_USER: root
      DB_PASS: root
      CONSUL_URL: http://consul:8500
    depends_on:
      - mysql-user
      - consul
  
  auth-service:
    build: ./auth-service
    ports:
      - "8002:8000"
    environment:
      JWT_SECRET: your-secret-key
      CONSUL_URL: http://consul:8500
  
  api-gateway:
    build: ./api-gateway
    ports:
      - "80:8000"
    environment:
      CONSUL_URL: http://consul:8500
    depends_on:
      - user-service
      - auth-service
        

5.2 服务Dockerfile


# user-service/Dockerfile
FROM php:8.1-fpm

# 安装扩展
RUN docker-php-ext-install pdo pdo_mysql 
    && pecl install swoole 
    && docker-php-ext-enable swoole

WORKDIR /var/www

COPY . .

# 安装Composer依赖
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN composer install --no-dev

EXPOSE 8000

CMD ["php", "src/server.php"]
        

六、服务注册与发现

6.1 Consul服务注册


<?php
// common/src/ServiceDiscovery.php

class ServiceDiscovery {
    private $consulUrl;
    
    public function __construct() {
        $this->consulUrl = getenv('CONSUL_URL') ?: 'http://localhost:8500';
    }
    
    public function registerService($serviceName, $serviceAddress, $servicePort) {
        $registration = [
            'ID' => "{$serviceName}-1",
            'Name' => $serviceName,
            'Address' => $serviceAddress,
            'Port' => $servicePort,
            'Check' => [
                'HTTP' => "http://{$serviceAddress}:{$servicePort}/health",
                'Interval' => '10s',
                'Timeout' => '5s'
            ]
        ];
        
        $client = new HttpClient();
        $response = $client->put("{$this->consulUrl}/v1/agent/service/register", 
            json_encode($registration)
        );
        
        return $response->getStatusCode() === 200;
    }
    
    public function resolve($serviceName) {
        $client = new HttpClient();
        $response = $client->get("{$this->consulUrl}/v1/health/service/{$serviceName}");
        $services = json_decode($response->getBody(), true);
        
        if (empty($services)) {
            throw new Exception("服务 {$serviceName} 未找到");
        }
        
        // 简单的负载均衡:随机选择一个健康实例
        $healthyServices = array_filter($services, function($service) {
            return $this->isServiceHealthy($service);
        });
        
        if (empty($healthyServices)) {
            throw new Exception("没有健康的 {$serviceName} 实例");
        }
        
        $selected = $healthyServices[array_rand($healthyServices)];
        return "http://{$selected['Service']['Address']}:{$selected['Service']['Port']}";
    }
}
?>
        

七、监控与日志聚合

7.1 分布式链路追踪


<?php
class TraceManager {
    public static function startSpan($name, $traceId = null) {
        $spanId = uniqid();
        $traceId = $traceId ?: uniqid();
        
        return [
            'trace_id' => $traceId,
            'span_id' => $spanId,
            'name' => $name,
            'start_time' => microtime(true)
        ];
    }
    
    public static function injectTraceHeaders($span, &$headers) {
        $headers['X-Trace-ID'] = $span['trace_id'];
        $headers['X-Span-ID'] = $span['span_id'];
        $headers['X-Parent-Span-ID'] = $span['span_id'];
    }
}

// 在网关中初始化跟踪
$span = TraceManager::startSpan('api-gateway');
TraceManager::injectTraceHeaders($span, $headers);
        

7.2 集中式日志收集


class Logger {
    public static function info($message, $context = []) {
        $logEntry = [
            'timestamp' => date('c'),
            'level' => 'INFO',
            'message' => $message,
            'context' => $context,
            'service' => getenv('SERVICE_NAME'),
            'trace_id' => $_SERVER['HTTP_X_TRACE_ID'] ?? null
        ];
        
        // 发送到ELK Stack或类似系统
        file_put_contents('php://stderr', json_encode($logEntry) . "n");
    }
}
        

八、总结与最佳实践

通过本文的完整实现,我们构建了一个生产就绪的PHP微服务架构,具备以下特性:

  • 服务自治:每个微服务独立开发、部署和扩展
  • 弹性设计:服务发现、负载均衡和容错机制
  • 可观测性:完整的监控、日志和追踪体系
  • DevOps友好:容器化部署和自动化运维

微服务架构虽然带来了技术优势,但也增加了系统复杂性。在实际项目中,需要根据团队规模、业务需求和运维能力谨慎选择架构模式。建议从关键业务开始逐步迁移,确保平滑过渡。

PHP微服务架构实战:构建分布式电商用户系统 | 容器化部署指南
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

淘吗网 php PHP微服务架构实战:构建分布式电商用户系统 | 容器化部署指南 https://www.taomawang.com/server/php/1434.html

下一篇:

已经没有下一篇了!

常见问题

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务