[Real MySQL] MySQL 엔진 아키텍처 요약

sa46lll·2023년 11월 26일
0

Real-MySQL

목록 보기
5/9

해당 글은 백은빈, 이성욱 님의 'Real MySQL 8.0 (1권)'을 학습하며 정리한 글입니다.

시작하기 전에...
Real MySQL은 횟수로만 보자면, 2번째 읽는 중이다.
해당 블로그 시리즈에 이미 몇 개의 게시물이 올라와있는데.. 아무것도 몰라서 머릿속에서 받아들이지 못했을 시절이라🤯 이번에는 어느정도 정리한 후에 올리는 과정이다.
이론적인 부분은 오히려 첫번째 정리했던 게시물이 많이 담고있다. 시작하겠다.

MySQL 서버에 대해 알아보자.
MySQL 서버는 우리가 흔히 말하는 MySQL과 동일하다.

1. MySQL 구조

MySQL 서버는 다음과 같은 구성 요소로 구성되어 있다.

  • MySQL 엔진
  • 스토리지 엔진

MySQL 엔진

MySQL 엔진은 요청된 SQL 문장을 분석하거나 최적화하는 등 DBMS의 두뇌에 해당하는 처리를 수행한다.
클라이언트로부터의 접속 및 쿼리 요청을 처리하는 커넥션 핸들러와 SQL 파서 및 전처리기, 쿼리의 최적화된 실행을 위한 옵티마이저가 중심을 이룬다.

스토리지 엔진

스토리지 엔진은 실제 데이터를 디스크 스토리지에 저장하거나 디스크 스토리지로부터 데이터를 읽어오는 부분을 전담한다. MySQL에서는 InnoDB, MyISAM, Memory 등의 스토리지 엔진을 기본으로 제공한다.

MySQL 엔진과 스토리지 엔진의 관계

MySQL 서버에서 MySQL 엔진은 하나지만, 스토리지 엔진은 여러 개를 동시에 사용할 수 있다.
다음과 같이 데이블이 사용할 스토리지 엔진을 지정하면 이후 모든 읽기나 변경 작업을 해당 스토리지 엔진이 처리한다.

-> 테이블을 생성할 때 InnoDB 스토리지 엔진을 사용하도록 지정하였다. 따라서 이 테이블에 대한 모든 읽기나 변경 작업은 InnoDB 스토리지 엔진이 처리한다.
만약 스토리지 엔진을 지정하지 않는다면, MySQL 서버의 설정에 따라 기본 스토리지 엔진이 사용된다.
MySQL 버전에 따라 기본 스토리지 엔진이 다르고, MySQL 5.5 버전부터는 InnoDB 스토리지 엔진이 디폴트이기 때문에 대부분의 경우 InnoDB 스토리지 엔진이 사용될 것이다.

핸들러 API

MySQL 엔진과 스토리지 엔진은 핸들러 API를 통해 연결되어 있다.
MySQL 엔진의 쿼리 실행기에서 데이터를 쓰거나 읽는 경우, 각 스토리지 엔진에 요청을 하게되는데, 이것을 핸들러 요청이라 하고, 이 때 사용되는 API를 핸들러 API라고 한다.
이 핸들러 API를 통해 얼마나 많은 데이터 작업이 있었는지는 다음 명령어로 확인할 수 있다.

2. MySQL 스레딩 구조

MySQL 서버는 스레드 기반으로 작동한다. 크게 포그라운드와 백그라운드 스레드로 구분할 수 있다.
실행 중인 스레드의 목록은 performance_schema DB > threads 테이블을 통해 확인할 수 있다.

대부분의 스레드가 백그라운드 스레드이고, 3개의 포그라운드 스레드가 존재한다.
이 중 'thread/sql/main' 스레드만 실제 사용자의 요청을 처리하는 포그라운드 스레드이다.

포그라운드 스레드 (클라이언트 스레드)

포그라운드 스레드는 각 사용자의 요청을 처리하는 스레드이다.
이 스레드는 DBMS 앞단에서 클라이언트와 통신하기 때문에 포그라운드 스레드라고 하며, 사용자 요청을 처리하기 때문에 사용자 스레드라고도 한다.

사용자의 요청이 있을 때마다 생성되고, 요청이 완료되면 종료되어 스레드 캐시로 되돌아간다. 스레드 캐시는 일정 개수의 스레드만 존재하게 하고, 초과하는 스레드는 종료시키는 역할을 한다.
스레드 캐시의 크기는 thread_cache_size 시스템 변수로 설정할 수 있다.

백그라운드 스레드

백그라운드 스레드는 MySQL 서버의 내부 작업을 처리하는 스레드이다. MyISAM은 별로 사용하지 않지만, InnoDB에서는 많이 사용된다.

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

이 역할 중에, 가장 중요한 것은 로그 스레드와 데이터를 디스크로 내려쓰는 스레드이다.

중간 정리하자면..

사용자의 요청을 처리하는 중 읽기 작업은 절대 지연되면 안되고, 쓰기 작업은 지연되어 처리될 수 있다.
따라서, 일반적인 상용 DBMS에서는 대부분 쓰기 작업을 백그라운드 스레드를 통해 버퍼링으로 일괄 처리하는 기능을 탑재하고 있고, InnoDB 또한 이러한 방식으로 되어있다.

하지만 MyISAM은 쓰기 작업까지 포그라운드 스레드에서 처리한다. 이러한 이유로 데이터가 삽입/변경/삭제 되는 경우에 디스크의 데이터 파일로 완전히 저장될 때까지 기다리지 않아도 된다.

3. 메모리 할당 및 사용 구조

MySQL 서버가 시작되면서 OS로부터 할당된다. 각 OS의 메모리 할당 방식은 상당히 복잡하며, MySQL 서버가 사용하는 메모리 양을 측정하는 것 또한 쉽지 않다.
단순하게 MySQL 시스템 변수로 설정해 둔 만큼 OS로부터 메모리를 할당받는다고 생각해도 된다.

MySQL에서 사용되는 메모리 공간은 크게 다음과 같이 구분한다.

  • 글로벌 메모리 영역
  • 로컬 메모리 영역

글로벌 메모리 영역

클라이언트 수와 상관없이 기본으로 하나의 메모리 공간만 할당된다. (필요에 따라 더 할당받을 수도 있긴 하다) 이 영역은 모든 스레드에 의해 공유된다.

대표적인 글로벌 메모리 영역이다.

  • 테이블 캐시
  • InnoDB 버퍼 풀
  • InnoDB 어댑티브 해시 인덱스
  • InnoDB 리두 로그 버퍼

로컬 메모리 영역

MySQL 서버의 포그라운드 스레드가 쿼리를 처리할 때 사용하는 메모리 영역이다.
포그라운드 스레드(클라이언트 스레드)가 사용하는 메모리 공간이라고 해서 클라이언트 메모리 영역이라고도 한다.

로컬 메모리는 각 포그라운드 스레드 별로 독립적으로 할당되고, 절대 공유되지 않는다.
글로벌 메모리 영역 크기는 주의해서 설정하지만, 로컬 메모리 영역은 크게 신경쓰지 않는데, 최악의 경우 메모리 부족으로 멈출 수도 있으므로 적절한 메모리 공간을 설정하자.

대표적인 로컬 메모리 영역이다.

  • 정렬 버퍼
  • 조인 버퍼
  • 바이너리 로그 캐시
  • 네트워크 버퍼

4. 플러그인 스토리지 엔진 모델

MySQL의 구조는 대표적으로 플러그인 모델을 사용한다. 플러그인 모델을 사용하면 기존의 기능을 커스텀하게 확장할 수 있거나, 손쉽게 업그레이드할 수 있다.
스토리지 엔진을 포함하여 인증이나 전문 검색 파서, 쿼리 재작성, 비밀번호 검증, 커넥션 제어 등 모두 플러그인 형태로 지원한다.

다만, 단점이 몇가지 있다.
플러그인끼리는 통신할 수 없고, 플러그인은 MySQL 서버의 변수나 함수를 직접 호출하기 때문에 안전하지 않다. 또한, 플러그인은 상호 의존 관계를 설정할 수 없어서 초기화가 어렵다.

5. 컴포넌트 아키텍처

MySQL 8.0부터 기존의 플러그인 아키텍처를 대체하기 위한 컴포넌트 아키텍처가 지원된다.
대표적으로 비밀번호 검증 기능이 컴포넌트로 개선되었다. 추후 알아보겠다.

6. 쿼리 실행 구조

MySQL 서버는 쿼리를 실행할 때, 다음과 같은 순서로 처리한다.

  1. 쿼리 파서: 사용자 요청의 쿼리 문장을 토큰을 분리, 트리 형태의 구조로 만들어낸다.
  2. 전처리기: 파서 과정의 트리를 기반으로 쿼리 문장에 구조적인 문제점이 있는지 확인한다.
  3. 옵티마이저: 쿼리 문장을 저렴하고 빠르게 처리할지 결정하는 역할 (DBMS의 두뇌 역랑) -> 이 과정이 아주 중요하고, 영향 범위도 넓다.
  4. 실행 엔진: 옵티마이저가 계획한대로 각 핸들러에게 쿼리를 실행하라고 요청하고, 받은 결과를 또 다른 핸들러에 요청한다.
  5. 핸들러: MySQL 서버의 가장 밑단에서 실행 엔든의 요청에 따라 데이터를 디스크로 저장하고, 디스크로부터 읽어 온다.

7. 복제

MySQL 서버에서 복제는 매루 중요한 역할을 담당한다. 그래서 추후 별도로 다루겠다.

8. 쿼리 캐시

빠른 응답을 필요로 하는 웹 기반의 프로그램에서 SQL 실행 결과를 캐시하는 기능이다. 동일 SQL 쿼리가 실행되면 즉시 결과를 반환하기에 매우 빠른 성능을 보인다.

하지만 결론적으로 말하자면, MySQL 8.0부터 완전히 제거된 기능이다.
테이블의 데이터가 변경되면 캐시의 변경된 테이블과 관련된 모든 데이터를 삭제해야 했다. 이는 심각한 동시 처리 성능 저하를 유발했고, 많은 버그의 원인이 되기도 했다.

9. 스레드 풀

스레드 풀은 MySQL 서버의 CPU가 제한된 개수의 스레드 처리에 집중할 수 있게 한다. 서버의 자원 소모를 줄이는 것이 목적이다.
이는 눈에 띄는 성능 향상을 보이진 않지만, OS 입장에서 불필요한 컨텍스트 스위치를 줄일 수 있다.
MySQL 커뮤니티 에디션은 제공하지 않고, 서버 엔터프라이즈 에디션에서 제공하고 있다.

10. 트랜잭션 지원 메타데이터

기존 파일 기반의 메타데이터의 일관성을 개선하기 위해 MySQL 8.0부터 지원되는 기능이다.
InnoDB에 테이블의 메타데이터를 저장하는 시스템 테이블을 만들었다.

MySQL 8.0부터 데잍 딕셔너리와 시스템 테이블이 모두 트랜잭션 기반의 InnoDB에 저장되도록 개선되면서,
중간에 MySQL 서버가 비정상적으로 종료해도 스키마 변경이 완전히 성공 또는 실패로 정리된다. 트랜잭션의 일관성을 보장하게 된 것이다.

profile
비열한 커비

0개의 댓글