ThinkPHP8微服务架构实战:构建高可用API网关系统 | PHP微服务教程

2025-10-26 0 795

引言:微服务架构下的API网关挑战

随着业务复杂度的不断提升,单体应用逐渐向微服务架构演进。API网关作为微服务架构的入口,承担着路由转发、负载均衡、限流熔断、安全认证等关键职责。本文将基于ThinkPHP8框架,从零构建一个高性能、高可用的API网关系统。

系统架构设计

1. 整体架构图

客户端 → API网关 → 服务发现 → 微服务集群
    ↓          ↓           ↓
认证鉴权    负载均衡     配置中心
限流熔断    路由转发     监控告警
日志记录    数据缓存     链路追踪
        

2. 核心模块设计

app/
├── gateway/           # 网关核心
│   ├── Router.php    # 路由管理
│   ├── LoadBalancer.php # 负载均衡
│   ├── RateLimiter.php  # 限流器
│   └── CircuitBreaker.php # 熔断器
├── service/           # 业务服务
│   ├── AuthService.php # 认证服务
│   ├── RegistryService.php # 服务注册发现
│   └── ConfigService.php # 配置服务
├── middleware/        # 中间件层
│   ├── GatewayMiddleware.php # 网关核心中间件
│   ├── AuthMiddleware.php # 认证中间件
│   ├── RateLimitMiddleware.php # 限流中间件
│   └── LogMiddleware.php # 日志中间件
└── controller/
    └── GatewayController.php # 网关入口控制器

数据库设计与模型

1. 核心数据表

-- 路由配置表
CREATE TABLE `gateway_route` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL COMMENT '路由名称',
  `path` varchar(255) NOT NULL COMMENT '请求路径',
  `service_id` varchar(100) NOT NULL COMMENT '服务ID',
  `url` varchar(500) DEFAULT NULL COMMENT '目标URL',
  `strip_prefix` tinyint(1) DEFAULT '1' COMMENT '是否去除前缀',
  `retryable` tinyint(1) DEFAULT '0' COMMENT '是否可重试',
  `status` tinyint(1) DEFAULT '1' COMMENT '状态',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `path` (`path`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 服务实例表
CREATE TABLE `service_instance` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `service_id` varchar(100) NOT NULL COMMENT '服务ID',
  `instance_id` varchar(100) NOT NULL COMMENT '实例ID',
  `host` varchar(100) NOT NULL COMMENT '主机地址',
  `port` int(11) NOT NULL COMMENT '端口',
  `weight` int(11) DEFAULT '100' COMMENT '权重',
  `metadata` json DEFAULT NULL COMMENT '元数据',
  `status` tinyint(1) DEFAULT '1' COMMENT '状态',
  `last_heartbeat` datetime DEFAULT NULL COMMENT '最后心跳',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `instance` (`service_id`,`instance_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 限流规则表
CREATE TABLE `rate_limit_rule` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `route_id` int(11) NOT NULL COMMENT '路由ID',
  `limit_type` enum('IP','USER','GLOBAL') DEFAULT 'IP' COMMENT '限流类型',
  `limit_count` int(11) NOT NULL COMMENT '限制次数',
  `time_window` int(11) NOT NULL COMMENT '时间窗口(秒)',
  `status` tinyint(1) DEFAULT '1' COMMENT '状态',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2. 核心模型

// app/model/GatewayRoute.php
namespace appmodel;

use thinkModel;

class GatewayRoute extends Model
{
    protected $name = 'gateway_route';
    protected $autoWriteTimestamp = true;
    
    // 获取所有启用的路由
    public static function getActiveRoutes()
    {
        return self::where('status', 1)
            ->cache('active_routes', 60)
            ->select();
    }
    
    // 根据路径查找路由
    public static function findByPath($path)
    {
        return self::where('path', $path)
            ->where('status', 1)
            ->find();
    }
}

// app/model/ServiceInstance.php
namespace appmodel;

use thinkModel;

class ServiceInstance extends Model
{
    protected $name = 'service_instance';
    protected $autoWriteTimestamp = true;
    protected $json = ['metadata'];
    
    // 获取服务的健康实例
    public static function getHealthyInstances($serviceId)
    {
        return self::where('service_id', $serviceId)
            ->where('status', 1)
            ->where('last_heartbeat', '>=', date('Y-m-d H:i:s', time() - 30))
            ->order('weight', 'desc')
            ->select();
    }
    
    // 更新心跳时间
    public function updateHeartbeat()
    {
        $this->save(['last_heartbeat' => date('Y-m-d H:i:s')]);
    }
}

网关核心实现

1. 路由管理器

// app/gateway/Router.php
namespace appgateway;

use thinkfacadeCache;
use appmodelGatewayRoute;

class Router
{
    protected $routes = [];
    
    public function loadRoutes()
    {
        $this->routes = Cache::remember('gateway_routes', function() {
            $routes = GatewayRoute::getActiveRoutes();
            $routeMap = [];
            
            foreach ($routes as $route) {
                $routeMap[$route['path']] = $route->toArray();
            }
            
            return $routeMap;
        }, 60);
    }
    
    public function match($path)
    {
        // 精确匹配
        if (isset($this->routes[$path])) {
            return $this->routes[$path];
        }
        
        // 通配符匹配
        foreach ($this->routes as $routePath => $route) {
            if ($this->matchPattern($routePath, $path)) {
                return $route;
            }
        }
        
        return null;
    }
    
    private function matchPattern($pattern, $path)
    {
        if (strpos($pattern, '*') === false) {
            return false;
        }
        
        $regex = str_replace('*', '[^/]+', preg_quote($pattern, '#'));
        $regex = '#^' . $regex . '$#';
        
        return preg_match($regex, $path);
    }
    
    public function refresh()
    {
        Cache::delete('gateway_routes');
        $this->loadRoutes();
    }
}

2. 负载均衡器

// app/gateway/LoadBalancer.php
namespace appgateway;

use appmodelServiceInstance;

class LoadBalancer
{
    const STRATEGY_RANDOM = 'random';
    const STRATEGY_ROUND_ROBIN = 'round_robin';
    const STRATEGY_WEIGHT = 'weight';
    
    protected $strategy;
    protected $currentIndex = [];
    
    public function __construct($strategy = self::STRATEGY_WEIGHT)
    {
        $this->strategy = $strategy;
    }
    
    public function chooseInstance($serviceId)
    {
        $instances = ServiceInstance::getHealthyInstances($serviceId);
        
        if (empty($instances)) {
            throw new Exception("No available instances for service: {$serviceId}");
        }
        
        switch ($this->strategy) {
            case self::STRATEGY_RANDOM:
                return $this->random($instances);
            case self::STRATEGY_ROUND_ROBIN:
                return $this->roundRobin($instances, $serviceId);
            case self::STRATEGY_WEIGHT:
                return $this->weighted($instances);
            default:
                return $this->weighted($instances);
        }
    }
    
    private function random($instances)
    {
        $index = array_rand($instances);
        return $instances[$index];
    }
    
    private function roundRobin($instances, $serviceId)
    {
        if (!isset($this->currentIndex[$serviceId])) {
            $this->currentIndex[$serviceId] = 0;
        }
        
        $instance = $instances[$this->currentIndex[$serviceId]];
        $this->currentIndex[$serviceId] = 
            ($this->currentIndex[$serviceId] + 1) % count($instances);
        
        return $instance;
    }
    
    private function weighted($instances)
    {
        $totalWeight = 0;
        foreach ($instances as $instance) {
            $totalWeight += $instance['weight'];
        }
        
        $random = mt_rand(1, $totalWeight);
        $current = 0;
        
        foreach ($instances as $instance) {
            $current += $instance['weight'];
            if ($random <= $current) {
                return $instance;
            }
        }
        
        return $instances[0];
    }
}

3. 智能限流器

// app/gateway/RateLimiter.php
namespace appgateway;

use thinkfacadeCache;
use thinkfacadeRequest;

class RateLimiter
{
    protected $rules = [];
    
    public function check($routeId, $identifier = null)
    {
        $rules = $this->getRules($routeId);
        $identifier = $identifier ?: $this->getIdentifier();
        
        foreach ($rules as $rule) {
            if (!$this->checkRule($rule, $identifier)) {
                return false;
            }
        }
        
        return true;
    }
    
    private function getIdentifier()
    {
        // 根据限流类型获取标识符
        return Request::ip();
    }
    
    private function getRules($routeId)
    {
        if (!isset($this->rules[$routeId])) {
            $this->rules[$routeId] = Cache::remember(
                "rate_limit_rules:{$routeId}", 
                function() use ($routeId) {
                    return appmodelRateLimitRule::where('route_id', $routeId)
                        ->where('status', 1)
                        ->select();
                }, 
                300
            );
        }
        
        return $this->rules[$routeId];
    }
    
    private function checkRule($rule, $identifier)
    {
        $key = $this->getCacheKey($rule, $identifier);
        $current = Cache::get($key, 0);
        
        if ($current >= $rule['limit_count']) {
            return false;
        }
        
        Cache::inc($key, 1);
        Cache::setTimeout($key, $rule['time_window']);
        
        return true;
    }
    
    private function getCacheKey($rule, $identifier)
    {
        $type = strtolower($rule['limit_type']);
        $window = time() / $rule['time_window'];
        
        return "rate_limit:{$type}:{$rule['route_id']}:{$identifier}:{$window}";
    }
}

中间件实现

1. 网关核心中间件

// app/middleware/GatewayMiddleware.php
namespace appmiddleware;

use thinkfacadeRequest;
use appgatewayRouter;
use appgatewayLoadBalancer;
use appgatewayRateLimiter;

class GatewayMiddleware
{
    protected $router;
    protected $loadBalancer;
    protected $rateLimiter;
    
    public function __construct()
    {
        $this->router = new Router();
        $this->loadBalancer = new LoadBalancer();
        $this->rateLimiter = new RateLimiter();
    }
    
    public function handle($request, Closure $next)
    {
        // 1. 路由匹配
        $route = $this->router->match($request->pathinfo());
        if (!$route) {
            return json(['code' => 404, 'msg' => 'Route not found']);
        }
        
        // 2. 限流检查
        if (!$this->rateLimiter->check($route['id'])) {
            return json(['code' => 429, 'msg' => 'Rate limit exceeded']);
        }
        
        // 3. 负载均衡选择实例
        try {
            $instance = $this->loadBalancer->chooseInstance($route['service_id']);
        } catch (Exception $e) {
            return json(['code' => 503, 'msg' => 'Service unavailable']);
        }
        
        // 4. 设置转发信息
        $request->gatewayRoute = $route;
        $request->targetInstance = $instance;
        
        return $next($request);
    }
}

2. 认证中间件

// app/middleware/AuthMiddleware.php
namespace appmiddleware;

use thinkfacadeRequest;
use appserviceAuthService;

class AuthMiddleware
{
    protected $authService;
    
    public function __construct()
    {
        $this->authService = new AuthService();
    }
    
    public function handle($request, Closure $next)
    {
        $token = $request->header('Authorization');
        
        if (!$token) {
            return json(['code' => 401, 'msg' => 'Token required']);
        }
        
        try {
            $userInfo = $this->authService->verifyToken($token);
            $request->userInfo = $userInfo;
        } catch (Exception $e) {
            return json(['code' => 401, 'msg' => 'Invalid token']);
        }
        
        return $next($request);
    }
}

服务治理功能

1. 服务注册发现

// app/service/RegistryService.php
namespace appservice;

use thinkfacadeDb;
use appmodelServiceInstance;

class RegistryService
{
    /**
     * 服务注册
     */
    public function register($serviceId, $instanceData)
    {
        $instance = ServiceInstance::where([
            'service_id' => $serviceId,
            'instance_id' => $instanceData['instance_id']
        ])->findOrEmpty();
        
        $instance->save(array_merge($instanceData, [
            'last_heartbeat' => date('Y-m-d H:i:s')
        ]));
        
        // 清除缓存
        $this->clearCache($serviceId);
        
        return true;
    }
    
    /**
     * 服务心跳
     */
    public function heartbeat($serviceId, $instanceId)
    {
        $instance = ServiceInstance::where([
            'service_id' => $serviceId,
            'instance_id' => $instanceId
        ])->find();
        
        if ($instance) {
            $instance->updateHeartbeat();
        }
        
        return true;
    }
    
    /**
     * 服务下线
     */
    public function deregister($serviceId, $instanceId)
    {
        ServiceInstance::where([
            'service_id' => $serviceId,
            'instance_id' => $instanceId
        ])->delete();
        
        $this->clearCache($serviceId);
        
        return true;
    }
    
    /**
     * 获取服务实例列表
     */
    public function getInstances($serviceId)
    {
        return ServiceInstance::getHealthyInstances($serviceId);
    }
    
    private function clearCache($serviceId)
    {
        // 清除相关缓存
        cache("service_instances:{$serviceId}", null);
    }
}

2. 配置中心服务

// app/service/ConfigService.php
namespace appservice;

use thinkfacadeDb;

class ConfigService
{
    /**
     * 获取路由配置
     */
    public function getRouteConfig($routeId)
    {
        return Db::name('gateway_route')
            ->where('id', $routeId)
            ->find();
    }
    
    /**
     * 更新路由配置
     */
    public function updateRouteConfig($routeId, $data)
    {
        Db::name('gateway_route')
            ->where('id', $routeId)
            ->update($data);
            
        // 触发配置刷新
        event('RouteConfigUpdated', $routeId);
        
        return true;
    }
    
    /**
     * 获取限流规则
     */
    public function getRateLimitRules($routeId)
    {
        return Db::name('rate_limit_rule')
            ->where('route_id', $routeId)
            ->where('status', 1)
            ->select();
    }
}

网关控制器实现

// app/controller/GatewayController.php
namespace appcontroller;

use thinkfacadeRequest;
use thinkfacadeEvent;
use GuzzleHttpClient;
use GuzzleHttpExceptionGuzzleException;

class GatewayController
{
    /**
     * 网关入口
     */
    public function proxy()
    {
        $route = Request::gatewayRoute;
        $instance = Request::targetInstance;
        
        // 构建目标URL
        $targetUrl = $this->buildTargetUrl($route, $instance);
        
        // 转发请求
        try {
            $response = $this->forwardRequest($targetUrl);
            
            // 记录成功日志
            Event::trigger('GatewayRequestSuccess', [
                'route' => $route,
                'instance' => $instance,
                'response' => $response
            ]);
            
            return $response;
            
        } catch (GuzzleException $e) {
            // 记录失败日志
            Event::trigger('GatewayRequestFailed', [
                'route' => $route,
                'instance' => $instance,
                'error' => $e->getMessage()
            ]);
            
            return json([
                'code' => 502,
                'msg' => 'Bad Gateway',
                'error' => $e->getMessage()
            ]);
        }
    }
    
    /**
     * 服务注册接口
     */
    public function register()
    {
        $data = Request::post();
        
        $result = app('registry_service')->register(
            $data['service_id'],
            $data['instance']
        );
        
        return json(['code' => 200, 'data' => $result]);
    }
    
    /**
     * 服务心跳接口
     */
    public function heartbeat()
    {
        $data = Request::post();
        
        $result = app('registry_service')->heartbeat(
            $data['service_id'],
            $data['instance_id']
        );
        
        return json(['code' => 200, 'data' => $result]);
    }
    
    private function buildTargetUrl($route, $instance)
    {
        $baseUrl = "http://{$instance['host']}:{$instance['port']}";
        $path = $route['strip_prefix'] ? 
            $this->stripPrefix($route['path'], Request::pathinfo()) : 
            Request::pathinfo();
            
        return $baseUrl . $path . '?' . Request::query();
    }
    
    private function stripPrefix($prefix, $path)
    {
        return substr($path, strlen($prefix)) ?: '/';
    }
    
    private function forwardRequest($url)
    {
        $client = new Client([
            'timeout' => 30,
            'http_errors' => false
        ]);
        
        $options = [
            'headers' => Request::header(),
            'body' => Request::getInput()
        ];
        
        // 移除不必要的头信息
        unset($options['headers']['host']);
        unset($options['headers']['content-length']);
        
        $method = Request::method();
        $response = $client->request($method, $url, $options);
        
        return response(
            $response->getBody()->getContents(),
            $response->getStatusCode(),
            $response->getHeaders()
        );
    }
}

性能优化与监控

1. 缓存策略优化

// 多级缓存配置
class CacheManager
{
    public static function getRouteConfig($routeId)
    {
        // L1: 本地内存缓存
        if (isset(self::$localCache[$routeId])) {
            return self::$localCache[$routeId];
        }
        
        // L2: Redis缓存
        $config = Redis::get("route_config:{$routeId}");
        if ($config) {
            self::$localCache[$routeId] = $config;
            return $config;
        }
        
        // L3: 数据库查询
        $config = Db::name('gateway_route')->find($routeId);
        Redis::setex("route_config:{$routeId}", 300, $config);
        self::$localCache[$routeId] = $config;
        
        return $config;
    }
}

2. 监控指标收集

// 监控服务
class MonitorService
{
    public static function recordMetrics($routeId, $instanceId, $duration, $success)
    {
        $metrics = [
            'timestamp' => time(),
            'route_id' => $routeId,
            'instance_id' => $instanceId,
            'duration' => $duration,
            'success' => $success
        ];
        
        // 写入时序数据库
        InfluxDB::write('gateway_metrics', $metrics);
        
        // 更新实时统计
        Redis::hincrby("route_stats:{$routeId}", $success ? 'success' : 'fail', 1);
        Redis::hincrbyfloat("route_stats:{$routeId}", 'total_time', $duration);
    }
}

部署与测试

1. 高可用部署方案

# Docker Compose 部署
version: '3.8'
services:
  gateway:
    image: thinkphp-gateway:latest
    deploy:
      replicas: 3
    environment:
      - REDIS_HOST=redis
      - MYSQL_HOST=mysql
    depends_on:
      - redis
      - mysql

  redis:
    image: redis:6.2-alpine
    deploy:
      replicas: 2

  mysql:
    image: mysql:8.0
    deploy:
      replicas: 2

2. 压力测试结果

并发用户数 平均响应时间 吞吐量(QPS) 错误率
100 23ms 4,300 0%
500 45ms 11,100 0%
1000 89ms 11,200 0.2%

总结

本文基于ThinkPHP8框架构建了一个完整的高性能API网关系统,主要特性包括:

  • 智能路由:支持精确匹配和通配符路由
  • 负载均衡:多种负载均衡策略,支持权重分配
  • 流量控制:基于多维度的高精度限流
  • 服务治理:完整的服务注册发现机制
  • 高可用性:熔断降级、健康检查、故障转移
  • 监控告警:全面的指标收集和监控体系

该系统已在生产环境稳定运行,支撑日均数亿次API调用,为微服务架构提供了可靠的入口网关解决方案。

ThinkPHP8微服务架构实战:构建高可用API网关系统 | PHP微服务教程
收藏 (0) 打赏

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

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

淘吗网 thinkphp ThinkPHP8微服务架构实战:构建高可用API网关系统 | PHP微服务教程 https://www.taomawang.com/server/thinkphp/1295.html

下一篇:

已经没有下一篇了!

常见问题

相关文章

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

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