profile image

L o a d i n g . . .

728x90

Chapter 1에서는 MySQL의 아키텍처에 대해 살펴보겠습니다. MySQL의 기본 아키텍처는 다음과 같습니다.

 

MySQL 아키텍처

MySQL Connectors & Shell

MySQL connector는 애플리케이션이 MySQL과 연결되어 작동할 수 있도록 도와주는 소프트웨어입니다. API를 통해 MySQL의 기능(쿼리 실행, 데이터 조회, 데이터 수정 등)을 활용할 수 있습니다. MySQL connector는 프로그래밍 언어에 따라 구현이 다르며, 대표적인 예시로 Java의 경우 JDBC(Java Database Connectivity)를 사용합니다. MySQL shell은 CLI(Command Line Interface) 또는 스크립트를 사용하여 MySQL을 다룰 수 있는 또 다른 방법입니다.

 

MySQL Engine 

MySQL 엔진은 클라이언트의 커넥션을 관리하고 클라이언트로부터 요청된 쿼리를 처리하기 위한 여러 컴포넌트로 구성되어 있습니다. 각 컴포넌트에 대해 자세히 알아보겠습니다.

 

커넥션 핸들러(Connection Handler) 

MySQL을 사용하기 위해서는 먼저 클라이언트가 MySQL 프로세스와 커넥션을 생성해야 합니다. 커넥션 핸들러는 클라이언트의 커넥션 생성 요청을 처리하는 컴포넌트입니다. 일반적으로 MySQL은 하나의 커넥션을 하나의 스레드로 처리합니다. 그러나 이 방식은 커넥션이 많아지면 스레드 수도 증가하여 운영체제의 자원 고갈 문제가 발생할 수 있습니다. MySQL Enterprise는 이러한 문제를 해결하기 위해 스레드 풀 기능을 제공하기도 합니다. 

 

SQL, NoSQL Interface 

MySQL의 SQL 인터페이스는 DML, DDL, 스토어드 프로시저 등의 기능을 클라이언트가 사용할 수 있도록 제공합니다. MySQL이 SQL 기능만 제공할 것이라는 통상적인 인식과는 달리, MySQL 8.0 이상에서는 NoSQL 기능(Document store, JSON 타입 칼럼)을 사용할 수 있도록 NoSQL 인터페이스를 제공합니다. 

 

쿼리 처리 과정 

클라이언트의 쿼리 요청은 여러 컴포넌트가 담당하여 처리합니다. 각각의 컴포넌트가 어떤 역할을 하는지 살펴보겠습니다. 

  1. 쿼리 캐시(Query cache): 쿼리 캐시는 실행 결과를 메모리에 저장하여 동일한 쿼리 요청 시 테이블을 읽지 않고 메모리에 저장된 결과를 반환합니다. 이로 인해 동일한 쿼리 요청을 빠르게 처리할 수 있다는 장점이 있습니다. 그러나 쿼리와 관련된 데이터가 변경되면 캐시 된 결과를 삭제해야 하며, 이는 성능 저하를 초래할 수 있습니다. MySQL 8.0부터는 쿼리 캐시 기능이 제거되어 사실상 사용되지 않습니다.
  2. 쿼리 파서(Query parser): 쿼리 파서는 요청된 쿼리를 토큰으로 분리하여 쿼리의 문법이 올바른지 확인하고 트리 형태의 구조(parse tree)를 생성하는 작업을 수행합니다. 토큰은 MySQL이 인식할 수 있는 최소 단위의 어휘를 의미합니다. 
  3. 전처리기(Preprocessor): 전처리기는 쿼리 문장의 구조적 문제를 확인하기 위해 트리(parse tree)를 분석합니다. 쿼리에 사용된 토큰을 테이블 이름, 칼럼 이름, 내장 함수 등에 매핑하여 유효성을 확인하고 쿼리를 실행할 수 있는 적절한 권한이 있는지 확인합니다. 
  4. 쿼리 옵티마이저(Query Optimizer): 옵티마이저는 쿼리를 효율적으로 처리하기 위한 실행 계획(execution plan)을 결정하는 컴포넌트입니다. 옵티마이저의 종류로는 CBO(Cost Based Optimzer)와 RBO(Rule Based Optimizer) 두 가지 방식이 있습니다. CBO는 비용을 기준으로 실행 계획을 세우는 방식으로, 디스크 접근 횟수 등을 고려하여 최적의 실행 계획을 결정합니다. RBO는 규칙을 기준으로 실행 계획을 세우는 방식으로, 미리 정의된 규칙을 사용하여 최적의 실행 계획을 선택합니다. MySQL은 기본적으로 CBO를 사용하여 쿼리를 처리합니다. 
  5. 쿼리 실행 엔진(Query Execution Engine): 옵티마이저가 생성한 실행 계획을 참조하여 핸들러(스토리지 엔진)를 호출하여 쿼리를 처리합니다. 요청을 받은 핸들러는 디스크로부터 데이터를 조회하거나 쓰는 작업을 수행합니다.

 

Storage Engine 

스토리지 엔진(storage engine)은 MySQL Engine으로부터 전달받은 요청을 토대로 디스크에 데이터를 저장하거나 읽어오는 역할을 수행합니다. MySQL 스토리지 엔진 구조의 장점은 다양한 유형의 스토리지 엔진을 사용할 수 있다는 점입니다. InnoDB, MyISAM과 Memory 등 다양한 스토리지 엔진을 용도에 맞게 선택하여 사용이 가능합니다. 가장 대표적으로 사용되는 InnoDB 스토리지 엔진에 대해서 자세히 살펴보겠습니다. 

InnoDB 아키텍처

메모리 구조 

InnoDB는 크게 메모리 구조와 디스크 구조로 구분됩니다. 먼저 메모리에 위치한 InnoDB의 컴포넌트에 대해 살펴보겠습니다. 

Buffer Pool

버퍼 풀은 디스크에 저장된 데이터 파일이나 인덱스를 메모리에 로드하기 위한 공간입니다. 또한 INSERT, UPDATE, DELETE 등의 쓰기 작업을 즉시 디스크에 반영하지 않고, 버퍼 풀에 모아서 처리함으로써 디스크의 작업 횟수를 줄일 수 있습니다. 

버퍼 풀은 메모리를 페이지(page) 단위로 관리합니다. 버퍼 풀에 찾고자 하는 데이터가 없는 경우 디스크의 페이지를 읽어 버퍼 풀에 로드합니다. 메모리는 일반적으로 디스크에 비해 크기가 작기 때문에 사용되지 않는 데이터 페이지는 버퍼 풀에서 삭제해야 합니다. 이를 위해 버퍼 풀은 LRU(Least Recently Used) 알고리즘을 사용합니다. 

버퍼 풀 구조

버퍼 풀의 구조는 신 영역(new sublist)과 구 영역(old sublist)으로 나뉩니다. 신 영역은 버퍼 풀 5/8 크기로 할당되고, 구 영역은 3/8로 크기로 할당됩니다. InnoDB는 디스크로부터 페이지를 읽을 때 중간지점(midpoint insertion)에 페이지를 로드합니다. 구 영역에 위치한 페이지가 참조되면 해당 페이지는 신 영역의 헤드(head)로 이동합니다. 참조되지 않는 페이지들은 각 영역의 테일(tail)로 이동되어 결국 버퍼 풀에서 제거됩니다.

O_DIRECT 플래그는 파일을 읽고 쓸 때 운영체제의 캐싱을 최소화하기 위해 사용되는 플래그입니다. 기본적으로 운영체제는 파일을 읽고 쓸 때 캐싱을 통해 성능을 향상합니다. 그러나 InnoDB는 캐시기능을 할 수 있는 버퍼 풀을 가지고 있기 때문에 운영체제의 캐시와 함께 사용하면 중복 캐싱이 발생합니다. InnoDB의 innodb_flush_method 설정에서 O_DIRECT를 활용하면 운영체제의 캐싱을 최소화할 수 있습니다.

 

Change Buffer 

데이터의 INSERT 또는 UPDATE가 발생하면 데이터 파일뿐만 아니라 테이블에 포함된 인덱스도 업데이트되어야 합니다. 인덱스를 업데이트하기 위해서는 인덱스가 위치한 페이지를 버퍼 풀에 로드해야 합니다. 그러나 대상 테이블의 인덱스가 많은 경우 인덱스를 버퍼 풀에 로드하는 과정에서 대량의 랜덤 디스크 액세스가 발생할 수 있습니다(디스크에서 찾고자 하는 인덱스 페이지가 순차적으로 위치할 확률은 낮기 때문입니다). 만약 인덱스가 이미 버퍼 풀에 존재한다면 업데이트를 즉시 수행할 수 있지만, 그렇지 않은 경우 인덱스의 변경 사항은 체인지 버퍼(Change Buffer)라는 임시 공간에 저장됩니다. 이후 해당 인덱스가 위치한 페이지가 버퍼 풀에 로드되면, 백그라운드 스레드가 체인지 버퍼에 저장된 변경사항을 버퍼 풀에 로드된 페이지에 반영합니다.

체인지 버퍼는 디스크의 system tablespace에도 존재합니다. 이는 MySQL 서버가 종료될 때 버퍼링된 인덱스의 변경사항을 디스크에 저장하기 위해 사용됩니다. 

체인지 버퍼는 프라이머리 인덱스(Primary Index)가 아닌 세컨더리 인덱스(Secondary Index)의 변경사항만 저장합니다.  

 

Adaptive Hash Index 

일반적으로 데이터 조회는 B-Tree 인덱스를 탐색하는 방식으로 수행됩니다. 메모리에 위치한 B-Tree를 순회하는 속도는 빠르지만, 어댑티브 해시 인덱스(Adaptive Hash Index)를 사용하면 한 단계 더 빠르게 데이터를 조회할 수 있습니다. 자주 접근되는 데이터의 위치를 어댑티브 해시 인덱스에 저장하여 B-Tree를 순회하지 않고도 해당 데이터가 위치한 페이지에 바로 접근할 수 있어 데이터 조회 속도가 향상됩니다. 어댑티브 해시 인덱스에 저장되는 키와 값은 다음과 같습니다.

 

(B-Tree 인덱스의 고유 식별 번호, 인덱스 키의 접두사) : (인덱스 키 값이 저장된 데이터 페이지의 주소) 

 

Log Buffer

로그 버퍼(Log Buffer)를 이해하기 위해서는 먼저 리두 로그(Redo Log)를 이해해야 합니다. 변경이 발생할 때마다 데이터 파일을 업데이트하는 경우 디스크의 랜덤 액세스를 유발하여 성능이 좋지 않습니다. 따라서 MySQL은 버퍼 풀의 변경을 바로 데이터 파일에 반영하지 않고 리두 로그에 저장합니다. MySQL이 비정상적으로 종료되는 경우, MySQL이 재기동되는 시점에 리두 로그를 참조하여 반영되지 않은 변경사항을 반영합니다. 로그 버퍼는 리두 로그와 같은 로그를 디스크로 플러시 하기 전에 임시로 메모리에 변경사항을 버퍼링 하는 공간입니다. 

왜 로그는 데이터 파일에 비해 쓰기 비용이 낮을까요? 로그는 디스크의 연속적인 공간에 쓰기 작업을 수행하는 반면, 데이터 파일의 쓰기 작업은 파일의 랜덤 한 위치에 접근해서 쓰기 작업을 수행합니다. 이로 인해 일반적으로 로그는 데이터 파일에 비해 쓰기 비용이 낮다고 간주됩니다.
메모리에 저장된 데이터를 디스크에 저장하는 과정을 플러쉬(flush)라고 합니다. MySQL 문서는 버퍼 풀의 변경사항을 디스크에 기록하는 과정을 플러쉬라는 용어를 통해 표현합니다.

 

디스크 구조 

Tablespace

테이블스페이스(Tablespace)는 용도가 유사한 데이터 파일을 모아두는 논리적인 공간입니다. 테이블 스페이스에 대해서 간략히 살펴보겠습니다. 

  • System Tablespace: 체인지 버퍼(Change Buffer)를 위한 저장 공간입니다. 이외에도 File-Per-Table Tablespaces에 저장되지 않은 테이블 또는 인덱스 데이터가 저장됩니다. 
  • File-Per-Table Tablespaces: 하나의 테이블과 관련된 모든 정보(데이터, 인덱스)를 하나의 데이터 파일에 저장하는 공간입니다. 테이블의 이름이 "example"이라면 해당 테이블을 저장한 파일 이름은 "example.ibd"가 됩니다. 
  • General Tablespaces: "CREATE TABLESPACE" 명령어를 통해 생성할 수 있는 공간입니다. 
  • Undo Tablespaces: 언두 로그(Undo Log)를 저장하는 공간입니다. 
  • Temporary Tablespaces: 임시로 생성된 테이블을 저장하는 공간입니다. 

 

Undo Log 

InnoDB는 트랜잭션과 격리 수준을 보장하기 위해 이전 버전의 데이터를 언두 로그에 저장합니다. 트랜잭션이 롤백되면 변경된 데이터를 이전 버전으로 복구해야 하는데, 이때 언두 로그에 저장된 데이터를 사용합니다. 또한, InnoDB는 서로 다른 트랜잭션을 격리하는 기능도 제공합니다. 격리 수준에 따라 트랜잭션이 조회할 수 있는 데이터의 버전이 결정되는데 이때 언두 로그를 활용합니다.

 

Redo Log 

로그 버퍼의 설명을 참조하세요. 

 

Double Write Buffer 

버퍼 풀의 변경된 페이지를 데이터 파일에 바로 저장하는 과정에서 MySQL 프로세스가 비정상적으로 종료되면, 페이지의 일부가 저장되지 않는 톤 페이지 현상이 발생할 수 있습니다. InnoDB는 이러한 현상을 방지하기 위해 Double Write Buffer를 사용하여 버퍼 풀의 변경사항을 먼저 반영하고, 그다음에 데이터 파일에 변경사항을 반영합니다.

I/O 디바이스 설정과 하드웨어 문제로 인해 톤 페이지 현상이 발생할 수 있습니다. 만약 디바이스 설정으로 인해 InnoDB 페이지 사이즈(기본 16KB) 보다 작은 단위로 데이터가 쓰이다가 중간에 하드웨어 문제가 발생하면 톤 페이지 현상이 발생할 수 있습니다.
728x90
복사했습니다!