Redis的批处理优化
Redis的批处理优化
大量的数据要导入到Redis中,要怎么处理?
单个命令的执行流程
客户端 发送命令 到Redis服务端,服务端 执行命令 ,然后 返回结果 给客户端。
共需要 1次往返的网络传输耗时 + 1次Redis执行命令耗时 。
N条命令批量执行
由于redis服务端处理命令的速度是很快的,是在微秒级别的,而网络IO进行发送命令和返回结果的速度是很慢的,是在毫秒级别的,所以我们可以批量发送多条命令,减少网络IO的次数,提高性能。
Redis提供了很多Mxxx这样的命令,可以实现批量插入数据,就例如:mset、hmset。
10万条商品数据的插入,使用批处理优化(每1000条批量发送一次),比单个单个的插入速度快约177倍(44秒 -> 248毫秒)。大大减少了网络事件。
Pipeline
hmset、sadd等命令的key都不能改变,批处理只能处理同一个key下的元素,而mset也只能批处理String类型的key,使用redis服务端提供的原生的命令不太好做批处理,有很多限制,所以可以使用一些Redis客户端提供的Pipeline功能,更丰富。
可以往pipeline里面不断地添加命令,然后如果想要发送给客户端执行了,就可以使用sync()方法,批量发给客户端执行。代码示例如下:
@Test
void testPipeline() {// 创建管道Pipeline pipeline = jedis.pipelined();for (int i = 1; i <= 100000; i++) {// 放入命令到管道pipeline.set("testkey_" + i, "value_" + i);if (i % 1000 == 0) {// 每放入1000条命令,批量执行pipeline.sync();}}
}
集群模式下的批处理
在集群下,由于每个Redis实例都负责管各自的插槽部分,所以批处理的所有key都需要落在一个插槽中,不然的话就会导致执行失败,因为多条命令是一起传输的,只能一次网络IO到目标Redis,这些命令不能拆分,如果目的地是不同的Redis实例的话,他们也没办法拆开来路由。
所以可以在客户端可以提前计算出每个key对应的slot,然后根据slot一致分为一组。每组都各自用pipeline批处理。这里之后就可以选择 串行 或者 并行 执行了。因为不同的插槽是不同的redis实例,所以可以并行更加节省时间。