性能优化

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

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

    使用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)
  • 空值缓存:查询到不存在的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;
    }
  • 接口限流:使用Nginx limit_req模块限制单IP每秒请求数
  • nginx http { limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; server { location /api/experiments/ { limit_req zone=mylimit burst=20 nodelay; # 其他配置... } } } ``` 数据对比 | 指标 | 优化前 | 优化后 | |--------------------|----------|----------| | 数据库QPS | 800 | 120 | | 接口500错误率 | 3.2% | 0 | | 平均响应时间 | 450ms | 80ms | | Redis内存占用 | 128MB | 142MB | 注意事项 - 布隆过滤器有一定的误判率(约1%),但不会漏判 - 空值缓存时间不宜过长,避免影响数据一致性 - 定期更新布隆过滤器,添加新的实验ID
    分享至:

    相关学习推荐

    性能优化

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

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

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

    2024-09-20
    查看详情