요약
- MySQL 서버의 구성 요소를 알게 되었다.
- MySQL 엔진의 역할을 알게 되었다.
- 스토리지 엔진의 역할을 알게 되었다.
- MySQL 엔진과 스토리지 엔진의 상호작용 방법을 알게 되었다.
- MySQL 의 스레딩 구조와 메모리 할당 방식을 알게 되었다.
발췌
- MySQL 서버는 프로세스 기반이 아니라 스레드 기반으로 작동한다.
메모
MySQL 서버는 다음과 같이 나눌 수 있다.
- MySQL 엔진 → 사람의 머리 역할
- 스토리지 엔진 → 손발 역할
- 핸들러 API 를 만족하는 커스텀 스토리지 엔진 구현하여 사용 가능
- ex) InnoDB 스토리지 엔진, MyISAM 스토리지 엔진
MySQL 엔진 아키텍처
- MySQL 서버는 다른 DBMS 에 비해 구조가 독특함.
- 독특한 구조로 인해 다른 DBMS 가 가질 수 없는 엄청난 혜택을 누릴 수 있음.
- 대신, 다른 DBMS 에서 겪지 않는 문제를 겪을 수 있음.
MySQL 전체 구조
- MySQL 은 일반 상용 RDBMS 와 같이 대부분의 프로그래밍 언어로부터 접근 방법을 모두 지원함.
- MySQL 고유의 C API, JDBC, ODBC, .NET 표준 드라이버를 제공함.
- 위 드라이버를 이용해 C/C++, PHP, 자바, 펄, 파이썬, 루비, .NET, 코볼과 같은 언어로 MySQL 서버에 쿼리를 사용할 수 있게 지원함.
MySQL 엔진
- 아래 4가지가 MySQL 엔진을 이룬다.
- 클라이언트로부터의 접속 & 쿼리 요청을 처리하는 커넥션 핸들러
- SQL 파서 (요청된 SQL 문장을 분석)
- 전처리기
- 쿼리 최적화 실행을 위한 옵티마이저
- 표준 SQL (ANSI SQL) 문법을 지원하므로 표준 문법에 따라 작성된 쿼리는 타 DBMS 와 호환되어 실행될 수 있음.
- MySQL 서버에서 MySQL 엔진은 하나임.
스토리지 엔진
- 실제 데이터를 디스크 스토리지에 저장
- 디스크 스토리지로부터 데이터를 읽어옴.
- MySQL 서버에서 스토리지 엔진은 여러개를 동시에 사용할 수 있음.
- 성능 향상을 위해 키 캐시(MyISAM 스토리지 엔진)나 InnoDB 버퍼 풀(InnoDB 스토리지 엔진) 과 같은 기능을 내장하고 있다.
mysql> CREATE TABLE test_table (fd1 INT, fd2 INT) ENGINE=INNODB;
- 위와 같이 특정 테이블에 INNODB 와 같이 사용할 스토리지 엔진을 지정할 수 있다.
- 지정된 스토리지 엔진이 해당 테이블의 모든 읽기 작업이나 변경 작업을 처리한다.
- test_table 이 InnoDB 스토리지 엔진을 사용한다.
- test_table 에 대해 INSERT, UPDATE, DELETE, SELECT, … 등의 작업을 InnoDB 스토리지 엔진이 처리한다.
핸들러 API
- MySQL 엔진의 쿼리 실행기에서 데이터를 쓰거나 읽어야 할 때, 각 스토리지 엔진에 쓰기 또는 읽기를 요청한다.
- 이 요청을
핸들러(Handler) 요청
이라고 한다. - 여기서 사용하는 API 를
핸들러 API
라고 한다.
- 이 요청을
- InnoDB 스토리지 엔진 또한 이 핸들러 API 를 이용해 MySQL 엔진과 데이터를 주고 받는다.
- 핸들러 API 를 통해 얼마나 많은 데이터(레코드) 작업이 있었는지
SHOW GLOBAL STATUS LIKE 'Handler&'
명령으로 확인할 수 있다.
MySQL 스레딩 구조
- MySQL 서버는 프로세스 기반이 아닌 스레드 기반으로 작동한다.
포그라운드(Foreground) 스레드
와백그라운드(Background) 스레드
로 구분할 수 있다.- MySQL 서버에서 실행 중인 스레드의 목록은
performance_schema
데이터베이스의threads
테이블에서 확인할 수 있다. - 백그라운드 스레드의 개수는 MySQL 서버의 설정 내용에 따라 가변적일 수 있다.
- 동일한 이름의 스레드가 2개 이상씩 보이는 것은 MySQL 서버의 설정 내용에 의해 여러 스레드가 동일 작업을 병렬로 처리하는 경우다.
지금 얘기한 스레드는 MySQL 서버가 전통적으로 가지고 있던 스레드 모델임.
MySQL 커뮤니티 에디션에서 사용되는 모델임.
MySQL 엔터프라이즈 에디션과, Percona MySQL 서버에서는 위 스레드 모델 뿐만 아니라
스레드 풀(Thread Pool) 모델을 사용할 수 있다.
전통적인 스레드 모델은 커넥션 별로 포그라운드 스레드가 하나씩 생성된다.
스레드 풀에서는 포그라운드 스레드와 커넥션이 1:1 관계가 아님. 하나의 스레드가 여러 개의 커넥션 요청을 전담하게 된다.
포그라운드 스레드(클라이언트 스레드)
- 최소한 MySQL 서버에 접속된 클라이언트의 수만큼 존재한다.
- 각 클라이언트 사용자가 요청하는 쿼리 문장을 처리한다.
- 클라이언트 사용자 작업이 마치고 커넥션이 종료되면 해당 작업을 맡던 스레드는 다시
스레드 캐시(Thread cache)
로 되돌아간다.- 이미 스레드 캐시에 일정 개수 이상의 대기중인 스레드가 있으면 스레드 캐시에 넣지 않고 스레드를 종료 시켜 일정 개수의 스레드만 스레드 캐시에 존재하게 한다.
- 스레드 캐시에 유지할 수 있는 최대 스레드 개수는
thread_cache_size
시스템 변수로 설정한다.
- 데이터를 MySQL 의 데이터 버퍼나 캐시로 부터 가져온다.
- 버퍼나 캐시에 없는 경우에는 직접 디스크의 데이터나 인덱스 파일로 부터 데이터를 읽고 작업을 처리한다.
- MyISAM 테이블은 디스크 쓰기 작업까지 포그라운드 스레드가 처리한다.
- MyISAM 도 지연된 쓰기가 있지만 일반적인 방식은 아니다.
- InnoDB 테이블은 데이터 버퍼나 캐시까지만 포그라운드 스레드가 처리하고 나머지 버퍼로부터 디스크까지 기록하는 작업은 백그라운드 스레드가 처리한다.
사용자 스레드와 포그라운드 스레드는 같은 의미이다.
포그라운드 스레드는 DBMS 의 앞단에서 사용자와 통신하기 때문에 포그라운드 스레드라고 한다.
(= 사용자 스레드 라고도 한다.)
백그라운드 스레드
- MyISAM 의 경우에는 별로 해당 사항이 없음.
- InnoDB 는 다음과 같은 여러 작업을 백그라운드로 처리된다.
- 인서트 버퍼(Insert Buffer) 를 병합하는 스레드
- 로그를 디스크로 기록하는 스레드
- InnoDB 버퍼 풀의 데이터를 디스크에 기록하는 스레드
- 데이터를 버퍼로 읽어 오는 스레드
- 잠금이나 데드락을 모니터링 하는 스레드
로그 스레드 (Log thread)
와 데이터를 디스크로 내려쓰는 작업을 처리하는쓰기 스레드 (Write thread)
가 가장 중요하다.- 5.5 버전 부터 데이터 쓰기 스레드와 데이터 읽기 스레드의 개수를 2개 이상 지정할 수 있게 됨.
innodb_write_io_threads
와innodb_read_io_threads
시스템 변수로 스레드의 개수를 설정한다.
- InnoDB 에서도 데이터를 읽는 작업은 주로 클라이언트 스레드에서 처리되므로 읽기 스레드는 많이 설정할 필요는 없음.
- But, 쓰기 스레드는 아주 많은 작업을 백그라운드로 처리함.
- 일반적인 내장 디스크를 사용할 때는 2~4 정도로 설정한다.
- DAS 나 SAN 과 같은 스토리지를 사용할 때는 디스크를 최적으로 사용할 수 있을 만큼 충분히 설정하는게 좋다.
- 사용자의 요청을 처리하는 도중, 데이터 쓰기 작업은 지연(버퍼링) 되어 처리될 수 있음.
- 데이터의 읽기 작업은 절대 지연될 수 없음.
- 일반 상용 DBMS 에는 대부분 쓰기 작업을 버퍼링 해서 일괄 처리하는 기능이 탑재되어 있음. (InnoDB 도 이러한 방식으로 처리함.)
- INSERT, UPDATE, DELETE 쿼리로 데이터가 변경되는 경우 데이터가 디스크의 데이터 파일로 완전히 저장될 때까지 기다리지 않아도 됨.
- MyISAM 의 경우 사용자 스레드가 쓰기 작업까지 함께 처리하도록 설계되어 있음.
- 일반적인 쿼리로 쓰기 버퍼링 기능을 사용할 수 없음.
메모리 할당 및 사용 구조
- MySQL에서 사용되는 메모리 공간은
글로벌 메모리 영역
과로컬 메모리 영역
으로 구분할 수 있다.- MySQL 서버 내에 존재하는 많은 스레드가 공유해서 사용하는 공간인지 여부에 따라 구분됨.
글로벌 메모리 영역
- 모든 메모리 공간은 MySQL 서버가 시작되면서 운영체제로부터 할당됨.
- 운영체제 종류에 따라 요청된 메모리 공간을 100% 할당해줄 수도 있고, 그 공간만큼 예약해두고 필요할 떄 조금씩 할당해 주는 경우도 있다.
- 각 운영체제의 메모리 할당 방식은 상당히 복잡함.
- MySQL 서버가 사용하는 정확한 메모리의 양을 측정하는 것 또한 쉽지 않음.
- 그냥 단순히 MySQL 시스템 변수로 설정해 둔 만큼 운영체제로부터 메모리를 할당받는다고 생각해도 됨.
- 클라이언트 스레드의 수와 무관하게 하나의 메모리 공간만 할당된다.
- 필요에 따라 2개 이상의 메모리 공간을 할당받을 수도 있지만 클라이언트의 스레드 수와 무관하다.
- 생성된 글로벌 영역이 N개라 하더라도 모든 스레드에 의해 공유된다.
- 다음은 대표적인 글로벌 메모리 영역이다.
- 테이블 캐시
- InnoDB 버퍼 풀
- InnoDB 어댑티브 해시 인덱스
- InnoDB 리두 로그 버퍼
로컬 메모리 영역
- MySQL 서버상에 존재하는 클라이언트 스레드가 쿼리를 처리하는 데 사용하는 메모리 영역이다.
- 대표적으로
커넥션 버퍼
와정렬(소트) 버퍼
가 있다. - 클라이언트 커넥션으로부터 요청을 처리하기 위해 스레드를 하나씩 할당한다. (위 MySQL 스레딩 그림을 참고하자.)
- 클라이언트 스레드가 사용하는 메모리 공간이라고 해서 클라이언트 메모리 영역 이라고도 한다.
- 클라이언트와 MySQL 서버와의 커넥션을 세션이라고 하기 때문에 세션 메모리 영역이라고도 함.
- 로컬 메모리는 각 클라이언트 스레드별로 독립적으로 할당되며 절대 공유되어 사용되지 않음.
- 일반적으로 글로벌 메모리 영역의 크기는 주의해서 설정함.
- 소트 버퍼와 같은 로컬 메모리 영역은 크게 신경 쓰지 않고 설정하지만, 최악의 경우에 MySQL 서버 메모리 부족으로 멈춰 버릴 수도 있으므로 적절한 메모리 공간을 설정하는게 중요함.
- 각 쿼리의 용도 별로 필요할 때만 공간이 할당되고 필요하지 않은 경우에는 MySQL 이 메모리 공간을 할당조차도 하지 않을 수 있다. (ex : 소트 버퍼, 조인 버퍼와 같은 공간)
- 커넥션이 열려 있는 동안 계속 할당된 상태로 남아 있는 공간도 있다.
- 커넥션 버퍼 or 결과 버퍼
- 쿼리를 실행하는 순간에만 할당했다가 다시 해제하는 공간도 있다.
- 소트 버퍼 or 조인 버퍼
- 대표적인 로컬 메모리 영역은 다음과 같다.
- 정렬 버퍼 (Sort buffer)
- 조인 버퍼
- 바이너리 로그 캐시
- 네트워크 버퍼
'Book > Real Mysql 8.0' 카테고리의 다른 글
책너두 (Real MySQL 8.0 1권) 8일차 (~107p) (1) | 2023.01.12 |
---|---|
책너두 (Real MySQL 8.0 1권) 7일차 (~97p) (1) | 2023.01.10 |
책너두 (Real MySQL 8.0 1권) 5일차 (~75p) (1) | 2023.01.07 |
책너두 (Real MySQL 8.0 1권) 4일차 (~64p) (0) | 2023.01.07 |
책너두 (Real MySQL 8.0 1권) 3일차 (~51p) (0) | 2023.01.06 |