프로젝트/개인 프로젝트 리팩토링

[개인프로젝트 리팩토링] 데이터베이스 레플리케이션 적용하기

dal_been 2024. 8. 3. 22:58
728x90

데이터베이스 레플리케이션을 적용해보았따.

 

 


레플리케이션 왜 필요한가?

 

보통 개인프로젝트 하다보면 데이터베이스를 한대만 운영한다. 데이터를 읽고 쓰는 작업이 하나의 데이터베이스에서 수행된다는 의미다

 

근데 갑자기 트래픽이 폭주했다고 가정해보자.

DB관점에서는 크게 2가지문제가 발생가능하다.

 

1. SPOF

물론 트랙픽에 대응해 DB성능 한대의 성능을 Scale up하는 방법도 존재한다. 그러나 한대의 데이터베이스가 다운될 경우 그냥 서비스가 다운이다. 데이터를 백업하지 않았다면 더 큰일... 

그래서 SPOF 하나의 장애가 시스템 전체 장애로 이어지는 상황이 발생하게 된다.

 

2. 성능저하

하나의 데이터베이스에 읽고 쓰는 작업이 모두 일어나다보면 부하가 늘어난다. 물론 이부분도 DB성능을 향상시키는 방법도 존재하지만...

부하가 발생할때마다 scale up 하는 것은 비용부분등이 쉽지 않을 것이다.

 

 

그래서 생각한 방법은 Replication이다.

서버는 하나의 DB에 데이터 쓰기 작업을 요청하고 또다른 DB에는 읽기작업을 요청하는 것이다.

즉 읽기 작업과 쓰기 작업의 부하를 분산시킨다. 

다만 데이터에 대한 정합성 문제를 해결해야한다.

 

 

적용해보기

 

우선 두개의 DB가 필요하다. (Master DB : write, Replica DB : read)

그래서 나는 Docker를 통해 2개를 준비했다.

두개의 DB에 모두 사용할 USER 계정을 생성해주고 데이터베이스를 생성해준다.

CREATE USER 'hello'@'%' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'hello'@'%';
FLUSH PRIVILEGES;

CREATE DATABASE TEST;
  • 계정 생성과 함께 모든 데이터베이스에 대한 권한을 부여하였다

 

DB서버 하나 먼저 세팅 (Master 서버)

/etc/mysql/my.cnf에 들어가서

[mysqld]
server-id = 1
log-bin = mysql-bin
binlog_format = ROW
max_binlog_size = 500M
sync_binlog = 1
expire-logs-days = 7
binlog_do_db = test

 

  • server-id : 서버의 ID. 레플리케이션 토폴로지 내의 서버는 고유한 서버 ID를 가져야한다.
  • log-bin : 바이버리 로그파일 경로
  • binlog_format : 바이너리 로그의 저장형식을 지정
  • max_binlog_size : 바이너리 로그의 최대 크기
  • sync_binlog: N개의 트랜젝션마다 바이너리 로그를 디스크에 동기화 시킬지 결정
  • expire-logs-days: 바이너리 로그가 만료되는 기간설정
  • binlog_do_db: 레이리케이션을 적용한 데이터베이스 이름 설정(설정하지 않으면 모든 데이터베이스가 대상이 됨)

 

Replica 서버가 Master 서버의 바이너리 로그 좌표를 알아야 데이터를 업데이트할 수 있따.

그래서 Master DB에 접속하여 아래 명령어를 통해 file과 position 값을 기억해두자.

show master status

 

이후 Master DB에 밑에 명령어를 해준다.

Master서버가 구동중이라면 데이터변경이 발생하면 바이너리 로그 좌표값이 변하기 때문이다.

Flush tables with read lock

 

 

Replica 서버 세팅

 

앞서 이야기했다싶이 레플리케이션 토폴로지 내에서는 모든 서버가 유일한 server-id를 가져야한다.

아래와 같이 세팅해준다

/etc/mysql/my.cnf에 들어가서

[mysqld]
server-id = 2

 

이후 Replica서버에 접속하여 

RESET REPLICA;

CHANGE MASTER TO
MASTER_HOST= #Master Server IP,
MASTER_USER= #Replication용 USER,
MASTER_PASSWORD= #Replication용 USER PW,
MASTER_LOG_FILE= #Master 서버 bin_log 파일,
MASTER_LOG_POS= #Master 서버 bin_log Position;

 

 

여기까지 마무리했다면 Master 서버에 insert하면 Replica 서버에도 반영되는 것을 볼 수 있따.

 


 

이후 SpringBoot에서 DataSource에 대한 분기가 필요하다.

트랜젝션 readonly가 true인 경우 Replica에서 false인경우 Master에서 하도록 분기해야한다. 이에 대한 내용은 다음 블로그에

적을 예정이다.