RedisJSON是Redis Labs官方推出的一个模块,专门用于在Redis中直接存储和处理JSON格式数据。传统Redis虽然支持字符串类型存储JSON,但查询和修改时需要客户端反序列化整个JSON对象,效率低下且无法进行内部字段操作。RedisJSON模块通过原生JSON支持彻底改变了这一局面。
这个模块的核心优势在于:
在实际项目中,我们经常遇到需要高速读写JSON数据的场景,比如:
首先确保系统是最新状态:
bash复制sudo apt update && sudo apt upgrade -y
安装必要的编译工具链:
bash复制sudo apt install -y build-essential tcl pkg-config cmake
注意:Ubuntu 22.04默认使用OpenSSL 3.0,而某些Redis模块可能需要兼容性调整。如果遇到SSL相关问题,可以安装兼容包:
bash复制sudo apt install -y libssl-dev
推荐通过官方PPA安装最新稳定版Redis:
bash复制sudo add-apt-repository ppa:redislabs/redis -y
sudo apt update
sudo apt install -y redis-server
验证Redis服务状态:
bash复制sudo systemctl status redis-server
配置Redis以模块方式运行(编辑/etc/redis/redis.conf):
conf复制loadmodule /usr/lib/redis/modules/rejson.so
下载最新版RedisJSON源码:
bash复制git clone --recursive https://github.com/RedisJSON/RedisJSON.git
cd RedisJSON
编译安装:
bash复制make setup
make build
安装到系统目录:
bash复制sudo cp build/rejson.so /usr/lib/redis/modules/
重启Redis服务后连接验证:
bash复制redis-cli
127.0.0.1:6379> MODULE LIST
正常输出应包含:
code复制1) 1) "name"
2) "ReJSON"
3) "ver"
4) "20007"
在redis.conf中添加以下优化参数:
conf复制# 内存分配策略
maxmemory-policy allkeys-lru
# 禁用持久化(纯缓存场景)
save ""
# 增大TCP backlog
tcp-backlog 511
# 启用透明大页
vm.overcommit_memory = 1
设置JSON文档:
bash复制JSON.SET user1 $ '{"name":"John","age":30,"address":{"city":"New York"}}'
获取完整文档:
bash复制JSON.GET user1
字段级操作:
bash复制# 获取特定字段
JSON.GET user1 .name
# 修改嵌套字段
JSON.SET user1 .address.city '"Boston"'
# 数字递增
JSON.NUMINCRBY user1 .age 1
JSONPath查询示例:
bash复制# 查找所有年龄大于25的用户
JSON.GET users $.[?(@.age>25)]
# 投影查询
JSON.GET users $..name
数组操作:
bash复制# 追加数组元素
JSON.ARRAPPEND user1 .hobbies '"reading"'
# 数组索引查询
JSON.GET user1 .hobbies[0]
利用Redis管道提升吞吐量:
python复制import redis
import json
r = redis.Redis()
pipe = r.pipeline()
for i in range(1000):
data = {'id':i, 'value':f'data_{i}'}
pipe.execute_command('JSON.SET', f'obj:{i}', '$', json.dumps(data))
pipe.execute()
bash复制# 不佳实践
JSON.SET product1 $ '{"views":"1000"}'
# 优化实践
JSON.SET product1 $ '{"views":1000}'
bash复制# 不佳实践
{"customerIdentificationNumber": "12345"}
# 优化实践
{"cust_id": "12345"}
bash复制# 大数组分块
JSON.SET logs:1 $ '{"chunk1":[...1000 items], "chunk2":[...]}'
bash复制# 创建索引集合
SADD user:age:25 user1 user2
# 组合查询
SINTER user:age:25 user:city:ny
bash复制# 不佳实践
JSON.GET hugeDoc $
# 优化实践
JSON.GET hugeDoc $.specificField
lua复制local doc = redis.call('JSON.GET', KEYS[1])
-- 复杂处理逻辑
return redis.call('JSON.SET', KEYS[1], ARGV[1], ARGV[2])
bash复制# 在每个节点加载模块
redis-server --loadmodule /path/to/rejson.so --cluster-enabled yes
conf复制# 混合持久化
aof-use-rdb-preamble yes
appendonly yes
bash复制# 关键指标监控
redis-cli --stat
redis-cli --bigkeys
问题1:模块加载失败,报错"version mismatch"
解决方案:
bash复制# 检查Redis和模块版本兼容性
redis-server --version
strings rejson.so | grep REDISMODULE
问题2:编译时缺少依赖
解决方案:
bash复制# 安装完整开发工具链
sudo apt install -y build-essential libclang-dev
问题1:JSONPath查询返回空
调试步骤:
bash复制# 1. 验证文档结构
JSON.GET doc $
# 2. 测试简单路径
JSON.GET doc .field
# 3. 检查特殊字符转义
问题2:内存使用过高
分析工具:
bash复制# 查看大键
redis-cli --bigkeys
# 内存分析
redis-cli MEMORY USAGE keyname
问题1:写入延迟高
优化方案:
bash复制# 1. 使用管道批量操作
# 2. 禁用持久化临时测试
CONFIG SET save ""
问题2:查询响应慢
诊断方法:
bash复制# 慢查询日志
CONFIG SET slowlog-log-slower-than 5000
SLOWLOG GET
数据结构设计:
json复制{
"userId": "u1001",
"preferences": {
"categories": ["electronics", "books"],
"brands": ["Apple", "Samsung"]
},
"behavior": {
"lastViewed": ["p100", "p205"],
"searchHistory": ["laptop", "phone"]
}
}
典型操作:
bash复制# 实时更新用户兴趣
JSON.ARRAPPEND u1001 $.preferences.categories '"home_appliance"'
# 个性化推荐查询
JSON.GET u1001 $.preferences.categories
设备状态模型:
json复制{
"deviceId": "thermo-001",
"readings": {
"temperature": 22.5,
"humidity": 45
},
"metadata": {
"lastCalibrated": "2023-07-15",
"firmware": "2.1.3"
}
}
时序数据处理:
bash复制# 添加历史记录
JSON.ARRAPPEND thermo-001 $.history '{"time":"2023-08-01T12:00:00","temp":22.5}'
# 条件查询
JSON.GET thermo-001 $.history[?(@.temp>30)]
聚合数据处理:
lua复制-- LUA脚本实现聚合计算
local data = redis.call('JSON.GET', KEYS[1], '$..metrics')
-- 计算平均值等统计指标
redis.call('JSON.SET', KEYS[1], '$.stats', new_stats)
bash复制FT.CREATE idx ON JSON SCHEMA $.name AS name TEXT $.age AS age NUMERIC
cypher复制GRAPH.QUERY social "MATCH (u:user) WHERE u.age > 30 RETURN u"
Python示例:
python复制from redis.commands.json.path import Path
import redis
r = redis.Redis()
# 设置文档
r.json().set('user:1000', Path.root_path(), {'name': 'Alice'})
# 条件查询
res = r.json().get('user:1000', Path('$.friends[?(@.age>20)]'))
Node.js示例:
javascript复制const redis = require('redis');
const client = redis.createClient();
client.json.set('user:1000', '$', { name: 'Bob' }, (err) => {
client.json.get('user:1000', { path: '$.name' }, console.log);
});
测试工具:
bash复制# 安装redis-benchmark
sudo apt install redis-tools
# 测试JSON.SET性能
redis-benchmark -n 100000 -c 50 -d 1000 \
eval "redis.call('JSON.SET', KEYS[1], ARGV[1], ARGV[2])" 1 foo $ '{"bar":"baz"}'
典型结果分析:
| 操作 | QPS | 延迟(ms) |
|---|---|---|
| JSON.SET | 125,000 | 0.4 |
| JSON.GET | 145,000 | 0.3 |
| JSONPath查询 | 85,000 | 0.7 |
conf复制# redis.conf配置
requirepass yourstrongpassword
rename-command CONFIG ""
# 网络隔离
bind 127.0.0.1
bash复制# 生成证书
openssl genrsa -out key.pem 2048
openssl req -x509 -new -key key.pem -out cert.pem
# redis.conf配置
tls-port 6379
tls-cert-file /path/to/cert.pem
tls-key-file /path/to/key.pem
conf复制# 每小时保存一次
save 3600 1
conf复制appendonly yes
appendfsync everysec
conf复制aof-use-rdb-preamble yes
bash复制# 导出指标
redis_exporter --redis.addr=localhost:6379
bash复制# 慢查询日志
slowlog-log-slower-than 5000
slowlog-max-len 128
python复制import redis
import json
r_old = Redis(old_config)
r_new = Redis(new_config)
for key in r_old.keys('user:*'):
data = json.loads(r_old.get(key))
r_new.json().set(key, Path.root_path(), data)
bash复制# 使用Redis复制
redis-cli --rdb dump.rdb
redis-cli -h new_host restore dump.rdb
bash复制# 1. 备份数据
redis-cli SAVE
# 2. 逐个节点升级
sudo apt update && sudo apt install --only-upgrade redis-server
# 3. 验证模块兼容性
redis-cli MODULE LIST
bash复制# 保留旧版本包
sudo apt download redis-server=6:6.2.6-1ubuntu1
在实际生产环境中,我们团队发现合理设计JSON文档结构对性能影响巨大。一个经验法则是:将频繁单独访问的字段放在顶层,嵌套层级最好不超过3层。对于数组元素超过1000个的情况,建议进行分块存储。另外,在Ubuntu 22.04上,使用jemalloc内存分配器比默认的malloc能有约15%的性能提升,可以通过LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 redis-server来启用。