去年我在某电商平台负责重构订单系统,将接口响应时间从1.2秒优化到180ms,QPS从80提升到420。以下是实战中总结的宝贵经验。
目录
[1. 滑动时间窗口算法(核心代码)](#1. 滑动时间窗口算法(核心代码))
[2. 限流效果对比](#2. 限流效果对比)
一、为什么API网关是电商系统的核心枢纽?

在我们日订单量10万+的电商系统中,所有请求首先经过PHP网关层。这个设计解决了三个关键问题:
- 统一鉴权:避免每个服务重复实现JWT验证
- 流量控制:防止突发流量击垮后端服务
- 请求路由:动态分配请求到不同版本的服务实例
php
// 网关入口核心逻辑
class ApiGateway {
public function handle(Request $request): Response {
$this->rateLimit($request); // 限流检查
$this->authenticate($request); // 鉴权验证
$service = $this->route($request); // 路由分发
return $service->execute();
}
}
二、JWT鉴权:那些文档不会告诉你的安全陷阱
错误示范(存在安全风险):
php
// 危险!直接暴露用户ID和角色
$payload = [
'user_id' => 123,
'role' => 'admin'
];
正确方案(我们最终采用的):
php
$uuid = bin2hex(random_bytes(16)); // 生成唯一标识
$redis->setex("auth:token:$uuid", 300, json_encode([
'user_id' => 123,
'permissions' => ['order:read', 'order:write']
]));
// JWT payload仅存储非敏感信息
$payload = [
'iss' => 'api.yourshop.com',
'sub' => 'user_uuid', // 非真实ID
'jti' => $uuid, // 令牌唯一标识
'exp' => time() + 3600
];

三、高并发场景下的限流算法实战
1. 滑动时间窗口算法(核心代码)
php
class SlidingWindowLimiter {
private $redis;
private $windowSize = 60; // 60秒窗口
private $maxRequests = 100; // 最大请求数
public function __construct(Redis $redis) {
$this->redis = $redis;
}
public function allow(string $ip): bool {
$now = microtime(true);
$key = "rate_limit:$ip";
// 删除过期请求记录
$this->redis->zremrangebyscore($key, 0, $now - $this->windowSize);
// 获取当前请求数
$count = $this->redis->zcard($key);
if ($count < $this->maxRequests) {
$this->redis->zadd($key, $now, $now);
$this->redis->expire($key, $this->windowSize);
return true;
}
return false;
}
}
2. 限流效果对比
| 策略 | 突发流量处理 | 资源消耗 | 实现复杂度 |
|---|---|---|---|
| 固定窗口 | 差 | 低 | 简单 |
| 漏桶算法 | 良 | 中 | 中等 |
| 滑动窗口 | 优 | 中高 | 复杂 |
四、缓存穿透:我们踩过的坑和终极解决方案
问题场景:攻击者请求大量不存在的商品ID,导致缓存失效,直接查询数据库
解决方案1:布隆过滤器
php
// 初始化布隆过滤器
$bloomFilter = new BloomFilter(1000000, 0.001);
// 预热有效商品ID
foreach ($productIds as $id) {
$bloomFilter->add($id);
}
// 请求处理
if (!$bloomFilter->contains($requestId)) {
return ['error' => '商品不存在']; // 直接拦截
}
解决方案2:空值缓存
php
// 查询不存在的商品时
$redis->setex("product:{$invalidId}", 300, 'NULL');
// 后续请求处理
$cache = $redis->get("product:{$id}");
if ($cache === 'NULL') {
return ['error' => '商品不存在'];
}

五、熔断机制:系统自保护的最后一环
当订单服务错误率超过阈值时,网关自动触发熔断:
php
class CircuitBreaker {
private $state = 'CLOSED';
private $failureCount = 0;
private $lastFailureTime = 0;
public function handleRequest() {
if ($this->state === 'OPEN') {
// 直接返回降级响应
return $this->fallbackResponse();
}
try {
$response = $this->callService();
$this->reset();
return $response;
} catch (Exception $e) {
$this->recordFailure();
throw $e;
}
}
private function recordFailure() {
$this->failureCount++;
if ($this->failureCount > 10 && time() - $this->lastFailureTime < 60) {
$this->state = 'OPEN';
// 启动定时器,30秒后进入半开状态
$this->startHalfOpenTimer();
}
}
}
六、性能优化前后对比(真实生产数据)
bash
graph LR
A[优化前] -->|响应时间| B[1200ms]
A -->|QPS| C[80]
D[优化后] -->|响应时间| E[180ms]
D -->|QPS| F[420]
style A fill:#ff9999,stroke:#333
style D fill:#99ff99,stroke:#333
优化关键点:
- OPcache加速脚本执行
- Redis管道技术减少网络开销
- 静态资源CDN分发
- MySQL查询优化(索引+分库分表)
七、总结:电商系统API网关最佳实践
- 安全优先:JWT中不存储敏感信息,权限实时查询
- 分层限流:全局限流+服务级限流+用户级限流
- 缓存策略:布隆过滤器+空值缓存+多级缓存
- 熔断降级:基于错误率的自动熔断机制
- 持续监控:Prometheus+Granfa构建监控看板
项目成果 :系统稳定运行8个月,618大促期间成功支撑单日所有订单,服务器资源节省40%。