on
데이터베이스를 지탱하는 기술 - 가용성과 데이터의 복제
데이터베이스를 지탱하는 기술 - 가용성과 데이터의 복제
언제든지 필요할 때 동작하는 서비스에서 장애에 대한 대책은 필수적이다. 데이터베이스에 대한 장애는 치명적이기 때문에 항상 장애에 대한 대비가 필요하다. 장애 대책에 대해 이야기하기 전에 먼저 어떤 장애 패턴이 있는지 살펴보겠다.
소프트웨어 장애
데이터베이스 프로그램의 폭주와 충돌처럼 소프트웨어 주변의 결함으로 인해 서비스를 제공할 수 없는 유형의 장애이다. 소프트웨어 장애는 그 소프트웨어의 품질이 장애 빈도와 심각성에 결정적인 영향을 미친다. 제품을 평가하는데 기능, 성능뿐만 아니라 품질도 이와 준하는 중요한 지표가 된다.
OS 장애
일반적으로 소프트웨어 장애로 분류되지만, 문제 해결에는 OS 및 하드웨어 주변의 고급 기술이 요구되기 때문에 RDBMS와 같은 미들웨어 장애와는 또 다른 어려움이 존재한다. 현실적으로 발생 빈도가 높은 문제로서는 장치 드라이버의 버그가 있다.
하드웨어 장애
OS 및 소프트웨어 주변의 장애는 결함을 제거해버리면 몇 년 단위에 걸쳐서 수십 대 이상의 서버를 장애로부터 막아낼 수 있다. 한편 하드웨어 장애의 경우는 그렇게까지는 힘들다. HDD와 같이 물리적으로 작동하는 것은 한 개당 수명이 2~3년 정도로 그다지 길지 않다. 그것이 1000대 규모에서 운용되고 있다면 하루 한 대는 어느 서버에선가 문제가 발생할 수 있다.
조작 실수
잘못해서 테이블을 지워버리는 식의 조작 실수에 의한 장애도 드물지 않다. 물론 실수를 하지 않는 것이 좋겠지만 많은 사람들이 참여할 수록 이런 문제가 일어날 확률이 높아진다.
디스크 이중화로 데이터 손실 방지하기
문제를 발생시키지 않는 것이 최선이겠지만, 현실적으로는 발생 확률을 제로로 만드는 것은 불가능하다. 확률을 줄이는 노력은 필요하나 서비스를 운영하는 관점에서 장애가 발생해도 서비스를 제공할 수 있도록 설계하는 것에 중점을 두어야 한다. 장애 대책 중에서도 특히 중요한 것이 데이터 손실 방지이다. 따라서 장애 중에서도 데이터 손실을 막기 위한 대책이 중요하다.
RAID
현재 데이터베이스의 데이터는 HDD에 저장되는 것이 보통이다. 하지만 HDD는 하드웨어 중 가장 고장률이 높은 부품이다. 그래서 하나의 서버에 여러 개의 HDD를 탑재하고 동일한 데이터를 두 개 이상의 HDD에 분산시키는 기술이 사용되고 있다. 이 기술을 RAID라고 한다.
서버 이중화에 의한 다운 타임 줄이기
장애의 원인이 되는 것은 디스크만이 아니다. CPU 고장, 커널 패닉, 데이터베이스 프로세스 장애도 존재한다. RAID 구성을 짜고 있다 해도 서버가 하나밖에 없으면 시스템은 즉시 다운된다. 따라서 서버는 두 대 이상이 필요하다. 두 대로 동일한 데이터를 가지고 있게 하면 크래쉬가 발생한 경우에도 남은 한 대를 사용해 서비스를 지속할 수 있다.
복제
웹서비스를 중심으로 현재 가장 널리 사용되고 있는 중복화 방식은 복제이다. 복제를 다른 서버에 생성하는 기술로 하나의 서버가 다운되더라도 나머지 서버에 동일한 데이터가 있기 때문에 서비스를 계속할 수 있다. 그렇다고 해도 복제에는 다양한 유형이 있어 성능을 희생해 데이터 무결성을 중시하는 것이 있는가 하면, 박대로 약간의 데이터 소실의 리스크를 수용하면서 성능을 추구하고 있는 것도 있다.
단방향 복제
- 단방향 비동기
단방향/비동기 복제는 마스터에서 갱신한 결과가 슬레이브에 비동기로 전파하는 유형의 복제이다. MySQL에서 표준으로 사용되는 복제 기능이다. 다음과 같은 순서로 동작하게 된다.
1. MySQL에서 마스터에서 실행한 갱신계의 SQL문이 바이너리 로그라는 전용 로그파일로 기록된다.
2. 이 로그 파일의 내용이 슬레이브로 전송되어 저장된다.
3. 슬레이브는 저장된 로그 파일을 순차적으로 실행함으로서 결과적으로 마스터와 슬레이브 상태가 일치하게 된다.
슬레이브에는 바이너리 로그 수신과 바이너리 로그 실행이라는 2단계로 구성되어 있다. 각각 별도의 스레드가 담당하고 있으며 전자는 I/O 스레드 후자는 SQL 스레드가 실행하고 있다. 이 모두가 비동기로 동작한다. 디스크에 비해 병목현상이 되는 일은 적기 때문에 수신은 거의 동기에 가까운 속도로 진행된다.
마스터가 다운되었을 경우 애플리케이션은 다운된 마스터 대신에 슬레이브를 새로운 마스터로 보고 업데이트를 하게 될 것이다. 이때 슬레이브가 바이너리 로그를 마지막까지 실행한 것을 확인 하고 나서 업데이트 트래픽을 옮길 필요가 있다. 마스터에서 생성한 바이너리 로그가 슬레이브에서는 마지막까지 수신되지 않은 상황이라면 슬레이브에서는 지금까지 업데이트 결과가 반영되지 않을 수도 있다.
- 단방향 비동기
슬레이브가 바이너리 로그를 수신하는 부분을 동기화 방식으로 동작하게 하는 방식으로 슬레이브로 전송하고 그 확인응답이 반환될 때까지 기다림으로써 업데이트가 슬레이브에 도착해있는 것을 보장하게 된다. 하지만 단점도 존재한다. 마스터-> 슬레이브 간의 바이너리 ㄹ로그 교환을 기다리는 동안만큼 응답 시간이 나빠지게 된다.
- 단방향 동기
MySQL에서는 기능으로서 구현되어 있지 않지만 슬레이브에 대한 업데이트 결과의 반영까지 마친 상태에서 처음으로 클라이언트에 응답을 반환하는 방식도 생각할 수 있다.
양방향 복제
지금까지 설명한 방식은 마스터 -> 슬레이브라는 단방향 제약이 있어 업데이트는 마스터에서만 할 수 있었다. 또한 대부분의 경우 슬레이브는 단일 스레드로 복제를 담당하게 되어 있으므로 갱신의 동시성이 없다. 최근의 멀티 코어 환경이 주목받고 있는 상황에서 그 혜택을 받을 수 없다는 것은 문제가 될 수 있다. 그래서 마스터를 두 개 이상 갖게 하고 각각의 마스터를 업데이트할 수 있도록 하는 멀티 마스터(양방향 복제) 구성도 생각해볼 수 있다.
하지만 양방향 복제는 기술적으로 어렵다. 문제는 업데이트가 서로 충돌하면 어떻게 하느냐라는 것이다. MySQL과 같이 비동기/준동기 복제를 기반으로 한 제품에서는 이런 배타 제어를 실현하는것이 어렵다.
이에 대해 데이터베이스 제품에 따라서 여러 서버에서 각각 업데이트를 할 수 있으며, 또한 그들이 자동으로 동기화 되는 구조를 가진 것이 이 있다. MySQL Cluster라는 제품이 이러한 양방향 복제의 구조를 가지고 있다. MySQL Cluster는 데이터 노드라고 하는 특수 서버에서 데이터를 가지고 있다. 중복성을 위해 두 개 이상의 데이터 노드에서 동일한 데이터를 서로 보관한다. 한 데이터 노드에 적용된 업데이트는 다른 쪽 데이터 노드에 동기적으로 반영된다.
MySQL Cluster에서는 동기 복제를 구현 하고 있어 A-> B로 업데이트하는 동안 동일한 ID를 B로 업데이트할 수 없게 되어 있다. 양방향/비동기 복제에서는 애플리케이션 로직을 배타 제어해야 할 필요가 있는 부분을 데이터베이스 측에서 배타 제어해 주는 것이 뛰어난 점이다.
장애로부터의 극복 방법
슬레이브 하드웨어 오류로 인해 해당 서버의 데이터를 소실했을 경우 장애가 발생해 손실되거나 불일치를 일으킨 슬레이브를 나중에 새로운 것으로 다른 서버에서 다시 만들어 복구시키는 방법이 있다. 다만 슬레이브를 처음부터 다시 만든다는 것은 적어도 다른 살아있는 슬레이브의 모든 데이터를 복사할 필요가 있다. 하지만 이것은 복구 시간이 문제가 될 수 있기 때문에 전체 데이터베이스를 복사해 복구하는 것이 아닌 장애 시점과 현시점과의 차이만을 복구하는 방법이 떠오르고 있다.
인위적인 실수에 대한 해결
실수로 필요한 테이블을 삭제했을 경우를 생각해보자. 복제와 같은 실시간 이중화 기술은 인위적 실수에 강하다고는 할 수 없다. 왜냐면 마스터에서 지워 버린 테이블을 슬레이브에 즉시 반영되어 슬레이브에서 같이 지워져 버리기 때문이다. 실수를 하지 않는 것이 좋지만 발생하는 일이 종종 있기에 이것을 대비한 것이 백업이다. 백업을 정기적으로 해두어 모든 DB 서버에서 데이터가 손실된 경우라 할지라도 백업 시점으로 복구할 수 있다.
백업을 해두었다면 백업 시점으로 복구할 수 있다. 하지만 백업은 데이터베이스를 복사하는 무거운 처리이므로 항상 실행할 수는 없다. 여기서 마지막 백업으로 부터 손실된 데이터는 복구할 수 없을까? MySQL에서는 업데이트 결과가 바이너리 로그라고 불리는 업데이트 로그에 기록되고 있기 때문에 마지막 백업 이후의 업데이트 로그가 성공적이라면 마지막 백업을 복구한 후에 그 이후의 업데이트 로그를 순차적으로 적용해 나가는 것으로 장애 이전 상태로 복구할 수 있다. 제대로 동작시키려면 업데이트 로그의 어느 위치가 마지막 백업 시점인가를 파악해야 한다. 이 방법은 여러 가지가 있지만 가장 흔한 방법으로 일시적으로 업데이트를 멈추고 백업을 하여 그 시점에서의 업데이트 로그의 위치를 특정하는 방법이 있다. 그러나 이 방법은 백업 중에 업데이트를 할 수 없다. 이 문제는 이후 설명할 트랜잭션 구조를 응용함으로써 업데이트를 멈추지 않고 백업을 하는 온라인 백업 기능을 사용할 수 있다.
from http://jinukix.tistory.com/109 by ccl(A) rewrite - 2021-11-19 10:00:59