若Laravel缓存体积过大,可启用zlib压缩、自定义压缩Store、改用msgpack序列化、按标签粒度压缩或绕过冗余序列化来优化内存占用。

如果您在 Laravel 应用中观察到缓存数据体积过大、序列化开销高或 Redis 内存占用异常上升,则可能是由于缓存值未启用压缩导致原始数据(尤其是长文本、JSON 数组、Eloquent 集合)未经压缩直接存储。以下是实现缓存压缩以节省内存的多种方法:
一、启用 PHP 的 zlib 压缩序列化器(推荐)
Laravel 13+ 支持自定义缓存序列化器,可通过配置 zlib 压缩器对缓存值进行透明压缩,显著降低 Redis 或 Memcached 中的存储体积,尤其适用于大字符串、HTML 片段、JSON 数据等。
1、在 config/cache.php 文件中,为指定缓存驱动(如 redis)添加 serializer 配置项:
2、将 'serializer' => 'zlib' 添加至 redis store 配置块内:
3、确保 PHP 已启用 zlib 扩展(运行 php -m | grep zlib 验证)。
4、重启队列监听器与 Web 服务以使配置生效。
二、自定义压缩缓存 Store(兼容 Laravel 12 及以下)
当项目无法升级至 Laravel 13 或需精细控制压缩阈值时,可手动封装一个支持条件压缩的缓存 Store,仅对大于指定字节数的值启用 zlib 压缩,避免小键值因压缩头开销反而增大体积。
1、在 app/Cache/CompressedRedisStore.php 中创建自定义 Store 类,继承 Illuminate\Cache\RedisStore。
2、重写 serialize() 和 unserialize() 方法,在序列化前判断长度并调用 gzcompress(),解序列化时自动检测并调用 gzuncompress()。
3、在 config/cache.php 的 stores 中注册该 Store:
4、通过 Cache::store('compressed-redis') 显式使用该压缩 Store。
三、使用 msgpack 替代默认 serialize(Laravel 13 内置支持)
Laravel 13 默认启用类型感知序列化,msgpack 编码相比 PHP 原生 serialize() 可减少约 40% 内存占用,且无需额外压缩即可提升传输与存储效率,特别适合 Eloquent 模型、嵌套数组等结构化数据。
1、确认已安装 msgpack PHP 扩展(pecl install msgpack)。
2、在 config/cache.php 的 redis store 中设置:
3、确保 'serializer' => 'msgpack' 已配置在对应 driver 下。
4、验证:缓存一个包含 100 条记录的集合,对比 Redis 中 MEMORY USAGE 值下降幅度。
四、结合前缀与标签控制压缩粒度
并非所有缓存都需压缩。通过 Cache Tags 或自定义键前缀区分数据类型,可对高体积缓存(如渲染 HTML、导出 CSV)启用压缩,而对短生命周期小键(如 token、计数器)保持原生序列化,兼顾性能与空间效率。
1、在业务代码中为需压缩的数据显式打标:
2、在自定义 Store 或中间件中拦截 tags(['html', 'export']) 类缓存操作,动态启用 gzcompress()。
3、配置环境变量控制开关,例如 CACHE_COMPRESS_TAGS=html,export,json。
4、在缓存写入逻辑中解析该变量,匹配标签后执行压缩分支。
五、禁用冗余序列化避免双重开销
当使用 Redis 驱动且缓存值已是 JSON 字符串(如 API 响应体),直接调用 Cache::put($key, $jsonString) 会导致 Laravel 默认将其再次 serialize(),产生嵌套序列化浪费内存。应绕过门面,使用底层连接直写原始字符串。
1、获取原生 Redis 连接实例:$redis = Cache::store('redis')->getRedis();
2、使用 setex() 直接写入未序列化的字符串值:
3、手动设置 TTL,单位为秒。
4、读取时使用 $redis->get($key) 获取原始字符串,跳过反序列化步骤。


















