디렉토리 구조

Docker Compose를 사용하여 MySQL 데이터베이스 구성
// docker-compose.yml
version: "1"
services:
# main 데이터베이스 서비스 정의
db-main:
# Dockerfile을 사용하여 이미지 빌드
build:
context: ./
dockerfile: main/Dockerfile
# 컨테이너 재시작 설정
restart: always
# 플랫폼 설정
platform: linux/x86_64
# 환경 변수 설정
environment:
MYSQL_DATABASE: 'db'
MYSQL_USER: 'user'
MYSQL_PASSWORD: '1234'
MYSQL_ROOT_PASSWORD: '1234'
# MySQL 서버 설정
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
# 포트 포워딩 설정
ports:
- '3307:3306'
# 컨테이너 이름 설정
container_name: main-db
# 볼륨 설정
volumes:
- my-db-main:/var/lib/mysql
- my-db-main:/var/lib/mysql-files
# 네트워크 설정
networks:
- net-mysql
# replica 데이터베이스 서비스 정의
db-replica:
# Dockerfile을 사용하여 이미지 빌드
build:
context: ./
dockerfile: replica/Dockerfile
# 컨테이너 재시작 설정
restart: always
# 플랫폼 설정
platform: linux/x86_64
# 환경 변수 설정
environment:
MYSQL_DATABASE: 'db'
MYSQL_USER: 'user'
MYSQL_PASSWORD: '1234'
MYSQL_ROOT_PASSWORD: '1234'
# MySQL 서버 설정
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
# 포트 포워딩 설정
ports:
- '3308:3306'
# 컨테이너 이름 설정
container_name: replica-db
# 볼륨 설정
volumes:
- my-db-replica:/var/lib/mysql
- my-db-replica:/var/lib/mysql-files
# 네트워크 설정
networks:
- net-mysql
# 볼륨 설정
volumes:
my-db-main:
my-db-replica:
# 네트워크 설정
networks:
net-mysql:
driver: bridge
Main DB 파일
// docker/main/Dockerfile
# MySQL 8.0 이미지를 기반으로 함
FROM mysql:8.0
# 로컬 파일 시스템에서 main 디렉토리에 있는 my.cnf 파일을 컨테이너 내부의 /etc/mysql/my.cnf 경로로 복사함
ADD ./main/my.cnf /etc/mysql/my.cnf
// docker/main/my.cnf
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
default-time-zone='+9:00'
# 바이너리 로그 활성화
log-bin = mysql-bin
# 서버 식별 ID 설정
server-id = 1
# 기본 인증 플러그인 설정
default_authentication_plugin=mysql_native_password
Replica DB 파일
// docker/replica/Dockerfile
# MySQL 8.0 이미지를 기반으로 함
FROM mysql:8.0
# 로컬 파일 시스템에서 replica 디렉토리에 있는 my.cnf 파일을 컨테이너 내부의 /etc/mysql/my.cnf 경로로 복사함
ADD ./replica/my.cnf /etc/mysql/my.cnf
// docker/replica/my.cnf
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
default-time-zone='+9:00'
# 바이너리 로그 활성화
log_bin = mysql-bin
# 서버 식별 ID 설정
server_id = 2
# MySQL 슬레이브 서버에서 사용되는 중계 로그의 저장 위치를 지정합니다.
relay_log = /var/lib/mysql/mysql-relay-bin
# 이 설정은 슬레이브 서버에서 발행된 변경 사항도 바이너리 로그에 기록하도록 허용합니다.
# 기본적으로, 슬레이브 서버에서 변경 사항은 바이너리 로그에 기록되지 않습니다.
log_slave_updates = 1
# 슬레이브 서버를 읽기 전용 모드로 설정합니다.
read_only = 1
# 기본 인증 플러그인 설정
default_authentication_plugin = mysql_native_password
application.yml
spring:
datasource:
main:
hikari:
jdbc-url: jdbc:mysql://localhost:3307/popcorntalk
read-only: false
username: root
password: 1234
driver-class-name: com.mysql.cj.jdbc.Driver
replica:
hikari:
jdbc-url: jdbc:mysql://localhost:3308/popcorntalk
read-only: true
username: root
password: 1234
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
properties:
hibernate:
show_sql: true
format_sql: true
highlight_sql: true
dialect: org.hibernate.dialect.MySQLDialect
MySQL Replication 설정
1. compose 실행 → docker-compose up -d
2. 메인 DB의 IP Address 조회 → docker network ls
3. 메인 DB의 status 조회, File과 Position 기록 → mysql-bin.000004, 157

4. 레플리카 DB 접속 -> 레플리카를 메인과 연결
MASTER_HOST : master 서버의 호스트명
MASTER_USER : master 서버의 mysql에서 REPLICATION SLAVE 권한을 가진 User 계정의 이름
MASTER_PASSWORD : master 서버의 mysql에서 REPLICATION SLAVE 권한을 가진 User 계정의 비밀번호
MASTER_LOG_FILE : master 서버의 바이너리 로그 파일명
MASTER_LOG_POS : master 서버의 현재 로그의 위치

6. 레플리카 DB 실행 → start replica;
7. replication 설정확인 → show replica status\G;
- Replica_IO_Running: 이 변수는 메인 서버에서 바이너리 로그를 읽는 I/O 스레드가 실행 중인지 여부를 나타냅니다. 이 변수가 "YES"로 설정되면 I/O 스레드가 실행 중이고 메인 서버의 바이너리 로그에서 업데이트를 성공적으로 가져오는 것을 의미합니다.
- Replica _SQL_Running: 이 변수는 I/O 스레드가 바이너리 로그에서 검색한 이벤트를 실행하는 SQL 스레드가 실행 중인지 여부를 나타냅니다. 이 변수가 "YES"로 설정되면 SQL 스레드가 실행 중이고 복제본 데이터베이스에 이벤트가 성공적으로 적용되고 있음을 의미합니다.

DataSourceConfig
@Configuration
public class DataSourceConfig {
// Main 데이터 소스 빈 이름
public static final String MAIN_DATASOURCE = "mainDataSource";
// Replica 데이터 소스 빈 이름
public static final String REPLICA_DATASOURCE = "replicaDataSource";
// Main 데이터 소스 빈 설정
@Bean(MAIN_DATASOURCE)
@ConfigurationProperties(prefix = "spring.datasource.main.hikari")
public DataSource mainDataSource() {
return DataSourceBuilder.create()
.type(HikariDataSource.class)
.build();
}
// Replica 데이터 소스 빈 설정
@Bean(REPLICA_DATASOURCE)
@ConfigurationProperties(prefix = "spring.datasource.replica.hikari")
public DataSource replicaDataSource() {
return DataSourceBuilder.create()
.type(HikariDataSource.class)
.build();
}
// 라우팅 데이터 소스 빈 설정
@Bean
@DependsOn({MAIN_DATASOURCE, REPLICA_DATASOURCE})
public DataSource routingDataSource(
@Qualifier(MAIN_DATASOURCE) DataSource mainDataSource,
@Qualifier(REPLICA_DATASOURCE) DataSource replicaDataSource) {
RoutingDataSource routingDatasource = new RoutingDataSource();
// 데이터 소스 맵 구성
Map<Object, Object> dataSourceMap = new HashMap<>() {
{
put("main", mainDataSource);
put("replica", replicaDataSource);
}
};
// 데이터 소스 맵 설정
routingDatasource.setTargetDataSources(dataSourceMap);
// 기본 데이터 소스는 Main으로 설정
routingDatasource.setDefaultTargetDataSource(mainDataSource);
return routingDatasource;
}
// 기본 데이터 소스 빈 설정
@Primary
@Bean
@DependsOn("routingDataSource")
public LazyConnectionDataSourceProxy dataSource(DataSource routingDataSource) {
return new LazyConnectionDataSourceProxy(routingDataSource);
}
}
RoutingDataSource
@Slf4j
public class RoutingDataSource extends AbstractRoutingDataSource {
// 현재 사용할 데이터 소스 키를 결정하는 메서드
@Override
protected Object determineCurrentLookupKey() {
// 현재 트랜잭션이 읽기 전용인지 확인하여 데이터 소스를 결정
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
log.info("replicaDB"); // replica DB 사용 확인 테스트
return "replica"; // 복제 데이터 소스 선택
}
log.info("mainDB"); // main DB 사용 확인 테스트
return "main"; // 메인 데이터 소스 선택
}
}'기술 블로그' 카테고리의 다른 글
| AWS EC2 & IaaS, PaaS, SaaS (0) | 2024.04.13 |
|---|---|
| MySQL Replication (0) | 2024.04.11 |
| Project Day 5 : S.A 피드백 수정 (0) | 2024.04.01 |
| Project Day 4 : 일주일 회고 (0) | 2024.03.29 |
| Project Day 1 : 주제 정하기 (2) | 2024.03.26 |