[CDC] WAL 기반 CDC 파이프라인 구축 (2)

WAL (Write-Ahead Log) 기본 개념

WAL은 데이터베이스가 시스템 충돌이나 장애 후에도 데이터의 일관성을 유지하도록 돕는 로그이다. 데이터베이스 변경사항(Insert, Update, Delete 등)이 발생하기 전에 이 변경사항을 먼저 로그 파일에 기록하여 데이터 변경 작업이 반영되기 전에 로그가 먼저 기록되므로 시스템이 예기치 않게 중단되어도 데이터베이스의 상태를 복구할 수 있다.

WAL 관련 config 설정

WAL 파일을 읽어들이는 CDC Connector를 붙이기에 앞서 소스 시스템인 PSQL의 WAL 파일 설정에 대해 알아보도록 할 것이다. postgesql.conf 파일에서 WAL 관련 설정을 변경할 수 있다. CDC를 할 때 기본적으로 고려해야하는 조건은 아래와 같다.

wal_level 설정을 logical로 변경
max_wal_senders : 동시에 실행될 수 있는 WAL 스트리밍 연결의 최대 수 설정
max_replication_slots : 데이터베이스에서 사용할 수 있는 복제 슬롯의 최대 수 설정
wal_sender_timeout(옵션) : WAL 스트리밍 연결의 응답이 없을 때 타임아웃 되는 시간 설정 (네트워크 지연 등)

Write-Ahead Log (WAL) 설정

일반 설정

  • wal_level: WAL의 상세 수준 설정 (서버 재시작 필요)
    • minimal: 필수적인 정보만 기록하여 성능 최대화
    • replica: 복제에 필요한 정보 기록
    • logical: 논리적 복제 및 디코딩을 위한 정보 기록
  • fsync: 크래시 안전성을 위해 데이터를 디스크에 실제로 기록할 것인지 설정
    • on: 활성화 상태 (데이터 안정성 확보)
  • synchronous_commit: 트랜잭션 커밋 완료 전 데이터 디스크 기록 시점 제어
    • on: 동기화 수준을 ‘on’으로 설정
  • wal_sync_method: WAL 데이터 동기화 방법 설정
    • fsync: 기본값 (운영 체제에 따라 다를 수 있음)
  • full_page_writes: 부분 페이지 쓰기 오류 복구를 위한 전체 페이지 쓰기 여부

  • wal_compression: 전체 페이지 쓰기 시 압축 사용 여부

  • wal_log_hints: 관련없는 업데이트에 대해서도 전체 페이지 쓰기 수행 여부 (서버 재시작 필요)

  • wal_init_zero: 새 WAL 파일 생성 시 0으로 초기화 여부

  • wal_recycle: WAL 파일 재활용 여부

  • wal_buffers: WAL 버퍼 크기 설정 (서버 재시작 필요)
    • -1: shared_buffers 기반으로 자동 설정
  • wal_writer_delay: WAL 라이터 지연 시간 설정 (밀리초 단위)
    • 200ms: 200 밀리초 지연
  • wal_writer_flush_after: WAL 라이터가 쓰기를 플러시하는 단위 설정
    • 1MB: 1MB 단위로 플러시
  • commit_delay: 커밋 지연 시간 설정 (마이크로초 단위)
    • 0: 지연 없음
  • commit_siblings: 커밋이 발생하기 전에 대기 중인 트랜잭션 수 설정
    • 5: 5개 트랜잭션 대기

체크포인트 설정 (Checkpoints)

  • checkpoint_timeout: 체크포인트 간 최대 시간 설정
    • 5min: 5분
  • max_wal_size: 최대 WAL 파일 크기 설정

  • min_wal_size: 최소 WAL 파일 크기 설정

  • checkpoint_completion_target: 체크포인트 완료 목표 설정 (0.0 - 1.0)
    • 0.5: 50% 목표
  • checkpoint_flush_after: 체크포인트 플러시 간격 설정
    • 256kB: 256kB 단위로 플러시
  • checkpoint_warning: 체크포인트 경고 시간 설정

아카이브 설정 (Archiving)

  • archive_mode: 아카이빙 활성화 여부 설정 (서버 재시작 필요)

  • archive_command: 아카이브할 로그파일 세그먼트를 처리할 명령어 설정

  • archive_timeout: 일정 시간 후 로그파일 세그먼트 강제 전환 시간 설정

    • 0: 비활성화 상태

아카이브 복구 설정 (Archive Recovery)

  • restore_command: 아카이브된 로그파일 세그먼트를 복구할 명령어 설정 (서버 재시작 필요)

  • archive_cleanup_command: 복구 모드에서 재시작 지점마다 실행할 명령어 설정

  • recovery_end_command: 복구 완료 시 실행할 명령어 설정

복구 목표 설정 (Recovery Target)

  • recovery_target: 복구를 종료할 시점 설정 (서버 재시작 필요)

  • recovery_target_name: 복구가 진행될 명명된 복구 지점 설정 (서버 재시작 필요)

  • recovery_target_time: 복구가 진행될 시간 설정 (서버 재시작 필요)

  • recovery_target_xid: 복구가 진행될 트랜잭션 ID 설정 (서버 재시작 필요)

  • recovery_target_lsn: 복구가 진행될 WAL LSN 설정 (서버 재시작 필요)

  • recovery_target_inclusive: 지정된 복구 목표 이후 또는 이전에 복구를 중지할지 여부 설정 (서버 재시작 필요)
    • on: 목표 이후 중지
  • recovery_target_timeline: 복구가 진행될 타임라인 설정 (서버 재시작 필요)
    • 'latest': 가장 최신 타임라인
  • recovery_target_action: 복구 목표 도달 후 수행할 동작 설정 (서버 재시작 필요)
    • 'pause': 일시 정지
접기/펼치기
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
#------------------------------------------------------------------------------

# - Settings -

wal_level = logical                    # minimal, replica, or logical
                                        # (change requires restart)
#fsync = on                             # flush data to disk for crash safety
                                        # (turning this off can cause
                                        # unrecoverable data corruption)
#synchronous_commit = on                # synchronization level;
                                        # off, local, remote_write, remote_apply, or on
#wal_sync_method = fsync                # the default is the first option
                                        # supported by the operating system:
                                        #   open_datasync
                                        #   fdatasync (default on Linux)
                                        #   fsync
                                        #   fsync_writethrough
                                        #   open_sync
#full_page_writes = on                  # recover from partial page writes
#wal_compression = off                  # enable compression of full-page writes
#wal_log_hints = off                    # also do full page writes of non-critical updates
                                        # (change requires restart)
#wal_init_zero = on                     # zero-fill new WAL files
#wal_recycle = on                       # recycle WAL files
#wal_buffers = -1                       # min 32kB, -1 sets based on shared_buffers
                                        # (change requires restart)
#wal_writer_delay = 200ms               # 1-10000 milliseconds
#wal_writer_flush_after = 1MB           # measured in pages, 0 disables

#commit_delay = 0                       # range 0-100000, in microseconds
#commit_siblings = 5                    # range 1-1000

# - Checkpoints -

#checkpoint_timeout = 5min              # range 30s-1d
max_wal_size = 1GB
min_wal_size = 80MB
#checkpoint_completion_target = 0.5     # checkpoint target duration, 0.0 - 1.0
#checkpoint_flush_after = 256kB         # measured in pages, 0 disables
#checkpoint_warning = 30s               # 0 disables

# - Archiving -

#archive_mode = off             # enables archiving; off, on, or always
                                # (change requires restart)
#archive_command = ''           # command to use to archive a logfile segment
                                # placeholders: %p = path of file to archive
                                #               %f = file name only
                                # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'
#archive_timeout = 0            # force a logfile segment switch after this
                                # number of seconds; 0 disables

# - Archive Recovery -

# These are only used in recovery mode.

#restore_command = ''           # command to use to restore an archived logfile segment
                                # placeholders: %p = path of file to restore
                                #               %f = file name only
                                # e.g. 'cp /mnt/server/archivedir/%f %p'
                                # (change requires restart)
#archive_cleanup_command = ''   # command to execute at every restartpoint
#recovery_end_command = ''      # command to execute at completion of recovery

# - Recovery Target -

# Set these only when performing a targeted recovery.

#recovery_target = ''           # 'immediate' to end recovery as soon as a
                                # consistent state is reached
                                # (change requires restart)
#recovery_target_name = ''      # the named restore point to which recovery will proceed
                                # (change requires restart)
#recovery_target_time = ''      # the time stamp up to which recovery will proceed
                                # (change requires restart)
#recovery_target_xid = ''       # the transaction ID up to which recovery will proceed
                                # (change requires restart)
#recovery_target_lsn = ''       # the WAL LSN up to which recovery will proceed
                                # (change requires restart)
#recovery_target_inclusive = on # Specifies whether to stop:
                                # just after the specified recovery target (on)
                                # just before the recovery target (off)
                                # (change requires restart)
#recovery_target_timeline = 'latest'    # 'current', 'latest', or timeline ID
                                # (change requires restart)
#recovery_target_action = 'pause'       # 'pause', 'promote', 'shutdown'
                                # (change requires restart)

Replication 설정

발신 서버 설정 (Sending Servers)

  • max_wal_senders: 최대 walsender 프로세스 수 설정 (서버 재시작 필요)
    • 10: 최대 10개의 walsender 프로세스 사용 가능
  • wal_keep_segments: 로그파일 세그먼트로 유지할 WAL 세그먼트 수
    • 0: 비활성화 상태
  • wal_sender_timeout: walsender 타임아웃 시간 (밀리초 단위)
    • 60s: 60초 타임아웃
  • max_replication_slots: 최대 복제 슬롯 수 (서버 재시작 필요)
    • 10: 최대 10개의 복제 슬롯 사용 가능
  • track_commit_timestamp: 트랜잭션 커밋 타임스탬프 수집 여부
    • off: 비활성화 상태

마스터 서버 설정 (Master Server)

  • synchronous_standby_names: 동기 복제를 수행할 스탠바이 서버 이름
    • '': 동기 복제 비활성화
  • vacuum_defer_cleanup_age: VACUUM 지연 정리 연기 트랜잭션 수
    • 0: 비활성화 상태

스탠바이 서버 설정 (Standby Servers)

  • primary_conninfo: 마스터 서버로의 연결 문자열 (서버 재시작 필요)

  • primary_slot_name: 마스터 서버의 복제 슬롯 이름 (서버 재시작 필요)

  • promote_trigger_file: 복구 종료를 트리거하는 파일 이름

  • hot_standby: 복구 중 쿼리 허용 여부
    • on은 쿼리 허용, off는 쿼리 불허
  • max_standby_archive_delay: 아카이브 WAL 읽기 시 쿼리 취소 전 최대 지연 시간

  • max_standby_streaming_delay: 스트리밍 WAL 읽기 시 쿼리 취소 전 최대 지연 시간

  • wal_receiver_status_interval: WAL 수신기 상태 간격

  • hot_standby_feedback: 스탠바이 서버로부터 마스터 서버에 정보 전송 여부
    • off: 비활성화 상태
  • wal_receiver_timeout: WAL 수신기 타임아웃 시간 (밀리초 단위)

  • wal_retrieve_retry_interval: WAL 검색 재시도 간격

  • recovery_min_apply_delay: 복구 적용 최소 지연 시간
    • 0: 즉시 적용

구독 설정 (Subscribers)

  • max_logical_replication_workers: 논리적 복제 작업자 최대 수 (서버 재시작 필요)
    • 4: 최대 4개의 작업자 사용 가능
  • max_sync_workers_per_subscription: 구독당 동기 작업자 최대 수
    • 2: 구독당 최대 2개의 동기 작업자 사용 가능
접기/펼치기
#------------------------------------------------------------------------------
# REPLICATION
#------------------------------------------------------------------------------

# - Sending Servers -

# Set these on the master and on any standby that will send replication data.

#max_wal_senders = 10           # max number of walsender processes
                                # (change requires restart)
#wal_keep_segments = 0          # in logfile segments; 0 disables
#wal_sender_timeout = 60s       # in milliseconds; 0 disables

#max_replication_slots = 10     # max number of replication slots
                                # (change requires restart)
#track_commit_timestamp = off   # collect timestamp of transaction commit
                                # (change requires restart)

# - Master Server -

# These settings are ignored on a standby server.

#synchronous_standby_names = '' # standby servers that provide sync rep
                                # method to choose sync standbys, number of sync standbys,
                                # and comma-separated list of application_name
                                # from standby(s); '*' = all
#vacuum_defer_cleanup_age = 0   # number of xacts by which cleanup is delayed

# - Standby Servers -

# These settings are ignored on a master server.

#primary_conninfo = ''                  # connection string to sending server
                                        # (change requires restart)
#primary_slot_name = ''                 # replication slot on sending server
                                        # (change requires restart)
#promote_trigger_file = ''              # file name whose presence ends recovery
#hot_standby = on                       # "off" disallows queries during recovery
                                        # (change requires restart)
#max_standby_archive_delay = 30s        # max delay before canceling queries
                                        # when reading WAL from archive;
                                        # -1 allows indefinite delay
#max_standby_streaming_delay = 30s      # max delay before canceling queries
                                        # when reading streaming WAL;
                                        # -1 allows indefinite delay
#wal_receiver_status_interval = 10s     # send replies at least this often
                                        # 0 disables
#hot_standby_feedback = off             # send info from standby to prevent
                                        # query conflicts
#wal_receiver_timeout = 60s             # time that receiver waits for
                                        # communication from master
                                        # in milliseconds; 0 disables
#wal_retrieve_retry_interval = 5s       # time to wait before retrying to
                                        # retrieve WAL after a failed attempt
#recovery_min_apply_delay = 0           # minimum delay for applying changes during recovery

# - Subscribers -

# These settings are ignored on a publisher.

#max_logical_replication_workers = 4    # taken from max_worker_processes
                                        # (change requires restart)
#max_sync_workers_per_subscription = 2  # taken from max_logical_replication_workers

WAL 파일 읽기

PostgreSQL의 pg_wal 디렉토리 안에 있는 WAL 파일들은 바이너리 형식으로 저장되어 있기 때문에 일반적인 텍스트 에디터로 읽을 수 없다. WAL 파일의 로그를 사람이 읽을 수 있도록 렌더링 도구가 있는데 그게 PostgreSQL에서 제공하는 pg_waldump이다. 다만 pg_waldump를 사용할때는 데이터베이스 서버의 성능에 영향을 줄 수 있으므로 운영 환경에서는 주의하여 사용해야한다.

  1. pg_waldump 사용
    wal 파일이 저장되는 폴더를 파악한 후 아래와 같이 명령어를 입력한다.
    pg_waldump /var/lib/postgresql/data/pg_wal/000000010000000000000001
    
  2. 로그 출력
    pg_waldump는 WAL 파일 내의 각 로그 레코드에 대한 정보를 출력한다. 이 정보에는 트랜잭션 ID, LSN(Low Sequence Number), 로그 레코드의 종류, 내용 등이 포함된다.

WAL을 직접 해석하여 트랜잭션을 처리하는 것은 복잡하기 때문에 일반적으로 Debezium과 같은 오픈 소스 CDC 플랫폼을 많이 사용한다. Debezium CDC 커넥터를 사용하면 WAL을 모니터링하여 데이터베이스에서 발생하는 모든 변경 사항을 감지하고 해당 변경 사항을 카프카 토픽으로 전송한다. 또한 전송된 변경사항을 싱크 커넥터로 연결하여 타겟 데이터베이스에 데이터를 적재하도록 할 수 있다.

Categories:

Updated:

Leave a comment