다음 링크를 번역하였습니다.
https://blogs.oracle.com/mysqlinnodb/entry/redo_logging_in_innodb
- InnoDB 는 높은 신뢰성과 성능이 균형을 이루는 일반적인 목적의 스토리지 엔진이다.
- 트랜잭션 스토리지 엔진으로, 모든 관계형 데이터베이스에서 기대되는 ACID 를 완전히 준수한다.
- InnoDB 에서 제공되는 내구성 보장은 redo log 에 의해 가능해진다.
- 이번 장에서는 리두로그 서브시스템의 개요 또는 InnoDB의 로그 서브시스템에 대한 정보가 제공된다.
- 이번 정리에서 상세히 볼 내용
- 중요한 데이터 구조와 정보에 접근할 수 있도록 제공되는 글로벌 로그 시스템 객체 (Global log system object)
- 모든 리두로그 레코드가 생성되는데 사용하는 미니 트랜잭션 (mtr : mini-transaction)
- global in-memory log buffer (혹은 log buffer) 내부에 미니 트랜잭션 버퍼로부터 기록된 리두로그가 존재한다.. 이 로그버퍼는 정기적으로 디스크의 log file 에 flush 된다.
- 디스크에 존재하는 리두로그 파일들과, 높은 수준의 내부 구조에 대해 알아본다.
- LSN 의 컨셉. 어떻게 LSN 의 다양한 값들이 Write-ahead logging (WAL) 를 구성하는데 사용되었는지에 대해 알아본다.
Redo Log Generation
앞서 Data Organization in InnoDB 기사에서, InnoDB 의 사용자 데이터파일 ( .ibd files ) 들이 동일한 페이지 사이즈로 순차적으로 구성되어 있는 것을 보았다.
이 페이지들은 space_id , page_no 를 사용해서 InnoDB system 내에서 유니크하게 식별 된다.
만일 어떤 페이지를 수정하거나 읽으려고 한다면, 메모리에 로딩 되어야 한다. 그래서 메모리와 디스크에 각각 한 개씩, 두 개의 페이지가 존재하게 된다.
다음은 리두로그가 생성되는 단계이다.
- 페이지가 변경되면, 가장 먼저 in-memory 에 페이지가 복사된다.
memory 에서 page 가 수정되고, 디스크에 flush 되기 전 까지 해당 페이지는 dirty page 로 메모리에 남아있는다. - memory 에 생성된 연관된 리두로그는 mini transaction (mtr) 버퍼에 위치한다. 이는 이후에 global in-memory redo log buffer 로 이동된다.
- 리두로그 레코드는 메모리내의 redo log buffer 에서 디스크의 redo log file 로 쓰여진다. 그 후에 디스크로 플러시(flush) 된다.
운영체제에 의한 파일 버퍼링으로 인해, 이 두 스텝들이 분리되도록 고려된다.- 리두로그 파일 쓰기
- 디스크로 리두로그 파일 flush
- dirty page 는 체크포인트 작업 중에, 어느 시점에서 메모리에서 디스크로 flush 된다.
이 순서는 매우 중요하다. 변경된 리두로그 레코드는 그에 상응하는 더티 페이지가 디스크에 플러시되기 전에, 디스크로 반드시 플러시된다.
이것이 write-ahead logging (WAL) 컨셉이다.
생성된 redo log 레코드는 이후 데이터베이스 복구 중에 동일한 작업을 수행시키는데 반드시 필요한 정보를 포함한다.
redo log 레코드는 원래의 page 셋 정보와, 이 페이지에 어떤 변경이 있었는지 정보를 포함한다. redo log 레코드를 사용해서 dirty page 세트가 database recovery 중 재생성 될 것이다.
Redo Log Files
기본적으로, InnoDB 는 2개의 redo log file ( ib_logfile0 , ib_logfile1 ) 을 생성한다. MySQL 5.6.8 이상 버전에서는 redo log file 사이즈가 각 48MB 이다.
이는 innodb_log_file_size 서버 옵션을 사용해서 설정할 수 있다. log file 의 갯수는 innodb_log_files_in_group 서버옵션으로 제어된다.
각각 동일한 사이즈의 몇 개의 log file 은 log group을 구성한다. MySQL 5.6 에서는 InnoDB 가 오로지 하나의 log group 을 지원하기 때문에 이후로도 논의되지 않는다.
redo log file들은 순환방식으로 사용된다. 이는 redo log 가 쓰여지기 시작해서 하나의 로그파일의 끝까지 쓰일 경우 다음 로그파일에 이어서 써지고, 마지막 로그파일에 다다를 때 까지 계속 써서, 다시 첫 번째 로그파일에 쓰여진다.
log file 은 "log blocks" 라 불리는 순차적인 block 으로 보여지는데, 이는 OS_FILE_LOG_BLOCK_SIZE 값으로, 512 byte 로 동일한 크기로 주어진다.
각 log file 은 LOG_FILE_HDR_SIZE 로 주어진 헤더 사이즈를 가지며 이는 4 * OS_FILE_LOG_BLOCK_SIZE 로 정의된다.
Redo Log File Header
각 redo log file 은 헤더에 4 개의 log block 으로 위치해있고, 아래 정보를 갖는다.
- 처음 4 byte 는 log file 내에 log group number 를 포함
- 다음 8 byte 는 log file 내의 데이터 시작점의 LSN 을 포함
- 첫 번째 체크포인트 필드는 두 번째 log block 시작점에 위치한다.
- 두 번째 체크포인트 필드는 네 번째 log block 시작점에 위치한다.
체크포인트 필드는 체크포인트를 식별하는데 필요한 정보를 포함하여 구성된다. ( 체크포인트 숫자와, 체크포인트의 LSN, 체크섬 정보와 기타 등등 ..)
Log Blocks
redo log 파일은 log block 들의 순서로 보여질 수 있다. log file 헤더에 속한 하나를 제외한 모든 log block 들은 헤더와 푸터를 포함한다. 헤더의 사이즈는 LOG_BLOCK_HDR_SIZE bytes 이다. ( 12bytes 로 정의됨 )
log block 트레일러 사이즈는 LOG_BLOCK_TRL_SIZE 이다. ( 4 bytes )
log block 헤더는 아래 정보를 포함한다.
- log block number. ( 이 필드는 4 bytes )
- 이 block 에 쓰여진 log 의 byte 수. ( 이 필드는 2 bytes )
- 이 log block 내에 mtr log 레코드그룹에 첫 번째 시작 offset, 없으면 0
- 이 log block 을 포함하는 체크포인트 숫자

Log Sequence Number (LSN)
LSN 은 중요한 컨셉이다. LSN 은 redo log file 내부의 offset 이다.
InnoDB 내에 log sequence number 는 8-byte unsigned integer 인 lsn_t 타입으로 표현된다.
각각의 다른 LSN 값은 매우 흥미롭다. 다음은 LSN 값의 리스트이다. (log_sys 는 다음 섹션에서 설명할 글로벌 로그 시스템 객체이다.)
LSN | 설명 |
log_sys->lsn | 다음으로 생성될 리두로그 레코드가 사용할 LSN |
log_sys->flushed_to_disk_lsn | 리두로그 파일은 이 LSN 까지 플러시 된다. LSN이 flushed_to_disk_lsn 보다 작은 값을 갖는 모든 리두로그 레코드는 디스크에 안전하게 저장된다. |
log_sys->write_lsn | 현재 쓰기가 진행중인 작업은 이 LSN까지 쓸 것이다. |
log_sys->current_flush_lsn | 현재 쓰기+플러시가 진행중인 작업은 이 LSN까지 쓸 것이다. |
LSN 은 더티 페이지와 리두로그 레코드, 리두로그 파일을 연결하는 것이다.
각 리두로그 레코드는 인메모리 로그 버퍼에 복사될 때, 연관된 LSN 값을 가져온다.
각 데이터베이스 페이지가 수정되면, 리두로그 레코드가 생성된다. 그래서 각 데이터베이스 페이지가 LSN 과 연관이 있는 것이다.
각 데이터베이스 페이지가 수정되면, 리두로그 레코드가 생성된다. 그래서 각 데이터베이스 페이지가 LSN 과 연관이 있는 것이다.
페이지 LSN 은 각 페이지의 헤더에 저장되어있다. 페이지 LSN 은 페이지 플러시 작업 이전에 반드시 플러시 되어야 하는 리두로그 파일의 LSN 을 알려준다.
Global Log System Object
글로벌 로그 시스템 객체인 log_sys ( log_t 타입 ) 은 InnoDB의 서브 시스템과 관련된 로그의 중요한 정보를 가지고 있다.
리두로그 버퍼와 리두로그 파일이 연관된 정보를 가지고 있다. 글로벌 log_sys 는 로그 버퍼의 "활성 영역(Active area)" 을 식별한다.
이 활성 영역은 아직 디스크에 안전하게 쓰이기 전의 리두로그를 저장한다.
글로벌 log_sys 는 리두로그 파일 내에서 로그 버퍼가 쓰여지고 플러시될 활성 영역을 식별한다.

글로벌 log_sys 는 리두로그 파일 내에서 로그 버퍼가 쓰여지고 플러시될 활성 영역을 식별한다.

- log_sys->buf 멤버는 인메모리 리두 로그 버퍼를 가르킨다.
이 버퍼는 mtr_commit() 이 쓰는 리두 로그 레코드의 버퍼이다. 이 버퍼의 크기는 log_sys->buf_size 에서 바이트 값으로 주어진다. - log_sys->buff_free 멤버는 인메모리 리두 로그 버퍼 내에 있는 오프셋으로, 다음 리두로그 레코드가 쓰여질 영역이다.
이는 디스크로 플러시 될 다음 리두로그에 대한 마지막 오프셋이다. - log_sys->buf_next_to_write 멤버는 아직 리두로그 파일에 쓰여지지 않은 리두로그 레코드에 대한 오프셋이다.
다음 차례에 리두로그 버퍼가 디스크로 플러시 될 때 이 영역으로 플러시 될 것이다. 이것은 디스크로 플러시될 다음 리두로그를 위한 시작 오프셋이다. - log_sys->flushed_to_disk_lsn 멤버는 디스크의 로그파일에 기록하고 플러시 되어야 하는 곳 까지의 LSN 을 표기한다.
이 LSN까지는 리두로그가 안전하게 디스크에 저장되어 있다. 이 값은 log_sys->write_lsn 과 log_sys->lsn 값보다 항상 작거나 같다. - log_sys->lsn 은 현재 LSN 을 나타낸다. 이 멤버는 mtr_commit() 하면 언제든 업데이트 된다.
mtr_commit() 함수는미니 트랜잭션 내에 생성되어있는 리두 로그 레코드의 묶음을, 글로벌 또는 시스템 범위의 메모리의 리두로그 버퍼에 쓰게된다.
이것은 항상 log_sys->flushed_to_disk_lsn 과 log_sys->write_lsn 값 보다 항상 크거나 같다. 이 값은 sys->buf_free 에 작성된 리두로그 레코드의 LSN이 될 것이다. - log_sys->write_lsn 멤버는 현재 동작중인 리두로그 버퍼 쓰기 작업의 마지막 LSN 을 나타낸다.
이는 log_sys->flushed_to_disk_lsn 값과 크거나 같고, log_sys->lsn 보다는 작거나 같다. - log_sys->current_flush_lsn 은 현재 동작중인 리두로그 버퍼 쓰기와 플러시 작업의 마지막 LSN을 나타낸다. 이 값은 대부분 log_sys->write_lsn 값과 동일하다.
글로벌 log_sys 객체는 인메모리 리두 로그 버퍼와 디스크에 있는 리두 로그 파일의 다양한 포지션들을 가르킨다.
다음 그림은 글로벌 log_sys 객체로부터 가르켜지는 위치를 보여준다. 이 그림은 리두로그 버퍼가 리두로그 파일의 특정 부분에 매핑되어 있는 것을 명확하게 보여준다.


Global In-memory Redo Log Buffer
인메모리 리두 로그 버퍼는 전역적이고, 유저 트랜잭션으로부터 생성된 모든 리두로그들은 이 버퍼에 쓰여질 것이다.
버퍼의 크기는 innodb_log_buffer_size 시스템 변수로 설정 가능하다. 리두 로그 버퍼의 기본 값은 8MB이다.
트랜잭션이 데이터베이스에 변경 작업을 실행중이라면, 리두로그가 생성될 것이고 이 로그 버퍼를 채우게 될 것이다.
이 로그 버퍼는 트랜잭션이 커밋되거나 로그 버퍼가 모두 찼을 때, 로그파일로 작성되거나 플러시 될 것이다.
리두로그 버퍼가 가득 차고, 리두 로그 레코드의 그룹을 로그 버퍼로 이동시키는 mtr_commit() 을 위한 공간이 더이상 없을 경우에
리두로그 버퍼가 가득 차고, 리두 로그 레코드의 그룹을 로그 버퍼로 이동시키는 mtr_commit() 을 위한 공간이 더이상 없을 경우에
로그 버퍼는 log_buffer_flush_to_disk() 를 사용하여 리두로그 파일로 동기화 플러시를 완료한다.
이 함수는 log_sys->buf_next_to_write 에서 log_sys->buff_free 로 로그 버퍼를 쓸 것이다.
LSN 의 측면에서는, log_buffer_flush_to_disk() 함수는 log_sys->flushed_to_disk_lsn 에서 log_sys->lsn 으로 리두로그를 플러시한다.
이 함수는 log_sys->buf_next_to_write 에서 log_sys->buff_free 로 로그 버퍼를 쓸 것이다.
LSN 의 측면에서는, log_buffer_flush_to_disk() 함수는 log_sys->flushed_to_disk_lsn 에서 log_sys->lsn 으로 리두로그를 플러시한다.
The mini transaction (mtr)
작은 트랜잭션인 mtr 은 모든 리두로그 레코드 생성에 사용된다.
작은 트랜잭션은 생성된 리두로그 레코드가 저장되는 로컬 버퍼 (작은 트랜잭션 버퍼라 불리는) 를 포함한다.
만일 리두로그 레코드 그룹의 생성이 필요할 경우에, 하나의 미니 트랜잭션으로 처리한다.
또한 리두로그 레코드에서, 미니 트랜잭션은 수정된 페이지의 리스트를 포함한다. ( 더티 페이지 )
일반적으로 미니 트랜잭션은 다음과 같이 사용된다.
- mtr_t 타입의 객체로 미니 트랜잭션을 생성
- mtr_start() 함수로 미니 트랜잭션을 시작. 이는 미니 트랜잭션 버퍼를 초기화 한다.
- mlog_write_ulint() 연관 함수를 사용하여 리두로그 레코드를 생성
- mtr_commit()함수로 미니 트랜잭션을 커밋한다. 이는 리두로그 레코드가 미니 트랜잭션으로부터 글로벌 리두 로그 버퍼로 이동시키도록 한다.
더티 페이지 리스트는 버퍼 플러시 리스트로 추가된다.
미니트랜잭션의 정의를 참조하기 위해 다음 설명을 제공한다.
Redo Log Record Types
데이터베이스 페이지를 수정할 때, 리두로그 레코드는 생성된다.
리두 로그 레코드는 페이지의 변경된 정보 (물리적인 리두 로그) 의 정보를 포함하거나, 어떻게 다시 변경 동작을 수행할 것인지를 포함한다. (논리 리두로그)
InnoDB는 물리 리두로그와 논리 리두로그를 결합하여 사용한다.
이를 이해하기 위해서는 페이지 재생성과 같은 작업을 고려해야 한다.
만일 이 작업에 대해서 물리 리두로그 레코드를 생성하였다면, 리두로그 레코드는 페이지 크기와 동일하게 생성될 것이다.
그러나 이 작엡에 대해서 InnoDB 가 논리 리두로그 레코드를 사용한다면, 리두로그 레코드의 크기는 크게 줄어들 것이다.
페이지 재구성을 나타내는 논리 리두로그 레코드의 경우, 우리가 필요한 것은 페이지를 유일하게 식별하기 위한 정보이고,
페이지 재구성 작업의 "타입" 이다.
각 리두로그 레코드는 타입을 갖는다. 하나의 리두로그 레코드 타입은 적용하거나 또는 복구 중에 리두로그를 실행하는데 사용되는 함수를 식별하는데 도움이 된다.
리두로그 레코드의 내용은 함수로부터 필요한 모든 매개변수를 포함하거나 파라미터를 포함해야 한다.
Life cycle of a redo log record
리두로그 레코드의 라이프사이클은 다음과 같다.
- 리두로그 레코드는 먼저 미니 트랜잭션에 의해 생성되고, 미니 트랜잭션 버퍼에 저장된다.
이는 리두가 데이터베이스 복구 시간에 동일한 작업을 실행하는 중요한 정보를 포함한다. - mtr_commit() 이 수행될 때, 리두로그 레코드가 글로벌 인메모리 리두 로그 버퍼로 이동된다.
만일 필요하면, 리두로그 버퍼가 리두로그 파일에 플러시 되어서 새로운 리두로그 레코드를 위한 공간을 만든다. - 리두로그 레코드는 해당 레코드와 관련된 특정 LSN 이 있다. 이는 리두로그 레코드가 mtr 버퍼에서 로그 버퍼로 이동될 때 mtr_commit()이 수행되는 동안에 연결이 설정된다.
해당 LSN이 리두로그 레코드에 대해 설정되면, 리두로그 파일에 해당 위치도 함께 설정된다. - 리두로그 레코드는 로그 버퍼에서 리두로그 파일로 이동되어 쓰기+플러시 된다. 이는 리두로그 레코드가 디스크로 안전하게 저장되었음을 의미한다.
- 각 리두로그 레코드는 더티페이지 리스트와 관련이 있다. 이 관계는 LSN을 통해서 설정된다.
리두로그 레코드는 연관된 더티페이지 이전에 반드시 디스크로 플러시 되어야 한다.
리두로그 레코드는 모든 관련된 더티페이지가 디스크로 플러시 된 이후에는 삭제될 수 있다. - 리두로그 레코드는 연관된 더티페이지 리스트를 재생성할 때에도 사용될 수 있다. 이는 데이터베이스 복구 동안에 수행된다.
Conclusion
이 아티클은 InnoDB스토리지엔진의 리두로그 서브시스템에 대한 개요를 제공한다.
리두로그 서브 시스템에서 사용되는 주요 데이터 구조체는 미니 트랜잭션 (mtr) , 인메모리 리두로그 버퍼, 그리고 디스크의 로그파일들이다.
InnoDB스토리지 엔진은 write-ahead 로깅 (WAL) 이 정확하게 동작하도록 하기위해서 다수의 LSN 값을 트래킹한다.
RDBMS에서 데이터 유실은 허용되지 않기 때문에, 리두로그 서브시스템은 성공적인 RDBMS 를 위해 매우 크리티컬한 부분이다.
그리고 리두로그는 DML 작업에 대해 동기적으로 생성되며, 이는 효율적으로 수행되는 것이 중요하다. 리두로그의 크기는 가능한한 작게 유지되어야 한다.
InnoDB스토리지 엔진은 write-ahead 로깅 (WAL) 이 정확하게 동작하도록 하기위해서 다수의 LSN 값을 트래킹한다.
RDBMS에서 데이터 유실은 허용되지 않기 때문에, 리두로그 서브시스템은 성공적인 RDBMS 를 위해 매우 크리티컬한 부분이다.
그리고 리두로그는 DML 작업에 대해 동기적으로 생성되며, 이는 효율적으로 수행되는 것이 중요하다. 리두로그의 크기는 가능한한 작게 유지되어야 한다.
댓글 없음:
댓글 쓰기