레이블이 availability인 게시물을 표시합니다. 모든 게시물 표시
레이블이 availability인 게시물을 표시합니다. 모든 게시물 표시

2018-03-25

CAP theorem

CAP theorem은 분산 스토리지는 consistency(a.k.a. C), availability(a.k.a A), partition tolerance(a.k.a. P)를 동시에 만족시킬 수 없다는 것이다. 여기서 C, A, P는 각자 일반적으로 사용되는 용어와 다른 용어로 사용되기 때문에 CAP theorem을 이해하려면 각자가 정의하는 것을 이해하는 것이 중요하다.

C는 모든 read operation이 최신 데이터를 받는 것을 보장하는 것이다. C를 보장하는 시스템은 만약 최신 데이터를 돌려줄 것을 보장하지 못한다면 에러를 돌려줘야 한다. 개인적으로 분산 스토리지를 구현할 때 C, A, P 중 가장 구현하기 어려운 특성은 C라고 생각한다.

A는 모든 operation이 에러가 아닌 데이터를 돌려주는 것이다. 이때 돌려주는 값은 최신 값이 아니어도 상관없다. 심지어 eventual consistencyA를 보장하는 시스템에서는 실제로 존재할 수 없는 데이터 조합이 생길 수도 있다.

P는 partition 상황에서도 시스템이 정상 동작해야 한다는 것이다. 여기서 시스템이 정상 동작한다는 것이 언제나 최신 데이터를 보장하거나 에러가 아닌 값을 준다는 것이 아니다. 그것은 CA가 보장하는 것이고 partition 상황에서도 partition이 아닌 상황과 같은 것을 보장하면 P를 보장한다고 할 수 있다.

근데 여기서 partition은 정말 네트워크 레이어에 문제가 생겨 물리적으로 다른 망이 구성되는 상황을 말하는 것이 아니다. partition은 일부 메시지가 전달되지 않는 상황도 포함된다. 이는 분산환경에서 매우 흔히 발생하는 일이고 P를 포기한다는 것은 결국, 분산 환경을 포기한다는 말이 되기 때문에 분산 데이터 스토리지를 만들 때는 결국 CPAP 중 하나를 선택해야 한다.

개인적으로 생각하기에 CPAP 중 구현하기 더 어려운 것은 CP라고 생각된다. 모든 노드가 언제나 같은 상태를 유지하게 하는 것은 생각보다 어렵고 비싸다. 게다가 CP는 근본적으로 AP보다 latency와 throughput이 떨어진다.

하지만 이런 문제에도 불구하고 데이터 스토리지를 사용하는 application을 선택하는 입장에서는 AP보다 CP를 선호해야 한다고 생각한다. CP 대신 AP를 선택하는 이유는 가용성 때문이다. 가용성은 분명 중요하다. 하지만 스토리지의 가용성과 application 전체의 가용성은 다른 말이다. 데이터 스토리지가 정상적으로 동작하고 있다고 하더라도, 데이터의 일관성이 보장되지 못해서 잘못된 값을 돌려주었다면 이 application은 정상적으로 동작했다고 말할 수 있을까.

이런 일을 방지하기 위해서 AP인 스토리지를 사용하는 로직에는 데이터를 체크하는 복잡한 로직이 들어간다. 복잡한 로직은 높은 버그 가능성과 같은 의미이다. application 로직이 복잡해져서 버그가 발생했고 이를 고치기 위해 서비스를 종료했다면 이 application의 가용성은 떨어지게 된다. 게다가 버그로 인해 잘못된 응답을 준 경우는 오히려 처리하기 쉽다. 만약 버그로 인해 잘못된 데이터가 스토리지에 저장됐다면 이는 잡기도 어려울뿐더러, 고치기도 어렵다.

APCP보다 latency와 throughput이 떨어지기 때문에 성능이 필요한 application을 위해서는 AP인 스토리지를 선택해야 주장하는 사람들도 있다. 하지만 성능도 가용성과 마찬가지로 스토리지의 성능은 스토리지를 사용하는 application의 성능과는 별개다. AP인 스토리지를 사용하여 CP인 스토리지를 사용할 때보다 높은 성능을 보여준다는 것을 주장하기 위해서는 데이터 스토리지의 처리 시간이 application 처리 시간의 대부분을 차지한다는 것을 증명해야 한다. 여기서 측정하는 시간은 단순히 데이터 스토리지에 요청한 operation의 처리속도가 아니라, 네트워크 전송 속도를 제외한 데이터 스토리지 내부의 소요 시간이어야 한다.

설령 스토리지가 처리 속도에 충분한 영향을 준다고 하더라도 AP인 데이터 스토리지를 선택하기 전에 중요한 것이 처리 속도인지, 스토리지를 바꾸지 않으면 처리 속도를 올릴 방법이 없는지 고민해봐야 한다.

2017-10-17

crash-only software - high availability server 만들기

 지난번 글에서 high availability 서버를 만들기 어려운 이유를 설명했었다. 그럼에도 high availability 서버를 만드는 것은 중요하기 때문에 availability를 높이기 위한 여러 가지 방법들이 존재한다. 이번에 설명할 crash-only software도 그중 하나다.

 Crash-only software의 기본 철학은 해결할 수 없는 문제가 발생했을 때, 다른 시도를 하지 않고 바로 종료시키는 것이 오히려 availability를 올린다는 것이다. 이렇게 하면 서버가 떠 있는지만 검사하면 되기 때문에 서버에 문제가 생겼는지 바로 알 수 있고, 문제가 생기면 바로 crash로 끝내기 때문에 빠르게 종료할 수 있다.

 다만 crash-only software는 언제든지 죽을 수 있기 때문에 persistence layer가 프로그램 외부로 빠져야 한다. 즉, 로직 레이어와 데이터 레이어가 구분되는 multitier architecture가 된다.

 자연스럽게 로직 레이어는 스테이트를 가지지 않게 되기 때문에 컴포넌트별로 독립시키기 쉽기 때문에 자연스럽게 마이크로 서비스로 만들게 되고, 서비스 하나의 크기가 줄어들기 때문에 재시작에 걸리는 시간도 줄어들고, 자연스럽게 availability가 증가하게 된다.

 또한, crash-only-software에서 사용하는 공유 자원은 사용권을 소유한다는 개념이 아니라 사용권을 빌린다는 개념으로 접근해야 한다. 사용권을 빌렸기 때문에 명시적으로 사용권을 돌려주지 않았더라도 일정 시간이 지나면 사용권을 잃고 다른 컴포넌트에서 사용할 수 있어야 한다.

2017-10-13

high availability 서버를 만들기 어려운 이유

 서비스에서 availability를 보장해주는 것은 매우 중요하다. three-nine(99.9%)의 availability를 보장하려면 일 년에 아홉 시간 이하의 다운타임만 있어야 하고, four-nine(99.99%)을 보장하려면 약 한 시간 이하, five-nine(99.999%)을 보장하려면 일 년에 다운 타임이 오 분 이하여야 한다.

 보통 서버 장애는 서버가 가장 바쁠 때 발생하기 때문에 가능하면 다운 타임을 줄이는 것이 중요하지만, 현실적으로 이는 쉽지 않다. 상용 서비스 중에서도 three-nine 이상 보장하는 서비스를 찾기 힘들고, 어느 정도 이름 있는 서비스들은 돼야 four-nine, 정말 안정화가 잘 돼 있는 서비스들만이 five-nine 이상의 availability를 보장한다.
 이는 high availability 서버를 만드는 것이 근본적으로 어려운 일이기 때문이다. 다운 타임이 적은 서버를 만들기 위해서는, 일단 버그가 없는 것은 기본이어야 한다. 하지만 서버 다운의 이유가 버그만 있는 게 아니다. 디스크나 네트워크 등 하드웨어 문제로 예상치 못하게 서버를 사용할 수 없게 되는 경우도 있다. 따라서 high availability 서버를 만들기 위해서는 문제가 생겼을 때 빠르게 재시작하는 것이 가장 중요한데 이를 위해서는 서버에 문제가 발생했을 때 이를 감시하고 있던 모니터가 빠르게 감지하여 서버에 문제가 발생하면 서버를 안전하게 죽이고, 새 서버를 띄워야 한다.

  보통 서버에서 일정 시간 간격으로 메시지를 보내고 메시지가 오지 않으면 죽은 것으로 판단하는 heartbeat 방식을 많이 사용한다. 이때 heartbeat 자체는 보통 몇 초에 한 번 보내지만, 실제 서버가 죽지는 않았지만, 네트워크나 다른 문제로 메시지가 오지 않았을 것을 대비하여 몇 번의 메시지가 도착하지 않았을 때 서버가 죽었다고 판단한다. 즉, 실제로 서버에 문제가 발생해도 그를 감지하는 데만 적게는 십수초 많게는 몇십초의 시간이 걸린다.
 그다음 문제는 서버를 빠르고 안전하게 죽이는 것이다. 보통은 프로그램이 죽는 것은 크게 신경 쓰지 않아도 된다. 프로그램이 죽으면 프로그램에서 사용하던 리소스는 OS가 알아서 처리해준다. 하지만 프로그램이 파일 시스템 등의 공유 자원을 사용하고 있었다면, 문제가 복잡해진다. 이 경우 수정한 공유자원을 원래대로 되돌리거나 처리하던 작업을 완료할 때까지 프로그램의 종료를 기다려야 한다.
 마지막 문제는 서버를 빠르게 띄우는 것이다. 단순히 서버를 실행시키는 것은 시간이 오래 걸리지 않는다. 하지만 실행된 서버가 클라이언트의 요청을 정상적으로 처리할 수 있는 상태가 되는데 얼마나 걸릴지는 다른 문제다. 서버에서 사용해야 하는 다른 자원이 있으면 이 자원들을 초기화해야 하고, 서버에서 다른 서비스들을 이용하고 있다면 이 서비스들과의 접속도 다시 확인해야 한다. 게다가 하드웨어의 문제로 서버가 죽은 경우라면 기존에 사용하던 공유자원을 깔끔하게 정리하지 못하고 죽었을 것이기 때문에 이를 정리하는 일까지 해야 한다.

 일반적으로 이상의 작업을 하면 서버에 문제가 발생하여 다시 시작하는 데까지 몇 분의 시간이 소모된다. 즉, 1년에 몇번의 장애만 발생해도 five-nine은 물론이고 four-nine조차 달성하기 어렵다.