ITPub博客

首页 > 数据治理 > 数据治理 > Redis 8.10 HIMPORT:更高效地批量写入 Hash 数据

Redis 8.10 HIMPORT:更高效地批量写入 Hash 数据

原创 数据治理 作者:虹科云科技 时间:2026-09-20 11:36:41 0 删除 编辑

Redis 8.10 引入了一个新的 Hash 数据导入命令: HIMPORT。

如果应用需要批量向 Redis 写入大量结构相同的 Hash,传统的 HSET 会反复传输相同的字段名。 HIMPORT 的核心思路,就是提前声明这组字段结构,后续写入时只传输对应的值,从而减少网络传输数据量,提高批量导入效率。

本文通过 Ruby 客户端 redis-rb 演示 HIMPORT 的基本用法,以及它与 HSET 在批量写入场景下的性能差异。

从 redis-rb 开始

本文使用 Ruby 主要有两个原因:

  1. redis-rb 最近发布了新版本;
  2. 新版本已经支持 Redis 的 HIMPORT 命令。

在 Ruby 中连接 Redis 很简单,只需要安装 redis gem,并准备一个 Redis OSS 服务端即可。

redis = Redis.new(
        host:     options[:host],
        port:     options[:port],
        username: options[:user],
        password: options[:password],
        himport_auto_prepare: true
)

这里的 himport_auto_prepare 默认值就是 true,之所以显式写出来,是因为它与后面的连接恢复机制有关。

为什么不直接使用 HSET?

假设需要向 Redis 写入一批玩家成绩数据,每条记录都包含三个字段:

  • _uid:玩家 ID
  • score:玩家取得的分数
  • tag:玩家标签

使用 HSET 时,代码可能类似这样:

redis.hset("scores:68430017", "_uid", "68430017", "score", 42, "tag", "vladvildanov")
...
redis.hset("scores:03DBA163", "_uid", "03DBA163", "score", 234, "tag", "nosqlgeek")

可以看到,每写入一条记录,不仅要发送实际数据,还需要重复发送 _uid、 score、 tag 这些字段名。

当所有 Hash 都采用相同结构时,这部分重复数据实际上是可以避免的。

这正是 HIMPORT 要解决的问题。

HIMPORT 如何工作?

HIMPORT 提供了多个子命令,其中首先需要了解的是 HIMPORT PREPARE。

它允许客户端提前声明一个字段集合(field set)。例如,可以创建一个名为 scores 的字段集合:

_uid
score
tag

随后,批量导入数据时只需要按照同样的字段顺序提供值即可。

使用 redis-rb 可以这样实现:

redis.himport_prepare("scores", %w[_uid score tag])
(1..NUM_IMPORTS).each { |i|
  uuid, score, tag = random_demo_data
  redis.himport_set(uuid, "scores", [uuid, score, tag])
}
redis.himport_discard("scores")

这里首先通过:

redis.himport_prepare("scores", %w[_uid score tag])

注册字段结构。

之后每次执行 himport_set 时,只需要指定目标 Key、字段集合名称以及对应的值:

redis.himport_set(uuid, "scores", [uuid, score, tag])

字段名本身不再随着每条记录重复传输。

需要特别注意的是:通过 HIMPORT PREPARE 创建的字段集合只在执行该命令的当前 Redis 连接上下文中有效。

连接重建与 himport\ auto\prepare

这时就需要重新看一下前面提到的:

himport_auto_prepare: true

redis-rb 客户端内部会维护一个已准备的 HIMPORT 字段集合注册表。

如果 Redis 连接断开后重新建立,客户端会自动重新注册此前准备好的字段集合。这样,应用就不需要在每次连接恢复之后自行重新执行 HIMPORT PREPARE。

当某个字段集合不再需要时,可以执行:

redis.himport_discard("scores")

将其删除。

执行 discard 后,该字段集合也会从客户端维护的注册表中移除。

模式一:应用启动时 Prepare,后续持续使用

示例项目中的 CLI 程序 himport_demo.rb 提供了一种 inline 模式:

ruby himport_demo.rb inline

这种方式模拟的是一种长期运行的应用场景:

应用启动时预先声明常用字段集合,之后在整个应用生命周期内都可以使用对应的 HIMPORT 写入数据。

借助 redis-rb 内部维护的字段集合注册表, HIMPORT 可以在这类场景中作为 HSET 的一种替代方式。

如果采用这种模式,建议保持:

himport_auto_prepare=true

这样即使底层 Redis 连接发生重连,客户端也能够自动恢复此前注册的字段集合。

需要注意, redis-rb 本身没有内置连接池。如果按照项目 README 中的方式额外使用连接池,那么必须保证连接池中的 每一条 Redis 连接都分别执行过字段集合 Prepare。

原因很直接: HIMPORT PREPARE 的状态属于连接上下文,而不是整个客户端实例或 Redis Server 的全局状态。

模式二:Prepare、批量导入,然后立即 Discard

另一种更典型的使用方式,是将 Prepare、批量写入和 Discard 放在同一个 Pipeline 中完成。

Redis Pipelining 可以一次发送多个命令,而不必在每个命令执行后等待服务器响应再发送下一个命令,因此非常适合批量数据导入。

同时,一个 Pipeline 始终运行在同一条 Redis 连接上,这正好满足 HIMPORT PREPARE 的连接级作用域要求。

这种情况下,可以将:

himport_auto_prepare

设置为 false。

示例程序中的 bulk 模式实现如下:

result = redis.pipelined do |pipeline|
  pipeline.himport_prepare("scores", %w[_uid score tag])
  (1..NUM_IMPORTS).each { |i|
    uuid, score, tag = random_demo_data
    pipeline.himport_set(uuid, "scores", [uuid, score, tag])
  }
  pipeline.himport_discard("scores")
end

整个过程非常明确:

  1. 先声明字段集合;
  2. 批量执行 HIMPORT SET;
  3. 数据导入完成后立即删除字段集合。

如果字段结构只是某次批量导入任务临时使用,这种方式通常更加合适。

HIMPORT 能带来多少性能提升?

示例 CLI 还包含一个简单的 Benchmark,用于比较 HSET 和 HIMPORT 的批量写入性能。

测试过程保持一致:

  1. 准备相同的数据;
  2. 使用 Pipeline 执行一定数量的 HSET;
  3. 测量完成整个导入所需的时间;
  4. 使用 HIMPORT 重复同样的测试。

测试在本地主机上进行,字段集合只有三个字段,总计写入 100 万条记录:

ruby himport_demo.rb benchmark
Benchmarking 1000000 records ...
HSET:    1000000 records in 12.029s
HIMPORT: 1000000 records in 10.589s

结果显示:

  • HSET:12.029 秒
  • HIMPORT:10.589 秒

在这次测试中, HIMPORT 的导入速度提高了约 11%。

需要注意,这里的字段集合只有三个字段。

HIMPORT 的主要收益来自减少网络中重复传输的字段名,因此字段数量越多、单批数据量越大,理论上可以节省的网络带宽也越明显,相应的性能收益也可能进一步增加。

换句话说, HIMPORT 并不是通过改变 Hash 本身的数据模型来提升效率,而是在大量结构一致的 Hash 写入场景中,减少协议层面的重复数据传输。

什么时候适合使用 HIMPORT?

从其工作方式来看, HIMPORT 最适合这样的数据写入模式:

大量 Redis Hash 具有相同或高度固定的字段结构,并且需要进行持续或批量写入。

例如前面的玩家成绩记录:

_uid
score
tag

如果需要导入几十万甚至上百万条结构相同的数据,那么使用 HSET 时,每一条命令都会重复携带这些字段名。

而通过 HIMPORT,字段名只需要提前声明一次,后续主要传输真正变化的数据值。

对于字段较多、数据规模较大的批量导入任务,这种差异会更加明显。

使用时则需要重点理解一个限制: Prepared field set 是连接级状态。

如果应用采用多个 Redis 连接、连接池或连接频繁重建,就必须正确处理每条连接上的字段集合初始化。 redis-rb 提供的 himport_auto_prepare 可以简化重连场景,但连接池中的不同连接仍然需要分别完成 Prepare。

完整示例代码

本文使用的完整代码和可执行示例可以在 GitHub 项目中找到:

https://github.com/nosqlgeek/himport\_demo

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70026953/viewspace-3183112/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
公众号(ID:艾体宝IT):分享数据存储、网络安全等相关的产品信息、解决方案、应用案例及行业信息,如Redis、ArangoDB、ONEKEY、Lepide等!艾体宝IT官网:https://www.itbigtec.com/ 联系我们:18483658974(同微信)

注册时间:2023-02-21

  • 博文量
    208
  • 访问量
    214680