designing-data-intensive-applications

결함과 부분 장애

클라우드 컴퓨팅과 슈퍼 컴퓨팅

신뢰성 없는 네트워크

현실의 네트워크 결함

결함 감지

타임아웃과 기약 없는 지연

네트워크 혼잡과 큐 대기

Untitled

동기 네트워크 대 비동기 네트워크

그냥 네트워크 지연을 예측 가능하게 만들 수는 없을까?

신뢰성 없는 시계

애플리케이션은 다양한 방식으로 시계에 의존한다.

  1. 이 요청이 타임아웃됐나?
  2. 사용자가 우리 사이트에서 시간을 얼마나 보냈나?
  3. 이 기사가 언제 게시 됐나?
  4. 로그 파일에 남은 오류 메시지의 타임스탬프는 무엇인가?

→ 1,2는 지속시간을 측정하고 5,8은 시점을 기술한다.

단조 시계 대 일 기준 시계

현대 컴퓨터는 최소 두 가지 종류의 시계를 갖고 있다.

일 기준 시계

직관적으로 시계에 기대하는 일을 한다.

단조 시계

단조 시계는 타임아웃이나 서비스 응답 시간 같은 구간을 재는 데 적합하다.

→ 단조 시계란 이름은 항상 앞으로 흐른다는 사실에서 나왔다.

시계 동기화와 정확도

정확한 시계를 알려주는 방법은 기대만큼 정확하지 않을 수 있다.

시계 정확도가 중요해서 상당한 자원을 투입할 생각이 있다면 시계 정확도를 매우 높힐수 있다.

→ GPS 수신기, 정밀 시간 프로토콜, 세심한 배포 및 모니터링

동기화된 시계에 의존하기

소프트웨어의 어떤 부분이 정확히 동기화된 시계에 의존한다면 그 결과는 극적인 고장보다는

조용하고 미묘한 데이터 손실이 발생할 가능성이 높다.

→ 동기화된 시계가 필요하다면 모든 장비 시계 차이를 모니터링해야 한다.

이벤트 순서화용 타임스탬프

Untitled

시계 읽기는 신뢰 구간이 있다.

공개 인터넷에 있는 NTP 서버를 사용하면 달성 가능한 최선 정확도는 수십 밀리초이고 혼잡이 있으면 오차는 100밀리초 이상으로 급증한다.

전용 스냅숏용 동기화된 시계

스냅숏 격리 구현은 단조 증가하는 트랜잭션 ID가 필요하다.

→ 여러 데이터센터에 있는 여러 장비에 데이터베이스가 있을 때는 전역 단조 증가 트랜잭션 ID를 생성하기 어렵다.

프로세스 중단

Untitled

이 코드는 동기화된 시계에 의존해서 동기화가 깨지면 이상한 일을 할 수 있다.

응답 시간 보장

가비지 컬렉션의 영향을 제한하기

→ 수명이 짧은 객체만 가비지 컬렉터를 사용하고 수명이 긴 객체의 전체 gc가 필요할만큼 쌓이기 전에 프로세스를 재시작하는 방법도 있다.

지식, 진실, 그리고 거짓말

분산 시스템

분산 시스템에서 우리는 동작(시스템 모델)에 관해 정한 가정을 명시하고, 가정을 만족시키는 방식으로 설계할 수 있다.

진실은 다수결로 결정된다.

  1. 노드는 자신에게 보내지는 메세지는 모두 받을 수 있지만, 보내는 메세지는 유실되거나 지연된다. 이러한 상황은 노드가 정상적으로 메세지를 받을 수 있는 상태여도 Timeout이 발생하면 노드를 죽었다고 판단한다.
  2. 한쪽 연결이 끊긴 노드는 보내는 메세지가 다른 노드로부터 응답을 받지 못하는 것을 알아내서 결함이 있는게 확실하다고 깨달을 수 있다. 그럼에도 다른 노드들이 노드가 죽었다고 잘못 선언하고, 한쪽 연결이 끊긴 노드는 그에 대해 아무 일도 할 수 없다.
  3. 긴 stop-the-world 가비지 컬렉션 중단 모든 스레드는 GC에 선점되고 1분동안 멈춘다. 결과적으론 아무 요청도 처리되지 못하고 아무 응답도 전송되지 않는다. 기다리면서 재시도 하다가 결국엔 노드가 죽었다고 판단한다. GC가 끝나고 스레드들은 실행은 재개한다.

노드는 언제든 장애가 날 수 있기 때문에 이러한 것을 방지하기 위해 정족수를 사용한다

리더와 잠금

분산 시스템에서 주의할 점

잠금을 잘못 구현해서 생긴 데이터 버그 예시 ![[Pasted image 20240127233638.png]] 요구사항

문제점

펜싱 토큰

시스템을 방해할 수 없도록 보장하기 위한 가장 단순한 방법 : 펜싱(fencing)

펜싱 토큰 예제 ![[Pasted image 20240127234009.png]] 펜싱 토큰(fencing token)

잠금 서비스로 주키퍼를 사용하면 트랜잭션 id zxid나 노드 버전 cversion을 펜싱 토큰으로 사용할 수 있다. 이들은 단조 증가가 보장되므로 필요한 속성을 지닌다.

하지만 이러한 것을 사용할 때 잠금으로 보호받지 않는 요청을 처리하지 않도록 일종의 확인이 필요하다.

서버 측에서 토큰을 확인하는 것은 아주 좋다.

비잔틴 결함

펜싱 토큰은 부주의에 의한 오류에 빠진 노드를 감지하고 차단할 수 있다. 그러나 노드가 고의로 시스템의 보장을 무너뜨리려 한다면, 가짜 펜싱 토큰을 포함한 메세지를 보내기만 하면 된다.

비잔틴 결함(Byzantine fault)

비잔틴 장군 문제

두 군대의 장군이 소통할 때 전령을 통해서 한다. 전령(네트워크 패킷)은 때때로 늦거나 실종된다.

또한 배신자가 있어서 사실에 방해를 줄 수도 있다. 가짜나 허위 메세지를 보내 다른 장군들을 속이거나 혼란스럽게 하려고 시도할 수 있다.

일부 노드가 오작동하고 프로토콜을 준수하지 않거나 악의적인 공격자가 네트워크를 방해하더라도 올바르게 동작하면 비잔틴 내결함성(Byzantine fault tolerant)을 지닌다.

예시 )

대부분 시스템은 비잔틴 결함이 없다고 가정한다.

웹 애플리케이션에선 클라이언트의 행동이 임의적이고 악의적이라고 예상한다.

소프트웨어 버그가 비잔틴 결함으로 간주할 수 있지만, 도움이 되진 않는다.

약한 형태의 거짓말

시스템 모델과 현실

시스템 모델(system model)

노드 장애

죽으면 복구하는 결함을 지닌 부분 동기식 모델이 가장 유용한 모델이다.

알고리즘 정확성

예제 )

모든 상황에서 그 속성들을 항상 만족시키면 해당 시스템 모델에서 정확하다. 하지만 모든 노드가 죽거나 모든 네트워크 지연이 갑자기 무한히 길어진다면 어떤 알고리즘이라도 아무것도 할 수 없다.

안전성과 활동성

분산 알고리즘에선 안전성 속성이 항상 만족되기를 요구하는게 일반적이다. 잘못된 결과를 반환하지 않는다고 보장해야 한다.

활동성 속성은 경고를 하는 게 허용된다. 예시 )

시스템 모델을 현실 세계에 대응 시키기

분산 시스템의 안전성과 활동성을 평가하는 데는 시스템 모델이 유용하다. 그러나 실제 구현에서는 저장소 오염, 하드웨어 오류 등의 현실적인 문제를 고려해야 한다. 정족수 알고리즘은 노드의 데이터 기억 상태를 중요시하며, 이를 잃을 경우 정확성이 위협된다. 추상 시스템 모델은 문제를 이해하고 해결하는 데 도움이 되지만, 현실 구현에서는 항상 적용되지 않을 수 있다. 이론적 분석과 경험적 실험이 함께 필요하다.