在双活数据库中存储 JSON

双活数据库的 JSON 支持和冲突解决规则。

RedisJSON v2.2 在 双活 Redis Enterprise 数据库中增加了对 JSON 的支持。

该设计基于 Kleppmann 和 Beresford 的《无冲突复制 JSON 数据类型》(A Conflict-Free Replicated JSON Datatype),但实现包含一些更改。一些冲突解决规则示例也改编自这篇论文。

创建双活 JSON 数据库

要在双活数据库中使用 JSON,必须在创建数据库时启用 JSON。

双活 Redis Cloud 数据库默认添加 JSON。详情请参阅 Redis Cloud 文档中的创建双活数据库

在 Redis Enterprise Software 中,双活数据库默认不启用 JSON。要在 Redis Enterprise Software 中创建双活 JSON 数据库

  1. 有关先决条件和详细步骤,请参阅 Redis Enterprise Software 文档中的创建双活地理复制数据库

  2. 在创建双活数据库屏幕的“功能”部分,选择 JSON

    Select JSON from the Capabilities section.
    注意
    选中 JSON 时,搜索和查询也会默认选中,以便您可以索引和查询 JSON 文档。如果您不想使用这些附加功能,可以取消选中搜索和查询复选框。
  3. 配置其他数据库设置。

  4. 选择创建

命令差异

某些 JSON 命令在双活数据库中工作方式不同。

JSON.CLEAR

JSON.CLEAR 重置 JSON 数组和对象。它支持来自双活数据库不同实例对 JSON 文档的并发更新,并允许合并结果。

冲突解决规则

在双活数据库中,两个不同实例可能尝试同时对相同数据执行写操作。如果发生这种情况,当副本尝试相互同步这些更改时,可能会出现冲突。冲突解决规则决定了数据库如何处理冲突的操作。

冲突解决有两种类型

  1. 合并

    • 操作是可结合的。

    • 合并两个操作的结果。

  2. 胜者为准

    • 操作是不可结合的。

    • 其中一个操作赢得冲突并设置值。

    • 忽略失败的操作。

以下冲突解决规则展示了双活数据库如何解决各种 JSON 命令的冲突。

将不同类型赋值给同一个键

冲突

两个实例并发地将不同类型的值赋给 JSON 文档中的同一个键。

例如

实例 1 将一个对象赋值给 JSON 文档中的一个键。

实例 2 将一个数组赋值给同一个键。

解决类型

胜者为准

解决规则

ID 较小的实例获胜,因此在给定示例中,键成为一个对象。

示例

时间 描述 实例 1 实例 2
t1 将同一个键设置为对象或数组 JSON.SET doc $.a '{}' JSON.SET doc $.a '[]'
t2 向对象和数组添加数据 JSON.SET doc $.a.x '“y”'

结果
{"a": {"x": "y"}}
JSON.SET doc $.a '["z"]'

结果
{“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 文档 JSON.SET doc $ '{"field": "a"}' JSON.SET doc $ '{"field": "b"}'
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 更新现有文档 JSON.SET doc $ '{"field2": "value2"}' JSON.SET doc $.field1 '[1, 2, 3]'
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 JSON.SET doc $ '{"field1": "value2"}'
t3 双活同步 – 同步 – – 同步 –
t4 实例 2 获胜 JSON.GET doc $

结果
{"field1": "value2"}
JSON.GET doc $

结果
{"field1": "value2"}

删除对比更新

冲突

实例 1 使用 JSON.DEL 删除一个 JSON 文档。

实例 2 使用 JSON.SET 更新同一文档的内容。

解决类型

胜者为准

解决规则

文档删除优先于更新。

示例

时间 描述 实例 1 实例 2
t1 文档存在于两个实例上 JSON.GET doc $

结果
{"field1": "value1"}
JSON.GET doc $

结果
{"field1": "value1"}
t2 实例 1 删除文档;实例 2 更新它 JSON.DEL doc JSON.SET doc $.field1 '[1, 2, 3]'
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 使用不同的数据更新同一个字段 JSON.SET doc $.field "b" JSON.SET doc $.field "c"
t3 双活同步 – 同步 – – 同步 –
t4 实例 1 获胜 JSON.GET doc $

结果
{"field": "b"}
JSON.GET doc $

结果
{"field": "b"}

更新对比清除

v2.2 版本之前的 RedisJSON 有两种不同的方式来重置 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 将 colors 重置为空对象 JSON.SET doc $.colors.red ‘#ff0000’ JSON.SET doc $.colors ‘{}’
t3 实例 2 添加新颜色 JSON.SET doc $.colors.green ‘#00ff00’
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 重置 colors JSON.SET doc $.colors.red ‘#ff0000’ JSON.CLEAR doc $.colors
t3 JSON.GET doc $

结果
{"colors": {"blue": "#0000ff", "red": "#ff0000"}}
JSON.GET doc $

结果
{"colors": {}}
t4 实例 2 添加新颜色 JSON.SET doc $.colors.green ‘#00ff00’
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"]
JSON.ARRINSERT doc $ 0 ‘“y”’

结果
["y", "a", "b", "c"]
t3 两个实例都向数组添加另一个元素 JSON.ARRINSERT doc $ 1 ‘“x”’

结果
["a", "x", "c"]
JSON.ARRINSERT doc $ 2 ‘“z”’

结果
["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 更新同一个元素 JSON.ARRPOP doc $.todo 0 JSON.SET doc '$.todo[0]["done"]' 'true'’
t3 JSON.GET doc $

结果
{“todo”: []}
JSON.GET doc $

结果
[{“title”: “buy milk”, “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 ‘“eggs”’ JSON.ARRAPPEND doc $.grocery ‘“milk”’
t3 向数组添加新元素 JSON.ARRAPPEND doc $.grocery ‘“ham”’ JSON.ARRAPPEND doc $.grocery ‘“flour”’
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" ]}
评价此页面
返回顶部 ↑