CS/Real MySQL 8.0 요약

4장 - MySQL 엔진 아키텍처

Junuuu 2023. 7. 24. 00:01

개요

MySQL 아키텍처를 정리해 보고, 더 잘 이해해보고자 합니다.

 

 

MySQL 아키텍처 구성도

https://dev.mysql.com/doc/refman/8.0/en/pluggable-storage-overview.html

MySQL 서버는 MySQL 엔진과 스토리지 엔진으로 구성되어 있습니다.

MySQL 엔진은 사람의 머리 역할을 담당하고, 스토리지 엔진은 손과 발의 역할을 담당합니다.

 

MySQL 엔진에는 Connection Handler, SQL Interface, SQL Parser, Optimizer, Caches & Bufferes가 있습니다.

스토리지 엔진에는 InnoDB, MyIsam, Memory 등이 존재합니다.

File System와 Files & Logs 부분은 운영체제 & 하드웨어에 부분에 해당합니다.

 

 

MySQL Connectors

다양한 언어들의 애플리케이션이 MySQL 데이터베이스에 연결하고 상호작용할 수 있도록 하는 라이브러리입니다. 

인터페이스를 제공하여 개발자가 쿼리 실행, 연결 관리 등 다양한 데이터베이스 작업을 수행할 수 있도록 도와줍니다.

저수준의 데이터베이스 연결 세부 사항을 처리할 필요 없이 애플리케이션에서 MySQL의 강력한 기능을 활용할 수 있습니다.

다운로드 가능한 Connecter들 목록

예를 들어 Spring에서 JPA를 통해 쿼리를 생성하고 연결하는 과정에서 사용되는 JDBC Driver가 위에 존재하는 것을 볼 수 있습니다.

 

MySQL Shell

사용자는 Shell을 통해 MySQL에 접속하고 명령을 수행할 수 있습니다.

 

커넥션 핸들러 (핸들러 API)

https://idea-sketch.tistory.com/42

공식문서에서는 커넥션 핸들러를 보여주는 그림이 없어 전반적인 MySQL 아키텍처를 나타내는 그림을 한번 더 가져왔습니다.

커넥션 핸들러는 MySQL 엔진이 데이터를 쓰거나 읽어야 할 때 각 스토리지 엔진에 쓰기 또는 읽기를 요청합니다.

이를 핸들러 요청이라 합니다.

 

 

MySQL 엔진

쿼리 파서, 전처리기, 옵티마이저 등으로 구성되어 있으며 옵티마이저가 MySQL의 두뇌를 담당합니다.

쿼리 파서는 기본적인 SQL 문장 오류를 체크하며 토큰으로 나누어 Parse Tree로 구성합니다.

Parse Tree를 기반으로 토큰에 존재하는 테이블, 칼럼이 실제로 존재하는 값인지 체크합니다.

옵티마이저는 내장된 우선순위에 따라 실행 계획을 수립합니다. 

다양한 방법들을 구상하고 실행 계획의 비용이 낮은 방법을 수행할 수 있습니다.

 

Query Parser

 

 

스토리지 엔진(Storage Engines)

실제 데이터를 디스크 스토리지에 저장하거나 불러오는 MySQL의 손발을 담당합니다.

MySQL 엔진의 핸들러 API를 통해 호출되며 대표적으로 InnoDB, MyISAM 스토리지 엔진이 존재합니다.

MySQL 엔진은 하나지만 스토리지 엔진은 여러 개를 동시에 사용할 수 있습니다.

스토리지 엔진은 플러그인 형태로 제공되어, 핸들러 API를 직접 구현하여 나만의 스토리지 엔진을 추가할 수 있습니다.

MySQL8.0부터는 플러그인 형태가 아닌 컴포넌트형태로 지원됩니다.

 

예를 들어 다음과 같이 테이블이 사용할 스토리지 엔진을 지정할 수 있습니다.

CREATE TABLE test_table (fd1 INT, fd2 INT) ENGINE=INNODB;

이후 CRUD 작업이 발생하면 InnoDB 스토리지 엔진이 해당 처리를 담당하고, 각 스토리지 엔진은 성능향상을 위해 버퍼풀(InnoDB), 키 캐시(MyISAM)와 같은 기능을 내장하고 있습니다.

 

나만의 스토리지 엔진을 구현할 때는 데이터 읽기/쓰기 작업만 구현하면 됩니다.

그렇다면 MyISAM 이나 InnoDB 스토리지 엔진 가운데 뭘 사용하던 별 차이가 없다고 생각할 수 있습니다.

하지만 데이터 읽기/쓰기 작업이 얼마나 달라질 수 있는지는 책 나머지 부분에서 설명합니다.

 

여기서 중요한 내용은 하나의 쿼리 작업은 여러 하위 작업으로 나뉘고 각 하위 작업이 MySQL 엔진 영역에서 처리되는지 스토리지 엔진 영역에서 처리되는지 구분할 줄 알아야 합니다.

 

운영체제 하드웨어 부분

실제 데이터와 로그 데이터를 저장하는 부분입니다.

Redo Log, Undo Log 등등 다양한 정보들을 저장합니다.

 

 

MySQL 스레딩 구조

MySQL 서버는 프로세스 기반이 아니라 스레드 기반으로 작동하며 크게 포그라운드 스레드와 백그라운드 스레드로 구분할 수 있습니다.

포그라운드 스레드가 실제 사용자의 요청을 처리하며 백그라운드 스레드는 MySQL 서버의 설정에 따라 가변적으로 달라집니다.

 

포그라운드 스레드는 MySQL 서버에 접속한 클라이언트의 개수만큼 존재합니다.

사용자가 작업을 마치고 커넥션을 종료하면 해당 커넥션을 담당하는 스레드는 다시 스레드 캐시로 돌아가고, 항상 일정 개수의 스레드가 유지됩니다.

데이터 버퍼나 캐시를 먼저 읽어서 데이터를 가져오고자 하며, 없는 경우 디스크의 데이터나 인덱스 파일로부터 데이터를 읽어 작업을 처리합니다.

InnoDB 테이블의 경우에는 데이터 버퍼나 캐시까지만 포그라운드 스레드가 처리하고, 나머지 버퍼로부터 디스크까지 기록하는 작업은 백그라운드 스레드가 처리합니다.

 

여기서 한가지 궁금증이 생깁니다.

일반적으로 사용자에게 데이터를 반환할 때까지 Blocking 되어 있을 것 같은데 포그라운드 스레드 대신 백그라운드 스레드가 왜 사용될까?

 

백그라운드 쓰레드는 단순하게 데이터를 읽어와 버퍼에 기록하는 것 이외에도 다양한 작업을 수행합니다.

  • 인서트 버퍼를 병합
  • 로그를 디스크로 기록
  • InnoDB 버퍼 풀의 데이터를 디스크에 기록
  • 데이터를 버퍼로 읽어오기
  • 잠금이나 데드락을 모니터링

즉, 백그라운드 쓰레드가 여러 개가 동작하며 모든 작업이 수행되면 포그라운드 스레드가 사용자에게 데이터를 보여주는 것을 기대할 수 있습니다.

 

메모리 할당 및 사용 구조

글로벌 메모리 영역과 로컬 메모리 영역으로 구분할 수 있습니다.

 

글로벌 메모리 영역은 MySQL 서버가 시작되면서 운영체제로부터 할당되며 모든 쓰레드에 공유됩니다.

로컬 메모리 영역은 세션 메모리 영역이라고도 표현되며, 클라이언트 쓰레드가 쿼리를 처리하는 데 사용하는 메모리 영역입니다.

각 클라이언트 쓰레드별로 독립적으로 할당되며 절대 공유되어 사용되지 않습니다.

 

쿼리 실행 구조

SQL 요청이 들어오게 되면 단계별로 역할을 수행합니다.

 

쿼리 파서 - 쿼리문장을 토크나이징 (기본 문법 에러 탐지)

전처리기 - 구조적인 문제점 확인 (테이블, 칼럼 이름 존재 여부 확인 및 접근 권한 확인)

옵티마이저 - 가장 저렴한 비용으로 빠르게 처리하도록 결정 (경영진의 역할)

실행엔진 - 핸들러에게 여러 요청을 담당 (중간 관리자의 역할)

핸들러 = 스토리지 엔진 - 실행엔진의 요청에 따라 데이터를 디스크에 저장하고 읽어오는 담당 (각 업무의 실무자의 역할)

 

쿼리 캐시

SQL 실행 결과를 메모리에 캐시하고 동일한 SQL 쿼리가 실행되면 즉시 결과를 반환하여 빠른 성능을 보입니다.

하지만 연관된 데이터가 변경되면 관련된 내용들을 모두 삭제해야 했고, 성능 저하와 버그를 유발했습니다.

MySQL 8.0으로 올라오면서 쿼리 캐시는 완전히 제거되었습니다.

 

스레드풀

스레드 풀은 내부적으로 사용자의 요청을 처리하는 스레드의 개수를 한정하여 서버의 자원 소모를 예측할 수 있도록 합니다.

스레드풀을 도입하거나 스레드가 많다고 무조건 좋은 것은 아니며 오히려 불필요한 콘텍스트 스위칭으로 성능이 더 안 좋아질 수 있습니다.

일반적으로는 스레드 그룹의 개수는 CPU 코어의 개수와 맞추는 것이 좋습니다.

 

트랜잭션 지원 메타데이터

메타데이터는  생성 및 변경 작업에 트랜잭션이 지원되지 않아 테이블의 생성 및 변경 도중 MySQL 서버가 비정상적으로 종료되면 데이터가 일관되지 않은 문제가 있었고, 이를 데이터베이스나 테이블이 깨졌다라고 표현했습니다.

 

MySQL 8.0 버전부터는 이런 문제점을 해결하기 위해 트랜잭션 기반의 InnoDB의 테이블에 저장하도록 개선되었습니다.

이 정보는 mysql.ibd라는 테이블스페이스에 저장됩니다.

 

 

참고자료

https://dev.mysql.com/doc/refman/8.0/en/pluggable-storage-overview.html

 

MySQL :: MySQL 8.0 Reference Manual :: 16.11 Overview of MySQL Storage Engine Architecture

16.11 Overview of MySQL Storage Engine Architecture The MySQL pluggable storage engine architecture enables a database professional to select a specialized storage engine for a particular application need while being completely shielded from the need to m

dev.mysql.com

RealMySQL