본문 바로가기
  • Where there is a will there is a way.
개발

MySQL 아키텍처

by 소확행개발자 2020. 12. 1.

MySQL 아키텍처

개발하면서 table 설계를 하다보면 

 

CREATE TABLE 'tableName' ( ~ ) ENGINE = InnoDB 라는 DDL 을 보게 될 것이다. 

 

예전에는 아무 생각이 없었지만 MySQL 책을 읽다보니 InnoDB 가 무엇인지에 대해 알게 되었다.

 

InnoDB 가 무엇인지에 대한 설명을 하려면 MySQL 에 대한 아키텍처 이야기를 해야한다.

 

플러그 스토리지 엔진 모델

MySQL 이라고 불리는 RDBMS 는 2가지의 처리 영역을 가지고 있다.

 

MySQL 엔진 ( or custom 파서 )

우리가 JDBC 등으로 보내는 쿼리를 파싱하고 옵티마징하고 실행하는 MySQL 엔진의 처리영역

 

스토리지 엔진 ( InnoDB or MyISM or 서드파티 스토리지 엔진 )

데이터의 읽기 / 쓰기 영역

 

위에 2가지 처리영역 모두 서드파티 또는 커스텀을 할 수 있는데, MySQL 이 오픈소스이고 플러그인 엔진 모델을 사용하고 있기 때문이다.

 

engine 끼리 서로 데이터를 전달할때는 handler 개념이 사용된다. 

 

복제 ( replication )

데이터베이스의 데이터가 갈수록 대용량화돼 가는 것을 생각하면 확장성은 DBMS 에서 아주 중요한 요소다. MySQL은 확장성을 위한 다양한 기술을 제공하는데 그중에서 가장 일반적인 방법이 복제이다.

 

일반적으로 MySQL 서버의 복제에서는 마스터는 반드시 1개이며 슬레이브는 1개 이상으로 구성될 수 있다.

처음에는 MySQL 서버에서 마스터와 슬레이브가 프로그램적으로 구분이 되어있는 줄 알았지만 아니다. 기술적으로는 MySQL 의 바이너리 로그가 활성화되면 어떤 MySQL 서버든 마스터가 될 수 있다. 애플리케이션의 입장에서 본다면 마스터 장비는 주로 데이터가 생성 및 변경, 삭제되는 주체라고 볼 수 있다.

 반대로 슬레이브는 데이터 (바이너리 로그) 를 받아 올 마스터 장비의 정보를 가지고 있는 경우 슬레이브가 된다. 

 

master

데이터의 조작이나 스키마를 변경하는 조작등 모든 쿼리 동작 -> 바이너리 로그에 기록 -> 슬레이브 서버에서 변경 내역을 요청 -> 마스터 장비는 바이너리 로그를 읽어 슬레이브로 넘긴다. 

 

slave

슬레이브 서버는 릴레이 로그를 가지고 있다. 일반적으로 슬레이브 서버는 읽기 전용으로 설정한다. ( 슬레이브와 마스터를 동일한 데이터로 유지하기 위해서 : 만약 읽기전용으로 안하고 수정하면 데이터의 정확성이 깨진다. ) 

릴레이 로그의 역할 ? -> 마스터 서버에 접속해 변경내역을 요청하고, 받아 온 내역을 릴레이 로그에 기록한다. -> 슬레이브 서버가 릴레이 로그의 변경내역을 재실행 함으로써 슬레이브의 데이터를 마스터와 동일한 상태로 유지한다.

주의 

- 슬레이브 서버용 장비는 마스터와 동일한 사양이 적합하다.

- 복제가 불필요할 경우에는 바이너리 로그 중지 ( 해당 로그를 축척하는데 더 많은 에너지를 사용하는 경우가 발생할 수 있음 )

 

InnoDB 스토리지 엔진

InnoDB 는 MySQL 에서 사용할 수 있는 스토리지 엔진 중에서 거의 유일하게 레코드 기반의 잠금을 제공하고 있다. 때문에 동시성 처리가 가능하고 또한 안정적이며 성능이 뛰어나다.

 

InnoDB 엔진 구조는 

메모리영역 | CPU 연산 영역 | 디스크 스토리지 영역 3가지로 나뉜다.

 

InnoDB 특징

  • 프라이머리 키에 의한 클러스터링
  • 잠금이 필요없는 일관된 읽기 ( SERIALIZABLE 은 제외 )
  • 외래 키 지원 
    • 외래 키에대한 지원은 InnoDB 스토리지 엔진 레벨에서 지원하는 기능 다른 엔진은 사용 불가
  • 자동 데드락 감지
  • 자동화된 장애 복구
  • 오라클의 아키텍처 적용

InnoDB 버퍼풀

InnoDB 개념에서 가장 핵심적인 부분이다. 

디스크의 데이터 파일이나 인덱스 정보를 메모리에 캐시해 두는 공간이다.

쓰기 작업을 지연시켜 일괄 작업우로 처리할 수 있게 해주는 버퍼 역할도 같이 한다.

일반적으로 전체 장착된 물리 메모리의 50~80% 수준에서 버퍼 풀의 메모리 크기를 결정한다.

 

Undo 로그

update 나 delete 와 같은 문장으로 데이터를 변경했을 때 변경되기 전의 데이터를 보관하는 곳

트랜잭션의 롤백 대비용

트랜잭션의 격리 수준을 유지하면서 높은 동시성을 제공

 

인서트 버퍼

 

인덱스와 잠금

InnoDB 는 레코드를 잠그는 것이 아니라 인덱스를 잠그는 방식으로 처리한다. 즉, 변경해야 할 레코드를 찾기 위해 검색한 인덱스의 레코드를 모두 잠가야 한다.

따라서 주의해야할 점이 만약 인덱스가 걸려있지 않은 컬럼을 업데이트 할때 락이 걸린다면 테이블을 풀 스캔하면서 UPDATE 작업을 하는데, 이 과정에서 테이블에 있는 30여 만 건의 모든 레코드를 잠그게 된다. 이것이 MYSQL 의 방식이다. 

 

인덱스 구조

DBMS 에서 인덱스는 데이터의 저장 성능을 희생하고 그 대신 데이터의 읽기 속도를 높이는 기능이다.

( 저장성능을 희생한다는말은 인덱스는 찾기를 빠르게 하기 위해서 선택된 값으로 정렬을 시켜야 하고, 정렬되어있기 때문에 데이터의 구조를 변경하면 재정렬해야하기 때문에 그만큼 성능이 떨어지게 된다. )

 

데이터 저장방식별로 구분하는 것은 사실 상당히 많은 분류가 가능하겠지만 대표적으로 B-Tree 인덱스와 Hash 인덱스로 구분가능하다. 그리고 최근에 Fractal-Tree 인덱스와 같은 알고리즘도 도입됐다. 

 

인덱스 선택도

인덱스의 선택도는 유니크한 값의 수를 의미한다.

인덱스는 선택도가 높을수록 검색 대상이 줄어들기 때문에 그만큼 빠르게 처리된다.

즉 인덱스를 걸때, 컬럼의 유니크한 값이 많을 수록 유리하다는 이야기이다.

 

B-Tree 인덱스를 통한 데이터 읽기

어떤 경우에 인덱스를 사용하도록 유도할지, 또는 사용하지 못하게 할지 판단하려면 MySQL이 어떻게 인덱스를 이용해서 실제 레코드를 읽어 내는지 알고 있어야 할 것이다.

 읽는 방법 3가지

  • 인덱스 레인지 스캔
    • 레인지 스캔은 하나 하나 I/O 를 찾기때문에 비용이 많이들고 따라서 레코드 범위가 20~25% 넘어가면 인덱스 통한 읽기가 테이블 데이터를 직접 읽는것보다 비효율적이다.
  • 인덱스 풀 스캔
    • 인덱스의 첫 번째 칼럼이 아닌 경우 인덱스 풀 스캔 방식이 사용된다. 예를 들어 인덱스는 칼럼의 순서대로 만들어져있지만 쿼리의 조건절은 B 칼럼이나 C 칼럼으로 검색하는 경우다. 
    • 물론 컬럼의 수가 적기 때문에 전체 컬럼을 읽는것보다는 효율적이지만 인덱스 개념에서는 효율적이지 못하다. 
  • 루스 인덱스 스캔

댓글