【Redis实用技巧#12】如何向 Redis 批量写入海量数据?
很多工程师第一次遇到这个问题,往往不是在面试,而是在生产事故现场:系统运行正常、接口没有超时、Redis 服务器负载也不高,但数据导入就是慢得离谱。当写入规模从几十万上升到几千万甚至上亿时,直觉中的“内存数据库应该飞快”开始失效。 真正的瓶颈,通常不在 Redis,而在写入方式。 最常见的实现方式如下: 乍看没有问题,逻辑清晰,Redis 也确实很快。但一旦写入规模变大,程序表现往往是: 问题的根源在于:网络往返成本(RTT)被无限放大。 一次普通写操作,至少包含: 当写入上千万条数据时,这个往返过程要重复上千万次。哪怕单次延迟只有 0.3 ms,累计开销也会变得惊人。 Redis 的计算几乎不是瓶颈,等待网络才是。 在工程实践和面试场景中,第一层正确答案通常是:使用 Pipeline 批量发送命令。 典型写法: Pipeline 的核心价值是: 客户端不再每条命令都等待响应,而是集中提交、集中接收。这一改变在高延迟网络环境下尤为明显,往往能带来数量级提升。 但如果场景是离线导入数亿数据,Pipeline 仍然不是终点。 Redis 2.6 起, 这个模式的设计理念非常激进: 与普通模式的区别: 服务器端依然是顺序执行命令,但客户端侧的等待时间几乎被压缩到极限。 在纯导入场景中,这种方式通常比 Java Pipeline 更快。 可以将其理解为: 它几乎是贴着 Redis 协议层飞行,而不是通过高层客户端 API 逐条调用。 当数据规模达到“迁移 / 冷启动 / 灾备恢复”等级时,工程上常见做法是直接构造 RESP 协议数据流。 示例(简化): 将批量命令预生成文本文件,再通过 这种方式的优势: 适合一次性海量数据灌入,而非在线业务路径。 典型原因有三类: 换句话说, 实践中可以按写入场景做简单划分: 关键并不在“哪种方式最先进”,而在于是否匹配使用场景。 Redis 很少成为批量写入慢的真正原因。真正的差距,往往来自客户端行为模型与网络交互模式: 在数据规模足够大时,写入策略本身就是性能工程的一部分。 理解这一点,既能避免生产问题,也能在应用中拉开差距。为什么「for 循环 + SET」几乎必败?
for (Record r : records) {
jedis.set(r.key(), r.value());}关键词:Pipeline
Pipeline pipe = jedis.pipelined();for (Record r : records) {
pipe.set(r.key(), r.value());}
pipe.sync();多条命令一次性发送,减少网络往返次数。
被低估的利器:redis-cli 的 Pipe Mode
redis-cli 提供了专门面向海量写入的模式:cat data.txt | redis-cli --pipe只管发送命令流,不等待逐条响应。
Pipe Mode 本质上做了什么?
RESP 协议级写入:更底层的思路
*3\r\n
$3\r\nSET\r\n
$4\r\nkey1\r\n
$5\r\nvalue\r\nredis-cli --pipe 导入:cat commands.resp | redis-cli --pipe为什么 Pipe Mode 往往比 Java Pipeline 更快?
redis-cli --pipe 是一个近似“协议工具”,而不是“应用客户端”。工程视角:不同场景的技术选型
总结