性能优化

Redis缓存穿透解决实验:从500错误到0异常的防护

2024-08-09 | Redis 6.2 + 布隆过滤器
问题场景 在高并发场景下,恶意用户频繁请求不存在的实验ID(如id=-1, id=999999),这些请求绕过缓存直接访问数据库,导致数据库压力激增,接口响应时间变长,甚至出现500错误。 解决方案
  1. 布隆过滤器预存:上线前将所有有效实验ID存入布隆过滤器
# 使用RedisBloom模块创建布隆过滤器
from redisbloom.client import Client

rb = Client()

估计元素数量和期望误判率

rb.bfCreate('experiment_ids', 0.01, 100000)

将所有实验ID添加到布隆过滤器

for exp_id in all_experiment_ids: rb.bfAdd('experiment_ids', exp_id)
  1. 空值缓存:查询到不存在的ID时,缓存null值(过期时间5分钟)
function getExperiment($id) {
    $cacheKey = "experiment:{$id}";
    $data = $redis->get($cacheKey);

    if ($data !== null) {
        // 缓存命中,无论是否为空值都直接返回
        return json_decode($data, true);
    }

    // 布隆过滤器检查
    if (!$redis->executeCommand('BF.EXISTS', ['experiment_ids', $id])) {
        // 布隆过滤器判断不存在,直接返回
        return null;
    }

    // 查询数据库
    $data = $db->query("SELECT * FROM experiments WHERE id = ?", $id);

    // 缓存结果,包括空值
    $redis->setex($cacheKey, 300, json_encode($data ?: null));

    return $data;
}
  1. 接口限流:使用Nginx limit_req模块限制单IP每秒请求数
http {
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;

    server {
        location /api/experiments/ {
            limit_req zone=mylimit burst=20 nodelay;
            # 其他配置...
        }
    }
}
数据对比
指标 优化前 优化后
-------------------- 800
120 接口500错误率 3.2%
0
平均响应时间 450ms 80ms
| Redis内存占用 | 128MB | 142MB | 注意事项 - 布隆过滤器有一定的误判率(约1%),但不会漏判 - 空值缓存时间不宜过长,避免影响数据一致性 - 定期更新布隆过滤器,添加新的实验ID
分享至:

相关学习推荐

性能优化

PHP接口响应优化实验:从500ms到80ms

2024-04-15
查看详情
性能优化

PHP会话从文件到Redis的迁移实验

2024-09-20
查看详情