Active-Active 데이터베이스의 JSON

Active-Active 데이터베이스의 JSON (JSON in Active-Active databases) (json-3)

Redis 공식 문서의 json-3 페이지를 한국어로 풀어드릴게요. 옆에서 하나씩 설명해 드리는 느낌으로 읽으시면 돼요.

출처: Redis 공식 문서 — json-3

Active-Active 데이터베이스에서 JSON 데이터 구조를 다루는 방법을 알려드릴게요. Active-Active 데이터베이스는 JSON 데이터 구조를 지원해요. 설계는 Kleppmann과 Beresford의 A Conflict-Free Replicated JSON Datatype 논문을 기반으로 하지만, 구현에는 몇 가지 변경이 있어요. 여러 충돌 해결 규칙 예시도 이 논문에서 가져왔어요.

사전 요구사항 (Prerequisites)

Active-Active 데이터베이스에서 JSON을 쓰려면 데이터베이스 생성 시 JSON을 활성화해야 해요.

  • Redis Cloud Active-Active 데이터베이스는 기본적으로 JSON을 추가해요. 자세한 내용은 Redis Cloud 문서의 Create an Active-Active subscription을 참고하세요.
  • Redis Software에서는 버전 8 이상으로 만들었거나 업그레이드한 Active-Active 데이터베이스가 자동으로 JSON을 활성화해요. 더 이른 Redis 버전은 Redis Stack/Redis Software 문서의 Create an Active-Active JSON database를 참고하세요.

명령 차이 (Command differences)

일부 JSON 명령은 Active-Active 데이터베이스에서 다르게 동작해요.

JSON.CLEAR

JSON.CLEAR은 JSON 배열과 객체를 초기화해요. Active-Active 데이터베이스에서 서로 다른 인스턴스가 JSON 문서에 동시에 업데이트하는 것을 지원하고, 결과가 병합되도록 해줘요.

충돌 해결 규칙 (Conflict resolution rules)

Active-Active 데이터베이스에서는 두 인스턴스가 동시에 같은 데이터에 쓰기 연산을 시도할 수 있어요. replica들이 이 변경들을 서로 동기화하려고 하면 충돌이 생길 수 있죠. 충돌 해결 규칙은 데이터베이스가 충돌하는 연산을 어떻게 처리할지 결정해요.

충돌 해결에는 두 가지 유형이 있어요.

  1. Merge (병합):
    • 연산들이 결합 법칙(associative)을 만족.
    • 두 연산의 결과를 병합.
  2. Win over (승리):
    • 연산들이 결합 법칙을 만족하지 않음.
    • 한 연산이 충돌에서 이겨 값을 설정.
    • 진 쪽 연산은 무시.

충돌 해결 규칙 요약

충돌 상황 해결 유형 해결 규칙
키에 다른 타입 할당 Win over ID가 더 작은 인스턴스가 이김
create vs create Win over ID가 더 작은 인스턴스가 이김
create vs update Win over 새 문서를 생성하는 연산이 이김
delete vs create Win over 문서 생성이 삭제를 이김
delete vs update Win over 문서 삭제가 업데이트를 이김
update vs update Win over ID가 가장 작은 인스턴스가 이김
update vs clear (RedisJSON < 2.2) Win over 문서 생성이 업데이트를 이김 (빈 객체 할당의 경우)
pop vs update Win over 삭제가 업데이트를 이김
update vs update object Merge 객체에 대한 모든 연산 결과를 병합

assign different types (서로 다른 타입 할당)

두 인스턴스가 같은 키에 서로 다른 타입의 값을 동시에 할당하는 충돌이에요. 예를 들어 Instance 1은 객체(object)를, Instance 2는 배열(array)을 같은 키에 할당해요. ID가 더 작은 인스턴스가 이기므로, 예시에서는 키가 객체가 돼요.

시간 설명 Instance 1 Instance 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 Active-Active 동기화 – Sync – – Sync –
t4 Instance 1이 이김 JSON.GET doc $ → {"a": {"x": "y"}} JSON.GET doc $ → {"a": {"x": "y"}}

update versus clear (update vs clear) — RedisJSON 2.2 이전

RedisJSON v2.2 이전 버전에서는 JSON 객체의 내용을 초기화하는 방법이 두 가지였어요.

  • 새 빈 JSON 객체를 할당: JSON.SET doc $.colors '{}' — 이 방법은 동시 업데이트와 병합할 수 없어요.
  • 키마다 JSON.DEL로 제거: JSON.DEL doc $.colors.blue — 이 방법은 초기화를 동시 업데이트와 병합할 수 있어요.

RedisJSON v2.2부터JSON.CLEAR 명령으로 각 키를 수동으로 제거하지 않고도 JSON 문서를 초기화할 수 있어요. 이 방법도 동시 업데이트를 병합할 수 있죠.

빈 객체 할당 (Assign an empty object) — v2.2 이전

Instance 1이 기존 "colors" 객체에 "red"를 추가하고, Instance 2가 "colors"에 새 빈 객체를 할당하는 충돌이에요. 문서 생성이 업데이트를 이기므로 결과는 빈 객체가 돼요.

시간 설명 Instance 1 Instance 2
t1 두 인스턴스에 문서 존재 JSON.GET doc $ → {"colors": {"blue": "#0000ff"}} JSON.GET doc $ → {"colors": {"blue": "#0000ff"}}
t2 Instance 1은 새 색상 추가, Instance 2는 빈 객체로 초기화 JSON.SET doc $.colors.red '#ff0000' JSON.SET doc $.colors '{}'
t3 Instance 2가 새 색상 추가 JSON.SET doc $.colors.green '#00ff00'
t4 JSON.GET doc $ → {"colors": {"blue": "#0000ff", "red": "#ff0000"}} JSON.GET doc $ → {"colors": {"green": "#00ff00"}}

동기화 후에는 Instance 1의 값(객체 생성)이 이겨서 최종적으로 빈 객체가 유지되는 식으로 해석됩니다. 참고: 원문 표기상 이 규칙 예시는 버전에 따라 결과 해석이 달라질 수 있어 확인 필요해요.

pop versus update (pop vs update)

Instance 1이 배열에서 요소를 제거하고, Instance 2가 제거된 요소를 업데이트하는 충돌이에요. 삭제가 업데이트를 이겨요.

시간 설명 Instance 1 Instance 2
t1 두 인스턴스에 문서 존재 JSON.GET doc $ → {"todo": [{"title": "buy milk", "done": false}]} JSON.GET doc $ → {"todo": [{"title": "buy milk", "done": false}]}
t2 Instance 1은 배열 요소 제거, Instance 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 Active-Active 동기화 – Sync – – Sync –
t5 Instance 1이 이김 JSON.GET doc $ → doc = {"todo": []} JSON.GET doc $ → doc = {"todo": []}

update versus update object (객체 업데이트 vs 객체 업데이트)

두 인스턴스가 같은 기존 객체를 서로 다른 내용으로 업데이트하는 충돌이에요. 이 경우에는 Merge로 해결돼요. 객체에 대한 모든 연산 결과를 병합하죠.

시간 설명 Instance 1 Instance 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 Active-Active 동기화 – Sync – – Sync –
t6 두 인스턴스의 결과 병합 JSON.GET doc . → {"grocery":["eggs","ham","milk", "flour"]} JSON.GET doc . → {"grocery":["eggs","ham","milk", "flour"]}

이렇게 객체 안의 요소들은 merge로 합쳐지고, 단순 필드 값은 win over로 결정되는 식으로 Active-Active 데이터베이스가 JSON 충돌을 일관되게 처리해요.

더 알아보기 (Learn more)

Active-Active 데이터베이스의 JSON에 대해 더 배우고 싶다면 아래를 참고하세요.