Laravel/PHPRedis为何发送额外Redis命令及优化咨询
Redis会话驱动下ElastiCache非键命令过多的排查与优化
问题背景
我使用Redis无服务器ElastiCache实例,Laravel配置为Redis会话驱动,采用PHPRedis客户端。观察缓存指标发现:
StringBasedCmds数量和应用请求数基本匹配TotalCmdsCount却是前者的6倍左右,额外命令全部来自NonKeyTypeCmds- 无服务器ElastiCache不支持
MONITOR命令,无法直接查看执行的命令 - 预期每个请求仅对应2个命令(请求开始
GET会话,结束SET会话),实际命令数远超预期
相关配置
.env配置:
SESSION_DRIVER=redis REDIS_HOST=<my-instance>.serverless.use1.cache.amazonaws.com REDIS_PORT=6379 REDIS_PASSWORD=***** REDIS_USERNAME=default
config/database.php中的Redis配置:
'redis' => [ 'client' => env('REDIS_CLIENT', 'phpredis'), 'options' => [ 'cluster' => env('REDIS_CLUSTER', 'redis'), 'prefix' => env('REDIS_PREFIX', (env('APP_ENV') === 'local' ? gethostname().':' : '').'myapp:'), 'persistent' => true, // Needed for TLS clustering to work! 'context' => [] ], 'clusters' => [ // More undocumented behavior - if you actually need to connect with a password, you need to supply it as an option // see PhpRedisConnector.php. I don't see a way to supply a non-default user name. 'options' => [ 'password' => env('REDIS_PASSWORD'), ], 'default' => [ [ 'url' => env('REDIS_URL'), 'host' => env('REDIS_HOST', '127.0.0.1'), 'port' => env('REDIS_PORT', '6379'), 'database' => env('REDIS_DB', '0'), ], ], 'cache' => [ [ 'url' => env('REDIS_URL'), 'host' => env('REDIS_HOST', '127.0.0.1'), 'port' => env('REDIS_PORT', '6379'), 'database' => env('REDIS_CACHE_DB', '1'), ], ], ],
额外命令的来源分析
这些NonKeyTypeCmds主要来自以下几类操作:
- 连接认证与选库:每次建立Redis连接时,会执行
AUTH(验证密码)和SELECT(切换到指定数据库)命令。如果同时使用default(db0)和cache(db1)两个集群,每次跨集群操作都会重复执行这两个命令。 - 持久连接检测:配置了
persistent => true后,PHPRedis可能会定期发送PING命令检测连接存活状态,尤其是连接空闲一段时间后。 - 集群模式相关命令:配置中
cluster => redis,PHPRedis会自动发送CLUSTER NODES或CLUSTER SLOTS命令发现集群节点,即使无服务器ElastiCache是单节点实例也会执行这类命令。 - 会话过期设置:Laravel的Redis会话驱动在写入会话时,除了
SET命令,还会单独执行EXPIRE命令设置过期时间,这个命令也可能被归类到非键操作统计中。
优化方案
针对上述来源,可通过以下方式减少非键命令:
统一Redis数据库
将会话和缓存使用同一个Redis数据库(比如都用db0),删除cache集群配置,避免跨集群操作时重复执行SELECT命令。修改config/database.php,统一会话和缓存的数据库配置,同时调整.env中的REDIS_CACHE_DB为0。优化持久连接配置
- 尝试关闭持久连接:如果应用请求量不高,
persistent => true可能导致更多PING检测命令,可改为false后观察命令数变化。 - 调整连接超时参数:在
options中添加'timeout' => 60(根据实际情况调整),减少因连接超时导致的重连,避免重复执行AUTH和SELECT。
- 尝试关闭持久连接:如果应用请求量不高,
关闭不必要的集群发现
无服务器ElastiCache并非真正的Redis集群,将cluster选项改为'none',避免PHPRedis发送集群相关命令。修改config/database.php中的'cluster' => env('REDIS_CLUSTER', 'none')。复用Redis连接
确保Laravel在单个请求周期内复用同一个Redis连接,避免多次建立连接。可通过代码中显式使用Redis::connection()获取连接实例,而非每次新建连接。检查会话配置细节
确认config/session.php中的expire_on_close是否为false,如果是true,Laravel可能会额外执行过期相关命令;同时排查是否有自定义中间件或服务在请求周期内额外操作Redis,带来非必要命令。
内容的提问来源于stack exchange,提问作者Mat
相关产品推荐
相关产品推荐

