master-slave

ClassBinu·2024년 6월 19일

F-lab

목록 보기
54/65

진짜 하루 종일 삽질함.
근데 덕분에 docker-compose 써보고, docker 명령어 좀 익숙해짐.
psql로 cli에서 DB다루고 쿼리 날리는 것도 해봄.

  1. typrORM 레플리카 설정으로 자동으로 마스터/슬레이브 쿼리를 나눴다.
    근데 자꾸 회원가입은 User Create인데 슬레이브로 쿼리가 날아간다.

다음 코드가 문제였다.

    const userExists = await this.usersService.findByUsername(
      createUserDto.username,
    );

회원가입 전 먼저 유저가 존재하는지 읽어오는데, 여기서 아직 스키마가 생성되지 않은 슬레이브로 접근해서 생기는 문제였다.

  1. 슬레이브 DB는 synchronize: true 적용이 안 됨.

커스텀 지정

const masterQueryRunner = dataSource.createQueryRunner("master")
try {
    const postsFromMaster = await dataSource
        .createQueryBuilder(Post, "post", masterQueryRunner) // you can either pass QueryRunner as an optional argument with query builder
        .setQueryRunner(masterQueryRunner) // or use setQueryRunner which sets or overrides query builder's QueryRunner
        .getMany()
} finally {
    await masterQueryRunner.release()
}

수동으로 생성된 QueryRunner인스턴스는 자체적으로 명시적으로 해제되어야 합니다. 쿼리 실행기를 해제하지 않으면 풀에서 연결이 체크아웃된 상태로 유지되고 다른 쿼리에서 해당 연결을 사용하지 못하게 됩니다.

볼륨 마운트

이거 때문에 하루 종일 실패함..

    volumes:
      - slave_data:/var/lib/postgresql/data
      - ./pg_hba.conf:/etc/postgresql/pg_hba.con

요지는 최초 컨테이너 실행 시 마운트 경로에는 아무 것도 없어어ㅑ 하는데,
같은 경로로 마운트를 동시에 연결해서 충돌이 생기는 거였음.

요점은 PostgreSQL 컨테이너를 처음 실행할 때 /var/lib/postgresql/data 디렉토리가 비어 있어야 하는데, 동일한 경로에 여러 파일을 마운트하면서 충돌이 발생한 것입니다.

WAL

WAL(Write-Ahead Logging)은 데이터베이스 시스템에서 데이터 무결성과 복구를 보장하기 위해 사용되는 기술
WAL의 주요 목적은 데이터베이스 트랜잭션을 로그에 기록하여 시스템 오류나 충돌 후에도 데이터 무결성을 유지하고, 복구를 가능하게 하는 것

  • 동작 원리
  1. 데이터베이스 트랜잭션이 발생하면, 해당 트랜잭션의 변경 사항이 WAL에 먼저 기록
  2. 트랜잭션이 커밋되면, WAL에 기록된 변경 사항이 데이터베이스 파일에 적용
  3. 일정 주기마다 데이터베이스는 체크포인트를 생성합니다. 체크포인트는 WAL의 특정 시점까지의 모든 변경 사항이 데이터베이스 파일에 적용되었음을 나타냅니다. 체크포인트 이후의 트랜잭션은 복구 시 WAL을 재생하여 반영됩니다.
  4. 시스템 오류나 충돌이 발생하면, 마지막 체크포인트 이후의 WAL 로그를 재생하여 데이터베이스를 복구

복제 원리

도커로 DB 띄우면서 알게 된 것

  1. DB 볼륨 마운트 폴더는 1개만 연결할 수 있음.
    /var/lib/postgresql/data

  2. pg_gba.conf는 etc의 위치에 있기만 하면 됨

  3. postgresql.conf는 위치 알려줘야 함 (커맨드 명령어)

  4. 기본적으로 public 스키마 안에 테이블이 만들어 짐. psql에서 스키마는 테이블의 폴더 같은 느낌
    DB > 스키마 > 테이블 이 구조
    DB가 물리적 구분이라면 스키마는 논리적 구분 같은 느낌?

docker-compose

다중 컨테이너 Docker 애플리케이션을 정의하고 실행하는 도구

postgres & psql

postgres 명령어는 PostgreSQL 서버 자체를 실행하고 설정 파일을 지정하는 데 사용됩니다.
psql 명령어는 PostgreSQL에 대한 대화형 터미널 클라이언트입니다.

docker -it

i 옵션: 터미널 내부에서 입력할 수 있게 함. 표준 입력을 컨테이너 내부 프로세스로 전달
t 옵션: 터미널 실행

postgresql.conf

슬레이브에 listen 설정 안 돼서 계속 접속이 안 됨

hot_standby = on
listen_addresses = '*'

아니, 슬레이브를 클라이언트에서 접속 하지 않는 경우도 있어?
ㅇㅇ 있음
슬레이브 서버는 백업 또는 분석 작업에만 사용 경우

컨테이너 통신

primary_conninfo = 'host=postgres_master port=5432 user=masteruser password=masterpassword sslmode=prefer sslcompression=1'

여기서 host를 localhost가 아니라 컨테이너 서비스 이름으로 해도 compose로 실행되는 컨테이너는 기본적으로 서비스 간 네트워킹이 설정됨. 그래서 서비스 이름을 호스트로 사용하여 접근할 수 있음.

docker compose 내부 네트워크

Docker Compose는 같은 네트워크에 속한 서비스들이 서로의 서비스 이름을 호스트 이름으로 사용하여 통신할 수 있도록 합니다.

standby.signal

네, PostgreSQL 12 이상 버전에서는 슬레이브 서버를 핫 스탠바이 모드로 설정하기 위해 standby.signal 파일을 생성하는 것이 필수?? 진짜??

연결 확인

슬레이브에서 이 쿼리에 연결 상태가 나와야 함

SELECT * FROM pg_stat_wal_receiver;

복제 방식

Log-shipping

동기
Master의 WAL 파일 자체를 전송하는 방식
응답이 없으므로 유실 가능
WAL 파일이 크기를 다 채워야만 Slave로 전송
WAL 파일의 크기를 채우는 동안 Master와 Slave는 동일하지 않은 데이터로 인해 불일치.

Streaming

동기, 비동기
Master의 WAL 내용을 전송하는 방식
복제 응답이 있음
단, wal_keep_segments 한도 내에서 덮어쓰기가 일어나므로 전송이 지연되면 wal 파일 덮어쓰기로 인해 유실 가능

마스터에서는 센터 프로세스, 슬레이브에서는 리시버 프로세스가 동작

권한

설정을 모두 열어놓았음에도 불구하고 slaveuser가 필요한 이유는 복제 및 데이터베이스 접근에 있어서 PostgreSQL이 사용자(role) 기반의 권한 관리를 수행하기 때문입니다. 권한 설정(pg_hba.conf)이 아무리 허용적이라 할지라도, 사용자 계정 자체가 데이터베이스 시스템에 존재하지 않으면 접근할 수 없습니다.

0개의 댓글