InnoDB 스토리지 엔진 아키텍처

특징

책너두 6기 9일차

백은빈, 이성욱의 Real MySQL8.0 1권 p.98 ~ p.107

내용정리

04 아키텍처

4.2 InnoDB 스토리지 엔진 아키텍처

InnoDB는 MySQL에서 사용할 수 있는 스토리지 엔진 중 거의 유일하게 리코드 기반의 잠금을 제공하며, 높은 동시성 처리가 가능하고 안정적이며 성능이 뛰어나다.

4.2.1 프라이머리 키에 의한 클러스터링

InnoDB의 모든 테이블은 기본적으로 프라이머리 키를 기준으로 클러스터링되어 저장된다. 프라이머리 키 값의 순서대로 디스크에 저장된다는 뜻이며 모든 세컨더리 인덱스는 레코드의 주소 대신 프라이머리 키의 값을 논리적인 주소로 사용한다.

4.2.2 외래 키 지원

외래 키는 부모 테이블과 자식 테이블 모두 해당 칼럼에 인덱스 생성이 필요하고, 변경 시에는 반드시 부모 테이블이나 자식 테이블에 데이터가 있는지 체크하는 작업이 필요하여 이로 인해 데드락이 발생할 때가 많으므로 주의하자. foreign_key_checks시스템 변수로 ON/OFF로 설정할 수 있다.

4.2.3 MVCC(Multi Version Concurrency Control)

잠그을 사용하지 않는 일관된 읽기를 제공하는 목적이다. 멀티 버전이라 함은 하나의 레코드에 대해 여러 개의 버전이 동시에 관리된다는 의미이다. 격리 수준(Isolation level)이 READ_COMMITTED인 MySQL 서버에서 테이블의 데이터 변경이 어떻게 처리되는지 살펴보자


mysql> create database test
    -> ;
Query OK, 1 row affected (0.01 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+
5 rows in set (0.00 sec)

mysql> use test;
Database changed
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)
    -> );
Query OK, 0 rows affected (0.07 sec)

mysql> insert into member (m_id, m_name, m_area) values (12,'hong', 'seoul');
Query OK, 1 row affected (0.01 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> update member set m_area='gyunggi' where m_id=12;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from member where m_id = 12;
+------+--------+---------+
| m_id | m_name | m_area  |
+------+--------+---------+
|   12 | hong   | gyunggi |
+------+--------+---------+
1 row in set (0.00 sec)

잘 바뀌었다!


바뀌는 상태를 insert문이 실행되면 메모리에서 InnoDB 버퍼 풀과 데이터 파일(디스크)에 다음과 같은 member가 존재할 것이다.

m_id m_name m_area
12 hong seoul

update가 실행되면 어떻게 될까?

InnoDB 버퍼 풀에서 바뀌어야 할 m_area의 내용이 언두 로그로 m_id와 함꼐 옮겨진다. 그리고 InnoDB 버퍼 풀의 m_area는 업데이트 된다.

데이터 파일(디스크)는 체크포인트나 InnoDB의 Write 스레드에 의해 새로운 값으로 업데이트돼 있을 수도 있고 아닐 수도 있다.

InnoDB 버퍼 풀

m_id m_name m_area
12 hong gyunggi

언두 로그

m_id m_area
12 seoul

데이터 파일(디스크)

m_id m_name m_area
12 hong ?

commit이나 roolback이 되지 않은 상태에서 작업중인 레코드를 조회하면 어디있는 데이터를 조회할까?

select *from member where m_id=12;

어떤 것을 조회하느냐는 시스템 변수에 설정된 격리 수준(Isolation level)에 따라 다르다. READ_UNCOMMITTED인 경우 현재 가지고 있는 변경된 데이터를 읽어서 반환하고, READ_COMMITTED나 그 이상의 격리 수준(REPEATABLE_READ, SERIALIZABLE)인 경우에는 아직 커밋되지 않았기 때문에 변경되기 이전것을 반환한다.

이러한 과정을 DBMS에서는 MVCC라고 표현한다.

4.2.4 잠금 없는 일관된 읽기(Non-Locking Consistent Read)

오랜 시간 동안 활성 상태인 트랜잭션으로 인해 MySQL 서버가 느려지거나 할 때가 있다. 이 기능으로 인해 언두 로그를 삭제하지 못해서 발생하는 문제다. 트랜잭션이 시작됐다면 가능한 한 빨리 롤백이나 커밋을 통해 트랜잭션을 완료하는 것이 좋다.

4.2.5 자동 데드락 감지

동시 처리 스레드가 매우 많은 경우에는 데드락 감지 스레드가 더 많은 CPU 자원을 소모하여 서비스에 영향을 끼칠 수 있다. innodb_deadlock_detect시스템 변수로 조절할 수 있다.

4.2.6 자동화된 장애 복구

innodb_force_recorvery시스템 변수로 조절할 수 있다.

서버가 가동되고 InnoDB 테이블이 인식되면 mysqldump를 이용해 데이터를 가능한한 만큼 백업하자.

문제 부분을 알 수 없다면 이 시스템 변수를 1부터 설정한후 재시작을 반복하며 숫자를 6까지 올려보자. 숫자 값이 커질수록 심각한 상황이고 데이터 손실 가능성이 커지고 복구 가능성은 작아진다.

6까지 해도 안되면 백업을 이용해 새로 구축하고 바이너리 로그를 사용해 최대한 데이터를 복구하자.

읽고나서

어떤 기능들이 있는지, 시스템 변수로 조절할 수 있다는 것만 기억하자!