경주장

4장 분산을 고려한 MySQL운 본문

기술서적/대규모서비스를지탱하는기술

4장 분산을 고려한 MySQL운

달리는치타 2021. 9. 12. 00:30

강의 11 - 인덱스를 올바르게 운용하기

세가지 포인트

  • OS 캐시 활용
  • 인덱스를 적절하게 설정하기
  • 확장을 전제로 한 설계

OS캐시 활용

. 전체 데이터 크기에 주의하라

-> 데이터량 < 물리 메모리 유지 : 전부 캐시에 올림

-> 메모리가 부족할 경우 증설

. 스키마 설계가 데이터 크기에 미치는 영향을 고려한다.

-> 최대한 낭비되는 Byte 가 없도록 설계

->설계의 복잡도와 속도의 TradeOff를 근거로 정규화 고려

 

인덱스의 중요성 - B트리

인덱스 = 색인

MySQL의 인덱스는 기본적으로 B+트리라는 데이터 구조다.

 

트리의 높이는 데이터 건수 n에 대해 반드시 log(n)이 되므로 검색의 계산량은 O(log(n))이다.

 

이분트리 vs B트리

  • 이분트리는 디스크가 읽는 Block의 단위에 관계없이 데이터 1개 단위로 검색을 수행하여 1개마다 디스크 탐색이 발생한다. (트리가 높다)
  • B트리의 노드당 데이터 수를 한번에 읽을 수 있는 Block의 Byte수 단위로 조정을 하여 최소한의 디스크 탐색으로 검색을 수행 할 수 있다.

 

인덱스의 효과

ex) 데이터 4,000만 건 테이블 에서의 탐색

- 인덱스 없음 -> 선형탐색            = O(n). 최대 4,000만번 탐색

- 인덱스 있음 -> B트리로 이분탐색 = O(n) 최대 25.25번 탐색

 

 

강의 12 MySQL의 분산 - 확장을 전제로 한 시스템 설계

MySQL의 분산은 어떻게 실현해갈 것인가?

 

 

MySQL에는 레플리케이션(replication)기능이 있다.

레플리케이션이란 Master를 정하고 뒤따르는 서버 Slave를 정해두면, 마스터에 쓴 내용을 슬레이브가 폴링(polling)해서 동일한 내용으로 자신을 갱신하는 기능이다. 슬레이브는 마스터의 레플리카(replica)가 되는 것이다.

 

마스터/슬레이브로 레플리케이션해서 서버를 여러 대 준비하게 되면

AP 서버에서는 로드밸런서를 경유하여 슬레이브로 Query를 한다. 이렇게 해서 쿼리를 여러 서버로 분산할 수 있다.

 

이때 AP 구현에서 Select등 참조 쿼리만 로드밸런서로 흘러가도록 한다.

갱신 쿼리는 마스터로 직접 던진다.

 

갱신 쿼리를 슬레이브로 던지게 되면 슬레이브와 마스터 간 내용을 동기화할 수 없다.

따라서 갱신은 반드시 마스터에서 이뤄지도록 한다.

 

이 부분은 O/R 매퍼에서 제어 할 수 있다.

 

 

마스터/슬레이브의 특징

- 참조계열(Select)은 확장하고 갱신계열(Update)은 확장하지 않는다.

 

마스터는 확장할 수 없다. 상당히 험난하다.

하지만 웹 어플리케이션에서는 대략 90%이상이 참조계열 쿼리이다. 쓰기는 상대적으로 훨씬 적다.

마스터가 병목이 되어 곤란한 상황이 발생하는 경우는 그렇게 많지 않다.

 

드물지만 마스터에 엄청난 쓰기작업이 발생하는 애플리케이션을 개발 해야 한다면

테이블을 분할하여 테이블 크기를 작게 해준다.

 

단순히 값을 저장하고 꺼내는 Logic만 필요하다면 Key-Value Store의 사용이 좋은 선택이다.

KVS는 오버헤드도 적고 압도적으로 빠르다. 

 

 

 

강의 13 MySQL의 스케일아웃과 파티셔닝

 

MySQL의 스케일아웃 전략

 

 

 

 

파티셔닝(테이블 분할)에 관한 보충

파티셔닝은 국소성을 활용해서 분산할 수 있으므로 캐시가 유효하고 그래서 파티셔닝은 표과적이다.

 

파티셔닝을 전제로 한 설계

어떤 태그를 포함하는 엔트리 목록을 뽑고자 하면 이런 데이터를 뽑을 때에는 JOIN 쿼리를 던져야한다.

JOIN 쿼리를 던지기 위해서는 Entry와 Tag를 분할 할 수 없다.

 

MySQL에는 기본적으로 서로 다른 서버에 있는 테이블을 JOIN하는 기능이 없다 

(* MySQL 5.1 이상에서는 FEDERATED 테이블을 이용하면 가능하다)

 

JOIN을 사용하지 않고 WHERE절을 적절히 사용하여 쿼리를 던지면 가능하다.

 

애플리케이션 개발자가 이 점에 주의하지 않고 열심히 JOIN쿼리를 던지면 나중에 곤란해진다.

 

E.g.

SELECT url
FROM entry
INNER JOIN bookmark on entry.eid=bookmark.eid
WHERE bookmark.uid=1234 limit 5;

를 

SELECT url
FROM entry
WHERE eid in

(
     SELECT eid
     FROM bookmark
     WHERE uid = 1234 limit 5;
)

로 분해 해서 사용 할 수 있다.

(다른 서버에 있으므로 각 SELECT문은 따로 호출 되어야 하지만 편의를 위해 위와 같이 작성함)

 

대충 JOIN QUERY를 막 던져도 서로 다른 서버에 있는 테이블의 JOIN을 호출 한 경우 자동으로 WHERE IN 구문으로 변경해서 동작하는 O/R 매퍼도 있다고 한다.

라이브러리 오버헤드가 부담스러워 직접 쓰는 경우도 있다고 한다.

 

파티셔닝의 상반관계

장점

  • 부하가 내려가고 국소성이 늘어나 캐시 효과가 높아진다.

단점

  • 운용이 복잡해진다. - 이 서버는 무슨 일을 하고 저 서버는 무슨 일을 하는지 머릿속으로 파악하기 어렵다.
  • 고장률이 높아진다.

예를들어 DB A를 분할하여 A'와 A''으로 나누었다고 하자.

분할에 따른 복잡도는 어마무시하게 증가한다.

 

서버는 4대 필요하기 때문 - 다중화

서비스를 24/365 가동 시키기 위해서/

고장에 대처하기 위해서/ 데이터 복사시에는 서비스를 정지해야 한다.