RedisTemplate 存进去的 key 为什么是乱码?Lettuce 要不要配连接池?pipeline 到底快多少?Redis 挂了应用会怎样?这篇在 Spring Boot 4.0.8、Spring Data Redis 4、Lettuce 上用自己起的 Redis 逐个实测。
自动配置的 RedisTemplate 的 key / value 序列化器:JdkSerializationRedisSerializer / JdkSerializationRedisSerializer;StringRedisTemplate:StringRedisSerializer / StringRedisSerializer
读回来:jdk → User[alice,30,[a, b]];json → {age=30, name=alice, tags=[a, b]}
redis 里的 key b'json:user':value 共 42 字节,前 60 字节 b'{"age":30,"name":"alice","tags":["a","b"]}'
redis 里的 key b'str:name':value 共 5 字节,前 60 字节 b'alice'
redis 里的 key b'\xac\xed\x00\x05t\x00\x08jdk:user':value 共 161 字节,前 60 字节 b'\xac\xed\x00\x05sr\x00\tdemo.User4>2S\xe9\xcfg\xa5\x02\x00\x03I\x00\x03ageL\x00\x04namet\x00\x12Ljava/lang/Strin'默认 RedisTemplate 用 JDK 序列化:key 带头、value 大、其他语言读不了;StringRedisTemplate 与 JSON 序列化器是可读的。
-- classpath 上没有 commons-pool2(默认):
Lettuce 默认的命令超时 = PT1M,连接超时 = PT10S;是否用连接池:false
空闲时 connected_clients = 1
64 个线程并发 GET 3 秒:共 286436 次(95479 次/秒);压测中间 connected_clients = 1
-- classpath 上有 commons-pool2(Boot 因此自动启用连接池):
Lettuce 默认的命令超时 = PT1M,连接超时 = PT10S;是否用连接池:true
空闲时 connected_clients = 1
64 个线程并发 GET 3 秒:共 285830 次(95277 次/秒);压测中间 connected_clients = 1
-- 有 commons-pool2,再把 spring.data.redis.lettuce.pool.enabled 显式设成 false:
Lettuce 默认的命令超时 = PT1M,连接超时 = PT10S;是否用连接池:false
空闲时 connected_clients = 1
64 个线程并发 GET 3 秒:共 305869 次(101956 次/秒);压测中间 connected_clients = 1
-- 有 commons-pool2,并把 shareNativeConnection 关掉(每次操作都从池里借连接,max-active=8):
Lettuce 默认的命令超时 = PT1M,连接超时 = PT10S;是否用连接池:true
空闲时 connected_clients = 1
64 个线程并发 GET 3 秒:共 163349 次(54450 次/秒);压测中间 connected_clients = 8默认所有线程共用一个连接;有 commons-pool2 也不一定真的用池;不共享连接的池反而更慢。
循环里一个一个 set:10000 个 key,中位 461 ms(378~624);dbsize = 10000 executePipelined:10000 个 key,中位 67 ms(60~121);dbsize = 10000 multiSet(一条 MSET):10000 个 key,中位 10 ms(8~12);dbsize = 10000
往返次数是主要代价:循环 461 ms,pipeline 67 ms,MSET 10 ms。
端口上没有 Redis:第一条命令失败,最里面的异常:Caused by: java.net.ConnectException: Connection refused
-- 运行中把 Redis 进程 kill -9(第 2.5 秒),第 7.5 秒再启动;spring.data.redis.timeout=2s;应用每 0.5 秒 GET 一次:
t= 0.2s GET 成功,用时 233 ms
t= 0.7s GET 成功,用时 3 ms
t= 1.2s GET 成功,用时 1 ms
t= 1.7s GET 成功,用时 1 ms
t= 2.3s GET 成功,用时 1 ms
t= 4.8s GET 失败 QueryTimeoutException / RedisCommandTimeoutException,用时 2006 ms
t= 7.3s GET 失败 QueryTimeoutException / RedisCommandTimeoutException,用时 2005 ms
t= 9.8s GET 失败 QueryTimeoutException / RedisCommandTimeoutException,用时 2005 ms
t=11.7s GET 成功,用时 1413 ms
t=12.2s GET 成功,用时 1 ms
t=12.7s GET 成功,用时 1 ms
t=13.2s GET 成功,用时 1 ms
t=13.7s GET 成功,用时 1 ms运行中宕机时每个命令等满超时才失败,恢复后重连会让第一次调用变慢。