CHAAANY ARCHIVE

전체 글

543개의 기록을 주제별로 둘러보세요.

로그 메트릭 트레이스는 장애를 어떻게 다른 각도에서 보여줄까? 관측 가능성의 세 단서

사용자가 결제 버튼을 눌렀는데 5초 뒤 오류가 났다고 하자. 서버 로그 한 줄만 보면 예외 메시지는 찾을 수 있어도 언제부터 얼마나 많은 요청이 느려졌는지, 데이터베이스와 외부 결제 중 어디에서 시간이 쓰였는지 알기 어렵다.관측 가능성(observability: 시스템 밖으로 나온 신호를 이용해 내부 상태와 실패 원인을 추론할 수 있는 정도)은 데이터를 많이 쌓는 것과 다르다. 로그, 메트릭, 트레이스가 어떤 질문에 답하도록 설계됐는지가 중요하다.로그는 한 사건의 구체적인 맥락을 남긴다로그(log: 특정 시점에 애플리케이션이나 시스템에서 일어난 사건을 구조화해 남긴 기록)는 오류 메시지, 주문 식별자, 상태 전이, 재시도 횟수처럼 한 사건의 세부 정보를 담는다.time=10:01:03level=error..

여러 서버는 누가 리더인지 어떻게 합의할까? 정족수와 로그 복제

세 서버가 같은 상태를 복제하고 있는데 기존 리더와의 연결이 끊겼다고 하자. 남은 서버는 새 리더를 뽑아야 한다. 하지만 기존 리더가 실제로 죽은 것이 아니라 네트워크만 갈라졌다면 양쪽에서 리더가 생길 수 있다.합의(consensus: 여러 서버가 장애와 메시지 지연이 있어도 하나의 값이나 작업 순서에 동의하도록 만드는 규칙)는 서버가 모두 같은 순간에 같은 화면을 보는 기능이 아니다. 어떤 제안을 확정된 것으로 인정할지와 새 리더가 이전 결정을 어떻게 이어 갈지를 정한다.실패와 지연을 완전히 구분할 수는 없다서버 A가 B의 응답을 받지 못했을 때 B가 죽었을 수도 있고 네트워크가 느릴 수도 있고 A 쪽 연결만 끊겼을 수도 있다.A ──?── B관찰 가능한 사실: 제한 시간 안에 응답이 없음알 수 없는 ..

처리할 수 있는 양보다 요청이 많아지면 어떻게 버틸까? 백프레셔와 부하 차단

서버가 초당 100건을 처리할 수 있는데 500건이 계속 들어오면 일시적인 버퍼만으로 해결할 수 없다. 요청을 모두 받아 쌓으면 메모리와 연결, 데이터베이스 풀이 차례로 가득 차고 결국 정상 요청까지 오래 기다리다 실패한다.백프레셔(backpressure: 뒤쪽 소비자가 처리할 수 있는 속도를 앞쪽 생산자에게 전달해 유입량을 조절하는 흐름 제어)는 과부하를 없애는 마법이 아니다. 시스템이 감당하지 못하는 일을 어디에서 기다리게 하고 언제 거절하며 무엇을 우선할지 정하는 규칙이다.처리율보다 유입률이 크면 대기열은 계속 늘어난다생산자(producer: 요청이나 작업을 만들어 다음 단계로 보내는 구성 요소)가 초당 500건을 보내고 소비자(consumer: 받은 요청이나 작업을 실제로 처리하는 구성 요소)가 ..

같은 요청이 다시 와도 결과가 한 번만 바뀌게 하려면? 멱등성과 멱등성 키

클라이언트가 주문 생성 요청을 보냈는데 응답을 받기 전에 연결이 끊겼다고 하자. 서버가 처리하지 않았을 수도 있고 처리는 끝났지만 응답만 사라졌을 수도 있다. 클라이언트는 실패인지 성공인지 알 수 없다.이때 재시도를 막으면 실제로 처리되지 않은 주문을 잃고 그대로 다시 보내면 주문이 두 개 생길 수 있다. 멱등성(idempotency: 같은 작업을 한 번 실행하든 여러 번 실행하든 최종 상태가 같게 되는 성질)은 이 불확실한 재시도를 안전한 상태 전이로 바꾸는 규칙이다.같은 요청과 같은 결과를 먼저 정의해야 한다사용자 7의 이메일을 x@example.com으로 설정은 여러 번 실행해도 최종 이메일이 같다. 반면 잔액에 10,000원을 더한다는 실행할 때마다 값이 바뀐다.설정: email = x@examp..

LSM 트리는 쓰기를 어떻게 모아 디스크에 정리할까? SSTable과 컴팩션

B-트리는 디스크 페이지 안에서 정렬된 키를 찾고 필요하면 노드를 제자리에서 나누거나 갱신한다. 쓰기가 매우 많을 때는 흩어진 페이지를 자주 바꾸는 비용이 커질 수 있다. LSM 트리는 쓰기를 메모리에 모은 뒤 정렬된 파일로 순차 기록하는 쪽을 택한다.LSM 트리(Log-Structured Merge-tree: 변경을 메모리와 여러 단계의 정렬 파일에 쌓고 나중에 병합하는 저장 구조)는 쓰기를 빠르게 받아들이는 대신 읽을 위치와 백그라운드 정리 작업이 늘어난다.쓰기는 WAL과 메모리 테이블에 먼저 들어간다새 키와 값을 받으면 먼저 WAL에 복구 기록을 남기고 memtable(memory table: 최근 변경을 키 순서로 보관하는 메모리 자료구조)에 넣는다.put("user:7", "active") →..

MVCC는 읽기와 쓰기가 서로 기다리지 않게 어떻게 도울까? 행 버전과 스냅샷

한 트랜잭션이 주문 상태를 바꾸는 동안 다른 트랜잭션이 같은 행을 읽는다고 하자. 읽을 때마다 쓰기가 끝날 때까지 기다리게 만들면 일관된 값은 얻기 쉽지만 조회가 자주 막힌다.MVCC(Multi-Version Concurrency Control: 같은 데이터의 여러 버전을 유지해 트랜잭션마다 자신에게 보이는 버전을 고르는 동시성 제어 방식)는 읽기와 쓰기가 서로 덜 기다리게 한다. 단순히 복사본을 많이 만드는 기능이 아니라 어떤 버전이 누구에게 보이는지를 정하는 규칙이다.UPDATE는 기존 값을 곧바로 없애지 않을 수 있다주문 7의 상태가 pending에서 paid로 바뀌는 모습을 단순화해 보자. MVCC를 사용하는 데이터베이스는 이전 버전을 남기고 새 버전을 만든 뒤 각 버전에 트랜잭션 정보를 붙일 수..

WAL은 데이터 페이지보다 로그를 왜 먼저 쓸까? 변경 기록과 체크포인트

데이터베이스가 주문 상태 한 줄을 바꿀 때 디스크의 데이터 페이지를 곧바로 제자리에 덮어쓰면 단순해 보인다. 하지만 여러 페이지를 바꾸는 중 전원이 끊기면 어느 페이지까지 반영됐는지 알기 어렵다. 작은 위치를 자주 덮어쓰는 작업도 저장장치에 불리할 수 있다.WAL(Write-Ahead Log: 데이터 페이지를 바꾸기 전에 변경 내용을 순서대로 먼저 남기는 로그)은 커밋의 내구성과 재시작 복구의 기준을 만든다. 이름의 Ahead는 변경 기록이 실제 데이터 페이지 반영보다 앞서야 한다는 순서 규칙을 뜻한다.데이터 페이지는 메모리에서 먼저 바뀔 수 있다데이터베이스는 자주 읽는 디스크 페이지를 버퍼 풀(buffer pool: 데이터와 인덱스 페이지를 메모리에 보관하고 재사용하는 데이터베이스 캐시)에 올린다. U..

육아휴직 6주차, 첫 백화점 나들이와 아내의 생일 준비

육아휴직 6주차.9월 7일 월요일은 장모님 생신이었다. 아내, 아기와 함께 생신 축하 겸 안부 전화를 드렸다. 여느 때처럼 아기를 돌보다가 오후에는 셋이 현대백화점으로 향했다. 아기의 첫 현대백화점 방문이었다.아기띠로 다니려다가 유모차를 빌렸다백화점에 간 주목적은 아내의 노스페이스 겨울 패딩을 실물로 보고 사는 것이었다. 먼저 3층 라운지에 들렀는데 다른 가족들도 있고, 유모차 대여에 수유실, 분유 포트까지 구색이 갖춰져 있었다.우리는 대여가 되는 줄 몰라서 포그내 아기띠로 안고 다니려고 했다. 그런데 싸이벡스 절충형 유모차를 빌릴 수 있어서 아주 편하게 다녔다.노스페이스와 노스페이스 화이트라벨 매장을 둘 다 가봤지만 겨울 제품은 추석 이후인 9월 말쯤 들어온다고 했다. 다른 패딩들을 구경하다가 나왔다...

리버스 프록시와 로드 밸런서는 요청을 어디로 보낼까? 분산 기준과 상태 확인

사용자는 하나의 도메인으로 접속하지만 뒤에는 여러 애플리케이션 서버가 있을 수 있다. 앞단의 서버는 연결을 받고 요청을 검사하고 처리할 서버 하나를 골라 전달한다.리버스 프록시(reverse proxy: 클라이언트 앞이 아니라 서버들 앞에서 요청을 대신 받고 내부 서버로 전달하는 중간 서버)와 로드 밸런서(load balancer: 여러 처리 대상에 요청이나 연결을 나누는 구성 요소)는 비슷한 위치에 있지만 강조점이 다르다. 리버스 프록시는 전달·보안·캐시·TLS 종료 같은 기능을, 로드 밸런서는 부하 분산과 장애 대상 제외를 중심으로 설명할 때가 많다. 하나의 제품이 두 역할을 함께 맡기도 한다.앞단 서버가 연결의 경계를 나눈다TLS 종료(TLS termination: 앞단 서버가 클라이언트와의 TLS..

TLS는 공개된 네트워크에서 어떻게 안전한 연결을 만들까? 인증서와 세션 키

DNS로 서버 주소를 찾고 TCP 연결을 만들었다고 안전한 통신이 시작된 것은 아니다. 중간에서 트래픽을 볼 수 있는 사람이 내용을 읽거나 바꿀 수 있고 연결한 서버가 가짜일 수도 있다.TLS(Transport Layer Security: 네트워크 연결의 상대를 확인하고 전송 내용을 암호화하며 변조를 탐지하는 보안 프로토콜)는 서버 인증과 키 합의, 데이터 보호를 한 연결 안에서 묶는다. HTTPS의 S가 맡는 핵심도 이 TLS 연결이다.TLS는 세 가지 질문에 답한다TLS 연결은 크게 세 가지를 확인한다.지금 연결한 서버가 요청한 도메인의 서버인가.통신 내용을 제삼자가 읽기 어렵게 만들 수 있는가.전달 중 내용이 바뀌었는지 알아낼 수 있는가.기밀성(confidentiality: 허가되지 않은 사람이 내..

도메인 이름은 어떻게 서버 주소를 찾을까? DNS 질의와 캐시

브라우저에 example.com을 입력해도 TCP는 도메인 이름으로 연결하지 않는다. 먼저 이름에 대응하는 IP 주소를 찾아야 한다. 이 일을 맡는 DNS(Domain Name System: 사람이 쓰는 도메인 이름을 IP 주소와 여러 네트워크 정보로 연결하는 분산 이름 시스템)는 전 세계의 한 서버가 모든 답을 보관하지 않고 영역을 나누어 관리한다.DNS 흐름을 이해하면 서버 주소를 바꿨는데 일부 사용자만 이전 서버로 가는 이유, DNS 장애가 애플리케이션 연결 실패로 보이는 이유, TTL을 낮추는 것만으로 즉시 전환되지 않는 이유를 설명할 수 있다.애플리케이션은 보통 재귀 리졸버에 질문한다운영체제나 애플리케이션의 리졸버(resolver: 도메인 이름에 해당하는 DNS 레코드를 찾아 달라고 요청하는 구..

이벤트 루프는 많은 소켓을 어떻게 한꺼번에 지켜볼까? 준비 상태와 epoll

서버가 연결 하나마다 read를 호출한 뒤 데이터가 올 때까지 멈춘다면, 첫 번째 연결이 조용한 동안 다른 연결의 요청도 처리하기 어렵다. 이벤트 루프는 각 연결을 계속 돌아보는 대신 운영체제에 “지금 처리할 수 있는 소켓만 알려 달라”고 요청한다.소켓(socket: 프로세스가 네트워크 연결이나 통신 끝점을 파일 디스크립터처럼 다루게 해 주는 운영체제 객체)의 준비 상태를 이해하면 비동기 I/O가 작업을 없애는 방식이 아니라 기다리는 대상을 모아 두고 실행할 순간을 고르는 방식이라는 점이 더 분명해진다.연결이 있다는 것과 읽을 데이터가 있다는 것은 다르다TCP 연결이 성립한 소켓이 있어도 상대가 아직 요청을 보내지 않았을 수 있다. 이때 블로킹 read(blocking read: 데이터가 올 때까지 호출..

728x90