- 官方文档:RedisJSON: A Redis JSON Store
- JSONPath: JSONPath 文档
RedisJSON
是 Redis
的一个扩展模块,提供原生 JSON
功能 。可以通过 Docker 镜像快速的运行。
Docker
镜像地址: https://hub.docker.com/r/redislabs/rejsondocker run -d -p 6379:6379 --name redis-rejson redis/rejson:latest
Github
地址:https://github.com/RedisJSON/RedisJSON- 官方文档:https://oss.redis.com/redisjson/
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 strings
、List
、Sets
、 Sorted sets
、 Hashes
、 Bit arrays (或 简单的 bitmaps)
、 HyperLogLogs
、Streams
。
提前占坑,近期单独去写文章分别介绍这 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.SET
和 JSON.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-py
在 Python
代码中直接使用 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
嵌套时性能确实高于其他两种,但是处理普通的性能就比较低了,估计是做了取舍吧。