redis数据快速落盘的实践——redis“超频”探索

817 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第29天,点击查看活动详情

前言

大家都知道我前几天介绍了我们的开发团队基于flink消费kafka的超多数据的场景。今天我将介绍一下我们在处理超多数据存储到redis的实践

业务场景简介

我们的业务场景十分简单,要实现1秒之内统计至少2万条数据的然后生成产量、最新的记录、最新的三条记录存储到redis。
但是在我们分析之后,发现需要寻找解决方案让redis实现“超频”,突破每秒10万的限制。主要的原因为:我们存储产量需要统计的颗粒度比较精细,需要统计总量、年、月、日、时、分的产量,加上统计最新的记录命令和5条记录最后三条数据的命令2条,我们在一条数据上就要执行6+5+2=11个redis命令。
现在的需求变为了:需要让redis可以实现每秒22w+的数据落盘
大家如果对最终实现感兴趣,我可以单开一篇文件介绍一下最终实现,今天我们只介绍redis的“超频”探索,希望会给大家带来一些收获

常见的redis超频方式

  • lettuce
  • lua脚本
  • pipelined管道传输 首先先和大家说一下,使用以上三种方式都无法突破10w/s的限制,本文只是总结一下三种常用的连接器的传输效率

lettuce

lettuce简介

lettuce是什么?一言以蔽之:基于netty的nio redis传输框架,因为我们使用lettuce时对于它的异步不太放心,最终就没有使用了。大家如果有不是很重要我的数据可以使用lettuce来存储。

lettuce使用

想在项目中使用lettuce传输redis其实十分简单,如果是spring boot项目引入如下依赖即可注入redisTemplate来使用lettuce

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

我发现有很多文章写了使用lettuce时引入common-pool2来做了连接池,但是参考lettuce github的wiki连接池,添加连接池显得画蛇添足了

1651244250(1).png

lua

lua简介

lua 是一个脚本语言,使用lua脚本的好处是。可以单线程原子性的来推送数据至redis。我们可以将11个命令中非固定命令的部分作为参数传入lua脚本中,一次就能执行

使用lua

我这里以spring boot +jedis为例,简单写一下如何使用

定义脚本、加载脚本

我们在resources文件夹下创建script.lua内容如下

redis.call('lpush',KEYS[1],ARGV[1])
redis.call('set', KEYS[2], ARGV[2])
redis.call('set', KEYS[3], ARGV[3])
redis.call('set', KEYS[4], ARGV[4])

然后建议在项目启动之后加载script中的脚本信息放到一个bean中,最后lua 脚本在我们的项目中以字符串的形式调用

使用lua

jedis.eval(scriptStr,keys,argvs);

1651245172(1).png

使用lua总体来说是个不错的解决方案,可以满足大部分的业务场景,接下来我们使用管道传输来进一步加快传输效率

pipelined

pipelined简介

属性nio的读者大部分对应文件流比较熟悉,其中channel就是使用管道传输大大加快了数据传输效率。感兴趣的可以去redis官网看一下管道传输

如何使用pipelined

我这里还是使用jedis来简单介绍一下使用方法 jedis获取管道

Pipeline pipeline = jedis.pipelined();

管道执行hset命令

pipeline.hset("key", "params",value);

最后执行sync

pipeline.sync();

关于pipeline有几点注意事项 1:最大支持在一个sync周期内刷新1万条记录 2:记录过多会内存溢出 3:sync建议:建议在一个周期内,每隔1000条刷新一次,且在最后一定要刷新一次 4:pipeline不是原子性!!!

结语

今天我们简单介绍了常见的几种redis优化策略,希望各位在阅读完之后能有所收获