
RDS를 사용해 쉽고 간편하게 데이터베이스를 구축해보자! 아래에서는 프리티어 수준의 MySQL 엔진을 사용하는 RDS를 구축한다.
Amazon Relational Database Service(RDS)는 총 소유 비용에 최적화되고 쉽게 관리할 수 있는 관계형 데이터베이스 서비스입니다. 수요에 따라 간편하게 설정, 운영 및 확장할 수 있습니다. Amazon RDS는 프로비저닝, 구성, 백업, 패치 적용처럼 획일적인 데이터베이스 관리 작업을 자동화합니다.
AWS가 프로비저닝, 백업, 구성 등을 간편하게 관리해주는 관계형 데이터베이스 서비스이다. 특정 DB 엔진과 인스턴스 유형의 경우 프리티어로 제공된다.
Aurora는 AWS 자체 서비스로, RDS와 비교해서 더 높은 성능과 가용성을 제공한다. 클러스터로 구성되어 있으며, 클러스터 서비스답게 매우 비싸다. 반드시 비용을 제대로 고려해서 도입하자.
사용하는 인스턴스, 엔진에 따라 비용이 다르다. read replica나 multi-az를 사용하는 경우 해당 rds 인스턴스 비용의 2배가 발생한다.
rds의 특정 엔진(MySQL, MariaDB, PostgreSQL, SQL Server) 및 특정 인스턴스에서 프리티어를 사용할 수 있다. multi-az는 프리티어 범위를 벗어나니 조심하자.
MySQL 엔진을 선택한다.

템플릿은 프리티어를 선택한다.

프리티어 탬플릿을 선택했기 때문에, 배포 옵션은 단일 DB 인스턴스로 고정된다. 만약 Multi-AZ를 사용하고 싶다면 프리티어 외의 템플릿을 선택하자.

아래의 설정을 작성한다.

인스턴스 클래스를 선택한다.

스토리지는 프리티어로 제공되는 범용 SSD(gp2) 또는 마그네틱을 선택한다.

아래의 연결 설정을 작성한다.



데이터베이스 인증은 암호 인증을 사용한다.


파라미터 그룹을 통해 데이터베이스의 환경 설정을 진행한다.
파라미터 그룹을 통해 아래의 세 가지를 설정한다.
파라미터 그룹을 생성한다.

생성한 파라미터 그룹의 값을 수정한다.
time_zone -> Asia/Seoulcharacter_set_xxx -> utf8mb4collation_xxx -> utf8mb4_general_ci데이터베이스 설정을 수정해 방금 생성한 파라미터 그룹을 적용한다.


MySQL 워크밴치에서 RDS를 접속하기 위해서는 몇 가지 조건을 만족해야 한다.
만약 위에서 구축한 것과 같이 Private Subnet에 RDS를 위치하고, 퍼블릭 액세스를 허용하지 않았다면 워크밴치에서 접속이 불가능하다. 이 경우 아래의 EC2에서 RDS에 접속하는 방법을 참고해 접속하자.
MySQL 워크밴치에서 RDS를 접속하는 방법은 다음과 같다.

EC2에서 RDS에 접속하기 위해서는 MySQL Client 설치, RDS 보안그룹 설정이 필요하다.
먼저, EC2에 MySQL Client를 설치한다. MySQL 명령줄 클라이언트 설치를 참고해 적절한 명령어를 입력한다. Amazon linux 2023을 사용하는 경우, 아래의 명령어를 입력한다.
# MySQL Client 설치
sudo dnf install mariadb105
# MySQL Client 설치 확인
mysql --version
RDS 보안 그룹을 설정한다. 아래의 인바운드 규칙을 추가한다.
아래의 명령어를 입력해 MySQL에 접속한다. 접속 시 마스터 암호를 입력해야 한다.
mysql -u [마스터 사용자 이름] -p -h [rds 엔드포인트]
MySQL에 접속한 후 아래의 명령어를 입력해 위에서 설정한 초기 데이터베이스 이름이 있는지 확인한다.
show databases;



스프링부트 서버에서 읽기 전용 복제본은 생성한다고 바로 읽기 전용 복제본을 사용하지 않는다. 코드 자체에서도 설정이 필요하다.
jdbc-url이 아닌 url로 작성하면 오류가 발생하니 주의하자.spring:
datasource:
read:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: "jdbc:mysql://[엔드포인트]:3306/[스키마]?useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true"
username: [username]
password: [pw]
write:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: "jdbc:mysql://[엔드포인트]:3306/[스키마]?useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true"
username: [username]
password: [pw]
jpa:
database: mysql
show-sql: true
hibernate:
ddl-auto: update
properties:
hibernate:
format_sql: true
dialect: "org.hibernate.dialect.MySQL8Dialect"
public class DataSourceRouter extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
String lookupKey = TransactionSynchronizationManager.isCurrentTransactionReadOnly() ? "replica" : "master";
// System.out.println("Current DataSource is " + lookupKey); // 테스트용 로그
return lookupKey;
}
}
@Configuration
@RequiredArgsConstructor
@EnableJpaRepositories(basePackages = "패키지")
@EnableConfigurationProperties
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.write")
public DataSource writeDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.read")
public DataSource readDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean
@DependsOn({"writeDataSource", "readDataSource"})
public DataSource routeDataSource(
@Qualifier("writeDataSource") DataSource writeDataSource,
@Qualifier("readDataSource") DataSource readDataSource) {
DataSourceRouter dataSourceRouter = new DataSourceRouter();
HashMap<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put("write", writeDataSource);
dataSourceMap.put("read", readDataSource);
dataSourceRouter.setTargetDataSources(dataSourceMap);
dataSourceRouter.setDefaultTargetDataSource(writeDataSource);
return dataSourceRouter;
}
@Bean
@Primary
@DependsOn({"routeDataSource"})
public DataSource dataSource(@Qualifier("routeDataSource") DataSource routeDataSource) {
return new LazyConnectionDataSourceProxy(routeDataSource);
}
}