MySQL 아키텍처
4-1 엔진 아키텍처
MySQL의 전체 구조
- MySQL서버는 MySQL엔진(사람의 머리)과 스토리지엔진(손발)로 구분할 수 있다.
- 스토리지엔진은 핸들러API를만족하면 바꿔끼워서 사용가능하다.(구현, 수정)
- MySQL엔진 - 커넥션 핸들러, SQL파서, 전처리기, 옵티마이저
- 스토리지엔진 - 실제 데이터를 디스크 스토리지에 저장하거나 읽어오는 역할, 여러 개를 동시에 사용 가능, 테이블 단위로 스토리지엔진을 지정할 수 있다.(ENGIN=INNODB)
- 핸들러API - MySQL엔진과 스토리지엔진간의 요청,응답 API
MySQL 스레딩 구조
- MYSQL서버는 프로세스 기반이 아닌 스레드 기반으로 작동
- 크게 포그라운드스레드와 백그라운드스레드로 구분
- 실행 중인 스레드 목록은 performance_schema DB의 threads 테이블로 확인가능
메모리 할당 및 사용 구조
- mysql서버에서 사용되는 메모리 공간은 크게 글로벌 메모리 영역과 로컬 메모리 영역으로 구분
- 글로벌 메모리 영역은 서버가 실행될 때 운영체제가 설정해둔 메모리 공간만큼을 할당해준다.
- 글로벌 메모리 영역은 모든 스레드에 공유되는 영역이다.( ex. 테이블캐시, InnoDB버퍼풀, InnoDB어댑티브해시인덱스, InnoDB리두로그버퍼)
- 로컬(세션) 메모리 영역은 클라이언트 스레드가 쿼리를 처리하는 데 사용하는 메모리 영역이다. (ex. 커넥션 버퍼, 정렬 버퍼)
플러그인 스토리지 엔진 모델
MySQL의 독특한 구조 중 대표적인 것( 플러그인 모델)
플러그인 형식으로 부가적인 기능을 더 제공하는 스토리지 엔진을 개발하여 적용할 수 있다.
파서, 인증 기능도 플러그인으로 커스터마이징 가능.
인증은 mysql 서버 접근 권한을 가지는 계정에 대한 인증을 의미. mysql8은 기본적으로 caching_sha2_password plugin을 사용. (이전에는 mysql_native_password plugin 사용)
기존에는 hash 기법 사용. mysql8에는 salt 추가.
컴포넌트
- MySQL8.0부터 기존의 플러그인 모델을 대체하기위한 모델이다.
- 플러그인 모델의 단점을 보완하는 모델이다.
쿼리 실행 구조
- step 1. 쿼리 파서 - 사용자 요청으로 들어온 쿼리 문장을 토큰으로 분리해 트리 형태의 구조로 만들어 내는 작업
- step 2. 전처리기 - 파서트리를 기반으로 쿼리 문장에 구조적 문제점 있는지 확인.
- step 3. 옵티마이저 - 저렵한 비용으로 가장 빠르게 처리하는 방법을 결정하는 역할
- step 4. 실행엔진 - 실행엔진이 구체적으로 무엇일까 ? 지금까지 공부한 내용으로는 핸들러API??
- step 5. 핸들러(스토리지엔진)
복제
- 복제는 매우 중요한 역할을 담당한다고 한다. 이유는 ?
쿼리 캐시
- SQL의실행 결과를 메모리에 캐시하고, 동일 SQL 쿼리가 실행되면 테이블을 읽지 않고 즉시 결과를 반환
- 다만 해당 결과 데이터가 변경되는 경우 변경된 것과 관련된 데이터를 캐시에서 모두 삭제해야하며 이는 성능 저하 및 버그를 유발함.
- MySQL 8.0에서 결국 쿼리 캐시 기능은 제거되었다.
스레드 풀
- 엔터프라이즈 에디션에서만 제공하는 기능
- 다만 커뮤니티 에디션에서도 동일 버전의 Percona Server의 스레드풀 플러그인 라이브러리를 설치해 사용가능
- 내부적으로 사용자요청을 처리하는 스레드 개수를 줄여서 동시 처리되는 요청이 많더라도 제한된 개수의 스레드 처리에만 집중할 수 있게하여 리소스 소모를 줄이는 것이 목적.
- 스레드 생성 및 삭제 비용이 작지않기 때문에 성능적인면에서도 스레드풀이 이점이 있지 않을까 ?
- 또한 스레드 생성과 삭제 과정이 없기에 동작 속도가 향상 될 것임.
트랜잭션 지원 메타데이터
- 메타데이터는 테이블의 구조 정보와 스토어드 프로그램 등의 정보를 의미함.
- 기존에는 해당 메타데이터의 생성 및 변경 작업에 대해 트랜잭션을 지원하지 않았어서 작업도중 서버가 비정상적으로 종료되면 일관되지 않은 상태로 남는 문제가 있었다. (데이터베이스나 테이블이 깨지는)
- MySQL 8.0버전부터는 이러한 문제점 해결을 위해, 해당 정보들을 모두 InnoDB의 테이블에 저장하도록 개선
4-2 InnoDB 스토리지 엔진 아키텍처
구조적으로 크게 ‘버퍼 풀’, ‘언두 로그’, 리두로그와 로그버퍼’, ‘체인지 버퍼’, ‘어댑티브 해시 인덱스’로 구분 지을 수 있으며, 해당 구조를 활용하여 구현된 기능들에 대해 설명한다.
- 구조적 관점과 기능적 관점.
- 스토리지 엔진 가운데 가장 많이 사용되는 스토리지 엔진.
- 스토리지 엔진 중 거의 유일하게 ‘레코드 기반의 잠금‘ 기능 제공.
- 높은 동시성 처리가 가능하고 안정적이며 성능이 우수.
프라이머리 키에 의한 클러스터링
- 세컨더리 인덱스, 클러스터링.
외래 키 지원
- MyISAM이나 memory 테이블에서는외래 키 지원 x.
MVCC(multi version concurrency control)
- 일반적으로 레코드 레벨의 트랜잭션을 지원하는 DBMS가제공하는 기능.
- 잠금을 사용하지 않는 일관된 읽기를 제공하는 것이 목적.
- Undo Log를 이용해 구현.
- 멀티 버전의 의미는 하나의 레코드에 대해 여러 개의 버전이 동시에 관리된다는 의미.
- 가령 레코드가 생성되고 업데이트되는 쿼리문이 순서대로 동작하는 경우, 두개의 버전이 존재하는 상황이 생기게 되며 이때 해당 레코드를 조회하는 경우, 설정된 격리 수준에 따라 두 개의 버전 중 하나가 조회될 수 있다.
- read uncommitted라면 버퍼 풀or 데이터파일(InnoDB는 ACID를 보장하므로 버퍼풀과 디스크의 상태는 같을 것임.)의 업데이터된 값을 조회할 것이며, read commited이면 언두 로그의 값을 조회할 것임. 나머지 격리단계에서도 마찬가지로 언두 로그의 값을 조회할 것임.
Non-Locking Consistent Read
- InnoDB 스토리지엔진은 MVCC를 이용해 잠금 없이 읽기 작업을 수행한다. 단, 격리 수준이 SERIALIZABLE인 경우에는 읽기에도 잠금이 발생.
- 변경 되기 전의 데이터를 읽기 위해서는 언두 로그를 사용한다.
- 언두 로그기능에 대해 주의할 점은, 트랜잭션의 활성 상태가 오랜 시간 유지될 경우, 언두 로그가 차지하는 용량이 늘어나 서버가느려지거나 문제가 발생할 수 있다. 따라서 트랜잭션이 시작됐다면 가능한 빨리 트랜잭션을 완료하는 것을 권장 (롤백 or 커밋).
자동 데드락 감지
- InnoDB 스토리지 엔진은 데드락 체크를 위해 잠금 대기 목록을 그래프 형태로 관리함.
- 주기적으로 해당 그래프를 담당 스레드가 검사해 데드락에 빠진 트랜잭션들을 찾아 그중 하나를 강제 종료함.
- 종료 대상의 판단 기준은 언두 로그의 양. 더 적게 가진 트랜잭션이 롤백의 대상이 됨. (롤백을 해도 언두 처리를 해야할 양이 적다는 것이기 때문에).
자동화된 장애 복구
- InnoDB에는 손실이나 장애로부터 데이터를 보호하기 위한 여러 가지 메커니즘이 탑재돼 있음.
InnoDB 버퍼풀
- InnoDB 스토리지 엔진의 가장 핵심적인 부분.
- 디스크의 데이터 파일이나 인덱스 정보를 메모리에 캐시해 두는 공간.
- 쓰기 작업을 지연시켜 일괄 작업으로 처리할 수 있게 해주는 버퍼 역할도 함. 버퍼 풀이 변경된 데이터 작업에 대해서 모아서 처리하면 랜덤한 디스크 작업의 횟수를 줄이는 효과를 가져옴.
- 버퍼 풀 크기 설정
- 동적으로 크기 조절 가능. (시스템변수 : innodb_buffer_pool_size).
- 쉽게 결정하기 어려운 부분이 있으므로 추이를 지켜보며 적절하게 변경해나가는 것을 권장.
- 버퍼 풀의 구조
- 페이지 크기(시스템변수 : innodb_page_size)로쪼개어 관리. 이를 위해 크게 LRU, FLUSH, FREE 리스트자료구조 사용.
- 버퍼 풀과 리두 로그
- InnoDB버퍼 풀은 서버의 성능 향상을 위해
- 데이터 캐시 기능
- 쓰기 버퍼링 기능을 담당하는데, 버퍼 풀의 크기를 늘리더라도 데이터 캐시 기능은 좋아지지만 버퍼링 기능은 향상되지 않는다. 버퍼링 기능 향상을 시키기 위해서는 버퍼풀과 리두 로그와의 관계를 이해해야함.
- InnoDB버퍼 풀은 서버의 성능 향상을 위해
- 버퍼 풀 Flush
- 버퍼풀 상태 백업 및 복구
- 워밍업 - 버퍼 풀이 잘 워밍되도록 하는 것.
- 최초의 실행이 없는 mysql은 조회 이력이 없기 때문에 버퍼풀에 적재된 데이터들이 없으며 메모리에서 데이터를 얻는 것과 디스크에서 얻는 것의 성능 차이가 크기 때문에 (대략 만배?) 워밍업을 해주는 것.
- 워밍업 - 버퍼 풀이 잘 워밍되도록 하는 것.
- 버퍼 풀의 적재 내용 확인.
Double Write Buffer
- Partial-Page(or Ton-page)의 발생을 막기 위한 기법.
언두 로그(Undo Log)
- 격리 수준을 보장하기 위한 백업용 로그.
- 해당 로그를 이용해 MVCC를 구현한다.
체인지 버퍼
리두 로그 및 로그 버퍼
- 리두 로그는 예상치 못한 상황으로 데이터 파일에 기록되지 못한 데이터를 잃지 않게 해주는 안정장치용 로그.
- 버퍼풀에서 디스크의 데이터 파일에 기록할 때, 보다 ACID를 보장하도록 순차적으로 디스크에 기록하는 로그파일이 리두 로그.
- 일반적으로 DBMS에서 로그라하면 리두 로그를 지칭.
- 로그 버퍼는 리두 로그 버퍼링에서 사용되는 공간. (전체를 한번에 버퍼링 하면 양이 많은 경우 문제가 될 수 있기에 좀 더 낮은 레벨에서 버퍼링 하는 것.)
어댑티브 해시 인덱스
- 일반적으로 DB에서 인덱스는 테이블에 사용자가 생성해둔 B-Tree 인덱스를 의미.
- 어댑티브 해시 인덱스는 InnoDB가 사용자가 자주 요청하는 데이터에 대해 자동으로 생성하는 인덱스.
- innodb_adaptive_hash_index로 활성화, 비활성화 가능.
- 일반적인 B-Tree 인덱스 기법의 검색 시간을 줄여주기 위해 도입된 기능.
- 즉 B-Tree 인덱스를 보조하는 기능.
- 해시를 이용해서 키값으로 레코드가 저장된 데이터 페이지를 즉시 찾아 갈 수 있음.
- B-Tree는루트노드부터 리프 노드까지 찾아가야함.
- 인덱스 키 값 - 데이터 페이지 주소 쌍으로 관리.
- 해시 인덱스의 키 값은 B-Tree 인덱스의 고유 id(여러 B-Tree 인덱스를 구분하는 값)와 B-Tree 인덱스의실제 키 값의 조합으로 생성.
- 데이터 페이지 주소는 버퍼 풀에 로딩된 데이터 페이지의 메모리 주소이다.
- 즉 버퍼풀에 올려진 데이터 페이지만 관리 가능.
- 즉 버퍼풀에 한해서 데이터에 접근하는 것을 더 빠르게 만드는 기능이기 때문에 디스크에서 읽어와야하는 케이스의 경우 성능향상에 도움이 안된다.
- 어댑티브 해시 인덱스도 결국 리소스를 할당 받으며 도움이 되지 않는 경우가 존재하기 때문에 반드시 활성화하는 것이 좋은 것은 아니다.
스토리지 엔진들 비교 (InnoDB, MyISAM, Memory)
- MySQL 5.5 버전 이전에는 MyISAM이 디폴트 스토리지 엔진으로 상용됨.(이후로는 InnoDB)
- 향후 MyISAM, MEMORY 스토리지 엔진은 없어질 것으로 예상.
- 8.0부터는 MyISAM만이 가지는 장점이 없는 상태.
- MEMORY 스토리지 엔진 또한 메모리에서 처리되면 빠를 것이라 예상할 수 있지만, 온라인 트랜잭션 처리(MySQL이 사용되는 일반적 용도)에 있어서 동시 처리 성능이 중요한데, InnoDB를 따라가지 못함.
4-3 MyISAM 스토리지 엔진 아키텍처
- ‘키 캐시’와 ‘운영 체제의 캐시/버퍼’에 대해 살펴본다.
- 키 캐시
- InnoDB의 버퍼 풀과 비슷한 역할, 키 버퍼라고도 불림.
- 인덱스만을 대상으로 작동, 디스크 쓰기 작업에 대해서 부분적으로 버퍼 역할.( 일반적으로 캐시는 읽기 목적, 버퍼는 쓰기 목적 )
- 운영체제의 캐시 및 버퍼
- MyISAM 엔진을 사용하는 테이블의 인덱스는 키 캐시를 이용해 빠르게 검색 가능하지만, 테이블의 데이터에 대해서 디스크로부터 값을 읽고 쓸만한 기능을 MyISAM은 가지고 있지 않음.
- 따라서 운영체제가 수행하며 따라서 데이터의 특성을 알고 좀 더 전문적으로 캐시나 버퍼링을 하지는 못하지만 나쁘지는 않다?
- InnoDB는 디스크로부터 데이터 I/O를 어떻게 수행하더라?
4-4 로그파일
- 로그파일을 이용하면 서버의 상태나 부하를 일으키는 원인을 쉽게 파악하고 해결할 수 있다.
- MySQL서버에 문제가 생겼을 때는 로그 파일을 우선적으로 자세히 확인하는 습관을 권장
에러 로그 파일
- MySQL이 실행되는 도중에 발생하는 에러나 경고 메시지가 출력되는 로그 파일.
제너럴 쿼리 로그 파일
- 쿼리 로그를 활성화하면 쿼리 로그 파일에서 실행되는 전체적인 쿼리 목록을 확인할 수 있다.
슬로우 쿼리 로그
- 서비스에서 사용되는 쿼리 중에 어떤 쿼리가 문제인지를 판단하는 데 슬로우 쿼리 로그가 상당히 많은 도움이 된다.
궁금증
MyISAM 스토리지엔진과 InnoDB스토리지엔진의 차이는 ?
- MyISAM은 읽기 기능이 많은 서비스에 적합, InnoDB는 트랜잭션 처리가 많고 대용량 데이터를 다루는데(데이터 변화가 많은 서비스)에 적합하다. 자세한건 뒷 장 공부하면서 알아가보자.
스레드풀기능을 살펴봤던 Percona Server란?
- percona라는 회사에서 만든 프로그램으로, Mysql의 테크니컬 서포트, 컨설팅 업무를 하는 회사로써 해당 프로그램은 MySQL의 성능 및 안정성, 편의성을 극대화 하는 것을 목표로 만들어진 프로그램이라고 한다. MySQL의 대체품으로 등장한 MariaDB와는 차이가 존재. (참고)
Percona Server를 컴포넌트로 적용도 가능한가 ?
캐시와 버퍼의 차이 ?
- 둘다 추가 메모리를 사용하여 성능을 높이는 도구.
- 캐시는 작업속도 향상이 목적 (좀더 빠르게 데이터 접근 가능하게 함으로써) / 버퍼는 작접 간의 속도 밸런싱을 위한 목적 (느린 곳에 버퍼를 둠으로써 우선적으로 보관해두고 순차적으로 처리되도록 하여 병목현상 완화)
- 캐시는 일반적으로 읽기 / 버퍼는 쓰기에 사용됨. (버퍼는 처리용량이 커서 작업이후에 데이터 폐기되기에 읽기에 부적합. )
클러스터링 인덱스란 ?
생각한 것들
MySQL의 글로벌 메모리와 로컬 메모리영역은 Java의 Stack 영역과 Heap 영역과 비슷하게 생각해볼 수 있다.
- Stack영역 - 지역 변수, 리턴 주소 등을 저장 / 스레드마다 할당
- Heap 영역 - 객체 저장 / 동적 할당 / 공유 영역
쿼리실행구조에서 파서, 전처리기, 옵티마이저의 처리 과정은 언어의 컴파일러의 동작 과정과 비슷하게 생각할 수 있다.
- 파서 ↔ 어휘, 구문 분석
- 전처리기 ↔ 의미 분석
- 옵티마이저 ↔ 코드 최적화
스터디 느낀점
- 버퍼 풀 , 캐시
- 포그라운드 스레드, 백그라운드 스레드
- 바이너리 로그 파일
- 위의 3가지 개념 좀 더 공부필요!
- mysql이 in-memory db는아니지만 메모리를 잘 활용한다. (mysql도 인메모리 모드 지원 )
- 바이너리로그로 복구하는방법.
참고자료
- https://www.youtube.com/watch?v=vQFGBZemJLQhttps://www.youtube.com/watch?v=vQFGBZemJLQ
- https://www.youtube.com/watch?v=vQFGBZemJLQ&t=3s
- https://www.youtube.com/watch?v=edpYzFgHbqs&t=1129shttps://www.youtube.com/watch?v=edpYzFgHbqs&t=1129s
- https://www.youtube.com/watch?v=utjn-cDSiog&list=PLyraqdoIVJhmCIlhXAYjZwqwxT5Ih1kBG&index=4
- https://dev.mysql.com/doc/refman/8.0/en/innodb-buffer-pool.html