PostgreSQL 9.4.0 문서 | |||
---|---|---|---|
이전 | 위로 | 장 29. 안정성 및 Write-Ahead 로그 | 다음 |
데이터베이스 성능에 영향을 미치는 WAL 관련 환경 설정 매개 변수가 몇 가지 있다. 이 절에서는 그것의 사용에 대해 설명한다. 서버 환경 설정 매개 변수의 설정에 대한 내용은 18장을 참조 바란다.
Checkpoints는 힙 및 인덱스 데이터 파일이 해당 checkpoint 전에 기록된 모든 정보로 업데이트되도록 보장하는 트랜잭션 시퀀스의 지점이다. checkpoint 시에, 모든 dirty 데이터 페이지는 디스크에 쓰기되고, 특수한 checkpoint 레코드는 로그 파일에 기록된다. (변경 레코드는 이전에 WAL 파일에 기록되었다.) 충돌 발생 시, 충돌 복구 프로시저는 REDO 명령을 시작해야 하는 로그의 지점을 판단하기 위해 최신 checkpoint 레코드를 찾아본다. 해당 지점 이전의 데이터 파일을 변경해도 디스크에는 남아 있다. 따라서, checkpoint 이후에 redo 레코드가 포함되기 이전의 로그 세그먼트는 더 이상 불필요하며, 재활용되거나 제거할 수 있다. (WAL 아카이빙이 완료되면 로그 세그먼트는 재활용 또는 제거되기 전에 아카이브되어야 한다.)
모든 dirty 데이터 페이지를 디스크에 쓰는 checkpoint 요구조건은 상당한 I/O 로드를 야기할 수 있다. 그러므로 checkpoint 시작 시 I/O가 시작되고, 다음 checkpoint가 시작되기 전에 완료되도록 checkpoint 활동이 조절된다. 이렇게 함으로써 checkpoint 시점에 성능 저하가 최소화된다.
서버의 checkpointer 프로세스는 매우 빈번하게 모든 checkpoint를 자동으로 수행한다. checkpoint는 모든 checkpoint_segments 로그 세그먼트 또는 모든 checkpoint_timeout 초마다 먼저 해당되는 것부터 시작된다. 기본 설정은 각각 3개의 세그먼트들 및 300초(5분)이다. 이전 checkpoint 이후로 기록된 WAL이 없으면 checkpoint_timeout을 초과했더라도 새 checkpoint를 건너뛴다. (WAL 아카이빙을 사용 중이고, 데이터 손실 가능성에 대한 제한을 두려고 파일 아카이빙 간격에 대한 하한을 설정하고 싶으면 checkpoint 매개 변수가 아니라 archive_timeout 매개 변수를 조절해야 한다.) SQL 명령 CHECKPOINT를 사용하여 checkpoint를 강제 적용하는 것도 가능하다.
checkpoint_segments 및/또는 checkpoint_timeout을 줄이면 checkpoint가 좀 더 빈번하게 발생한다. 이렇게 하면 redo에 필요한 작업이 줄어들므로 충돌 후 복구가 빨라진다. 그러나 dirty 데이터 페이지를 빈번하게 기록함으로써 늘어나는 비용 간에 균형을 맞출 필요가 있다. full_page_writes가 설정된 경우(기본값), 다른 요소를 고려해야 한다. 데이터 페이지의 일관성을 유지하려면 각 checkpoint 후 데이터 페이지의 첫 번째 수정은 결과적으로 전체 페이지 내용을 로깅하는 것으로 이어진다. 이런 경우 checkpoint 간격이 짧을수록 WAL 로그로의 출력 볼륨이 증가하여 짧은 간격으로 사용하는 목적이 부분적으로 무력화되고, 경우에 따라서는 디스크 I/O가 늘어나기도 한다.
checkpoint는, 첫째로 모든 현재의 dirty 버퍼를 기록해야 하고, 둘째로 위에서 설명한 대로 추후 WAL 트래픽이 추가 발생하기 때문에 매우 비싸다. 따라서, checkpoint가 너무 빈번하지 않도록 checkpointing 매개 변수를 최대한 크게 설정하는 것이 좋다. checkpointing 매개 변수의 간단한 정상 여부 검사로서 checkpoint_warning 매개 변수를 설정할 수 있다. checkpoint가 checkpoint_warning 초에서 설정된 것보다 간격이 짧은 경우 checkpoint_segments를 늘리라는 서버 로그 권고문이 메시지로 출력된다. 해당 메시지가 가끔씩 출현하면 경고가 발생하지 않지만 빈번하게 나타날 경우 checkpoint 제어 매개 변수를 증가해야 한다. checkpoint_segments를 충분히 크게 설정한 경우 거대(large) COPY 전송 같은 대량 작업으로 해당 경고가 다수 나타날 수 있다.
폭발적인 페이지 쓰기량으로 인한 I/O 시스템 폭주를 막기 위해 checkpoint 중 dirty 버퍼 쓰기는 일정 기간에 걸쳐 분산된다. 해당 기간은 checkpoint_completion_target에 의해 제어되며, 이것은 checkpoint 간격의 분획으로 지정된다. 지정된 checkpoint_segments WAL 세그먼트 분획이 checkpoint 시작 후에 소모되었거나, 지정된 checkpoint_timeout 초 분획을 경과한 경우, 둘 중에 빠른 것에 의해 checkpoint가 완료되도록 I/O 속도가 조정된다. 기본값이 0.5인 PostgreSQL은 다음 checkpoint가 시작되기 전 시간의 약 절반이 지난 후 각 checkpoint를 완료하는 것으로 예상한다. 정상 실행 중에 최대 I/O 처리량에 매우 근접한 시스템에서는 I/O 로드를 checkpoint로부터 줄이고자 checkpoint_completion_target를 늘리려고 할 수 있다. 이것의 단점은, 복구 시에 사용할 수 있도록 WAL 세그먼트를 더 많이 확보해야 하기 때문에 연장된 checkpoint가 복구 시간에 영향을 준다는 것이다. checkpoint_completion_target을 1.0로 설정할 수는 있지만 checkpoint는 dirty 버퍼 쓰기 외에 다른 활동도 일부 포함하므로 그것보다는 낮게 유지하는 것이 좋다(최대 0.9). 1.0로 설정하면 checkpoint가 제시간에 완료되지 않을 가능성이 높으므로, 필요한 WAL 세그먼트 수의 예상치 못한 변동으로 성능 손실이 야기될 수 있다.
항상 하나 이상의 WAL 세그먼트 파일이 있으며, 일반적으로(2 + checkpoint_completion_target) * checkpoint_segments + 1 또는 checkpoint_segments + wal_keep_segments + 1개의 파일 이하이다. 각 세그먼트 파일은 일반적으로 16 MB이다(이 크기는 서버 빌드 시에 변경 가능). 이것을 사용하여 WAL에 필요한 공간을 측정할 수 있다. 보통은 이전 로그 세그먼트 파일이 더 이상 필요 없을 때 재활용된다(즉, 번호 순서에 따라 추후 세그먼트가 될 이름으로 변경). 로그 출력 속도가 단기간 최고치에 도달해, 3 * checkpoint_segments + 1 개의 세그먼트 파일보다 많아질 경우 시스템이 이 제한으로 내려올 때까지는 불필요한 세그먼트 파일이 재활용되지 않고 삭제된다.
아카이브 복구 또는 스탠바이 모드에서 서버는 주기적으로 restartpoints,를 수행하는데, 이것은 정상 실행된 checkpoints와 유사하다. 서버는 모든 상태를 디스크에 강제로 기록하고, pg_control 파일을 업데이트하여 이미 처리된 WAL 데이터를 다시 스캔할 필요가 없음을 표시하여 pg_xlog 디렉토리에 있는 예전 로그 세그먼트 파일을 재활용할 수 있게 한다. restartpoints는 checkpoint 레코드에서만 수행될 수 있으므로 restartpoints는 마스터에서의 수행 빈도가 checkpoints보다 적다. 마지막 restartpoint 이후에 최소한 checkpoint_timeout 초를 경과한 경우 checkpoint 레코드에 도달하면 restartpoint가 트리거된다. 스탠바이 모드에서, 최소한 checkpoint_segments 로그 세그먼트가 마지막 restartpoint 이후에 리플레이된 경우에도 restartpoint가 트리거된다.
일반적으로 사용되는 내부 WAL 함수는 XLogInsert
및 XLogFlush
의 두 가지가 있다.
XLogInsert
는 공유 메모리에서 새 레코드를 WAL 버퍼에 배치할 때 사용된다.
새 레코드를 위한 공간이 없는 경우, XLogInsert
는 몇 개의 채워진 WAL 버퍼를 기록해야 한다(커널 캐시로 이동).
영향을 받는 데이터 페이지에 배타적 잠금이 걸려 있어서 명령이 가능한 빨라야 하는 경우, XLogInsert
가 모든 데이터베이스 저수준 변경(예를 들면, 행 삽입)에 사용되므로 이는 바람직하지 않다.
더 안 좋은 것은, WAL 버퍼 쓰기 작업 때문에 새로운 로그 세그먼트가 생성되어 시간이 더 늘어날 수도 있다는 것이다.
일반적으로, WAL 버퍼는 XLogFlush
요청에 의해 쓰기 되어야 하지만, 대부분의 경우 트랜잭션 레코드가 영구적인 저장소에 기록되도록 트랜잭션 커밋 시에 발생한다.
로그 출력이 많은 시스템에서 XLogFlush
요청은 XLogInsert
가 쓰기를 금지할 만큼 빈번하지 않다.
해당 시스템에서는 wal_bufferswal_buffers 매개 변수를 변경하여 WAL 버퍼 수를 늘려야 한다.
full_page_writes가 설정된 경우 및 시스템이 매우 바쁜 경우, wal_buffers를 큰 값으로 설정하면 각 checkpoint 바로 다음 기간 중에 순조로운 반응 시간을 유도할 수 있다.
commit_delay 매개 변수는 그룹 커밋 리더 프로세스가 XLogFlushXLogFlush
내에서 잠금을 획득한 후에 슬립하는 마이크로초 시간을 정의하며, 그룹 커밋 팔로워는 리더 뒤에서 대기한다.
이러한 지연은 다른 서버 프로세스가 자신의 커밋 레코드를 WAL 버퍼에 추가하는 것을 허용하므로 이들 모두는 리더의 최종 동기화 명령에 의해 쓰기 된다.
fsync가 활성화되지 않으면 슬립이 발생하지 않으며, commit_siblings보다 적을 경우 다른 세션이 현재 활성 트랜잭션이 된다.
이렇게 하면 다른 세션이 곧 커밋하지 않을 경우에 슬립을 방지할 수 있다.
일부 플랫폼에서 슬립 요청 시간은 10밀리초이므로 1에서 10000마이크로초 사이의 숫자에서 0이 아닌 값으로 commit_delay를 설정하면 동일한 효과를 갖는다.
일부 플랫폼에서 슬립 명령은 매개 변수에 의해 요청된 것보다 약간 길 수 있다.
commit_delay의 목적은 각 쓰기 명령의 비용이 동시 커밋된 트랜잭션 간에 분할되도록 하는 것이므로(트랜잭션 대기 시간 비용) 설정 전에 비용을 적절하게 선택할 수 있도록 정량화할 필요가 있다. 비용이 클수록 트랜잭션 처리량을 증가시키는 데 commit_delay의 효율이 어느 정도까지 커진다. pg_test_fsync 프로그램을 사용하면 단일 WAL 쓰기 명령을 수행할 때의 평균 시간을 마이크로초 단위로 측정할 수 있다. 단일 8kB 쓰기 명령 후에 쓰기에 소요되는 것으로 프로그램이 리포트한 평균 시간의 절반 값은 commit_delay에 가장 효율적인 설정이므로 이 값은 특정 작업 부하를 최적화할 때 사용되는 시작점으로 권장된다. commit_delay 튜닝은 WAL 로그가 고비용의 대기 회전 디스크(high-latency rotating disk)에 저장된 경우에 특히 유용하며, solid-state drive 또는 배터리 백업 쓰기 캐시가 있는 RAID 배열 같이 동기화 시간이 매우 빠른 저장 매체에서도 장점을 발휘한다. 단, 이것은 대표적인 작업 부하에 대해 테스트해야 한다. 그런 경우 commit_siblings에 더 큰 값을 설정해야 하는데, commit_siblings 값을 작게 하면 대기 시간이 긴 매체에서 종종 유용하다. commit_delay 설정이 너무 크면 총 트랜잭션 처리에 걸리는 시간만큼 트랜잭션 대기 시간이 늘어날 수 있다.
commit_delay가 0으로 설정된 경우(기본값), 발생하는 그룹 커밋 형태로 여전히 가능하지만 각 그룹은 이전 쓰기 명령(있을 경우)이 발생한 시간에 커밋 레코드를 기록해야 하는 지점에 도달하는 세션만으로 환경 설정된다. 높은 클라이언트 카운트에서 "통로 효과(gangway effect)"가 발생하는 추세이면 commit_delay가 0일 때 그룹 커밋의 효과는 상당히 크며, 따라서 commit_delay의 명시적 설정은 무용지물이 될 가능성이 높다. commit_delay 설정은, (1) 일부 동시 커밋 트랜잭션이 있는 경우 및 (2) 처리량이 커밋 속도에 의해 일정 수준으로 제한되는 경우에만 도움이 된다. 그러나 높은 회전 대기 시간을 사용하는 경우 두 개의 클라이언트만큼의 트랜잭션 처리량 증가 시 이 설정이 효율적일 수 있다(즉, 형제 트랜잭션이 1개 있는 단일 커밋 클라이언트).
wal_sync_method 매개 변수는 PostgreSQL이 디스크로의 WAL 업데이트를 커널에 요청하는 빈도를 결정한다. 다른 옵션은 그렇지 않지만, 디스크 캐시에 강제로 쓰기할 수 있는 fsync_writethrough를 제외하고는 안정성 측면에서 모든 옵션은 동일해야 한다. 그러나 어떤 것이 가장 빠른지는 플랫폼에 따라 다르다. pg_test_fsync 프로그램을 사용하면 서로 다른 옵션의 속도를 테스트해 볼 수 있다. fsync가 해제된 경우에는 이 매개 변수가 무효화된다.
wal_debug 환경 설정 매개 변수(PostgreSQL이 지원을 사용하여 컴파일된 경우)를 활성화하면,
결과적으로 각 XLogInsert
및 XLogFlush
WAL 호출이 서버 로그에 로깅된다.
이 옵션은 나중에 좀 더 일반적인 메커니즘으로 교체될 수 있다.