서비스를 안정적이게 운영하기 위해서는 서비스가 중간에 다운 되거나, 응답이 없거나, 장애가 발생하는 상황이 생기지 않아야 한다. 서비스가 이러한 응답을 제대로 받는지에 대한 측정 지표를 가용성(availability)이라고 하는데, 안정적인 서비스는 고가용성(HA; high availability) 을 지킨다 라고 표현한다. 이번 글에서는 서비스의 고가용성 즉 HA 를 만족시키기 위한 여러가지 방법들에 대해서 알아본다.
1. 쿠버네티스(kubernetes) 사용
Production-Grade Container Orchestration
Production-Grade Container Orchestration
kubernetes.io
가장 쉽고 대표적으로 고가용성을 만족하기 위한 방법으로는 쿠버네티스를 사용하는 방법이 있다. 쿠버네티스는 컨테이너 오케스트레이션 툴로, 서비스를 이미지 형식으로 만든 후 쿠버네티스 환경 위에서 pod 라는 형태로 동작시키면 쿠버네티스가 알아서 해당 pod 가 죽으면 다시 살려주는 과정을 반복한다. 더 나아가서 deployment 라고 하는 형태로 동작시킨 다면 우리가 원하는 replicas 의 갯수대로 pod 가 운영되면서 서비스의 갯수도 동적으로 조절하고 다운되지 않도록 자동으로 설정이 가능한다.
2. primary - standby 구조 적용
primary - standby 구조는 DB 를 운영할 때 많이 들어볼 수 있는 용어이다. primay - standby 구조는 하나의 primary 와 standby 구조로 이루어져 있는 형태로, 사용자 요청을 받고 수행하는 주체를 primary 라고 하고 혹시 primary 가 문제가 발생했을 때를 대비해 언제든 구동될 준비가 되어 있는 상태의 서버를 의미한다. 그래서 DB 서비스를 예로 들자면, primary DB 는 read/write query 를 모두 수행할 수 있고, secondary 는 read-only 형태로 동작하는 구조를 생각 할 수 있다.
이런 형태도 쿠버네티스 위에 올릴수 있겠지만, 단 한대의 서버만 운영되어야 하는 상황이라면 deployment 형식으로 확장시키기도 어려울 것이다. 심지어 쿠버네티스 위에 올리지 못하는 환경의 경우, 예를 들어 vm 을 사용해야 하는 경우나 클라이언트 서버에 설치되어야 한다면 직접 고가용성을 제어해야 한다.
이때, 직접 고가용성을 제어하는 여러 방법들이 있는데 그중에 leader election 을 이용한 방법들에 대해서 몇가지를 살펴 보겠다.
leader election 은 말 그대로 리더를 선출 하는 방식인데, 선출된 리더를 primary 로 사용하고, 만약 리더에 문제가 생기면 대기 하고 있던 후보 군들 (standby) 에서 한 놈이 리더로 승격되는 구조를 의미 한다.
2-1. 분산 메타 저장소를 이용한 방법 (e.g. zookeeper)
leader election 을 적용하기 위한 방법들 중 가장 대표적인 방법이 분산 메타 저장소를 이용하는 방식이다. 대표적인 플랫폼으로는 zookeeper 가 있다. zookeeper 는 분산 코디네이터로 key value 형식의 메타데이터를 이용해 서버 간의 상태를 파악하고 관리하는 형식이다.
예를 들어서, 3대의 서버가 있고 이 서버간의 고가용성을 유지하기 위해 leader election 방법을 적용하고 싶다고 하자. 그리고 leader election 을 제어하기 위한 목적으로 zookeeper 를 이용한다고 가정해 보자. 이때 적용할 수 있는 아주 간단한 방법으로는 zookeeper 에 key-value 형식으로 {"leader" : "name: server-1, timestamp:2023:11:12:9392"} 과 같은 식으로 저장해 두는 방식이다. 여기서 의미하는건 server 1 이 leader 인 겻이고 server-1 의 health check time 을 주기적으로 업데이트 한다. 이렇게 하면 leader 가 해당 데이터에 주기적으로 생존신고를 하면서 살아 있음을 알리게 되는데 만약 timestamp 가 일정 시간 이후 까지 업데이트가 안된다면 후보군들이었던 다른 서버들이 "leader" key 를 가진 객체에 자신의 데이터를 업데이트 한다. 하지만 동일한 key 에는 여러 value 가 나올수 없으므로 결국 하나의 server 만 leader 객체에 업데이트 성공하게 될 것이다.
혹은, zookeeper 의 znode 데이터 특성을 이용해서 leader 를 선택할 수도 있다. (참고) znode 와 연결된 서버의 connection 이 끊기면 데이터가 사라진다는 특성과 znode 안에서 순차적으로 데이터를 넣을수 있는 특성을 이용해서 가장 첫번째 입력되었던 즉 queue 형식이라면 가장 오래된 데이터와 연결되 서버가 leader 가 되는 것이고, 이때 서버와의 연결이 끊기면 queue 에서 빠져나간 이후 그 다음에 들어온 서버가 leader 로 선정되는 방식이다.
2-2. 서버 들 간의 자체 통신을 통한 방법 (e.g. raft)
2-1 에서 살펴본 방식은 외부 저장소를 이용해 leader 를 선출하는 방식인데, 이런 경우 외부 저장소에 의존성이 생길수 있다는 특징이 있다. 이런 경우 각 서버간의 서로 통신을 주고 받으며 leader 를 선정하는 방식이 있는데 대표적으로 raft 알고리즘이 있다. raft 알고리즘은 간단히 말해서 리더가 주기적으로 후보자 서버들에게 ping 을 보내고, 후보자는 해당 ping 을 보고 리더가 살아있음을 인지하게 된다. 이때 리더가 죽으면 ping 을 보내지 못하게 되고 후보자들 중 한명이 먼저 리더가 죽었다는 것을 알아 차리면 본인이 리더로 스스로 승격 하며 다른 후보자들에게 ping 을 보내게 된다.
하지만 raft 알고리즘을 적용할때 주의해야 하는 점은 정족수(quorum) 을 지켜야 한다는 점이다. 정족수는 서버들 중에서 리더를 선출하거나 문제가 생김을 방지 하기 위해 존재해야 하는 최소 갯수를 의미하는데 보통 (n/2)+1 개를 의미 한다. 3개의 서버가 있을때 1개가 죽으면 남아 있는 서버가 2개 이므로 (3/2)+1 = 2 로 정족수를 만족하지만, 2개가 죽으면 남은 서버는 1대 이기 때문에 정족수를 만족시키지 못하고 가용성 구조를 지키지 못하게 된다.
이렇게 해서 고가용성을 지키기 위한 다양한 방법을 보았다. 각 방법들마다 특징들이 있기 때문에 서비스에 맞는 방법을 적용하는 것을 추천한다.
'아키텍쳐' 카테고리의 다른 글
[강의 정리] Distributed System 6.2: Raft consensus algorithm (..ing..) (0) | 2023.04.12 |
---|---|
[강의 정리] Distributed System 6: Consensus (0) | 2023.04.11 |
[강의 정리] Distributed System 5.3: Replication using broadcast (0) | 2023.03.31 |
[강의 정리] Distributed System 5.2: Quorums (정족수) (0) | 2023.03.31 |
[강의 정리] Distributed Systems 5: Replication (0) | 2023.03.29 |
댓글