Search
📖

[데이터 중심 애플리케이션 설계] 8. 분산 시스템의 골칫거리

내용 정리

1. 결함과 부분 장애

1.1. 단일 / 분산 시스템 소프트웨어

단일 시스템 소프트웨어
결정적
하드웨어가 올바르게 동작하면 같은 연산은 항상 같은 결과를 냄
하드웨어 문제가 있으면 시스템이 완전히 실패하는 결과를 낳음
일종의 원자성 개념
완전히 동작하거나, 전체 장애가 발생하거나
분산 시스템 소프트웨어
부분 장애 / 비결정적
시스템의 일부만 동작하고 다른 일부가 고장

1.2. 클라우드 컴퓨팅과 슈퍼(고성능) 컴퓨팅

고성능 컴퓨팅
수천개의 CPU를 가짐
계산 비용이 높은 과학 계산 작업에 활용
일기 예보, 분자 동력학 등
결정적. 단일 노드 컴퓨터에 가까움.
클라우드 컴퓨팅
멀티 테넌트 데이터 센서
IP 네트워크 (이더넷)으로 연결된 컴퓨터
신축적/주문식 자원 할당
계량 결제
분산 시스템이 동작하게 하기 위한 조건들
부분 장애 가능성 수용
소프트웨어에 내결함성 메커니즘 적용
신뢰성 없는 구성 요소를 사용해 신뢰성 있는 시스템 구축 필요
오류 수정 코드
단일 비트 오류 처리
IP → TCP
손실된 패킷 재전송, 중복 제거, 패킷을 보낸 순서에 맞춰 재조립 보장

2. 신뢰성 없는 네트워크

분산 시스템
비공유 시스템
네트워크로 연걸된 다수의 장비
네트워크를 통해 오직 통신
각 장비는 자신만의 메모리와 디스크를 갖고 있으며, 다른 장비의 메모리, 디스크에 접근 불가 (네트워크 통해 서비스 요청 제외)
비동기 패킷 네트워크
인터넷, 데이터센터 내부 네트워크 (이더넷)
노드간의 메세지(패킷) 전송 가능
그러나 언제 메세지가 도착하는지 도착할 것인지 보장 X
전송 측에서는 패킷이 전송됐는지 아닌지 조차 구별 불가. 응답을 못받은 이유 아는 것은 불가능
요청 손실 (네트워크 케이블 빠짐)
요청이 큐에 대기하고 잇다가 나중에 전송 (네트워크나 수신자 과부하)
원격 노드 장애 (죽었거나 파워 나감)
원격 노드가 일시적으로 응답 멈췄다가(가비지 컬렉션 휴지 길어짐) 다시 응답
원격 노드가 요청 처리 했으나 응답이 네트워크에서 손실
원격 노드가 요청 처리 했으나 응답 지연 또는 나중에 전송
타임아웃을 통해 일반적으로 문제 대응

2.1. 현실의 네트워크 결함

데이터센터처럼 제어된 환경에서도 네트워크 문제는 흔함
네트워크 분단
네트워크 결함
network partition, netsplit
네트워크 결함으로 인해 네트워크 일부가 다른 쪽과 차단되는 것
네트워크 결함의 오류 처리 정의 & 테스트 필요
소프트웨어가 네트워크 문제에 어떻게 반응 하는지 알고, 시스템이 그로부터 복구할 수 있도록 보장해야한다.
카오스 몽키
고의로 네트워크 문제 유발 & 시스템 반응 테스트

2.2. 결함 감지

결함 자동 감지 필요
로드 밸런서
죽은 노드로 요청 보내기 중단 필요
단일 리더 복제 사용하는 분산 데이터베이스
리더 장애시, 팔로워 승격
네트워크의 불확실성으로 인해 노드 동작 여부 판단 어려움
동작 여부를 알려주는 명시적 피드백 받을 수도 있으나, 여기에 의존할 수 없음
예) TCP 확인 응답 하더라도 애플리케이션 처리 과정에서 죽을 수 있음. 애플리케이션 자체에서 긍정 응답 필요

2.3. 타임아웃과 기약 없는 지연

적정 타임 아웃 시간? 정답은 없음
긴 타임아웃 → 노드 죽었다고 선언까지 대기 시간 김
짧은 타임 아웃 → 빠른 결함 감지, but 일시적인 느려짐에도 죽었다고 잘못 선언 가능
성급하게 노드 죽었다고 선언 시
노드가 실제로 살아있고 어떤 동작 수행 중(예. 이메일 전송), 다른 노드가 역할을 넘겨 받으면 중복 실행 발생 가능
죽은 노드의 책무를 다른 노드로 전달 필요
다른 노드와 네트워크에 추가 부하. 문제 악화의 가능성
연쇄 장애 유발 가능
기약 없는 지연 (unbounded delay)

2.4. 네트워크 혼잡과 큐 대기

큐 대기 지연
네트워크 패킷 지연의 변동성 주요 원인
예시
네트워크 혼잡 (스위치 큐)
여러 다른 노드가 동시에 같은 목적지로 패킷 전송시, 네트워크 스위치는 패킷을 큐에 넣고 하나씩 목적지 네트워크로 보냄
네트워크 링크가 붐비면, 패킷은 슬롯을 얻을 때 까지 잠시 대기
네트워크 잘 동작하더라도, 인풋 데이터가 많아 스위치 큐가 초과하면 패킷 유실되어 재전송 필요
운영체제 큐
패킷이 목적지 장비에 도착하더라도, CPU 코어가 바쁜 상황
애플리케이션에서 준비가능할 때까지 운영체제 큐에서 대기
가상 환경 운영체제 큐
다른 가상 장비가 CPU 코어 사용 동안 가상 환경 운영체제 수십 밀리초 동안 멈추는 경우 흔함
가상 장비는 네트워크에서 어떠허나 데이터도 받을 수 없음
데이터를 큐에 넣어 버퍼링.
TCP 흐름 제어
혼잡 회피, 배압
노드가 네드워크 링크나 수신 노드에 과부하를 가하지 않도록 송신율 제한
TCP
타임 아웃 안에 확인 응답을 받지 않는 경우 패킷 손실 간주 → 손실된 패킷 자동 재전송 → 지연 발생
UDP
흐름 제어 하지 않음.
손실된 패킷 재전송 X
지연된 데이터의 가치가 없는 상황에서 활용하기 좋음
예) VoIP
타임 아웃을 실험적으로 선택할 수 밖에 없음
지연의 변동성 확인
긴 기간, 여러 장비에 걸쳐 네트워크 왕복 시간 분포 측정
애플리케이션 특성을 고려하여 장애 감지 지연과 너무 이른 타임아웃 위험성 적절히 트레이드 오프 진행

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

동기 네트워크
제한 있는 지연 (bounded delay)
패킷 전송 지연 시간 최대치 고정
패킷 유실하지 않음
예) 전화 네트워크
극단적인 신뢰성 보장. 종단 지연 시간이 낮음
음성 샘플 전송 대역폭 충분함
회선 (circuit) 활용
통화 하는 동안 고정되고 보장된 양의 대역폭 할당 & 통화가 끝날때 까지 유지
ISDN 네트워크는 초당 4000ㅍ 레임의 고정된 비율로 실행.
통화시 각 프레임 내에 양방향으로 16비트 공간 할당
통화 하는 동안, 양측은 250마이크로 초마다 정확히 16비트의 오디오 데이터 보낼 수 있게 보장
네트워크의 다음 홉에 통화당 16비트의 공간이 힐당되어 있음. 큐 대기 문제 발생 X
TCP 연결
전화 네트워크 회선과 다름
회선: 다른 누구도 사용할 수 없는 고정된 양의 예약된 대역폭
TCP 연결 패킷: 가용한 네트워크 대역폭을 기회주의적으로 사용
이더넷과 IP
큐 대기의 영향을 받는 패킷 교환 프로토콜
네트워크에 기약 없는 지연이 존재
회선의 개념이 없음
패킷 교환 프로토콜 사용 이유
순간적으로 몰리는 트래픽 최적화
TCP는 가용한 네트워크 용량에 맞춰 데이터 전송률을 동적으로 조절 가능
현재 배포될 기술로는 네트워크 지연과 신뢰성 보장 불가
네트워크 혼잡, 큐 대기, 기약없는 지연 발생 가능
타임아웃에 올바른 값은 없으며, 실험을 통해 결정 필요

3. 신뢰성 없는 시계

분산 시스템에서는 통신이 즉각적이지 않으므로 시간 다루기 까다로움
네트워크 시간 프로토콜 (NTP)
서버 그룹에서 보고한 시간에 따라 컴퓨터 시계 조정

3.1. 단조 시계 대 일 기준 시계

일 기준 시계 (time-of-day clock)
어떤 달력에 따라 현재 날짜와 시간 반환
epoch
UTC 1970년 1월 1일 이래로 흐런 초(밀리초) 반환
NTP로 동기화
단조 시계 (monotonic clock)
지속 시간(시간 구간) 측정에 적합
서비스 응답 시간
두 단조 시계 값 사이의 차이
타이머

3.2. 시계 동기화와 정확도

시계가 정확한 시간을 알려주는 방법은 신뢰성이 있거나 정확하지 않음
하드웨어 시계, NTP 변덕스러울 수 있음
드리프트 현상
컴퓨터 시계와 NTP 서버 시간 차 클 경우, 동기화 거부 or 로컬 시계 강제 리셋
윤초 이슈 (1분 - 59초 / 61초)

3.3. 동기화된 시계 의존하기

동기화된 시계가 필요한 소프트웨어 사용시, 필수적으로 모든 장비의 시계 차이 모니터링 필요
다른 노드와 시계가 너무 차이 나는 노드는 클러스터에서 제거
이벤트 순서화용 타임스탬프
여러 노드에 걸친 이벤트 순서 정하는 문제
다중 리더 복제에서의 쓰기 시간 꼬인 경우, 최종 쓰기 승리 (LWW)로 데이터 손실 발생 가능
예시
NTP를 쓰더라도 잘못된 순서는 발생할 수 있음. 잘못된 순서화가 발생하지 않을 정도로 NTP 동기화 하는 것은 불가능
논리적 시계
진동하는 수정 대신 증가하는 카운터 기반
이벤스 순서화의 안전한 대안
일 기준 시간이나 경과한 초 수 측정 X. 이벤트의 상대적인 순서만 측정
물리적 시계
일 기준 시계
단조 시계
시계 읽기의 신뢰 구간
시계 읽기를 어떤 시점으로 생각하는 것은 타당하지 않음
어떤 신뢰구간에 속하는 시간의 범위를 읽을 것
예) 스패너의 구글 트루타임 API
로컬 시계의 신뢰 구간을 명시적으로 보고 타임스탬프 범위 (가장 이른것, 가장늦은것) 두개의 값을 받음
전역 스냅샷용 동기화된 시계
스냅샷 격리 구현
단조 증가 트랜잭션 ID 필요
데이터베이스가 여러 데이터센터에 분산되어있는 경우, 코디네이션 필요.
전역 단조 증가 트랜잭션 ID 생성 어려움
동기화된 일 기준 시계 타임스탬프를 트랜잭션 ID로 활용?
동기화를 충분히 잘한다면 괜찮음.
여전히 시계정확도의 불확실성은 존재
예) 스패너
트루타입 API가 보고한 시계 신뢰 구간을 사용하여 스냅샷 구현
분산 트랜잭션 시맨틱용으로 시계 동기화를 쓰는것이 활발히 연구 중

3.4. 프로세스 중단

파티션마다 리더가 있는 분산 시스템
리더만 쓰기 가능
노드가 여전히 리더인지, 그리고 안전하게 쓰기를 받아들일 수 있을지 어떻게 알 수 있을까?
임차권
리더가 다른 노드들로부터 임차권 얻는것 (타임아웃 있는 잠금과 비슷)
특정 시점에 오직 하나의 리더만 임차권 획득 가능
어떤 노드가 임차권 획득하면 임차권 만료까지 얼마동안 리더인지 알 수 있음
리더로 남아있으려면 임차권 갱신 필요
노드 장애 발생 시, 임차권 갱신 만료→ 다른 노드가 리더 역할을 넘겨 받음
요청 처리 루프 예시 코드
while(true) { request = getIncomingRequest(); // 항상 임차권이 적어도 10초는 남아 있게 보장 if(lease.expiryTimeMillis - System.currentTimeMillis() < 10000) { lease = lease.renew(); } if(lease.isValid()) { process(request); } }
TypeScript
복사
잘못된 이슈 존재
1.
동기화된 시계에 의존
임차권 만료 시간이 다른장비에서 설정되었으나, 로컬 시스템 시계와 비교
2.
로컬 단조 시계만 사용하도록 프로토콜 수정하더라도 문제 발생
시간 확인하는 시점(System.currentTimeMillis())과 요청을 처리하는 시점(process(request)) 사이에 매우 짧은 시간 흐르는 경우, 코드가 아주 빨리 실행되어, 10초의 버퍼는 요청 처리 도중 임차권 만료되지 않도록 보장하는 데 필요한 것 이상이다.
프로그램 실행 중에 예상치 못한 중단 발생 시
(스레드가 lease , isValid() 근처에서 마지막으로 진행되기 전에 15초동안 멈춘 경우)
이 경우 요청 처리 시점에서 임차권이 만료돼서 다른 노드가 이미 리더 역할을 넘겨 받았을 가능성이 높음
그러나 이스레드에게 임차권이 만료되었다고 말하지 않으므로 다음회차까지 알아차리지 못함
이미 요청을 처리하게 됨
스레드가 아주 오랫동안 멈출 수 있는 상황은 발생 가능한 시나리오임
실행중인 스레드는 어떤 시점에 선점(preempt)하고 얼마간의 시간이 흐른 후 재개 가능
선점된 스레드는 이를 알지 못함
예시
가비지 콜렉터 중단 (stop the world GC 중단)
가상환경의 가상 장비
서스펜드(suspend) → 재개 (resume) 될 수 있음
최종 사용 기기
서스펜드(suspend) → 재개 (resume) 될 수 있음
예) 노트북 덮개 닫기
운영체제 스레드 컨텍스트 스위치 / 하이버바이저 다른 가상 장비 스위치
스틸 타임
가상장비의 경우, 다른 가상 장비에서 소비된 CPU 시간
애플리케이션 동기식 디스크 접근
운영체제 디스크 스왑(페이징)
유닉스 프로세스 SIGSTOP 신호
단일 장비에서 다중 스레드 코드 작성시 thread safe하게 만드는 도구들
뮤텍스
세마포어
원자적 카운터
잠금 없는 자료구조
블로킹 큐
분산 시스템에서는 공유 메모리가 없고 신뢰성 없는 네트워크를 통해 메세지를 보내므로 위 도구 활용 힘듦
엄격한 실시간 시스템 (hard real-time)
소프트웨어가 응답해야하는 데드라인이 명시되어 있음
데드라인을 만족시키지 못하면, 전체 시스템 장애 유발
예시) 자동차 에어백
많은 양의 부가 작업이 필요하고 사용할 수 있는 프로그래밍 언어, 라이브러리, 도구의 범위 엄격히 제안
실시간 시스템 개발은 높은 비용이 듬.
안전이 필수인 임베디드 장치에서 흔하게 사용
cf) 실시간 운영체제 (rea-time operation system, RTOS)
시스템 실시간 보장을 위해서는 소프트웨어 스택의 모든 수준에서 지원 필요
프로세스가 명시된 간격의 CPU 시간을 할당 받을 수 있게 보장되도록 스케줄링
가비지 컬렉션의 영향 제한하기
GC 중단을 노드가 잠시동안 계획적으로 중단하는 것으로 간주
클라이언트의 요청을 다른 노드들이 처리하게 함
런타임이 애플리케이션에게 노드가 곧 GC 중단이 필요하다고 경고만 할수 있다면 트래픽 중단 후 리밸런싱 가능

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

분산 시스템
공유메모리가 없음 → 지연 변동이 큰 신뢰할 수 없는 네트워크를 통해 메세지를 보냄
부분 장애, 신뢰성 없는 시계, 프로세스 중단 발생 가능
원격 노드가 응답하지 않을 때, 어떤 상태인지 알 수 없음
네트워크 문제? 노드 자체 문제?

4.1. 리더와 잠금

시스템이 오직 하나의 뭔가가 필요할 때, 분산 시스템에서는 구현 주의가 필요함
예시
스플릿 브레인 → 오직 한 노드만 파티션 리더가 될 수 있음
특정 자원이 객체 동시쓰기 / 오염 방지를 위해 오직 하나의 트랜잭션이나 클라이언트만 객체 잠금 획득 가능
갱신 손실 방지를 위해 오직 한명의 사용자만 특정한 사용자명으로 등록 가능
어떤 노드가 스스로 선택된자라고 생각 할지라도 노드의 정족수는 다를 수 있음
노드의 과반수가 어떤 노드가 죽었다고 선언했음에도 그 노드가 선택된 자 인처럼 계속 행동한다면 신중하게 설계되지 않은 시스템에서 문제를 유발 할 수 있음
프로세스 중단 임차권 예시
임차권을 가진 클라이언트가 너무 오래 멈춰있으면 임차권 만료
다른 클라이언트가 임차권 획득하여 쓰기 시작
멈췄던 클라이언트가 다시 돌아와 파일 덮어쓰기
쓰기 충돌, 파일 오염
예시

4.2. 펜싱 토큰

펜싱(fencing)
“선택된 자” 라고 잘못 믿는 노드가 나머지 시스템을 방해할 수 없도록 보장 해주는 기법
펜싱 토큰
잠금 서버가 잠금이나 임차권을 승인할때마다 증가하는 (잠금 서비스가 증가시키는) 숫자
클라이언트가 쓰기 요청을 저장소 서비스로 보낼때마다 자신의 펜싱 토큰을 포함하도록 요구
부주의한 오류에 빠진 노드를 감지하고 차단 가능
주키퍼
잠금 서비스로 활용 가능.
트랜잭션 ID zxid나 노드 버전 cversion을 펜싱 토큰으로 사용 가능
단조 증가가 보장되므로 필요한 속성을 지님
예시

4.3. 비잔틴 결함

펜싱 토큰의 한계
노드가 고의로 시스템의 보장을 무너뜨리려고 하는 경우 한계 발생
예) 가짜 펜싱 토큰을 포함한 메시지 보내기
비잔틴 결함
어떤 노드가 실제로는 받지 않은 특정한 메세지를 받았다고 주장하는 동작
분산 시스템 내 노드가 거짓말을 하는 경우
비잔틴 장군 문제
신뢰할 수 없는 환경에서 합의에 도달하는 문제
비잔틴 내결함성 알고리즘
일부 노드가 오동작하고 프로토콜을 준수하지 않거나, 악의적인 공격자가 네트워크를 방해하더라도 시스템이 계속 올바르게 동작하는 시스템
웹 애플리케이션에서는 웹브라우저 같은 클라이언트 행동이 임의적이고 악의적이라고 예상해야함
입력 확인 (input validation)
살균 (sanitization)
출력 이스케이핑 (output escaping)

4.4. 약한 형태의 거짓말

약한 형태의 거짓말
하드웨어 문제
소프트웨어 버그
잘못된 설정으로 인한 유효하지 않은 메세지
위의 이슈로 부터 보호해주는 메커니즘 추가 필요
예시)
네트워크 패킷 오염
어플리케이션 수준 프로토콜에서 체크섬 사용
공개적으로 접근 가능한 애플리케이션
사용자 입력 신중히 살균
NPT 클라이언트
동기화 시, 클라이언트는 모든 서버에 접속해 오차 추정후, 이상치를 검출하여 동기화에서 제거

4.5. 시스템 모델과 현실

분산 시스템의 다양한 결함 및 종류를 정형화 필요
시스템 모델(system model)을 정의하여 정형화
알고리즘이 가정하는 것을 기술한 추상화
시스템 모델의 종류
동기식 모델
네트워크 지연, 프로세스 중단, 시계 오차 모두 제한이 있다고 가정
기약없는 지연과 중단이 발생함
부분 동기식 모델
시스템이 대부분의 시간에는 동기식 시스템처럼 동작
때때로 네트워크 지연, 프로세스 중단, 시계 드리프트의 한계치를 초과
많은 시스템의 현실적인 모델
비동기식 모델
알고리즘은 타이밍에 대해 어떠한 가정도 할 수 없음
노드용 시스템 모델
죽으면 중단하는 (crash-stop) 결함 모델
알고리즘은 노드에 장애가 나는 방식이 하나뿐, 다시 말해 죽는 것뿐이라고 가정
노드가 어느 순간에 갑자기 응답하기를 멈추면, 그 노드는 영원히 사용할 수 없음
죽으면 복구하는 (crash-recovery) 결함 모델
노드가 어느 순간 죽을 수 있지만, 아마도 일정 시간이 지나면 다시 응답할 것이라고 가정
노드는 메모리에 있는 상태는 손실되지만, 죽어도 데이터가 남아있는 안정된 저장소가 있다고 가정
비잔틴(임의적인) 결함 모델
노드는 다른 노드를 속이거나 기만하는 것을 포함해 전적으로 무슨일을 할 수 있다고 가정

4.6. 분산 알고리즘 대응

현실적으로는 죽으면 복구하는 결함을 지닌 부분 동기식 모델이 가장 일반적
분산 알고리즘은 이 모델에 어떻게 대응할 수 있을까?
알고리즘의 정확성
알고리즘이 정확하다는 의미를 정의하기 위해 알고리즘의 속성 기술 필요
예) 펜싱 토큰 생성 시
유일성
펜싱 토큰이 같은 값을 반환하지 않는다.
단조 일련번호
요청 x가 토큰 t1을 , 요청 y가 토큰 t2를 반환했고, y가 시작하기 전에 x가 완료되었다면 t1 < t2를 만족한다.
가용성
펭신 토큰을 요청하지 않고 죽은 노드는 결국에는 응답을 받는다.
알고리즘은 시스템 모델에서 발생하리라 가정한 모든 상황에서 그 속성들을 항상 만족시키면 해당 시스템 모델에서 정확하다.
그러나 이를 어떻게 이해할 수 있을까?
모든 노드가 죽거나, 모든 네트워크 지연이 갑자기 무한히 길어진다면 어떤 알고리즘이라도 아무것도 할 수 없다.
알고리즘의 안전성(safety)과 활동성(liveness)
안전성
나쁜일은 일어나지 않는다.
안전성이 위반되면 그 속성이 깨진 특ㅌ정 시점을 가리킬 수 있다.
안전성 속성이 위반된 후 그 위반을 취소할 수 없다. 이미 손상된 상태다.
예) 유일성 & 단조 일련번호
활동성
좋은 일은 결국에는 일어난다.
어떤 시점을 정하지는 못하지만(예를 들어, 노드가 요청을 보냈지만 아직 응답을 받지 못했을 수 있다), 항상 미래에 그 속성을 만족시킬수 있다(다시말해 응답을 받음으로써)는 희망이 있다.
예) 가용성
분산 알고리즘은 시스템 모델의 모든 상황에서 안전성 속성이 항상 만족되기를 요구하는게 일반적임
모든 노드가 죽거나, 네트워크 전체가 장애가 나더라도, 알고리즘은 잘못된 결과를 반환하지 않음을 보장해야함
활동성 속성에 대해서는 경고를 하는게 허용됨

5. 정리

분산 시스템에서 일어날 수 있는 문제
부분 장애
신뢰성 없는 시계
프로세스 중단 발생 가능
분산 시스템의 특징
부분 장애 / 부분 실패
구성요소의 일부가 고장나더라도, 전체로서의 시스템은 계속 동작할 수 있도록 부분 실패 내성을 소프트웨어에 내장하려고 노력 필요
결함을 감지하는 것이 매우 어려움
분산 알고리즘은 타임아웃을 활용

스터디

Harry

분산 시스템에서 발생 가능한 문제 상황 3가지를 말해주세요 → 부분 실패 가능성이 언제든 존재
펜싱 토큰이란?
비잔틴 결함이란?

Matthew

비동기 패킷 네트워크의 특징은 무엇인가요
왜 데이터센터 네트워크와 인터넷은 패킷교환을 사용할까요?