在Active-Active数据库中存储JSON
JSON支持和冲突解决规则适用于Active-Active数据库。
RedisJSON v2.2 增加了对 Active-Active Redis Enterprise 数据库 中 JSON 的支持。
该设计基于Kleppmann和Beresford的无冲突复制JSON数据类型,但实现中包含了一些变化。一些冲突解决规则的例子也改编自这篇论文。
创建一个Active-Active JSON数据库
要在Active-Active数据库中使用JSON,您必须在数据库创建期间启用JSON。
默认情况下,Active-Active Redis Cloud 数据库会添加 JSON。有关详细信息,请参阅 Redis Cloud 文档中的 创建 Active-Active 数据库。
在Redis企业版软件中,默认情况下,JSON功能并未为Active-Active数据库启用。要在Redis企业版软件中创建Active-Active JSON数据库:
-
请参阅Redis企业软件文档中的创建Active-Active地理复制数据库以了解先决条件和详细步骤。
-
在创建Active-Active数据库屏幕的功能部分,选择JSON:
注意:当你选择JSON时,搜索和查询也会默认被选中,以便你可以索引和查询JSON文档。如果你不想使用这些额外的功能,你可以取消选中搜索和查询复选框。 -
配置额外的数据库设置。
-
选择创建。
命令差异
一些JSON命令在Active-Active数据库中的工作方式不同。
JSON.CLEAR
JSON.CLEAR
重置JSON数组和对象。它支持在Active-Active数据库中从不同实例并发更新JSON文档,并允许合并结果。
冲突解决规则
使用Active-Active数据库时,两个不同的实例可能会尝试同时对相同的数据执行写操作。如果发生这种情况,当副本尝试同步这些更改时,可能会产生冲突。冲突解决规则决定了数据库如何处理冲突操作。
有两种类型的冲突解决方式:
-
合并:
-
操作是关联的。
-
合并两个操作的结果。
-
-
赢得:
-
操作不具有结合性。
-
一个操作赢得冲突并设置值。
-
忽略失败的操作。
-
以下冲突解决规则展示了Active-Active数据库如何解决各种JSON命令的冲突。
为键分配不同的类型
冲突
两个实例同时将不同类型的值分配给JSON文档中的同一个键。
例如:
实例1将对象分配给JSON文档中的一个键。
实例2将数组分配给相同的键。
解决类型
赢得
解决规则
ID较小的实例获胜,因此在给定的示例中,键成为一个对象。
示例
时间 | 描述 | 实例 1 | 实例 2 |
---|---|---|---|
t1 | 将相同的键设置为对象或数组 | JSON.SET doc $.a '{}' | JSON.SET doc $.a '[]' |
t2 | 向对象和数组添加数据 | 结果: {"a": {"x": "y"}} |
结果: {“a”: ["z"]} |
t3 | 主动-主动同步 | – 同步 – | – 同步 – |
t4 | 实例1获胜 | JSON.GET doc $ 结果: {"a": {"x": "y"}} |
JSON.GET doc $ 结果: {"a": {"x": "y"}} |
创建与创建
冲突
两个实例同时使用 JSON.SET
将一个新的 JSON 文档分配给同一个键。
解决类型
赢得
解决规则
ID较小的实例获胜。
示例
时间 | 描述 | 实例 1 | 实例 2 |
---|---|---|---|
t1 | 创建一个新的JSON文档 | ||
t2 | 主动-主动同步 | – 同步 – | – 同步 – |
t3 | 实例1获胜 | JSON.GET doc $ 结果: {"field": "a"} |
JSON.GET doc $ 结果: {"field": "a"} |
创建与更新
冲突
实例1创建一个新文档并将其分配给现有键,使用JSON.SET
。
实例2使用JSON.SET
更新相同键的现有内容。
解决类型
赢得
解决规则
创建新文档的操作获胜。
示例
时间 | 描述 | 实例 1 | 实例 2 |
---|---|---|---|
t1 | 文档在两个实例中都存在 | JSON.GET doc $ 结果: {"field1": "value1"} |
JSON.GET doc $ 结果: {"field1": "value1"} |
t2 | 实例1创建一个新文档;实例2更新现有文档 | ||
t3 | 主动-主动同步 | – 同步 – | – 同步 – |
t4 | 实例1获胜 | JSON.GET doc . 结果: {"field2": "value2"} |
JSON.GET doc . 结果: {"field2": "value2"} |
删除与创建
冲突
实例1使用JSON.DEL
删除一个JSON文档。
实例2使用JSON.SET
创建一个新的JSON文档,并将其分配给实例1删除的键。
解决类型
赢得
解决规则
文档创建胜过删除。
示例
时间 | 描述 | 实例 1 | 实例 2 |
---|---|---|---|
t1 | 文档在两个实例上都存在 | JSON.GET doc $ 结果: {"field1": "value1"} |
JSON.GET doc $ 结果: {"field1": "value1"} |
t2 | 实例1删除文档;实例2创建新文档 | JSON.DEL doc | |
t3 | 主动-主动同步 | – 同步 – | – 同步 – |
t4 | 实例2获胜 | JSON.GET doc $ 结果: |
JSON.GET doc $ 结果: {"field1": "value2"} |
删除与更新
冲突
实例1使用JSON.DEL
删除一个JSON文档。
实例2使用JSON.SET
更新同一文档的内容。
解决类型
赢得
解决规则
文档删除胜过更新。
示例
时间 | 描述 | 实例 1 | 实例 2 |
---|---|---|---|
t1 | 文档存在于两个实例上 | JSON.GET doc $ 结果: |
JSON.GET doc $ 结果: {"field1": "value1"} |
t2 | 实例1删除文档;实例2更新它 | JSON.DEL doc | |
t3 | 主动-主动同步 | – 同步 – | – 同步 – |
t4 | 实例1获胜 | JSON.GET doc $ 结果: (nil) |
JSON.GET doc $ 结果: (nil) |
更新与更新
冲突
实例1使用JSON.SET
更新JSON文档中的一个字段。
实例2使用不同的值更新相同的字段。
解决类型
赢得
解决规则
ID最小的实例获胜。
示例
时间 | 描述 | 实例 1 | 实例 2 |
---|---|---|---|
t1 | 文档在两个实例中都存在 | JSON.GET doc $ 结果: {"field": "a"} |
JSON.GET doc $ 结果: {"field": "a"} |
t2 | 使用不同的数据更新相同的字段 | ||
t3 | 主动-主动同步 | – 同步 – | – 同步 – |
t4 | 实例1获胜 | JSON.GET doc $ 结果: {"field": "b"} |
JSON.GET doc $ 结果: {"field": "b"} |
更新与清除
RedisJSON v2.2 之前的版本有两种不同的方式来重置 JSON 对象的内容:
-
分配一个新的空JSON对象:
JSON.SET doc $.colors '{}'
如果使用此方法,则无法与并发更新合并。
-
对于每个键,使用
JSON.DEL
删除它:JSON.DEL doc $.colors.blue
使用这种方法,它可以将重置与并发更新合并。
自 RedisJSON v2.2 起,您可以使用 JSON.CLEAR
命令来重置 JSON 文档,而无需手动删除每个键。此方法还允许合并并发更新。
分配一个空对象
冲突
实例1使用JSON.SET
将“red”添加到现有的“colors”对象中。
实例2为“colors”分配了一个新的空对象。
解决类型
赢得
解决规则
文档创建优先于更新,因此结果将是一个空对象。
示例
时间 | 描述 | 实例 1 | 实例 2 |
---|---|---|---|
t1 | 文档在两个实例中都存在 | JSON.GET doc $ 结果: {"colors": {"blue": "#0000ff"}} |
JSON.GET doc $ 结果: {"colors": {"blue": "#0000ff"}} |
t2 | 实例1添加新颜色;实例2将颜色重置为空对象 | JSON.SET doc $.colors ‘{}’ | |
t3 | 实例2添加了一种新颜色 | ||
t4 | JSON.GET doc $ 结果: {"colors": {"blue": "#0000ff", "red": "#ff0000"}} |
JSON.GET doc $ 结果: {"colors": {"green": "#00ff00"}} |
|
t5 | 主动-主动同步 | – 同步 – | – 同步 – |
t6 | 实例2获胜 | JSON.GET doc $ 结果: {"colors": {"green": "#00ff00"}} |
JSON.GET doc $ 结果: {"colors": {"green": "#00ff00"}} |
使用 JSON.CLEAR
冲突
实例1使用JSON.SET
将“red”添加到现有的“colors”对象中。
实例2使用JSON.CLEAR
清除了"colors"对象,并将"green"添加到"colors"中。
解决类型
合并
解决规则
合并所有操作的结果。
示例
时间 | 描述 | 实例 1 | 实例 2 |
---|---|---|---|
t1 | 文档在两个实例中都存在 | JSON.GET doc $ 结果: {"colors": {"blue": "#0000ff"}} |
JSON.GET doc $ 结果: {"colors": {"blue": "#0000ff"}} |
t2 | 实例1添加新颜色;实例2重置颜色 | JSON.CLEAR doc $.colors | |
t3 | JSON.GET doc $ 结果: {"colors": {"blue": "#0000ff", "red": "#ff0000"}} |
JSON.GET doc $ 结果: {"colors": {}} |
|
t4 | 实例2添加了一种新颜色 | ||
t5 | JSON.GET doc $ 结果: {"colors": {"green": "#00ff00"}} |
||
t6 | 主动-主动同步 | – 同步 – | – 同步 – |
t7 | 合并两个实例的结果 | JSON.GET doc $ 结果: {"colors": {"red": "#ff0000", "green": "#00ff00"}} |
JSON.GET doc $ 结果: {"colors": {"red": "#ff0000", "green": "#00ff00"}} |
更新与更新数组
冲突
两个实例用不同的内容更新同一个现有数组。
解决类型
合并
解决规则
合并数组上所有操作的结果。保留每个实例中的原始元素顺序。
示例
时间 | 描述 | 实例 1 | 实例 2 |
---|---|---|---|
t1 | 文档在两个实例上都存在 | JSON.GET doc $ 结果: '["a", "b", "c"]' |
JSON.GET doc $ 结果: '["a", "b", "c"]' |
t2 | 实例1移除一个数组元素;实例2添加一个 | JSON.ARRPOP doc $ 1 结果: ["a", "c"] |
结果: ["y", "a", "b", "c"] |
t3 | 两个实例都向数组中添加了另一个元素 | 结果: ["a", "x", "c"] |
结果: ["y", "a", "z", "b", "c"] |
t4 | 主动-主动同步 | – 同步 – | – 同步 – |
t5 | 合并两个实例的结果 | JSON.GET doc $ 结果: ["y", "a", "x", "z", "c"] |
JSON.GET doc $ 结果: ["y", "a", "x", "z", "c"] |
更新与删除数组元素
冲突
实例1使用JSON.ARRPOP
从JSON数组中移除一个元素。
实例2更新了实例1删除的相同元素。
解决类型
赢得
解决规则
删除胜过更新。
示例
时间 | 描述 | 实例 1 | 实例 2 |
---|---|---|---|
t1 | 文档在两个实例上都存在 | JSON.GET doc $ 结果: {“todo”: [{“title”: “buy milk”, “done”: false}]} |
JSON.GET doc $ 结果: {“todo”: [{“title”: “buy milk”, “done”: false}]} |
t2 | 实例1删除一个数组元素;实例2更新相同的元素 | ||
t3 | JSON.GET doc $ 结果: {“todo”: []} |
JSON.GET doc $ 结果: [{“title”: “买牛奶”, “done”: true}]} |
|
t4 | 主动-主动同步 | – 同步 – | – 同步 – |
t5 | 实例1获胜 | JSON.GET doc $ 结果: doc = {“todo”: []} |
JSON.GET doc $ 结果: doc = {“todo”: []} |
更新与更新对象
冲突
两个实例用不同的内容更新同一个现有对象。
解决类型
合并
解决规则
合并对象上所有操作的结果。
示例
时间 | 描述 | 实例 1 | 实例 2 |
---|---|---|---|
t1 | 文档在两个实例上都存在 | JSON.GET doc $ 结果: '{"grocery": []}' |
JSON.GET doc $ 结果: '{"grocery": []}' |
t2 | 向数组中添加新元素 | JSON.ARRAPPEND doc $.grocery ‘“milk”’ | |
t3 | 向数组中添加新元素 | JSON.ARRAPPEND doc $.grocery ‘“ham”’ | |
t4 | JSON.GET doc $ 结果: {"grocery":["eggs", "ham"]} |
JSON.GET doc $ 结果: {"grocery":["milk", "flour"]} |
|
t5 | 主动-主动同步 | – 同步 – | – 同步 – |
t6 | 合并两个实例的结果 | JSON.GET doc . 结果: {"grocery":["eggs","ham","milk", "flour"]} |
JSON.GET doc . 结果: {"grocery":["eggs","ham","milk", "flour" ]} |