MySQL Engine Architecture
mysql 서버는 사람의 머리 역할을 담당하는 MySQL 엔진과 손발 역할을 하는 스토리지 엔진으로 구분할 수 있다.
그리고 손과 발의 역할을 담당하는 스토리지 엔진은 핸들러API를 만족하면 누구든지 스토리지 엔진을 구현하여 MySQL 서버에 추가해서 사용할 수 있다는 특징이 있다.
아래의 이미지는 MySQL Server의 전체 아키텍처를 나타낸다.
MySQL은 크게 MySQL 엔진과 스토리지 엔진으로 구분할 수 있다. 하나씩 알아보자.
MySQL 엔진
MySQL 엔진은 클라이언트로부터 접속 및 쿼리 요청을 처리하는 커넥션 핸들러와 SQL파서 및 전처리기, 쿼리의 최적화된 실행을 위한 옵티마이저가 중심을 이룬다. 또한 MySQL은 표준 SQL(Ansi) 문법을 지원하기 때문에 표준 문법에 따라 작성된 쿼리는 타 DBMS와 호환되어 실행될 수 있다는 특징이 있다.
스토리지 엔진
실제 데이터를 디스크 스토리지에 저장하거나 디스크 스토리지로부터 데이터를 읽어오는 부분은 스토리지 엔진이 전담하게 된다. MySQL 서버에서 MySQL 엔진은 하나지만, 스토리지 엔진은 여러 개를 동시에 사용할 수 있다는 특징이 있다.
아래의 예제와 같이 테이블이 사용할 스토리지 엔진을 지정하면 이후 해당 테이블의 모든 읽기 작업이나 변경 작업은 정의된 스토리지 엔진이 처리하게 된다.
CREATE TABLE tb_test (fd1 INT, fd2 INT) ENGINE = INNODB;
위의 쿼리 예제에서 tb_test는 InnoDB 스토리지 엔진을 사용하도록 정의했다. 이제 tb_test 테이블에서 CRUD 작업이 발생하면 InnoDB 스토리지 엔진이 처리를 담당하게 된다. 그리고 각 스토리지 엔진은 성능 향상을 위해 키 캐시나 InnoDB 버퍼 풀과 같은 기능을 내장하고있다.
핸들러 API
MySQL엔진의 쿼리 실행기에서 데이터를 쓰거나 읽어야 할 때는 각 스토리지 엔진에 쓰기 또는 읽기를 요청하는데, 이러한 요청을 핸들러 요청이라 표현한다. 그리고 여기서 사용되는 API를 핸들러 API라고 한다.
MySQL 스레딩 구조
MySQL 서버는 프로세스 기반이 아니라 스레드 기반으로 작동하며, 크게 포그라운드 스레드와 백그라운드 스레드로 구분할 수 있다.
MySQL은 위의 이미지와 같은 모델을 띄고있으며 만약 서버에서 실행중인 스레드 목록을 확인하고 싶다면 다음 쿼리를 입력하면 된다.
SELECT thread_id, name, type, processlist_user, processlist_host
FROM performance_schema, threads ORDER BY type, thread_id;
포그라운드 스레드
포그라운드 스레드는 최소한 MySQL 서버에 접속된 클라이언트 수만큼 존재하며, 주로 각 클라이언트가 요청하는 쿼리 문장을 처리하는 역할을 한다. 클라이언트 사용자가 작업을 마치고 커넥션을 종료하면 해당 커넥션을 담당하던 스레드는 다시 스레드 캐시로 되돌아가게 된다.
이 때 이미 스레드 캐시에 일정 개수 이상의 대기 중인 스레드가 있다면 스레드 캐시에 넣지않고 스레드를 종료시켜 일정 개수의 스레드만 스레드 캐시에 존재하게 된다.
참고로,
MySQL에서 사용자 스레드와 포그라운드 스레드는 똑같은 의미로 사용된다. 클라이언트가 MySQL 서버에 접속하게 되면 MySQL 서버는 그 클라이언트의 요청을 처리해 줄 스레드를 생성해 그 클라이언트에게 할당한다. 이 스레드는 DBMS의 앞단에서 사용자와 통신하기 때문에 포그라운드 스레드라 하며, 사용자가 요청한 작업을 처리하기 때문에 사용자 스레드라고도 한다.
백그라운드 스레드
InnoDB는 아래와 같은 작업들은 백그라운드로 처리된다.
- 인서트 버퍼를 병합하는 스레드
- 로그를 디스크로 기록하는 스레드
- InnoDB 버퍼 풀의 데이터를 디스크에 기록하는 스레드
- 데이터를 버퍼로 읽어오는 스레드
- 잠금이나 데드락을 모니터링하는 스레드
쿼리 실행 구조
MySQL의 구조를 간략하게 그림으로 표현하면 다음과 같이 기능 별로 나눠 볼 수 있다.
쿼리 파서
사용자 요청으로 들어온 쿼리 문장을 토큰으로 분리하여 트리 형태의 구조로 만들어 내는 작업을 의미한다. 쿼리 문장의 기본 문법 오류는 이 과정에서 발견되고 사용자에게 오류 메세지를 전달하게 된다.
전처리기
파서 과정에서 만들어진 파서 트리를 기반으로 쿼리 문장에 구조적인 문제점이 있는지 확인한다. 각 토큰을 테이블 이름이나 컬럼 이름, 또는 내장 함수와 같은 개체를매핑하여 해당 객체의 존재 여부와 객체의 접근 권한 등을 확인하는 과정을 이 단계에서 수행한다.
옵티마이저
옵티마이저란 사용자의 요청으로 들어온 쿼리 문장을 저렴한 비용으로 가장 빠르게 처리할지를 결정하는 역할을 하며, DBMS의 두뇌에 해당한다고 볼 수 있다.
실행엔진
옵티마이저가 두뇌라면, 실행 엔진과 핸들러는 손과 발에 비유할 수 있다. (ex: 회사로 비유하면 옵티마이저는 회사의 경영진, 실행 엔진은 중간 관리자, 핸들러는 각 업무의 실무자로 비유할 수 있다.) 실행 엔진이 하는 일을 더 쉽게 이해할 수 있게 간단하게 예를 들어보면 다음과 같다.
옵티마이저가 GROUP BY를 처리하기 위해 임시 테이블을 사용하기로 결정했다고 해보자.
- 실행 엔진이 핸들러에게 임시 테이블을 만들라고 요청
- 다시 실행 엔진은 where 절에 일치하는 레코드를 읽어오라고 핸들러에게 요청
- 읽어온 레코드들을 1번에서 준비한 임시 테이블로 저장하라고 다시 핸들러에게 요청
- 데이터가 준비된 임시 테이블에서 필요한 방식으로 데이터를 읽어오라고 핸들러에게 다시 요청
- 최종적으로 실행 엔진은 결과를 사용자나 다른 모듈로 넘긴다.
이렇듯 실행 엔진은 만들어진 계획대로 각 핸들러에게 요청해서 받은 결과를 또 다른 핸들러 요청의 입력으로 연결하는 역할을 수행한다.
핸들러(스토리지 엔진)
핸들러는 MySQL 서버의 가장 밑단에서 MySQL 실행엔진의 요청에 따라 데이터를 디스크로 저장하고 디스크로부터 읽어오는 역할을 담당한다. 핸들러는 결국 스토리지 엔진을 의미하며, MyISAM 테이블을 조작하는 경우에는 핸들러가 MyISAM 스토리지 엔진이 되고, InnoDB 테이블을 조작하는 경우에는 핸들러가 InnoDB 스토리지 엔진이 된다.
스레드풀
우선 MySQL 서버 엔프라이즈 에디션은 스레드 풀 기능을 제공하지만, 커뮤니티 에디션은 스레드 풀 기능을 지원하지 않는다.
이 스레드풀은 내부적으로 사용자의 요청을 처리하는 스레드 개수를 줄여서 동시 처리되는 요청이 많다하더라도 MySQL 서버의 CPU가 제한된 개수의 스레드 처리에만 집중할 수 있게 해서 서버의 자원 소모를 줄이는 것이 목적이다. 보통 스레드풀을 사용하면 눈에 띄는 성능 향상을 보여준다 생각하지만 오해이다. 만약 스케줄링 과정에서 CPU 시간을 제대로 확보하지 못하는 경우에는 쿼리 처리가 더 느려지는 사례도 발생한다.
물론 제한된 수의 스레드만으로 CPU가 처리하도록 적절히 유도한다면 CPU의 프로세서 친화도도 높이고 운영체제 입장에서는 불필요한 컨텍스트 스위치를 줄여서 오버헤드를 낮출 수 있다.
'Self-Development > Study' 카테고리의 다른 글
도메인과 도메인 모델(Domain Model) (0) | 2024.06.05 |
---|---|
실용적이고 안정감있는 테스트 코드 작성하기 (0) | 2023.09.27 |
2022년 정보 처리 기사 실기 - 모의고사 문제 및 오답 노트 정리 3 (0) | 2022.05.02 |
2022년 정보 처리 기사 실기 - 모의고사 문제 및 오답 노트 정리 2 (2) | 2022.04.29 |
2022년 정보 처리 기사 실기 - 모의고사 문제 및 오답 노트 정리 1 (0) | 2022.04.29 |
댓글