728x90
8장. 분산 서버 구조
8.1 수직 확장과 수평 확장
- 확장성(scalability)이란 사용자 수가 늘어나더라도 쉽게 대응할 수 있어야 한다는 의미다. 최대로 처리할 수 있는 사용자 수가 무제한이여도 가능해야 한다는 것이 확장성 목표이다. 사용자 수가 늘어나도 서버 성능을 유지하려면 보통 다음 두 가지 중 하나를 수행한다.
- 스케일 업(scale-up) : 수직 확장
- 스케일 아웃(scale-out) : 수평 확장
- 수직 확장은 서버의 하드웨어를 더 좋은 것으로 교체하여 처리량을 늘리는 것을 의미한다. 수평 확장은 서버 대수를 늘려서 더 많은 처리를 하는 것이다. 수평 확장이 더 많이 사용되는 방법이지만, 소프트웨어 설계가 더 복잡하다는 대가가 따른다. 또 수평 확장은 수직 확장으로 서버보다 단위 처리 속도가 더 느릴 수 있다.
8.2 서버 분산이 없다면?
- 64 비트에서는 서버의 물리적 메모리보다 더 많은 양의 메모리를 할당하면서 대량의 메모리 스와핑이 발생한다. 이 때문에 프로그램 실행속도가 급락하면서 메모리 할당량이 더욱 증가하는 악순환도 발생한다. 물론 여기서도 메모리 스와핑을 할 수 있는 한계에 부딪히게 되면 메모리 할당함수가 이러한 문제를 일으킨다.
- 게임 서버는 CPU와 메모리를 주로 이용합니다만, 하드디스크를 많이 쓰는 데이터베이스에서는 좀 다른 현상이 발생한다. 데이터베이스에서는 디스크의 최대 처리 속도를 웃도는 디스크 I/O를 요구하는 명령(DB질의)이 쌓인다. 그러면서 램 사용량이 증가하다가 이 같은 문제가 발생한다.
8.3 논리적 단일 서버 분산
- 게임 서버 절차 분산
- 단일 서버 기준에서 과부하가 걸리는 지점을 분석해서 파악한다.
- 과부하가 걸리는 지점을 앞으로 소개할 여러 가지 분산 처리 방ㅅ식으로 분산한다.
- 서버의 과부하 지점을 찾았으면 이제 어떻게 분산할지 알아볼 차례이다. 분산 처리에는 크게 다음과 같은 분산 단위가 있다.
- 데이터 단위 분산
- 기능 단위 분산
- 그리고 게임 로직의 분산 처리 방식이 다음과 같이 나뉜다.
- 동기 분산 처리
- 비동기 분산 처리
- 데이터 복제 및 로컬처리
- 분산 처리 유형은 이들의 2X3 조합이다.
8.4 데이터 분산 VS 기능적 분산
- 데이터 분산이란 한 머신이 처리해야 하느는 잉터를 갖는 역할을 하는 여러 머신이 나뉘어서 처리를 하는 것이다.
- 기능적 분산은 이와 다르게 한 머신이 처리해야 하는 데이터의 처리 단계를 세부화해서 여러 머신이 나누어 처리된다.
- 분산 처리 원리는 게임 서버 뿐만 아니라 데이터베이스에서도 비슷하다. 이렇게 데이터베이스를 분산하는 것을 파티셔닝이라고 한다.
- 기능 단위 분산이라면 서로 다른 테이블을 서로 다른 서버에 배치하는 것을 의미한다.
8.5 조직처리의 분산방식들
- 조칙 처리의 분산 방식은 다음과 같이 크게 세 가지가 있다.
- 동기 분산 처리
- 비동기 분산 처리
- 데이터 복제 및 로컬 처리
- 어떤 조직이 있으면 되도록 서로 다른 머신 간에 분산 처리를 할 일이 없게 하는 것이 가장 좋다. 그러나 어쩔 수 없이 조직처리를 분산 처리해야 한다면 세 가지 방식 중 하나를 선택해야 한다.
- 각 방식은 일장일단이 있으며, 어느 한 방법이 절대적으로 우세하지 않다. 따라서 상황에 따라 이 중 한 방법을 선택해야 한다.
동기 분산 처리
- 동기 분산 처리에서는 어떤 연산을 다른 서버에 던져놓고 그 결과가 올 때까지 대기한다. 대기 할 뿐만 아니라 그 연산과 관계된 데이터가 도중에 변경되지 않게 잠금(lock)을 해야 한다.
비동기 분산 처리
- 비동기 분산 처리에서는 다음 일을 한다.
- 서버1은 어떤 연산 명령을 다른 서버2에 송신한다.
- 서버1은 서버2의 명령 처리 결과를 기다리지 않는다. 그리고 일방적으로 자기가 해야하는 다음 일을 시작한다.
- 이 처리 방식은 게임 개발 이외의 영역에도 많이 사용된다. MRI(Message Passing Interface)나 액터모델(actor model)등으로 부른다.
- 이 방식이 가진 가장 큰 장점은 동기 분산 처리와 달리 잠금으로 인한 병목이 없다는 것이다. 각 서버가 가진 성능을 최대로 활용할 수 있다. 그러나 단점도 있다. 모든 로직을 이 방식으로 구현하기 어렵거나 불가능하기 때문이다.
- 이 방식으로 프로그래밍 할 때는 요청에 대한 응답을 기다리는 과정이 없기 때문에 반환 값을 주고 받을 수 없다. 그 대신 다음 방식으로 구현해야 한다.
- 한쪽에서 저쪽으로 명령을 보낸다.
- 저쪽에서 이쪽으로 명령을 또 보낸다.
데이터 복제에 기반을 둔 로컬처리
- 앞서 살펴본 두 가지 분산처리 방식은 분산 처리에 관여되는 데이터들이 원본서버에만 있었다.
- 데이터 복제에 기반을 둔 로컬처리는 결과적으로 게임 플레이를 위한 로직 처리를 두 서버에 분산한다. 그러나 어떤 처리가 다른 서버와 맞물려 돌아가지 않고 각 서버가 알아서 처리한다. 한쪽 서버에서 데이터 변화가 발생하면 나머지 서버에도 전파된다. 즉 데이터 복제가 일어난다.
- 각 서버 프로세스는 데이터 원본이나 사본을 가진다.
- 이 전제하에 어떤 연산을 할 대는 서버 프로세스 안의 원본과 사본을 가지고 연산을 수행한다.
- 이렇게 분산처리를 하면, 분산 처리에서 발생하는 병목 현상이 없을 뿐만 아니라 여러 머신에 걸쳐 연산하지도 않으므로 응답속도도 분산하기 전과 같이 빠르다.
- 하지만 이 방식의 다른 문제가 있다. 사본 데이터는 원본 데이터와 간발의 차이로 생기는 스테일 데이터 문제(stale data problem)가 있을 수 있다. 이때 서버가 가진 데이터를 모두 신뢰할 경우 데이터 불일치로 잘못된 연산이 발생할 수 있는데, 이를 하이젠버그 라고 한다.
8.6 데이터 응집도
- 분산 처리가 가장 적게 일어나는 방법을 찾으면 좋은데, 그 중 한 방법은 응집도가 높은 데이터끼리는 가급전 분산 처리를 하지 말고, 응집도가 낮은 데이터에 대해 분산 처리를 하는 것이다.
- 응집도(coherency, locality)는 특정 영역 안에 얼마나 많은 데이터가 관련되고 뭉쳐있는지 의미한다. 다시 말해서 어떤 데이터가 있을 때 그 데이터와 자주 상관되는 다른 데이터가 얼마나 많은지 의미한다. 다.
- 데이터 간 응집도를 고려한다면, 좁은 지역에 많은 캐릭터가 있을 경우 서버 한 대가 이것을 모두 처리하게 하는것이 낫다. 캐릭터의 지리적 위치를 응집도를 기준으로 하여 가까운 거리에 있는 캐릭터끼리는 같은 서버에 두는 것이다.
8.7 기능적 분산 처리
- 기능적 분산 처리, 수직 분산 처리는 데이터 단위 분산 처리, 즉 수평 분산 처리를 할 수 없을 때 선택할 수 있는 대안이다.
- 기능적 분산 처리는 분산 처리를 할 수 있는 범위가 제한되어 있다. 또 기능적 분산 처리는 수평 분산 처리보다 분산 효율성이 떨어진다. 따라서 기능적 분산 처리는 최후 수단이다.
- 상황에 따라 기능적 분산 처리와 데이터 분산 처리를 혼용해도 된다.
8.8 고가용성
- 고가용성(High Availability, HA)이란 사용자가 항상 서비스를 이용할 수 있게 하는 것이다. 서버가 고장나거나 껐다 켜는 상황이 발생함에도 서버 역할을 계속하는 것을 말한다.
- 사용자 입장에서는 논리적 서버 한 대 처럼 보이지만, 이 서버의 정체는 컴퓨터 여러대로 구성된 서버 클러스터이다. 이 서버 중에서 몇몇 서버가 과부하에 걸리거나 오작동으로 정지하더라도, 나머지 서버가 계속해서 사용자 요청을 처리할 수 있다.
- 서버 클러스터에 있는 서버 중 하나가 죽었을 때, 다른 서버가 죽은 서버를 대신해서 일을 하고 그 동안 죽은 서버가 다시 살아나는 것을 장애 극복이라고 한다. 장애 극복을 위해 필요 이상의 서버를 두는 것을 이중화 혹은 다중화라고 한다.
- 고가용성을 위한 서버 구성 패턴에는 여러가지가 있다.
- 첫째, 액티브 - 패시브(active - passive) 패턴이다. 마스터 - 슬레이브(master - slave)패턴이라고도 한다. 이 패턴에는 서버가 두 대 있는데, 하나는 액티브 서버고 다른 하나는 패시브 서버이다.
- 두 대 중 첫 번째 서버(액티브)만 클라이언트 요청을 전담한다. 즉, 실제로 활성화된 서버이다. 두 번째 서버는 아무 일도 하지 않는다. 클라이언트 연결도 받지 않는다. 필요할 때 액티브 서버의 데이터를 지속적으로 복제 받는다. 전담하던 액티브 서버가 죽으면 패시브 서버는 액티브 서버로 승격된다. 그리고 클라이언트에서 들어오는 요청을 처리한다. 죽었던 액티브 서버가 다시 살아나면 이 서버는 패시브 서버가 된다.
- 이 방식의 단점은 패시브 서버는 그저 백업 역할만 할 뿐 다른 하는 일이 없다. 즉, 서버 자원의 낭비이다. 이 문제를 해결하려면 두 서버가 모두 액티브 서버 역할을 해야 한다. 이러한 패턴을 액티브 - 액티브 라고 한다.
- 액티브 - 액티브 패턴에서는 서버 두 대가 클라이언트측 요청을 분담하여 처리하고, 필요할 때면 두 서버는 각자 가진 데이터를 상대방에게 전송한다. 받은 쪽에서는 데이터를 복제한다. 즉 서버의 상태가 서로 동기화 된다.
- 하나가 죽으면 클라이언트 요청은 아직 살아있는 나머지 서버로 몰린다.이 패턴은 액티브 - 패시브 와 달리 서버의 모든 성능을 사용할 수 있다. 그러나 경우에 따라 데이터 스테일(data stale) 문제를 해결하려는 노력이 필요하다. 스테일 문제를 해결하기 위해 두 액티브 서버 사이에 메모리 저장소 역할을 담당하는 서버를 두면 된다.
- 이 방식에서 두 액티브 서버는 공유 메모리 서버로만 데이터 액세스를 한다. 각 서버는 데이터 원본을 가지고 있지 않으며, 데이터 액세스를 할 때는 공유 메모리 서버에 데이터 읽기/쓰기를 요청하여 그 응답을 받는 형태이다.
- 이 방식은 스테일 문제가 발생하지 않는다는 장점이 있지만 각 액티브 서버는 데이터에 접근을 할 때마다 기기간 통신이 발생한다는 단점도 있다. 한편 이 방식은 메모리 저장소 서버가 죽는 경우를 해결하지 못한다 정작 메모리 저장소 서버가 죽어버리면 고가용성을 지킬 수 없다. 이 문제를 해결하려면 메모리 저장소도 이중화 해야한다.
8.9 데이터베이스의 분산
- 게임 서버가 분산 처리되어 있다고 하더라도 데이터베이스를 분산처리 하지 않으면 결국 서비스 가용성은 떨어진다. 더 많은 사용자를 처리하고자 데이터베이스가 수평 확장을 할 때는 갖고 있는 레코드를 서로 다른 데이터베이스에 나누어 놓는다. 이를 파티셔닝이라고 한다.
728x90
'책 > 운영체제' 카테고리의 다른 글
운영체제 34. 분산시스템 (0) | 2024.04.02 |
---|---|
운영체제 33. 데이터 무결성과 보호 (0) | 2024.03.31 |
운영체제 32. 크래시 일관성 : FSCK와 저널링 (2) | 2024.03.31 |
운영체제 31. 지역성과 Fast File System (0) | 2024.03.30 |
운영체제 30. 파일 시스템 구현 (0) | 2024.03.29 |