Active-Active 데이터베이스의 리스트

Active-Active 데이터베이스의 리스트 (Lists in Active-Active databases) (lists-3)

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

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

Active-Active 데이터베이스에서 리스트(List) 데이터 구조를 다루는 방법을 알려드릴게요. Active-Active 데이터베이스의 리스트는 일반 Redis 리스트와 똑같아요. 다만 동시 쓰기가 일어날 때의 동작을 잘 알아둬야 해요. 예시를 따라가며 하나씩 살펴볼게요.

리스트 기본 개념

Redis 리스트는 단순히 삽입 순서대로 정렬된 문자열들의 목록이에요. 리스트의 머리(왼쪽, head)나 꼬리(오른쪽, tail)에 새 요소를 밀어 넣을 수 있어요. 큐(queue)는 LPUSHRPOP으로, 스택(stack)은 LPUSHLPOP으로 쉽게 구현할 수 있죠.

단순 리스트 예시

시간 CRDB Instance 1 CRDB Instance 2
t1 LPUSH mylist "hello"
t2 — Sync — — Sync —
t3 LPUSH mylist "world"
t4 — Sync — — Sync —
t5 LRANGE mylist 0 -1 => "world" "hello" LRANGE mylist 0 -1 => "world" "hello"

설명: 최종 리스트에는 "world"와 "hello" 두 요소가 그 순서대로 들어 있어요. Instance 2가 "world"를 추가할 때 "hello"를 관찰했기 때문에 그 뒤에 붙은 거예요.

동시 삽입 (Concurrent Insertions) 예시

시간 CRDB Instance 1 CRDB Instance 2
t1 LPUSH L x
t2 — Sync — — Sync —
t3 LINSERT L AFTER x y1
t4 LINSERT L AFTER x y2
t5 LRANGE L 0 -1 => x y1 LRANGE L 0 -1 => x y2
t6 — Sync — — Sync —
t7 LRANGE L 0 -1 => x y1 y2 LRANGE L 0 -1 => x y1 y2

설명: Instance 1이 x 뒤에 y1을, Instance 2가 x 뒤에 y2를 추가했어요. 최종 리스트에는 세 요소가 들어 있어요. x가 첫 요소이고, 그 뒤에 y1, y2 순서죠. Active-Active 데이터베이스는 충돌을 임의로 해결하지만, 그 해결은 모든 Active-Active 인스턴스에 일관되게 적용돼요.

리스트 삭제하면서 새 요소 밀어 넣기 예시

시간 CRDB Instance 1 CRDB Instance 2
t1 LPUSH L x
t2 — Sync — — Sync —
t3 LRANGE L 0 -1 => x LRANGE L 0 -1 => x
t4 LPUSH L y DEL L
t5 — Sync — — Sync —
t6 LRANGE L 0 -1 => y LRANGE L 0 -1 => y

설명: t4~t6에서 DEL관찰된 요소만 삭제해요. 그래서 L에는 여전히 y가 남아 있어요. 다른 인스턴스가 추가한 y는 이 인스턴스가 아직 "보지" 못했으니 삭제되지 않죠.

리스트에서 요소 Pop 예시

시간 CRDB Instance 1 CRDB Instance 2
t1 LPUSH L x y z
t2 — Sync — — Sync —
t3 RPOP L => x
t4 — Sync — — Sync —
t5 RPOP L => y
t6 — Sync — — Sync —
t7 RPOP L => z RPOP L => z

설명: t1에서 x, y, z를 L에 밀어 넣었어요. t3에서는 큐에서 기대되는 대로 순차 pop이 동작해요. t7의 동시 pop은 두 인스턴스 모두 같은 결과(z)를 보여줄 수 있어요. z 제거에 대해 동기화가 되지 않아서, 각 인스턴스 관점에서는 z가 리스트에 있어 pop할 수 있는 상태인 거예요. 동기화 후 두 리스트 모두 비워져요.

주의할 점 (스택/큐로 쓸 때)

리스트를 스택이나 큐로 쓸 때 Active-Active 동작을 잘 알아둬야 해요. 위 예시에서 보듯, 두 인스턴스가 수행한 두 개의 병렬 RPOP 연산은 동시 연산의 경우 같은 요소를 가져올 수 있어요. Active-Active 데이터베이스의 리스트는 각 요소가 적어도 한 번은 POP되는 걸 보장하지만, 정확히 한 번만 POP되는 걸 보장하지는 못해요. 이런 동작은 예를 들어 리스트를 프로세스 간 통신(IPC) 시스템의 구성 요소로 쓸 때 반드시 고려해야 해요.

같은 요소를 애플리케이션이 두 번 처리하면 안 되는 상황이라면, POP 연산은 하나의 Active-Active 인스턴스에서만 수행하고, PUSH 연산은 여러 인스턴스에서 수행하는 것을 권장해요.

더 알아보기 (Learn more)

Active-Active 데이터베이스의 리스트에 대해 더 알아보고 싶다면 아래를 확인해 보세요.