RedisJSON:一个可以存储 JSON 的 Redis

RedisJSONRedis 的一个扩展模块,提供原生 JSON 功能 。可以通过 Docker 镜像快速的运行。

Redis 常用的扩展模块:

  • RediSearch : 基于 Redis 的查询和索引引擎,提供二级索引,全文搜索和聚合等功能。
  • RedisJSON:支持 JSON 数据类型的 Redis
  • neural-redis :在线可训练的神经网络作为 Redis 数据类型。

RedisJSON 虽然支持 JSON ,但是标准版的 Redis 还是不支持。Redis 标准版(截止到 2021-12-17,Redis 最新版为 6.2.6 )现在已经支持 8 中数据类型(5中基本类型+3中特殊的类型),分别是:Binary-safe stringsListSetsSorted setsHashesBit arrays (或 简单的 bitmaps)HyperLogLogsStreams

提前占坑,近期单独去写文章分别介绍这 8 中数据类型。

言归正传,继续扯 RedisJSON

虽然 Redis 有大量的核心数据结构,但是没有一个符合 JSON 的要求。当然可以通过使用其他数据类型来解决问题:比如在实际项目中,我们经常会使用 Strings 来存储原始的序列化 JSON 串;或者使用 Hashes 来展示 JSON 对象。但是这并不是原生的 JSON,并且只是在少数地方去用。这种体验会留下一种非 Redis 的感觉,并且它们的笨拙与通常使用 Redis 的简单和优雅产生了很大的冲突。

但是借助于 Redis 提供的模块化,Itamar Haber 以及 Dvir Volk 一伙人就开始了 RedisJSON 模块的开发工作。RedisJSON 模块提供了一种新的数据类型,用于快速高效的处理 JSON 。像其他 Redis 数据类型一样,RedisJSON 的值存储在对应的 keys 中,并且可以通过一个专门的命令子集访问。通过这些命令或模块暴露的 API,就可以在 Redis 上对 JSON 进行相应的操作。下面的例子展示了如何存储和获取值:

127.0.0.1:6379> JSON.SET scalar . '"Hello JSON!"'
OK
127.0.0.1:6379> JSON.SET object . '{"foo": "bar", "ans": 42}'
OK
127.0.0.1:6379> JSON.GET object
"{"foo":"bar","ans":42}"
127.0.0.1:6379> JSON.GET object .ans
"42"
127.0.0.1:6379> ^C
~$ 

像其他优秀的优秀的模块一样,RedisJSON 的命令都带有前缀。JSON.SETJSON.GET 都需要使用 key 的名称作为它们的第一个参数。在上面的示例中,将名为 scalar(键)的根( root. 就表示其根)设置为字符串值 Hello JSON!;然后使用 JSON 对象(首先读取整个对象)设置一个名为 object 的不同键,然后按路径获取单个子元素。

每当调用 JSON.SET 时,模块都会通过流词法分析器( streaming lexer)来解析输入的 JSON 并对其构建树形数据结构,如下图所示:

RedisJSON 将数据以二进制格式存储在树的节点上,并支持 JSONPath 的子集,以便于子元素的引用。它为每种 JSON 值类型提供了专有的原子命令库,包括:JSON.STRAPPEND 用于附加字符串; JSON.NUMMULTBY 用于数字相乘; 和 JSON.ARRTRIM 用于修剪数组……。这些都在 RedisJSON 中被提供。

因为 RedisJSON 是作为一个 Redis 模块实现的,所以可以在任何 Redis 客户端中使用它:

  • 支持模块(无 ATM
  • 允许发送原始命令(ATM

例如,下面的例子中,通过 redis-pyPython 代码中直接使用 Redis 服务器(启用了 RedisJSON)。

import redis
import json

data = {
    'foo': 'bar',
    'ans': 42
}

r = redis.StrictRedis()
r.execute_command('JSON.SET', 'object', '.', json.dumps(data))
reply = json.loads(r.execute_command('JSON.GET', 'object'))

但这只是 RedisJSON 的厉害的一半。 RedisJSON 不仅是一个漂亮的 API,在性能方面也是一个强大的工具。 初始性能基准已经证明,例如:

上面两个图比较了在具有三个嵌套级别的 3.4KB JSON 负载上执行的读写操作的速率( operations/sec,操作数/秒)和平均延迟(ms,毫秒)。 RedisJSON 与两种将数据存储在字符串中的变体进行比较。 两种变体都作为 Redis 服务器端 Lua 脚本实现,其中 json.lua 变体存储原始序列化 JSON,而 msgpack.lua 使用的是 MessagePack 编码。

【注】从图中可以看出 RedisJSON 在处理 JSON 嵌套时性能确实高于其他两种,但是处理普通的性能就比较低了,估计是做了取舍吧。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注