MySQL innoDB는 어떻게 생겼나요? [InnoDB Architecture]
위의 이미지는 모든 구조를 다 기술한 것은 아니며, 중요한 부분을 발췌하여 표현하였습니다.
innoDB는 크게 메모리 영역, CPU연산영역, 디스크 스토리지 영역으로 구분할 수 있습니다.
$ cd /var/lib/mysql/
$ ls -al
-rw-rw---- 1 mysql mysql 1202616 10월 30 13:36 ib_buffer_pool
-rw-rw---- 1 mysql mysql 50331648 11월 5 16:58 ib_logfile0
-rw-rw---- 1 mysql mysql 50331648 11월 5 16:58 ib_logfile1
-rw-rw---- 1 mysql mysql 348127232 11월 5 16:58 ibdata1
-rw-rw---- 1 mysql mysql 12582912 10월 30 13:36 ibtmp1
$ cd /var/lib/mysql/test
$ ls -al
-rw-rw---- 1 mysql mysql 440 9월 28 21:25 test.frm
-rw-rw---- 1 mysql mysql 98304 9월 28 21:25 test.ibd
우리가 흔히 보던 테이블명.frm, 테이블명.ibd, ibdata1, ib_logfile0, ib_logfile1 등과 같은 파일들은 주황색으로 표현된 디스크 스토리지 영역입니다.
또한, 파란색(메모리영역), 회색(CPU 연산 영역)으로 다이어그램을 그려놓았습니다.
이번장에서는 메모리 영역 위주로 설명하겠습니다.
Innodb buffer pool
Innodb스토리지 엔진에서 가장 핵심적인 부분으로, 디스크의 데이터 파일이나 인덱스 정보를 메모리에 캐시해두는 공간입니다.
무슨말인지 좀 아리송합니다.
SELECT, INSERT 발생되었다는 가정으로 간략하게 흐름을 따라가보죠.
(이해 안가도 한번 집중해서 따라와 보시면 감이 잡히실거에요)
mysql> select * from table_name where idx = 10;
위와 같이 select 쿼리를 보냈다면 대략 아래와 같은 흐름으로 데이터를 가져올겁니다.
- innoDB Buffer Pool 에서 해당 데이터가 있는 조사를 합니다. 캐시된 데이터가 있다면 결과값을 그대로 리턴해줍니다.
- 만약 버퍼풀에 해당 데이터가 없다면 ibdata를 뒤집니다.
(innodb_file per table이 활성화 되어있다면 해당테이블.ibd를 뒤집니다.)
결과값을 버퍼풀 DATA PAGE UBFFER에 기록하고 해결 결과값을 리턴합니다.
결국 버퍼풀에 결과값을 캐시 해놓는다는것이 주 핵심입니다.
그럼 insert 쿼리를 보낸다면 어떤 흐름이 발생될까요?
mysql> INSERT INTO 테이블이름(필드이름1, 필드이름2, 필드이름3, ...)
VALUES (데이터값1, 데이터값2, 데이터값3, ...);
- 명령문이 들어오면 “page”가 BUFFER POOL에 존재하는지 확인합니다.
버퍼풀에는 변경(INSERT, UPDATE, DELTE) 또는 읽기(select)가 필요한 모든 데이터 페이지가 들어 있습니다.
색인 및 데이터 페이지가 모두 포함됩니다. 따라서 위의 INSERT문은 POOL에 이미 값이 있는지 확인합니다.
페이지를 찾으면 페이지를 변경하고, 페이지를 찾지 못하면 디스크 스토리지 영역에서 메모리(버퍼풀)로 읽은 다음 변경합니다. - innoDB 버퍼 풀은 아직 디스크에 기록되지 않은 변경된 데이터를 가지고있습니다. (이러한 데이터를 가지고 있는 페이지를 더티페이지(Dirty Page)라고 합니다.)
버퍼풀에서 데이터 및 인덱스 페이지가 변경되면 페이지가 “DIRTY(더티)”로 표시되고 INSERT문은 트랜젝션 로그 버퍼에 기록됩니다. - 트랜잭션 로그 버퍼의 내용을 하드디스크에 포함합니다.
인스턴스 충돌 동안 트랜잭션 복구를 사용되며 복구 시점에 사용됩니다.
이 파일이 바로 ib_logfile1, ib_logfile2입니다.
파일은 순환 방식으로 사용되며, 처음에는 innoDB가 ib_logfile0을 채우고 ib_logfile1을 채우기 시작합니다. - 일반적으로 ibdata1파일로 이름이 지정된 테이블 공간 파일은 여러 목적으로 사용됩니다.
실제 데이터 및 인덱스 테이터(innodb_file_per_table이 비활성화 된 경우), 데이터 사전(innoDB테이블에 대한 메타 데이터) 및 실행취소 로그(ROLLBACK에 사용됨)를 저장합니다. - 따라서 버퍼풀의 더티 페이지는 IO스테드에 의해 테이블 공간 파일에 기록됩니다.
흐름 따라가다보니 복잡하게 기술되었는데,
"결국적으로 insert한 내용도 버퍼풀에 캐시되어 다음에 사용한다."
"insert구문이 발생 시 해당 데이터가 캐시 안되어있으면 캐시도 생성하고 물리적인 파일에도 내용 기술한다." 이런 내용입니다.
이와 같이 변경된 데이터를 모아서 처리하기 때문에 랜덤한 디스크 작업의 횟수를 줄일수 있습니다.
더티페이지는 주기적 또는 특정 조건이 되면 체크포인트가 발생하는데 이때 wirte thread가 필요한 만큼의 데이터 페이이지만 디스크로 기록합니다. 체크포인트가 발생한다고 해서 버퍼풀의 모든 더티페이지가 디스크로 기록되는것은 아닙니다.
버퍼풀은 쓰기 작업을 지연시켜 일괄적으로 처리할 수 있게 해주는 버퍼 역할도 같이 합니다.
일반적으로 innodb_buffer_pool_size는 전체 장착된 무리 메모리의 50~80 수준의 크기를 잡는것이 좋습니다.
Undo(언두) 로그
언두 영역은 데이터가 변경했을 때(update, delete) 변경되기 이전의 데이터를 보관하는 곳입니다.
Update 문을 실행하면 실제 데이터 파일에는 변경된 데이터가 저장됩니다.
그리고 변경되지 이전의 데이터를 언두 영역에 백업시켜 놓습니다.
이 상태에서 commit을 하게 되면 현재 상태가 그대로 유지되고, rollback을 시키면 언두 영역의 백업된 데이터를 다시 데이터 파일로 복구 시킵니다.
언두의 데이터는 크게 두가지 용도로 사용되는데, 첫번째는 롤백을 위한 용도이며, 두번째는 높은 동시성을 제공하는데 사용됩니다.
insert buffer
데이터가 insert 또는 update 될때 데이터 파일만 변경되는것이 아니라 인덱스 또한 변경되어야 합니다.
그러나 인덱스 업데이트 작업은 디스크이 많은 자원을 소모하게 되는데 그 때 필요한 것이 insert buffer입니다.
인덱스 변경이 필요할때 인덱스 페이지가 버퍼 풀에 있으면 바로 업데이트를 수행하고, 그러지 않다면 이를 즉시 실행하지 않고 임시 공간에 저장해 두고 바로 사용자에게 결과를 반환하는 형태로 성능을 향상시킵니다.
이때 사용되는 임시 메모리 공간을 인서트 버퍼라고합니다.
인서트 버퍼에 임시로 저장되어있는 인덱스 레코드 조각은 이후 백그라운드 인서트 버퍼 머지 스레드에 의해 병합됩니다.
Redo(리두) 로그 및 로그 버퍼
쿼리로 데이터를 변경을 할때 순차적으로 변경된 내용을 기록하는 파일을 리두 로그라고 합니다.
대용량 작업에서 리두 로그 기록 작업이 큰 문제가 되는데 이러한 부분을 보완하기 위해 최대한 ACID 속성을 보정하는 수준에서 버퍼링하게 됩니다. 로그 버퍼는 이러한 리두 로그 버퍼링에 사용되는 공간입니다.
이 크기를 innodb_log_buffer_size로 조정할 수 있는데, 4~16M로 설정하는것이 좋습니다. 설정값이 클수록 디스크 사용량이 줄어서 성능이 향상되지만, 시스템 다운 시 손실되는 트랜잭션 양도 증가합니다. 반면에 크기가 작으면 로그 버퍼를 로그파일에 쓰기 위한 부하가 많이 발생될 수도 있습니다. (어쩌라는건지...;;;)
TABLE SPACE
디스크 스토리 영역중 테이블 스페이스는 크게 두가지로 나뉩니다. 시스템 테이블 스페이스와 유저 테이블 스페이스입니다. 파일명으로 포면 시스템 테이블 스페이스는 ibdata1 에 해당되고,유저 테이블 스페이스는 테이블명.ibd 에 속합니다.
유저테이블스페이스에는 인덱스 파일과 데이터 파일이 속해있고, 시스템 테이블에는 dictionary(테이블 정보 등) 및 undo 등 적지 않은 내용들이 속해있습니다.
처음 아무것도 설정하지 않았다면 유저테이블스페이스는 존재하지 않습니다.
my.cnf에서 "innodb_file_per_table"을 설정해야만 유저테이블스페이스가 생성되고, 이를 좋다 나쁘다 이야기를 간간히 하시는것 같은데, 저는 운영편의상 무조건 하는게 좋다는 쪽입니다.
운영 중간에 innodb_file_per_table을 설정하면 ibdata1이 이미 존재하던 데이터와 꼬이는(복원 등 하는 사례 아닌 이상은 안 꼬입니다) 현상이 발생되므로 처음 설치 시 설정해놓고 시작하는것을 권고드립니다.
참고로 테이블 스페이스 레이아웃 설명 잘해놓은 블로그가 있어서 링크 올려봅니다.
실제 ibdata1에는 어떤 공간으로 구성되어있는지, .ibd에는 어떤 공간으로 구성되어있는지 등이 자세히 기술 되어있습니다. [레이아웃 보러가기]
[참고문서]
https://rrhh234cm.tistory.com/142
본 글은 나의 다른 블로그(폐쇄예정) 에서 작성한 글을 이관한 포스팅입니다. (2018년 11월 5일 작성)
'개발 > MariaDB' 카테고리의 다른 글
MariaDB 리플리케이션(Replication) 이해 및 구축(Rocky Linux) (2) | 2022.11.22 |
---|---|
XMPP mariadb 데이터 초기화 하는 방법 (0) | 2022.10.28 |
[MySQL] MySQL 리플리케이션 UUID 관련 에러 (0) | 2022.10.25 |
sphinx #4 :: 스핑크스 주기적 인덱스 방법 (delta + crontab) (0) | 2022.10.25 |
sphinx #3 :: MySQL에서 스핑크스 직접 join하기 (sphinxSE) (0) | 2022.10.25 |
댓글
이 글 공유하기
다른 글
-
MariaDB 리플리케이션(Replication) 이해 및 구축(Rocky Linux)
MariaDB 리플리케이션(Replication) 이해 및 구축(Rocky Linux)
2022.11.22 -
XMPP mariadb 데이터 초기화 하는 방법
XMPP mariadb 데이터 초기화 하는 방법
2022.10.28 -
[MySQL] MySQL 리플리케이션 UUID 관련 에러
[MySQL] MySQL 리플리케이션 UUID 관련 에러
2022.10.25 -
sphinx #4 :: 스핑크스 주기적 인덱스 방법 (delta + crontab)
sphinx #4 :: 스핑크스 주기적 인덱스 방법 (delta + crontab)
2022.10.25