개발관련 도서/대규모 서비스를 지탱하는 기술

3-2. 분산을 고려한 MySQL 운용

prden 2021. 5. 5. 08:49

앞서 설명한 바와 같이 분산을 할 때는 데이터 규모에 맞게 탑재 메모리를 조정하고, 메모리 증설로도 대응할 수 없을 경우 분산해야 한다. 앞으로는 DB레이어에서 MySQL운용, 스케일 아웃 전략에 대해 공부해보자 (OS 캐시, 인덱스를 적절하게 설정하기, 확장을 전제로 한 시스템 설계 순으로 공부한다. 

 

1. OS 캐시 활용

전체 데이터 크기에 주의해서 데이터량 < 물리 메모리를 유지해야 한다. 메모리가 부족할 경우에 증설을 하고 스키마 설계가 데이터 크기에 미치는 영향을 고려해야 한다. 그냥 아무 생각 없이 create table로 스키마 설정하면 안 돼. 최소 정수 int형은 32비트 = 4바이트, 문자열은 8비트=1바이트 같은 기본적인 수치는 기억하자.

 

2. 인덱스의 중요성

MySQL의 인덱스는 기본적으로 B+트리라는 데이터 구조를 가진다. B+트리는 B트리에서 파생된 데이터 구조로 B트리는 트리를 구성하는 각 노드가 여러 개의 자식을 가질 수 있는 다분 트리다. 또한 데이터 삽입이나 삭제를 반복한 경우에도 트리의 형태에 치우침이 생기지 않는 평형 트리이기도 하다. 

 4000만 건의 테이블에서 인덱스 없는 선형 탐색을 할 경우 최대 4000만 번을 탐색해야 하지만 인덱스 있는 B트리로 이분 탐색을 할 경우 로그 4000만으로 최대 25.25번만 탐색하면 된다. 여기서 인덱스의 중요성을 볼 수 있다. 또한, MySQL에서의 인덱스는 복수의 칼럼이 인덱스를 가지고 있다 해도, 양쪽 모두 인덱스를 태우고자 할 경우 쌍으로 한 복합 인덱스를 설정해주어야 한다. 그렇지 않으면 두 칼럼 중 하나의 인덱스만 가지고 탐색을 하게 된다. 

3. MySQL의 레플리케이션 기능

src=대규모서비스를 지탱하는 기술 p103

1) 그림에 대한 설명

 레플리케이션이란 마스터를 정하고 마스터를 뒤따르는 서버인 슬레이브를 정해두어서 마스터에 쓴 내용을 슬레이브가 폴링 해서 동일한 내용으로 자신을 갱신하는 것이다. 즉, 슬레이브는 마스터의 레플리카가 되는 것이다. 이렇게 동일한 내용의 서버를 여러 대 마련할 수 있는 것이다. 쿼리를 로드밸런서를 통해 여러 서버로 분산시켜 처리한다. 이때 select 등 참조 쿼리만 로드밸런서로 흘러가도록 해야 하고 갱신 쿼리는 마스터로 직접 던져야 한다. 갱신 쿼리를 슬레이브로 던지면 슬레이브와 마스터 간 내용을 동기화할 수 없기 때문이다. 

 또한, 이와 같은 로드밸런서를 사용하지 않고 애플리케이션 측에서 분배까지 제어하거나 MySQL Proxy와 같은 것을 사용해도 된다. 

 

2) 마스터/슬레이브의 특징

 참조 계열 쿼리(select)는 확장을 위해 서버를 늘리면 되는데, 서버를 늘린다고 해도 대수만 늘리면 되는 것이 아니라 메모리에 맞추는 것이 중요하다. 마스터는 확장하기 어려워 갱신 계열 쿼리가 늘어나면 상당히 험난해진다. 웹 애플리케이션에서는 약 90% 이상이 참조 계열 쿼리여서 쓰기는 상대적으로 적다. 

 

3) 갱신/쓰기계열을 확장하고자 할 때

마스터 테이블이 과부하가 걸리지 않도록 하기 위해 테이블을 분할해서 테이블 크기를 작게 해 주면 된다. 그러면 분할로 인한 쓰기 작업이 분산된다. 아니면 처음부터 RDBMS를 사용하지 않고 key-value 스토어 방식으로 처리할 수 있다. 

4. 파티셔닝

파티셔닝(테이블 분할)이란 테이블 A와 테이블 B를 서로 다른 서버에 놓아서 분산하는 방법이다. (부하가 내려가고 국소성이 늘어나 캐시 효과가 높아짐)

 

1) 파티셔닝을 전제로 한 설계 : join을 아무 생각 없이 쓰지 말자

 A테이블과 B테이블을 JOIN 해서 사용하려면, 이 두 테이블은 앞으로도 서버 분할하지 않을 것이라고 확신할 수 있을 때 JOIN쿼리를 사용해야 한다. MySQL에는 기본적으로 서로 다른 서버에 있는 테이블을 JOIN 하는 기능이 없기 때문이다. 테이블 데이터 크기를 볼 때 반드시 분할해야 한다는 것을 알고 있으면 JOIN을 쓰지 말아야 한다. 

 

2) JOIN의 배제 : Where in을 이용하자 

3) 파티셔닝의 나쁜 점 : 

 a. 운용이 복잡해진다 : 앞서 설명한 바와 같이 A테이블과 B테이블을 서로 다른 서버로 나누어야 하는 것처럼 각기 서버가 무슨 일을 하는지 머릿속으로 파악하고 있어야 장애 복구 시간을 단축할 수 있다. 그러나 서버가 많아질수록 각기 다른 서버의 역할을 한눈에 파악하기 어렵기 때문에 파티셔닝을 할수록 운용이 복잡해지는 것이다.  

 b. 고장률이 높아진다:

 서버 대수가 늘어나는 만큼 고장확률이 높아진다. 

다중화에 필요한 서버대수는 통상적으로 4대이다. 그 이유는 아래와 같다. 

src=대규모 서비스를 지탱하는 기술 p114

만약 3대가 1세트(마스터1대, 슬레이브 2대) 일 때 슬레이브가 1대 고장 나면 다른 쪽 슬레이브가 동작하고 있으니 다행이라고 생각할 수 있다. 그러나 새로운 DB서버를 준비해 복사를 하려면 남아있던 슬레이브를 중지하지 않고서는 복사를 할 수없게 된다. 따라서 복구를 위해서 서비스를 중지해야 하는 상황이 발생한다. 반면, 슬레이브가 3대가 있다면 1대가 고장 나더라도 남은 2 대중 1대는 유지하고 새로운 서버로 데이터를 복사해서 고장 난 슬레이브 이외의 슬레이브 3대를 정리해서 복구할 수 있다. 따라서 다중화를 완벽하게 고려하려면 4대를 1세트로 생각할 필요가 있는 것이다.