在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数据库:

  1. 请参阅Redis企业软件文档中的创建Active-Active地理复制数据库以了解先决条件和详细步骤。

  2. 创建Active-Active数据库屏幕的功能部分,选择JSON

    Select JSON from the Capabilities section.
    注意:
    当你选择JSON时,搜索和查询也会默认被选中,以便你可以索引和查询JSON文档。如果你不想使用这些额外的功能,你可以取消选中搜索和查询复选框。
  3. 配置额外的数据库设置。

  4. 选择创建

命令差异

一些JSON命令在Active-Active数据库中的工作方式不同。

JSON.CLEAR

JSON.CLEAR 重置JSON数组和对象。它支持在Active-Active数据库中从不同实例并发更新JSON文档,并允许合并结果。

冲突解决规则

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

有两种类型的冲突解决方式:

  1. 合并:

    • 操作是关联的。

    • 合并两个操作的结果。

  2. 赢得:

    • 操作不具有结合性。

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

    • 忽略失败的操作。

以下冲突解决规则展示了Active-Active数据库如何解决各种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"}

更新与清除

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.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重置颜色 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”: “买牛奶”, “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" ]}
RATE THIS PAGE
Back to top ↑