|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: " 분산 시스템에서 순서가 보장되지 않은 이벤트를 다루는 전략 " |
| 4 | +categories: Tech |
| 5 | +author: goodGid |
| 6 | +use_math: true |
| 7 | +--- |
| 8 | +* content |
| 9 | +{:toc} |
| 10 | + |
| 11 | +## 분산 시스템에서 최종적 일관성이란 |
| 12 | + |
| 13 | +* DB, Cache, 서비스 등 여러 시스템이 |
| 14 | + |
| 15 | + 특정 시점에는 서로 다른 데이터를 가질 수 있지만 |
| 16 | + |
| 17 | + 최종적으로는 같은 상태와 값을 갖음을 보장하는 것을 뜻한다. |
| 18 | + |
| 19 | +* 최종적 일관성을 기반으로 구축된 시스템은 |
| 20 | + |
| 21 | + 노드 간에 **엄격한 순서**나 동기화된 업데이트를 강제하지 않으므로 |
| 22 | + |
| 23 | + 제품 재고가 한 서버에서는 몇 초 동안 "재고 있음"으로 표시되고 |
| 24 | + |
| 25 | + 다른 서버에서는 "재고 없음"으로 표시될 수 있다. |
| 26 | + |
| 27 | +--- |
| 28 | + |
| 29 | +### 이벤트 기반 시스템에서 강력한 일관성을 유지하는 게 어려운 이유 |
| 30 | + |
| 31 | +* 분산 시스템 환경에선 |
| 32 | + |
| 33 | + 네트워크 지연, 서비스 충돌, 재시도, 파티션 등 예측 불가능한 장애가 가득하다. |
| 34 | + |
| 35 | +* EDA(Event-Driven Systems) 시스템에서 |
| 36 | + |
| 37 | + 강력한 일관성을 요구하는 것은 |
| 38 | + |
| 39 | + 분산 시스템 본질에 대해 도전하는 행위가 된다. |
| 40 | + |
| 41 | +* 예를 들면 사용자가 제품에 대한 리뷰를 제출하면 |
| 42 | + |
| 43 | + 리뷰 서비스는 "리뷰 생성됨"이라는 이벤트를 생성한다. |
| 44 | + |
| 45 | + 이후 분석 서비스는 평균 평점을 업데이트하고 |
| 46 | + |
| 47 | + 사용자 프로필 서비스는 사용자의 기여 횟수를 기록한다. |
| 48 | + |
| 49 | + 한 서비스가 즉시 업데이트되고 |
| 50 | + |
| 51 | + 다른 서비스가 지연되거나 장애가 발생하면 |
| 52 | + |
| 53 | + 시스템은 일시적으로 서로 다른 상황을 보여주게 된다. |
| 54 | + |
| 55 | +* 강력한 일관성은 모든 서비스가 성공적으로 완료되거나 |
| 56 | + |
| 57 | + 아니면 아무것도 완료되지 않아야 한다는 것을 요구하지만 |
| 58 | + |
| 59 | + 비동기 이벤트 기반 환경에선 충족시키는 건 매우 어렵다. |
| 60 | + |
| 61 | +--- |
| 62 | + |
| 63 | +## 순서 없는 이벤트를 처리하는 전략 |
| 64 | + |
| 65 | +* 순서에 대한 강제성이 없기 때문에 |
| 66 | + |
| 67 | + 이벤트를 발생한 순서가 아닌 |
| 68 | + |
| 69 | + 시스템에 이벤트가 도착한 순서대로 작업이 처리되면 |
| 70 | + |
| 71 | + 의도치 않게 작업 순서가 바뀔 수 있다. |
| 72 | + |
| 73 | +* 이럴 경우 어떻게 대응할 수 있는지 몇 가지 전략에 대해 알아보자. |
| 74 | + |
| 75 | +--- |
| 76 | + |
| 77 | +### Event Versioning |
| 78 | + |
| 79 | +* 각 이벤트는 해당 이벤트가 나타내는 상태를 나타내는 |
| 80 | + |
| 81 | + 버전 또는 시퀀스 번호를 갖게 한다. |
| 82 | + |
| 83 | +* 서비스는 이벤트 처리 시 |
| 84 | + |
| 85 | + 현재 보유하고 있는 버전과 비교한다. |
| 86 | + |
| 87 | +* 더 최신 버전인 경우 이벤트를 적용하고 |
| 88 | + |
| 89 | + 이전 버전인 경우 삭제하거나 무시하고 |
| 90 | + |
| 91 | + 중복된 경우 멱등적으로 처리한다. |
| 92 | + |
| 93 | +* DynamoDB 및 Couchbase와 같은 시스템은 |
| 94 | + |
| 95 | + 업데이트 충돌을 안전하게 해결하기 위해 |
| 96 | + |
| 97 | + 내부 버전 관리(벡터 클록 또는 문서 수정 사용)를 사용하는 경우가 많다. |
| 98 | + |
| 99 | +--- |
| 100 | + |
| 101 | +### Idempotent Event Handlers |
| 102 | + |
| 103 | +* 멱등성은 동일한 이벤트를 여러 번 처리해도 동일한 결과가 생성됨을 보장한다. |
| 104 | + |
| 105 | +* 이 원칙은 이벤트가 재시도, 중복 또는 재정렬될 때 시스템을 보호한다. |
| 106 | + |
| 107 | +* 멱등성을 달성하는 방법은 |
| 108 | + |
| 109 | + 처리된 이벤트 ID를 기록하여 중복을 건너뛴다. |
| 110 | + |
| 111 | +* 업데이트를 가산적인 방식이 아닌 |
| 112 | + |
| 113 | + 덮어쓰기 방지 방식으로 구성한다. |
| 114 | + |
| 115 | + ex) "발송 카운터 증가" 대신 "주문 상태를 발송됨으로 설정" |
| 116 | + |
| 117 | +--- |
| 118 | + |
| 119 | +### Reordering Buffers |
| 120 | + |
| 121 | +* 이벤트가 약간 순서가 어긋나지만 |
| 122 | + |
| 123 | + 예측할 수 있는 패턴(ex. 순차 번호 매기기)으로 도착하는 경우 |
| 124 | + |
| 125 | + 서비스는 재정렬 버퍼(Reordering Buffers)를 사용할 수 있다. |
| 126 | + |
| 127 | +* 이 전략은 버퍼 크기와 시간제한을 신중하게 조정해야 한다. |
| 128 | + |
| 129 | + 버퍼 크기가 너무 작으면 순서가 어긋난 이벤트가 포함되지 못하고 |
| 130 | + |
| 131 | + 너무 크면 지연 시간이 불필요하게 증가한다. |
| 132 | + |
| 133 | +> Process Step |
| 134 | +
|
| 135 | +1. 이벤트를 다루는 Small Window를 유지한다. |
| 136 | + |
| 137 | +2. 버전 또는 타임스탬프를 기준으로 이벤트를 재정렬한다. |
| 138 | + |
| 139 | +3. 순서가 맞춰줬다고 판단이 되면 이벤트를 처리한다. |
| 140 | + |
| 141 | +> Example |
| 142 | +
|
| 143 | +* 메시징 앱은 수신 채팅 메시지를 즉각적으로 렌더링하기 전에 |
| 144 | + |
| 145 | + 몇 초 동안 버퍼링하여 |
| 146 | + |
| 147 | + "안녕"이 "잘 지내?"보다 먼저 표시되도록 적용할 수 있다. |
| 148 | + |
| 149 | +--- |
| 150 | + |
| 151 | +## Reference |
| 152 | + |
| 153 | +* [Engineering Trade-offs: Eventual Consistency in Practice](https://blog.bytebytego.com/p/a-guide-to-eventual-consistency-in) |
0 commit comments