Redis大量数据插入过程

 更新时间:2025年08月05日 08:40:33   作者:懒虫虫~  
本文介绍Redis处理大数据插入的三种高效方法:redis-cli管道模式、Jedis pipelined()方法及RedisTemplate批量保存,旨在减少通信开销并提升吞吐量

有些时候,Redis实例需要装载大量用户在短时间内产生的数据,数以百万计的keys需要被快速的创建。

我们称之为大量数据插入(mass insertion),本文档的目标就是提供如下信息:Redis如何尽可能快的处理数据。

本文参考网上方案特意整理总结如下:

方式一:使用Luke协议,通过redis-cli –pipe发送数据到服务器

使用正常模式的Redis 客户端执行大量数据插入不是一个好主意:因为一个个的插入会有大量的时间浪费在每一个命令往返时间上。

使用管道(pipelining)是一种可行的办法,但是在大量插入数据的同时又需要执行其他新命令时,这时读取数据的同时需要确保请可能快的的写入数据。

只有一小部分的客户端支持非阻塞输入/输出(non-blocking I/O),并且并不是所有客户端能以最大限度的提高吞吐量的高效的方式来分析答复。

例如,如果我们需要生成一个10亿的`keyN -> ValueN’的大数据集,我们会创建一个如下的redis命令集的文件:

SET Key0 Value0
SET Key1 Value1
...
SET KeyN ValueN

从Redis 2.6开始redis-cli支持一种新的被称之为pipe mode的新模式用于执行大量数据插入工作。使用pipe mode模式的执行命令如下:

cat data.txt | redis-cli --pipe

这将产生类似如下的输出:

All data transferred. Waiting for the last reply...
Last reply received from server.
errors: 0, replies: 1000000

使用redis-cli将有效的确保错误输出到Redis实例的标准输出里面。

1.1 生成Redis协议

它会非常简单的生成和解析Redis协议,Redis协议文档请参考Redis协议说明。 但是为了生成大量数据插入的目标,你需要了解每一个细节协议,每个命令会用如下方式表示:

*<args><cr><lf>
$<len><cr><lf>
<arg0><cr><lf>
<arg1><cr><lf>
...
<argN><cr><lf>

这里的是”\r”(或者是ASCII的13)、是”\n”(或者是ASCII的10)。

例如:命令SET key value协议格式如下:

*3<cr><lf>
$3<cr><lf>
SET<cr><lf>
$3<cr><lf>
key<cr><lf>
$5<cr><lf>
value<cr><lf>

或表示为引用字符串:

"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n"

你需要将大量插入数据的命令按照上面的方式一个接一个的生成到文件。

1.2 pipe mode的工作原理是什么?

dis-难点是保证recli在pipe mode模式下执行和netcat一样快的同时,如何能理解服务器发送的最后一个回复。

这是通过以下方式获得:

redis-cli –pipe试着尽可能快的发送数据到服务器。

读取数据的同时,解析它。

  • 一旦没有更多的数据输入,它就会发送一个特殊的ECHO命令,后面跟着20个随机的字符。我们相信可以通过匹配回复相同的20个字符是同一个命令的行为。
  • 一旦这个特殊命令发出,收到的答复就开始匹配这20个字符,当匹配时,就可以成功退出了。

同时,在分析回复的时候,我们会采用计数器的方法计数,以便在最后能够告诉我们大量插入数据的数据量。

1.3 示例代码操作

1.3.1 准备数据文件,格式是文本文件,名称是:redis_commands.txt。

我在Windows环境下生成了一个txt文件,一条数据一行,代码如下:

                 SET Key0 Value0
                 SET Key1 Value1
                 SET Key2 Value2
                 SET Key3 Value3
                 SET Key4 Value4
                 SET Key5 Value5
                 SET Key6 Value6
                 SET Key7 Value7
                 SET Key8 Value8
                 SET Key9 Value9
                 SET Key10 Value10
                 ...
                 SET KeyN ValueN
public class getStringTest {
    /**
     * 格式化成输入字符串
     */
    private String getString(String... args) {
        StringBuilder sb = new StringBuilder();
        sb.append("*").append(args.length).append("\r\n");
        for (String arg : args) {
            sb.append("$").append(arg.length()).append("\r\n");
            sb.append(arg).append("\r\n");
        }
        return sb.toString();
    }
 
    @Test
    public void initFile2() {
        Long startTime = System.currentTimeMillis();
        String file = "d:\\d.txt";
        BufferedWriter w = null;
        StringBuilder sb = new StringBuilder();
        try {
            w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "utf-8"));
                for(int i=0 ;i < 10000000;i++){
                //for (int i = 1; i <= 100; i++) {
                if (i / 3 == 0) {
                    w.flush();
                }
                sb.setLength(0);
                sb.append(this.getString("set", "u" + i, "name" + i));
//sb.append(this.getString("hmset", "usr" + i, "userid", "usr" + i, "username", "usrname" + i));
                w.append(sb.toString());
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                w.flush();
                w.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        long endTime = System.currentTimeMillis();
        System.out.println("耗时: "+(endTime - startTime)/1000+" s。");
    }
}

我生成了1000万的数据,因为这个文本文件我是在Windows环境下生成的,所以需要格式转换。

1.3.2 如果使用Windows环境下生成的文件,需要进行格式转换,如果是在Linux环境下生成的文件就不需要格式转换,如果文本文件比较大,执行转换时间会有几秒,等待即可。

执行格式转换

[root@linux ~]# unix2dos redis_commands.txt
unix2dos:converting file redis_commands.txt to DOS format ...

以上代码进行格式转换完毕

需要说明一点,unix2dos这个命令需要先安装,如果没有安装,会提示:command not found。

执行以下命令安装:

[root@linux ~]# yum install unix2dos

1.3.3 进行数据批量插入

[root@linux ~]# cat d.txt | redis-cli -h 134.177.11.22 -p 6379 [-a "password"] -n 0 --pipe
All data transferred.Waiting for the last reply...
Last reply received from server.
errors:0,replies:10000000

方案二:采用Jedis的父类中的pipelined()方法获取管道

我们可以采用Jedis的父类中的pipelined()方法获取管道,它可以实现一次性发送多条命令并一次性返回结果,这样就大量的减少了客户端与Redis的通信次数,可以有效的提高程序效率(但是,因为Redis要一次性返回所有结果,它会把这些结果都缓存起来,因此命令越多,缓存消耗的内存也会越大,具体还要视情况而定).此外Pipeline的原理是队列(先进先出),这样也保证了数据的顺序性。

public static void main(String[] args) throws Exception {
 
        Jedis jedis = new Jedis("127.0.0.1", 6474);
        Pipeline p = jedis.pipelined();
        p.setex("key_a", 120, "11111");
        p.setex("key_b", 120, "2222");
        p.sync();
        if (jedis != null && jedis.isConnected()) {
            jedis.close();
        }
    }

方案三:使用RedisTemplate批量保存数据

public void saveDataToRedis(Map<String, String> map) {
        redisTemplate.executePipelined(new RedisCallback<String>() {
            @Override
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                map.forEach((key, value) -> connection.set(redisTemplate.getKeySerializer().serialize(key), redisTemplate.getValueSerializer().serialize(value)));
                return null;
            }
        });
    }

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。 

相关文章

  • 一文搞懂阿里云服务器部署Redis并整合Spring Boot

    一文搞懂阿里云服务器部署Redis并整合Spring Boot

    这篇文章主要介绍了一文搞懂阿里云服务器部署Redis并整合Spring Boot,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • 关于使用IDEA的springboot框架往Redis里写入数据乱码问题

    关于使用IDEA的springboot框架往Redis里写入数据乱码问题

    这篇文章主要介绍了用IDEA的springboot框架往Redis里写入数据乱码问题,本文给大家分享解决方法通过图文示例相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • 解析Redis Cluster原理

    解析Redis Cluster原理

    redis最开始使用主从模式做集群,若master宕机需要手动配置slave转为master;后来为了高可用提出来哨兵模式,该模式下有一个哨兵监视master和slave,若master宕机可自动将slave转为master,但它也有一个问题,就是不能动态扩充;所以在3.x提出cluster集群模式
    2021-06-06
  • Redisson 主从一致性问题详解

    Redisson 主从一致性问题详解

    这篇文章主要为大家介绍了Redisson 主从一致性问题详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • Redis常见数据类型List列表使用详解

    Redis常见数据类型List列表使用详解

    Redis的List是一种有序的字符串集合,支持两端高效插入和删除,适用于队列和栈,这篇文章主要介绍了Redis常见数据类型List列表使用的相关资料,需要的朋友可以参考下
    2024-12-12
  • redis内部数据结构之SDS简单动态字符串详解

    redis内部数据结构之SDS简单动态字符串详解

    SDS是Redis中实现的一种数据结构,用来存储字符串,最近学习中正好学习到了这里,所以下面这篇文章主要给大家介绍了redis内部数据结构之SDS简单动态字符串的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-11-11
  • Redis中AOF与RDB持久化策略深入分析

    Redis中AOF与RDB持久化策略深入分析

    Redis作为一款内存数据库,因为是内存读写,所以性能很强,但内存存储是易失性的,断电或系统奔溃都会导致数据丢失,因此Redis也需要将其数据持久化到磁盘上面,当Redis服务重启时,会把磁盘上的数据再加载进内存,Redis提供了两种持久化机制-RDB快照和AOF日志
    2022-11-11
  • 一步步教会你redis如何配置密码

    一步步教会你redis如何配置密码

    Redis的配置文件中可以设置密码来保护访问,下面这篇文章主要给大家介绍了关于redis如何配置密码的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-01-01
  • Redis如何存储对象与集合示例详解

    Redis如何存储对象与集合示例详解

    redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、 zset(sorted set --有序集合)和hash(哈希类型)本文介绍了关于Redis是如何存储对象与集合的相关资料,需要的朋友可以参考下
    2018-05-05
  •  Redis 串行生成顺序编码的方法实现

     Redis 串行生成顺序编码的方法实现

    本文主要介绍了 Redis 串行生成顺序编码的方法实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04

最新评论