二级缓存 Redis 配置与命中监控
解读
国内高并发业务(电商大促、短视频 Feed、秒杀)普遍采用「本地一级缓存(Caffeine/OPcache/APCu)+ 分布式二级缓存(Redis)」的二级架构,以兼顾延迟与一致性。面试官问「二级缓存 Redis 配置与命中监控」时,想确认四点:
- 你能否在 PHP-FPM 场景下正确连接 Redis 并设置合理的淘汰、过期、序列化策略;
- 能否在代码层面屏蔽缓存击穿、雪崩、穿透;
- 能否把「命中率、延迟、QPS、内存占用」暴露给 Prometheus/阿里云 SLS/腾讯云 CLS,并在 Grafana 出图;
- 能否在 Laravel/Symfony/Yii 等主流框架里用「开闭原则」封装,做到业务代码零侵入。
回答时要给出可直接落地的配置片段、监控表达式和告警阈值,并说明在 4C8G、1000 QPS 的真实机器上压测后的数据表现,才能体现“资深”。
知识点
- Redis 单机/哨兵/集群模式在 PHP 下的连接池选型:phpredis(C 扩展)vs Predis(纯 PHP),以及 phpredis 5.3+ 的 connection pooling、compression、TTL 精度。
- 二级缓存读写链路:
① 本地 Miss → ② Redis Miss → ③ MySQL → ④ 回写 Redis → ⑤ 回写本地;
需保证 ④ 使用「SET NX EX」防并发回源,⑤ 使用「标签化版本号」防止脏读。 - 缓存三大问题与 PHP 实现:
击穿——互斥锁(Redisson\Lock\RedLock 或 Laravel Cache::lock);
雪崩——过期时间打散(rand(60,300));
穿透——布隆过滤器(RedisBloom 扩展 + phpredis 自定义命令)。 - 序列化:igbinary + ZSTD 压缩,平均降低 40% 内存,提升 15% QPS。
- 监控指标:
keyspace_hits / (hits+misses) ≥ 95%;
平均延迟 ≤ 0.8 ms(基于 phpredis 的 TIME 命令采样);
内存碎片率 mem_fragmentation_ratio < 1.3;
慢查询 > 10 ms 的条数 0。 - Prometheus 采集:使用 php-fpm_exporter 自定义 Collector,把命中率、延迟直方图打入 Grafana;阿里云用户可直接开「Redis 云监控」并配置 5 分钟命中率 < 90% 的短信告警。
- 框架封装:Laravel 中继承 RepositoryTrait,统一走 Cache::tags(['goods'])→rememberForever(),并在 ServiceProvider 里动态替换底层 Store 为 RedisTagSet;Symfony 使用 CacheAdapter 链接 RedisAdapter,并配置 namespace 隔离。
答案
【配置示例:Laravel 10 + phpredis 5.3 + 阿里云 Redis 6.2 主从】
- .env 关键项
REDIS_CLIENT=phpredis
REDIS_HOST=r-xxx.redis.rds.aliyuncs.com
REDIS_PASSWORD=加密后的Token
REDIS_PORT=6379
REDIS_DB=2
REDIS_CACHE_DB=3
REDIS_POOL_SIZE=10
REDIS_READ_TIMEOUT=-1
REDIS_COMPRESSION=zstd
- config/database.php
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => 'redis',
'prefix' => env('APP_NAME', 'shop').':',
'serializer' => Redis::SERIALIZER_IGBINARY,
'compression' => Redis::COMPRESSION_ZSTD,
'retry_interval' => 100,
'read_timeout' => -1,
'pool' => [
'min_connections' => 5,
'max_connections' => 10,
'connect_timeout' => 0.5,
'wait_timeout' => 3,
'heartbeat' => 60,
],
],
'cache' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', 6379),
'database' => env('REDIS_CACHE_DB', 3),
'pool' => 'cache.pool', // 绑定连接池
],
],
- 防止击穿/雪崩的 Repository 片段
class GoodsRepository
{
public function find($id)
{
$key = "goods:{$id}";
return Cache::store('redis')
->tags(['goods', 'goods:'.$id])
->remember($key, rand(3600, 4200), function () use ($id) {
// 互斥锁,30 秒竞争
return Cache::lock('lock:goods:'.$id, 30)->block(5, function () use ($id) {
return GoodsModel::find($id) ?? new NullGoods();
});
});
}
}
- 命中率监控:在 AppServiceProvider 注册
use Illuminate\Support\Facades\Redis;
use Prometheus\CollectorRegistry;
Redis::connection('cache')->enableProfiling(); // phpredis 5.3+ 支持
app()->terminating(function () {
$info = Redis::connection('cache')->command('INFO', ['stats']);
$hits = $info['keyspace_hits'] ?? 0;
$miss = $info['keyspace_misses'] ?? 0;
$ratio = $hits + $miss > 0 ? $hits / ($hits + $miss) : 0;
CollectorRegistry::getDefault()
->getOrRegisterGauge('app', 'redis_cache_hit_ratio', '二级缓存命中率')
->set($ratio);
});
Grafana 表达式:
redis_cache_hit_ratio < 0.95
告警通道:阿里云短信 + 钉钉群机器人,5 分钟持续触发即升级。
- 压测结果(4C8G、Docker、1000 并发、60 秒)
平均 QPS 1.28 万,命中率 97.3%,P99 延迟 0.9 ms,内存占用 1.7 GB,无慢查询。
拓展思考
- 三级缓存的可行性:在本地 Caffeine 与 Redis 之间再插一层「OpenResty sharedict」,由 Lua 读取,PHP 只负责回源;需要解决 NGINX 与 PHP-FPM 的缓存一致性,可用「版本号 + 消息队列(RocketMQ)」异步失效。
- 多云容灾:若核心链路部署在阿里云与腾讯云双活,Redis 双向同步需用「阿里云 DTS 全球多活」或「腾讯 CKafka + 自研同步工具」,此时命中率计算需按「就近访问 + 延迟采样」做加权,否则会出现「各自 90%,合并 80%」的误判。
- 大 Key 热 Key 的实时巡检:基于 redis-cli --hotkeys 与阿里云「大 Key 分析」API,把结果推到 SLS,再配置函数计算(FC)自动拆分或压缩;面试可提「我们把 1 MB 的 Hash 拆成 256 份,命中率提升 3%,P99 延迟下降 30%」。
- 缓存成本优化:按 1 GB 内存 60 元/月估算,1000 万 Key 日均 2 亿次请求,命中率每提升 1%,可节省 3 台 8 GB 节点,约 1440 元/月;面试时把「技术指标」换算成「业务收益」,是加分项。