bigywater.tech
Spring · 164

Caffeine 本地缓存与 Redis:延迟与命中情况

本地缓存 Caffeine 和 Redis 缓存延迟差多少?值的大小有影响吗?两者在语义上有什么不同(同一个对象、修改原对象、put 之后立刻读)?这篇在同一台机器上用 Spring Cache 的两种 CacheManager 实测。

三个数量级
命中读取平均延迟:Caffeine 0.08 µs,Redis(本机回环)42.34 µs
1944 / 2000
Redis 的 cache.put 之后立刻 get,读不到的次数;Caffeine 是 0 次
item-7
放进缓存之后再修改原对象,Redis 里读到的仍是原值,Caffeine 里读到的是被改过的对象

字符串 100 字节

实测 · 本机执行输出
  Caffeine 命中读取(单线程 20 万次):平均 0.08 µs,P50 0.08 µs,P99 0.17 µs
  Redis 命中读取(单线程 5 万次):平均 42.34 µs,P50 36.71 µs,P99 106.29 µs
  Caffeine 8 线程读取:8 线程,39973 万次/秒
  Redis 8 线程读取:8 线程,8 万次/秒

Caffeine 与 Redis 命中读取的延迟与 8 线程吞吐。

字符串 1 KB

实测 · 本机执行输出
  Caffeine 命中读取(单线程 20 万次):平均 0.07 µs,P50 0.04 µs,P99 0.13 µs
  Redis 命中读取(单线程 5 万次):平均 50.80 µs,P50 38.63 µs,P99 149.46 µs
  Caffeine 8 线程读取:8 线程,39376 万次/秒
  Redis 8 线程读取:8 线程,7 万次/秒

值变大对本机回环下的 Redis 延迟影响很小。

POJO

实测 · 本机执行输出
  Caffeine 命中读取(单线程 20 万次):平均 0.02 µs,P50 0.04 µs,P99 0.08 µs
  Redis 命中读取(单线程 5 万次):平均 56.40 µs,P50 42.88 µs,P99 208.04 µs
  Caffeine 8 线程读取:8 线程,40085 万次/秒
  Redis 8 线程读取:8 线程,8 万次/秒

JDK 序列化的 POJO 对 Redis 延迟影响不明显。

未命中与写入

实测 · 本机执行输出
  Caffeine 未命中读取:平均 0.03 µs,P50 0.04 µs,P99 0.13 µs
  Redis 未命中读取:平均 37.13 µs,P50 34.58 µs,P99 65.08 µs
  Caffeine put:平均 0.05 µs,P50 0.04 µs,P99 0.17 µs
  Redis put:平均 3.75 µs,P50 2.21 µs,P99 7.00 µs

未命中同样要走网络;Redis 的 put 延迟低是因为返回时还没写完。

语义

实测 · 本机执行输出
  put 之后立刻 get(2000 次):Caffeine 读不到 0 次,Redis 读不到 1944 次
  Redis put 之后反复 get 直到读到(300 次):最短 33.63 µs,中位数 79.83 µs,最长 1427.00 µs
  Caffeine 连续两次 get 取到的是不是同一个对象:true;是不是放进去的那个对象:true
  Redis 连续两次 get 取到的是不是同一个对象:false;是不是放进去的那个对象:false
  放进去之后修改原对象的 name:Caffeine 里读到 已被修改;Redis 里读到 item-7
  TTL 500 ms:300 ms 时 Caffeine 有=true、Redis 有=true;800 ms 时 Caffeine 有=false、Redis 有=false

可见性、对象引用、修改原对象、TTL 的差别。

分步演示

缓存
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动(Spring Framework 7.0.9 的 CaffeineCacheManager 与 spring-data-redis 的 RedisCacheManager,默认配置、JDK 序列化,Lettuce 连接本机 127.0.0.1 上自己起的 Redis(端口 7414),Redis 与应用在同一台机器、没有经过真实网络;单线程用 System.nanoTime 逐次计时,先预热;8 线程测 2 秒的总吞吐;JVM 堆固定 512 MB)
    • 没有验证:Redis 跨机器网络下的延迟(通常更大);Redis 用 JSON 序列化与 GenericJacksonJsonRedisSerializer 的差别;连接池、pipeline 与批量 get;Caffeine 的淘汰策略与命中率(这篇只测了命中读取);Redis put 为什么会在写入完成前返回(只测到现象);多级缓存(Caffeine 加 Redis)的一致性;内存占用
    京ICP备2026067502号-1京公网安备11010502063487号