MySQL은 크게 MySQL 엔진과 MySQL 스토리지 엔진으로 이뤄져있습니다.
MySQL 엔진
MySQL엔진은 커넥션 핸들러와 파서, 옵티마이저, 캐시/버퍼로 이루어져있습니다.
커넥션 핸들러는 클라이언트와의 접속, 쿼리 요청을 담당하며, 파서는 쿼리의 문법적 오류를 담당, 옵티마이저 및 캐시는 쿼리의 최적화된 실행을 담당합니다.
쿼리파서
쿼리 문장을 최소 의미단위인 토큰단위로 나누고 이를 기반으로 파서 트리를 생성. 기본 문법오류 탐지.
전처리기
파서 트리를 기반으로 쿼리의 구조적 오류 탐지, 칼럼/테이블/내장함수같은 객체의 존재유무 판별, 권한 탐지 등 존재여부와 접근 권한을 탐색
옵티마이저
쿼리 문장을 가장 저렴한 비용으로 빠르게 실행하는 방법을 결정.
(옵티마이저는 만능이 아니고, 이것이 더 나은 선택을 하도록 유도하는것도 중요한 요소중 하나라고 합니다.)
쿼리 실행기 - Executer
핸들러 API를 통해 가져온 데이터를 임시 테이블, 캐시, 버퍼를 활용해 클라이언트 요청을 처리해 결과를 반환
핸들러 API
핸들러 요청에서는 캐시/버퍼 또는 SQL에서 실제 디스크에 파일 저장까지 실질적인 데이터의 읽기/쓰기 작업을 담당합니다.
핸들러 API란, MySQL 엔진이 읽기/쓰기 요청 시 스토리지 엔진에 데이터 저장을 요청하는 인터페이스입니다.
아래와 같이 요청하면 위 그림과 같이 핸들러 요청을 몇번 요청했는지 확인할 수 있습니다.
(로컬에서 부하테스트를 한적이 있어 커밋 횟수가 굉장히 많은걸 볼 수 있습니다.)
show global status like 'HADNLER%';
(만약 쿼리 캐시기능이 ON으로 설정되어있다면, 파싱,옵티마이징을 건너뛰고 바로 캐시 결과를 반환해주는 기능이 있었는데…없어졌습니다. MySQL8.0부터 확장성 이슈로 Deprecated)
그렇기에 뒤이어 설명드릴 모든 ‘캐시’에 관련된 내용은 스토리지엔진에서 동작하는 내용으로, 쿼리캐시와 관련이 없습니다.
참고글 https://dev.mysql.com/blog-archive/mysql-8-0-retiring-support-for-the-query-cache/
스토리지 엔진
스토리지 엔진의 경우 데이터 처리에 관한 MySQL의 핸들러 요청을 처리해주는 부분입니다. 운영체제의 System Call API를 통해 실제 디스크에 있는 데이터에 대한 읽기/쓰기를 처리하는 모듈입니다.
++) 스레드 풀
MySQL 엔터프라이즈 에디션(유료) 또는 Percona Server에서는 “스레드 풀” 기능을 지원합니다.
스레드 풀 기능은 다수의 스레드가 동시에 접근하는 상황을 가정합니다. 만약 100개 커넥션에 대한 요청을 처리해야한다고 가정해봅시다.
운영체제 입장에서는 100개의 스레드를 처리하기 위해 100개의 스레드를 Ready Queue에 넣고, Round Robin같은 스케쥴링 알고리즘을 통해 CPU를 할당합니다. 이는 반환시간(TurnAround Time)관점에서 굉장히 느린 방법이며, 캐시는 새로운 데이터를 가져오기 위해 잦은 캐시 미스를 발생시켜 성능을 저하시킬 것입니다.
이때문에 동시에 100개의 스레드를 처리하는것은 10개의 스레드를 처리하는것보다 10배 이상의 시간이 걸리게 됩니다.
스레드 풀은 실제 처리하는 스레드의 수를 관리해 Context Switch Overhead 또는 Cache Affinity(캐시 친화도)측면에서 성능을 개선시키는 방법입니다.
기본적으로 cpu 코어 개수만큼 스레드 그룹을 생성해 프로세서 친화도를 개선합니다.
포그라운드 스레드는 서버에서 처리하는 커넥션수만큼 존재하며 클라이언트에서 요청한 쿼리 문장을 처리하기 위해 존재합니다.
데이터 읽기 작업을 수행할 경우 데이터 버퍼/캐시에서 가져오며, 여기에 데이터가 존재하지 않는 경우 Handler API를 통해 디스크에서 데이터를 가져옵니다.
스레드 캐시
처리를 마치면 포그라운드 스레드 캐시에 저장되고, 같은 요청이 발생했을 때 캐싱을 통해 빠른 속도로 처리할 수 있습니다.
쓰기지연
InnoDB 엔진: 포그라운드 스레드는 MySQL엔진의 캐시/버퍼까지만 쓰기를 완료하면 캐시의 데이터를 스토리지 엔진으로 보내는것은 백그라운드 스레드의 역할입니다. 이를 “쓰기 지연”이라고 합니다.
백그라운드 스레드 :인서트버퍼, 로그기록, 잠금/데드락 감지, 버퍼 풀 기록(쓰기지연)
메모리 구조 역시 스레드 구조와 비슷하게 사용됩니다.
글로벌 메모리 영역 - 서버당 하나의 메모리 영역입니다. 모든 스레드가 참조할 수 있지만 일반적으로 백그라운드 스레드가 참조합니다.
( 필요에 따라 개수를 늘릴 수 있음 )
로컬메모리 영역 - 클라이언트 하나 당 독립된 공간을 사용하며, 포그라운드 스레드가 쿼리를 처리할 때 필요한 메모리 영역입니다.
일반적으로 커넥션이 시작될때 할당, 끝날 때 해제되며, 정렬/조인버퍼의 경우 쿼리를 실행하는 순간에만 할당 및 해제됩니다.
백은빈,이성욱 저 Real MySQL 8.0 ( http://www.yes24.com/Product/Goods/103415627 )