04. 아키텍처
4.1 MySQL 엔진 아키텍처
- MySQL 엔진과 스토리지 엔진으로 나뉜다.
- MySQL 엔진
- 커넥션 핸들러, SQL 파서 및 전처리기, 옵티마이저
- 스토리지 엔진
- 실제 데이터를 디스크 스토리지에 저장하거나 디스크 스토리지로부터 데이터를 읽어오는 부분을 담당
- 성능 향상 : MyISAM - 키 캐시, InnoDB - InnoDB 버퍼풀
- 핸들러 API
- MySQL 엔진 → 스토리지 엔진으로 요청 시 사용되는 API
- MySQL 서버는 프로세스 기반이 아닌 스레드 기반으로 작동
- 포그라운드 스레드
- 전통적으로는 커넥션별로 스레드가 하나씩 할당된다.
- 엔터프라이즈 에디션에서는 스레드풀 사용 가능
- 커넥션이 종료되면 스레드 캐시로 되돌아간다.
- 데이터를 데이터 버퍼나 캐시로부터 가져온다. 버퍼나 캐시에 없는 경우에는 디스크의 데이터나 인덱스 파일로부터 데이터를 읽어와서 작업을 처리한다.
- (InnoDB) 쓰기 시에는 데이터 버퍼나 캐시까지만 처리하고, 버퍼로부터 디스크에 기록하는 작업은 백그라운드 스레드가 처리한다.
- 백그라운드 스레드
- 로그 스레드
- 로그를 디스크로 기록
- 쓰기 스레드
- 읽기 작업은 지연되면 안되지만, 쓰기 작업은 지연되어도 되기에 버퍼링해서 일괄 처리한다.
- 인서트 버퍼를 병합
- InnoDB 버퍼풀의 데이터를 디스크에 기록
- 메모리는 글로벌 메모리 영역과 로컬 메모리 영역으로 나뉜다.
- 글로벌 메모리 영역
- MySQL 서버가 시작되면서 운영체제로부터 할당된다.
- 종류
- 테이블 캐시
- InnoDB 버퍼 풀
- InnoDB 어댑티브 해시 인덱스
- 자주 사용되는 인덱스 검색 패턴을 모니터링하고 자동으로 해시 인덱스를 생성
- 자주 액세스되는 페이지의 일부분만 인덱싱
- InnoDB 리두 로그 버퍼
- 트랜잭션 변경사항을 임시로 저장
- 리두 로그 파일에 기록되기 전 변경 사항을 임시로 저장
- 데이터베이스 복구 시 사용
- 로컬 메모리 영역
- 세션 메모리 영역이라고도 표현하며 클라이언트 스레드별로 독립적으로 할당된다.
- 커넥션 버퍼
- 커넥션이 열려있는 동안 계속 할당된 상태
- Sort 버퍼
- 쿼리를 실행하는 순간에만 할당했다가 다시 해제
- Group by나 Order by를 수행할 때 사용
- 정렬할 데이터가 Sort 버퍼보다 크면 임시 파일을 사용하여 외부 정렬을 수행한다.
- 인텍스를 활용하여 정렬을 회피하는 것이 좋다.
- 실행 순서
- 레코드 버퍼에 수집
- 버퍼 내에서 퀵소트 알고리즘으로 정렬. 전체 과정이 메모리 내에서 수행됨
- 메모리보다 크다면 메모리 크기만큼만 불러와서 처리
- Join 버퍼
- 조인 작업을 최적화하기 위해 사용
- 각 조인 작업마다 할당
- 네트워크 버퍼
- MySQL 8.0부터는 플러그인 아키텍처를 대체하기 위해 컴포넌트 아키텍처가 지원된다.
- 쿼리 실행 구조
- 쿼리 파서
- 토큰 단위로 분리해 트리 형태의 구조로 만든다.
- 기본 문법 오류를 처리한다.
- 전처리기
- 파서 트리를 기반으로 쿼리 문장에 구조적인 문제를 체크한다.
- 각 객체와 매핑하여 실제 존재하지 않거나 권한상 사용할 수 없는 토큰을 걸러낸다.
- 옵티마이저
- 쿼리 문장을 어떻게 저렴하고 빠르게 처리할지 결정한다.
- 옵티마이저가 더 나은 선택을 할 수 있게 유도해야 한다.
- 실행 엔진은 만들어진 계획대로 각 핸들러에게 요청해서 받은 결과를 또 다른 핸들러 요청의 입력으로 연결하는 역할을 수행한다.
- 스레드 풀을 활용하여 실행하는 스레드 개수를 줄여서 사용 리소스를 줄이고 CPU의 프로세서 친화도를 높인다.
4.2 InnoDB 스토리지 엔진 아키텍처
4.2.1 프라이머리 키에 의한 클러스터링
- InnoDB의 모든 테이블은 프라이머리 키를 기준으로 클러스터링 되어 저장된다.
- 모든 세컨더리 인덱스는 레코드의 주소 대신 프라이머리 키의 값을 논리적인 주소로 사용한다.
4.2.2 외래 키 지원
- 외래 키에 대한 지원은 InnoDB 스토리지 엔진 레벨에서 지원하는 기능이다.
- 외래 키는 실 서비스에서는 생성하지 않는 경우도 자주 있다.
- 시스템 변수를 수정하여 현재 작업 중인 세션에서만 외래 키 체크 기능을 멈추게 할 수 있다.
4.2.3 MVCC
- MVCC의 가장 큰 목적은 잠금을 사용하지 않는 일관된 읽기를 제공하는 것이다.
- InnoDB는 언두 로그를 이용해 이 기능을 제공한다.
- InnoDB의 버퍼풀이 새로운 값으로 변경되면, 언두 로그에는 이전 값이 저장된다.
- 언두 로그 삭제
- Rollback 시 바로 삭제
- Commit 시 이 값을 필요로 하는 트랜잭션이 더는 없을 때 삭제
- REPEATABLE_READ, SERIALIZABLE
- 따라서 오랜시간 활성 상태인 트랜잭션이 있다면 언두 로그가 삭제되지 못한다.
- 격리 수준에 따라 조회 시 반환 값이 달라진다.
- READ_COMMITED
- 커밋 전에는 언두 로그의 값을 반환
- REPEATABLE_READ, SERIALIZABLE
- 세션 종료 전에는 언두 로그의 값을 반환
4.2.4 잠금 없는 일관된 읽기
- InnoDB 스토리지 엔진은 MVCC 기술을 이용해 잠금을 걸지 않고 읽기 작업을 수행한다.
- SERAILIZABLE이 아니라면 INSERT와 연결되지 않은 순수한 SELECT 작업은 다른 트랜잭션의 변경 작업과 관계없이 항상 잠금을 대기하지 않고 바로 실행된다.
4.2.5 자동 데드락 감지
- InnoDB 스토리지 엔진은 내부적으로 데드락을 체크하기 위해 잠금 대기 목록을 그래프 형태로 관리한다.
- 데드락 감지 스레드가 잠금 대기 그래프를 검사해 교착상태에 빠진 트랜잭션을 강제로 종료한다.
- 언두 로그 레코드가 더 적은 트랜잭션을 먼저 강제 종료 후 롤백한다.
- InnoDB 스토리지 엔진의 상위 레이어인 MySQL 엔진에서 관리되는 테이블 잠금은 볼 수 없다.
- 동시 처리 스레드가 매우 많은 경우 데드락 감지 스레드는 더 많은 CPU 자원을 소모할 수 있다.
- innodb_deadlock_detect를 Off로 설정하여 데드락 감지를 비활성화 할 수 있다.
- 이럴 경우, 데드락 처리를 위해 innodb_lock_wait_timeout을 기본값인 50초보다 훨씬 낮은 값으로 설정하여 잠금을 획득하지 못하는 경우 쿼리를 실패 처리하고 데드락이 발생하지 않도록 한다.
4.2.6 자동화된 장애 복구
디스크나 서버 하드웨어 이슈로 InnoDB 스토리지 엔진이 자동으로 복구하지 못하여 MySQL 서버를 기동하지 못하는 경우가 생길 수 있다. 이럴 경우 innodb_force_recovery 시스템 변수 설정을 통해 MySQL 서버를 시작해야 한다.
- InnoDB의 로그 파일이 손상되었다면 6으로 설정하고 MySQL 서버를 기동한다.
- InnoDB 테이블의 데이터 파일이 손상되었다면 1로 설정하고 MySQL 서버를 기동한다.
- 어떤 부분이 문제인지 알 수 없다면 1부터 6까지 변경하면서 재시작 해본다. 값이 커질수록 그만큼 심각한 상황이어서 데이터 손실 가능성이 커지고 복구 가능성은 작아진다.
서버가 기동되고 InnoDB 테이블이 인식된다면 mysqldump를 이용해 데이터를 가능한 만큼 백업한다. 만일 위와 같이 진행했음에도 MySQL 서버가 시작되지 않으면 백업과 바이너리 로그를 사용해 복구할 수 있다.
4.2.7 InnoDB 버퍼 풀
InnoDB 스토리지 엔진의 가장 핵심적인 부분으로 디스크의 데이터 파일이나 인덱스 정보를 메모리에 캐시해 두는 공간이다. 쓰기 작업의 버퍼 역할도 같이 한다.
버퍼 풀의 크기 설정
버퍼 풀의 크기는 운영체제와 각 클라이언트 스레드가 사용할 메모리 등을 고려하여 설정해야 한다. 클라이언트 세션이 사용하는 공간을 레코드 버퍼라고 하는데 전체 커넥션 개수와 각 커넥션에서 읽고 쓰는 테이블 개수에 따라서 결정된다. 따라서 InnoDB 버퍼 풀의 크기는 적절히 작은 값으로 설정해서 조금씩 상황에 따라 증가시키는 것이 좋다.
InnoDB 버퍼 풀은 Innodb_buffer_pool_size 시스템 변수로 크기를 설정할 수 있으며, 동적으로 버퍼풀의 크기를 확장할 수 있다. 또한 버퍼 풀의 크기를 늘리는 작업은 시스템 영향도가 크지 않지만 줄이는 작업은 시스템 영향도가 매우 크므로 가능하면 줄이는 작업은 하지 않도록 한다. 버퍼 풀은 내부적으로 128MB 청크 단위로 관리되므로 크기 변경의 단위로 사용한다.
Share article