티스토리 뷰
InnoDB의 엔진 아키텍처는 다음과 같다.
하나하나 살펴보도록하자!!
프라이머리 키에 의한 클러스터링
InnoDB의 모든 테이블은 기본적으로 프라이머리 키를 기준으로 클러스터링 되어 저장된다. 즉, 프라이머리 키 값의 순서대로 디스크에 저장된다는 뜻이며, 모든 세컨더리 인덱스는 레코드의 주소 대신 프라이머리 키의 값을 논리적인 주소로 사용한다. 프라이머리 키가 클러스터링 인덱스이기 때문에 프라이머리키를 이용한 레인지 스캔은 상당히 빨리 처리될 수 있다.
하지만 이 기능은 MyISAM에서는 지원하지 않는다. 그래서 프라이머리 키와 세컨더리 인덱스는 구조적으로 아무 차이가 없다.
외래 키 지원
외래 키에 대한 지원은 InnoDB 스토리지 엔진 레벨에서 지원하는 기능으로 MyISAM이나 MEMORY 테이블에서는 사용할 수 없다. 외래 키는 데이터베이스 서버 운영의 불편함 때문에 서비스용 데이터베이스에서는 생성하지 않는 경우도 자주 있는데, 그렇다 하더라도 개발 환경의 데이터베이스에서는 좋은 가이드 역할을 할 수 있다. InnoDB에서 외래 키는 부모 테이블과 자식 테이블 모두 해당 칼럼에 인덱스 생성이 필요하고, 변경 시에는 반드시 부모 테이블이나 자식 테이블에 데이터가 있는지 체크하는 작업이 필요하므로 잠금이 여러 테이블로 전파되고, 그로 인해 데드락이 발생할 때가 많으므로 개발할 때 이러한 점을 주의해야 한다.
MVCC
일반적으로 레코드 레벨의 트랜잭션을 지원하는 DBMS가 제공하는 기능, 가장 큰 목적은 잠금을 사용하지 않는 일관된 읽기를 제공하는 것이다.
예제를 살펴보자, 다음 예제들은 테이블에 한 건의 레코드를 INSERT한 다음에 UPDATE하는 것이다.
mysql> CREATE TABLE member (
-> m_id INT NOT NULL,
-> m_name VARCHAR(20) NOT NULL,
-> m_area VARCHAR(100) NOT NULL,
-> PRIMARY KEY (m_id),
-> INDEX ix_area (m_area)
-> );
mysql> INSERT INTO member (m_id, m_name, m_area) VALUES (12, '홍길동', '서울');
mysql> COMMIT;
INSERT 문이 실행되면 데이터베이스의 상태는 다음과 같다.
이 후 UPDATE문장이 실행되면
mysql> UPDATE member SET m_area='경기' WHERE m_id=12;
UPDATE 문장이 실행되면 커밋 실행 여부와 관계없이 InnoDB의 버퍼 풀은 새로운 값인 '경기'로 업데이트 된다. 그리고 디스크의 데이터 파일에는 체크 포인트나 InnoDB의 Write 스레드에 의해 새로운 값으로 업데이트돼 있을 수도 있고 아닐 수도 있다.
실제로 SELECT를 해보면 m_area가 경기로 바뀐 것을 알 수있다. 즉, 데이터가 커밋 됐든 안됐든 변경된 상태의 데이터를 반환한다. 하지만 READ_COMMITED나 그 이상의 격리 수준인 경우 아직 커밋이 되지 않았기 때문에 언두 로그에 들어있는 서울을 반환할 것이다.
이 상태에서 COMMIT을 하면 지금 상태의 데이터를 영구적인 데이터로 만들지만 롤백을 하면 InnoDB 언두 영역에 있는 백업된 데이터를 다시 버퍼 풀로 복구하고 언두 영역의 내용을 삭제한다. 또 커밋이 된다고 바로 삭제되지 않는다. 이 언두 영역을 필요로하는 트랜잭션이 없을 때 삭제된다.
자동 데드락 감지
InnoDB 스토리지 엔진은 내부적으로 잠금이 교착 상태에 빠지지 않았는지 체크하기 위해 잠금 목록을 그래프 형태로 관리한다. InnoDB 스토리지 엔진은 데드락 감지 스레드를 갖고 있어서 데드락 감지 스레드가 주기적으로 그래프를 검사해 교착 상태에 빠진 트랜잭션을 찾아서 그 중 하나를 강제 종료한다. 이때 종료 우선순위의 기준은 트랜잭션의 언두 로그 양이며 언두 로그 레코드를 더 적게 가지면 롤백을 가장 높은 우선순위이다. 이유는 트랜잭션 강제 롤백으로 인한 MySQL 서버의 부하도 덜 유발하기 때문이다.
자동화된 장애 복구
InnoDB에는 손실이나 장애로부터 데이터를 보호하기 위한 여러 가지 메커니즘이 탑재돼 있다. 그러한 메커니즘을 이용해 MySQL 서버가 시작될 때 완료되지 못한 트랜잭션이나 디스크에 일부만 기록된 데이터 페이지 등에 대한 일련의 복구 작업이 자동으로 진행된다.
InnoDB 스토리지 엔진은 매우 견고해서 데이터 파일이 손상되거나 MySQL 서버가 시작되지 못하는 경우는 거의 발생하지 않는다. 하지만 MySQL 서버와 무관하게 디스크나 서버 하드웨어 이슈로 InnoDB 스토리지 엔진이 자동으로 복구를 못 하는 경우도 발생할 수 있는데, 일단 한 번 문제가 생기면 복구하기가 쉽지 않다. InnoDB 데이터 파일은 기본적으로 MySQL 서버가 시작될 때 항상 자동 복구를 수행한다. 이 단계에서 자동으로 복구될 수 없는 손상이 있다면 자동 복구를 멈추고 MySQL 서버는 종료돼 버린다.
이때는 MySQL 서버의 설정 파일에 innodb_force_recovery 시스템 변수를 설정해서 MySQL 서버를 시작해야 한다. 이 설정값은 MySQL 서버가 시작될 때 InnoDB 스토리지 엔진이 데이터 파일이나 로그파일의 손상 여부 검사 과정을 선별적으로 진행할 수 있게 한다.
- InnoDB의 로그 파일이 손상 됐다면 6으로 설정하고 MySQL 서버를 기동한다.
- InnoDB 테이블의 데이터 파일이 손상 됐다면 1로 설정하고 MySQL 서버를 가동한다.
- 어떤 부분이 문제인지 알 수 없다면 innodb_force_recovery 설정값을 1부터 6까지 변경하면서 MySQL을 재시작 해 본다. 즉, innodb_force_recovery 설정 값을 1로 설정한 후 MySQL 서버를 재시작해 보고, MySQL이 시작되지 않으면 다시 2로설정하고 재시작해 보는 방식이다. innodb_force_recovery 값이 커질수록 그만큼 심각한 상황이어서 데이터 손실 가능성이 커지고 복구 가능성은 적어진다.
Reference.
Real MySQL - 백은빈, 이성욱
'CS > DB' 카테고리의 다른 글
클러스터링 인덱스 vs 논 클러스터링 인덱스 (1) | 2023.04.21 |
---|---|
Index란? (0) | 2022.08.25 |
프로젝트에 커버링 인덱스를 적용해볼까? (0) | 2022.07.21 |
InnoDB 버퍼 풀 - 1부 (0) | 2022.04.09 |
MySQL 아키텍처 (0) | 2021.11.28 |
- Total
- Today
- Yesterday
- 코딩
- 동시성
- 취준
- 프로그래밍
- MySQL
- 인터뷰
- thread
- 취업
- docker
- Redis
- DB
- 개발자
- 취업준비
- 프로젝트
- java
- Spring
- 백엔드
- 개발
- Kotlin
- IT
- DevOps
- 자바
- 면접 준비
- CS
- JPA
- swarm
- 면접
- 게시판
- 면접준비
- 코드
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |