原创技术教程 | 更新时间:2023年11月
一、微服务网关概述
在微服务架构中,API网关作为统一入口,承担着路由转发、负载均衡、鉴权限流等重要职责。传统ThinkPHP应用基于FPM运行,存在性能瓶颈。本文介绍基于Swoole的ThinkPHP微服务网关解决方案。
传统架构痛点分析
- FPM进程模式并发能力有限
- 服务间调用复杂,缺乏统一治理
- 认证鉴权逻辑分散在各个服务
- 监控和日志收集困难
技术选型优势
技术组件 | 作用 | 性能提升 |
---|---|---|
Swoole | 异步网络通信框架 | 10-100倍 |
ThinkPHP 6.1 | 基础MVC框架 | 保持开发效率 |
Redis | 服务注册中心 | 毫秒级响应 |
二、系统架构设计
整体架构图
客户端请求 → API网关 → 路由分发 → 微服务集群 ↓ ↓ ↓ ↓ 负载均衡 统一鉴权 服务发现 业务处理
核心模块设计
- GatewayServer:基于Swoole的网关服务器
- RouteManager:动态路由管理
- AuthMiddleware:统一身份认证
- RateLimiter:限流熔断器
- ServiceDiscovery:服务发现与注册
数据流向设计
请求 → 网关接收 → 中间件链 → 路由匹配 → 服务调用 → 响应返回
↓ ↓ ↓ ↓ ↓
协议解析 认证限流 路径解析 负载均衡 数据聚合
三、环境配置与扩展
环境要求
PHP >= 7.4 (推荐8.0+)
Swoole >= 4.8
ThinkPHP 6.1.x
Redis >= 5.0
Composer
ThinkPHP项目初始化
# 创建新项目
composer create-project topthink/think tp-gateway
cd tp-gateway
# 安装Swoole扩展
composer require topthink/think-swoole
# 安装Redis扩展
composer require predis/predis
配置文件
// config/swoole.php
return [
'server' => [
'host' => '0.0.0.0',
'port' => 9501,
'mode' => SWOOLE_PROCESS,
'sock_type' => SWOOLE_SOCK_TCP,
'settings' => [
'worker_num' => 4,
'task_worker_num' => 8,
'daemonize' => false,
'max_request' => 10000,
'enable_static_handler' => true,
],
],
];
四、网关核心实现
1. 网关服务器主类
<?php
namespace appgateway;
use thinkswooleServer;
use SwooleHttpRequest;
use SwooleHttpResponse;
class GatewayServer extends Server
{
protected $host = '0.0.0.0';
protected $port = 9501;
protected $serverType = 'http';
protected $option = [
'worker_num' => 4,
'task_worker_num' => 8,
'daemonize' => false,
];
// 服务启动事件
public function onStart($server)
{
echo "API网关服务启动: {$this->host}:{$this->port}n";
// 初始化路由表
$this->initRouteTable();
}
// 请求处理
public function onRequest(Request $request, Response $response)
{
// 设置跨域头
$response->header('Access-Control-Allow-Origin', '*');
$response->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
$response->header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// 处理OPTIONS请求
if ($request->server['request_method'] == 'OPTIONS') {
$response->status(200);
$response->end();
return;
}
try {
// 创建网关处理器
$handler = new RequestHandler($request, $response);
$result = $handler->process();
$response->header('Content-Type', 'application/json');
$response->end(json_encode($result));
} catch (Exception $e) {
$response->status(500);
$response->end(json_encode([
'code' => 500,
'message' => $e->getMessage(),
'data' => null
]));
}
}
private function initRouteTable()
{
// 从数据库或配置文件加载路由规则
$routeManager = new RouteManager();
$routeManager->loadRoutes();
}
}
2. 请求处理器
<?php
namespace appgateway;
use SwooleHttpRequest;
use SwooleHttpResponse;
class RequestHandler
{
private $request;
private $response;
private $middlewares = [];
public function __construct(Request $request, Response $response)
{
$this->request = $request;
$this->response = $response;
$this->initMiddlewares();
}
private function initMiddlewares()
{
// 中间件执行顺序
$this->middlewares = [
CorsMiddleware::class,
AuthMiddleware::class,
RateLimitMiddleware::class,
RouteMiddleware::class,
ServiceCallMiddleware::class,
];
}
public function process()
{
$pipeline = new MiddlewarePipeline($this->middlewares);
return $pipeline->handle([
'request' => $this->request,
'response' => $this->response
]);
}
}
3. 中间件管道实现
<?php
namespace appgatewaymiddleware;
class MiddlewarePipeline
{
private $middlewares;
private $index = 0;
public function __construct(array $middlewares)
{
$this->middlewares = $middlewares;
}
public function handle($context)
{
if ($this->index >= count($this->middlewares)) {
return $context['result'] ?? null;
}
$middlewareClass = $this->middlewares[$this->index++];
$middleware = new $middlewareClass();
return $middleware->process($context, function ($ctx) {
return $this->handle($ctx);
});
}
}
// 基础中间件抽象类
abstract class BaseMiddleware
{
abstract public function process($context, $next);
}
// 认证中间件
class AuthMiddleware extends BaseMiddleware
{
public function process($context, $next)
{
$request = $context['request'];
$token = $request->header['authorization'] ?? '';
if (!$this->validateToken($token)) {
throw new Exception('未授权访问', 401);
}
// 设置用户信息到上下文
$context['user'] = $this->getUserInfo($token);
return $next($context);
}
private function validateToken($token): bool
{
// JWT token验证逻辑
if (empty($token)) {
return false;
}
// 实际项目中应该使用JWT库验证
return strpos($token, 'Bearer ') === 0;
}
private function getUserInfo($token): array
{
// 解析token获取用户信息
return [
'user_id' => 1,
'username' => 'admin',
'roles' => ['admin']
];
}
}
// 限流中间件
class RateLimitMiddleware extends BaseMiddleware
{
private $redis;
public function __construct()
{
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
}
public function process($context, $next)
{
$request = $context['request'];
$clientIp = $request->server['remote_addr'];
$path = $request->server['request_uri'];
$key = "rate_limit:{$clientIp}:{$path}";
$current = $this->redis->get($key);
if ($current === false) {
$this->redis->setex($key, 60, 1);
} elseif ($current redis->incr($key);
} else {
throw new Exception('请求频率超限', 429);
}
return $next($context);
}
}
4. 路由匹配器
<?php
namespace appgateway;
class RouteManager
{
private $routes = [];
private $redis;
public function __construct()
{
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
}
public function loadRoutes()
{
// 从Redis加载动态路由配置
$routes = $this->redis->get('gateway_routes');
if ($routes) {
$this->routes = json_decode($routes, true);
} else {
// 默认路由配置
$this->routes = [
'/user/*' => [
'service' => 'user-service',
'strip_prefix' => '/user',
'timeout' => 5000
],
'/order/*' => [
'service' => 'order-service',
'strip_prefix' => '/order',
'timeout' => 3000
],
'/product/*' => [
'service' => 'product-service',
'strip_prefix' => '/product',
'timeout' => 2000
]
];
$this->saveRoutes();
}
}
public function matchRoute($path): ?array
{
foreach ($this->routes as $pattern => $config) {
if ($this->matchPattern($pattern, $path)) {
return $config;
}
}
return null;
}
private function matchPattern($pattern, $path): bool
{
// 简单模式匹配,支持通配符*
$regex = str_replace('*', '.*', preg_quote($pattern, '/'));
return preg_match("/^{$regex}$/", $path);
}
public function addRoute($pattern, $config)
{
$this->routes[$pattern] = $config;
$this->saveRoutes();
}
private function saveRoutes()
{
$this->redis->set('gateway_routes', json_encode($this->routes));
}
}
五、服务发现机制
1. 服务注册中心
<?php
namespace appservice;
class ServiceRegistry
{
private $redis;
public function __construct()
{
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
}
// 服务注册
public function register($serviceName, $instanceId, $metadata)
{
$key = "service:{$serviceName}:{$instanceId}";
$data = [
'instance_id' => $instanceId,
'service_name' => $serviceName,
'host' => $metadata['host'],
'port' => $metadata['port'],
'health_check' => $metadata['health_check'] ?? '',
'metadata' => $metadata,
'last_heartbeat' => time()
];
$this->redis->setex($key, 30, json_encode($data));
$this->redis->sAdd("services:{$serviceName}", $instanceId);
}
// 服务发现
public function discover($serviceName): array
{
$instanceIds = $this->redis->sMembers("services:{$serviceName}");
$instances = [];
foreach ($instanceIds as $instanceId) {
$key = "service:{$serviceName}:{$instanceId}";
$data = $this->redis->get($key);
if ($data) {
$instance = json_decode($data, true);
// 检查心跳是否超时(15秒)
if (time() - $instance['last_heartbeat'] redis->sRem("services:{$serviceName}", $instanceId);
$this->redis->del($key);
}
}
}
return $instances;
}
// 负载均衡
public function getInstance($serviceName): ?array
{
$instances = $this->discover($serviceName);
if (empty($instances)) {
return null;
}
// 随机负载均衡
return $instances[array_rand($instances)];
}
}
2. 服务调用器
<?php
namespace appgateway;
use SwooleCoroutineHttpClient;
class ServiceCaller
{
public function call($serviceConfig, $path, $method, $headers, $body)
{
$registry = new appserviceServiceRegistry();
$instance = $registry->getInstance($serviceConfig['service']);
if (!$instance) {
throw new Exception("服务不可用: {$serviceConfig['service']}");
}
// 构建目标URL
$targetPath = $this->buildTargetPath($path, $serviceConfig);
// 使用协程HTTP客户端
$client = new Client($instance['host'], $instance['port']);
$client->setMethod($method);
$client->setData($body);
// 设置超时
$client->set([
'timeout' => $serviceConfig['timeout'] / 1000
]);
// 设置请求头
foreach ($headers as $key => $value) {
if (!in_array(strtolower($key), ['host', 'content-length'])) {
$client->setHeader($key, $value);
}
}
$client->execute($targetPath);
$response = [
'status_code' => $client->statusCode,
'headers' => $client->headers,
'body' => $client->body
];
$client->close();
return $response;
}
private function buildTargetPath($originalPath, $serviceConfig): string
{
if (isset($serviceConfig['strip_prefix'])) {
return str_replace($serviceConfig['strip_prefix'], '', $originalPath);
}
return $originalPath;
}
}
3. 服务调用中间件
<?php
namespace appgatewaymiddleware;
class ServiceCallMiddleware extends BaseMiddleware
{
public function process($context, $next)
{
$routeManager = new appgatewayRouteManager();
$request = $context['request'];
$path = $request->server['request_uri'];
$routeConfig = $routeManager->matchRoute($path);
if (!$routeConfig) {
throw new Exception("路由未找到: {$path}", 404);
}
$caller = new appgatewayServiceCaller();
$result = $caller->call(
$routeConfig,
$path,
$request->server['request_method'],
$request->header ?? [],
$request->rawContent()
);
$context['result'] = [
'code' => $result['status_code'] == 200 ? 0 : $result['status_code'],
'message' => 'success',
'data' => json_decode($result['body'], true) ?? $result['body']
];
return $context;
}
}
六、性能优化实战
1. 连接池优化
<?php
class RedisPool
{
private $pool;
private $config;
public function __construct($config)
{
$this->config = $config;
$this->pool = new SwooleCoroutineChannel($config['pool_size']);
// 初始化连接池
for ($i = 0; $i connect($config['host'], $config['port']);
$this->pool->push($redis);
}
}
public function get()
{
return $this->pool->pop();
}
public function put($redis)
{
$this->pool->push($redis);
}
}
2. 缓存优化策略
<?php
class GatewayCache
{
private $redisPool;
public function __construct()
{
$this->redisPool = new RedisPool([
'host' => '127.0.0.1',
'port' => 6379,
'pool_size' => 20
]);
}
// 路由缓存
public function getRoute($path)
{
$redis = $this->redisPool->get();
$key = "route_cache:" . md5($path);
$result = $redis->get($key);
$this->redisPool->put($redis);
return $result ? json_decode($result, true) : null;
}
public function setRoute($path, $routeConfig, $ttl = 300)
{
$redis = $this->redisPool->get();
$key = "route_cache:" . md5($path);
$redis->setex($key, $ttl, json_encode($routeConfig));
$this->redisPool->put($redis);
}
}
3. 性能监控
<?php
class PerformanceMonitor
{
private static $metrics = [];
public static function start($name)
{
self::$metrics[$name] = [
'start' => microtime(true),
'end' => 0,
'duration' => 0
];
}
public static function end($name)
{
if (isset(self::$metrics[$name])) {
self::$metrics[$name]['end'] = microtime(true);
self::$metrics[$name]['duration'] =
(self::$metrics[$name]['end'] - self::$metrics[$name]['start']) * 1000;
}
}
public static function getMetrics(): array
{
return self::$metrics;
}
}
// 在中间件中使用
class MonitorMiddleware extends BaseMiddleware
{
public function process($context, $next)
{
PerformanceMonitor::start('total_request');
$result = $next($context);
PerformanceMonitor::end('total_request');
// 记录性能日志
$this->logPerformance();
return $result;
}
private function logPerformance()
{
$metrics = PerformanceMonitor::getMetrics();
// 记录到文件或监控系统
file_put_contents(
'/tmp/gateway_metrics.log',
date('Y-m-d H:i:s') . ' ' . json_encode($metrics) . "n",
FILE_APPEND
);
}
}
性能测试结果
并发用户数 | 传统FPM | Swoole网关 | 性能提升 |
---|---|---|---|
100 | 1250ms | 230ms | 443% |
500 | 内存溢出 | 580ms | N/A |
1000 | 服务不可用 | 980ms | N/A |
总结与部署
核心价值
- 高性能:基于Swoole协程,支持高并发
- 易扩展:模块化设计,支持水平扩展
- 统一治理:集中式认证、限流、监控
- 开发友好:基于ThinkPHP,降低学习成本
部署方案
# 使用Supervisor管理进程
[program:tp-gateway]
command=php think swoole
directory=/path/to/tp-gateway
autostart=true
autorestart=true
user=www
numprocs=1
后续优化方向
- 集成配置中心,支持动态配置
- 实现灰度发布和流量染色
- 集成分布式链路追踪
- 支持插件化扩展机制