Skip to content

Commit

Permalink
feat-be: DataSource Routing을 통한 DB Read/Write 요청 분산 (#704)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Leetaehoon <66353672+xogns1514@users.noreply.github.com>
  • Loading branch information
github-actions[bot] and xogns1514 authored Sep 26, 2024
1 parent ce03ba0 commit bb12b49
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 15 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/be-cd_prod-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ jobs:
# DB Configuration secrets info from Github Secrets
DB_PORT=${{ secrets.DB_PORT }}
DB_IP_ADDRESS=${{ secrets.DB_IP_ADDRESS }}
DB_URL=${{ secrets.DB_URL }}
READ_DB_URL=${{ secrets.READ_DB_URL }}
WRITE_DB_URL=${{ secrets.WRITE_DB_URL }}
DB_USER=${{ secrets.DB_USER }}
DB_PASSWORD=${{ secrets.DB_PASSWORD }}
DDL_AUTO=${{ secrets.DDL_AUTO }}
Expand Down
59 changes: 59 additions & 0 deletions backend/src/main/java/com/cruru/config/DataSourceConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.cruru.config;

import com.zaxxer.hikari.HikariDataSource;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy;

@Configuration
public class DataSourceConfig {

private static final String READ_DATASOURCE = "readDataSource";
private static final String WRITE_DATASOURCE = "writeDataSource";
private static final String ROUTE_DATASOURCE = "routeDataSource";

@Bean(name = READ_DATASOURCE)
@ConfigurationProperties(prefix = "spring.datasource.read")
public DataSource readDataSource() {
return DataSourceBuilder.create()
.type(HikariDataSource.class)
.build();
}

@Bean(name = WRITE_DATASOURCE)
@ConfigurationProperties(prefix = "spring.datasource.write")
public DataSource writeDataSource() {
return DataSourceBuilder.create()
.type(HikariDataSource.class)
.build();
}

@Bean(name = ROUTE_DATASOURCE)
@DependsOn({READ_DATASOURCE, WRITE_DATASOURCE})
public DataSourceRouter routeDataSource() {
DataSourceRouter dataSourceRouter = new DataSourceRouter();
DataSource writeDataSource = writeDataSource();
DataSource readDataSource = readDataSource();

Map<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put(DataSourceRouter.READ_DATASOURCE_KEY, readDataSource);
dataSourceMap.put(DataSourceRouter.WRITE_DATASOURCE_KEY, writeDataSource);
dataSourceRouter.setTargetDataSources(dataSourceMap);
dataSourceRouter.setDefaultTargetDataSource(writeDataSource());
return dataSourceRouter;
}

@Bean
@Primary
@DependsOn(ROUTE_DATASOURCE)
public DataSource defaultDataSource() {
return new LazyConnectionDataSourceProxy(routeDataSource());
}
}
18 changes: 18 additions & 0 deletions backend/src/main/java/com/cruru/config/DataSourceRouter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.cruru.config;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.transaction.support.TransactionSynchronizationManager;

public class DataSourceRouter extends AbstractRoutingDataSource {

public static final String READ_DATASOURCE_KEY = "read";
public static final String WRITE_DATASOURCE_KEY = "write";

@Override
protected Object determineCurrentLookupKey() {
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
return READ_DATASOURCE_KEY;
}
return WRITE_DATASOURCE_KEY;
}
}
47 changes: 34 additions & 13 deletions backend/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ spring:
console:
enabled: true
datasource:
url: jdbc:h2:mem:database;MODE=MySQL;
read:
jdbc-url: jdbc:h2:mem:database;MODE=MySQL;
write:
jdbc-url: jdbc:h2:mem:database;MODE=MySQL;
flyway:
enabled: false
jpa:
Expand Down Expand Up @@ -68,10 +71,16 @@ spring:
activate:
on-profile: dev
datasource:
url: ${DB_URL}
driver-class-name: com.mysql.cj.jdbc.Driver
username: ${DB_USER}
password: ${DB_PASSWORD}
read:
jdbc-url: ${DB_URL}
driver-class-name: com.mysql.cj.jdbc.Driver
username: ${DB_USER}
password: ${DB_PASSWORD}
write:
jdbc-url: ${DB_URL}
driver-class-name: com.mysql.cj.jdbc.Driver
username: ${DB_USER}
password: ${DB_PASSWORD}
flyway:
enabled: true
baseline-on-migrate: true
Expand Down Expand Up @@ -147,10 +156,16 @@ spring:
activate:
on-profile: test
datasource:
url: ${DB_URL}
driver-class-name: com.mysql.cj.jdbc.Driver
username: ${DB_USER}
password: ${DB_PASSWORD}
read:
jdbc-url: ${DB_URL}
driver-class-name: com.mysql.cj.jdbc.Driver
username: ${DB_USER}
password: ${DB_PASSWORD}
write:
jdbc-url: ${DB_URL}
driver-class-name: com.mysql.cj.jdbc.Driver
username: ${DB_USER}
password: ${DB_PASSWORD}
flyway:
enabled: true
baseline-on-migrate: true
Expand Down Expand Up @@ -225,10 +240,16 @@ spring:
activate:
on-profile: prod
datasource:
url: ${DB_URL}
driver-class-name: com.mysql.cj.jdbc.Driver
username: ${DB_USER}
password: ${DB_PASSWORD}
read:
jdbc-url: ${READ_DB_URL}
driver-class-name: com.mysql.cj.jdbc.Driver
username: ${DB_USER}
password: ${DB_PASSWORD}
write:
jdbc-url: ${WRITE_DB_URL}
driver-class-name: com.mysql.cj.jdbc.Driver
username: ${DB_USER}
password: ${DB_PASSWORD}
flyway:
enabled: true
baseline-on-migrate: true
Expand Down
37 changes: 37 additions & 0 deletions backend/src/test/java/com/cruru/config/DataSourceRouterTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.cruru.config;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.transaction.support.TransactionSynchronizationManager;

@DisplayName("Datasource Routing 테스트")
class DataSourceRouterTest {

private final DataSourceRouter dataSourceRouter = new DataSourceRouter();

@Test
void determineCurrentLookupKeyForReadOnlyTransaction() {
// given
TransactionSynchronizationManager.setCurrentTransactionReadOnly(true);

// when
Object lookupKey = dataSourceRouter.determineCurrentLookupKey();

// then
assertThat(lookupKey).isEqualTo(DataSourceRouter.READ_DATASOURCE_KEY);
}

@Test
void determineCurrentLookupKeyForReadWriteTransaction() {
// give
TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);

// when
Object lookupKey = dataSourceRouter.determineCurrentLookupKey();

// then
assertThat(lookupKey).isEqualTo(DataSourceRouter.WRITE_DATASOURCE_KEY);
}
}
5 changes: 4 additions & 1 deletion backend/src/test/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ spring:
console:
enabled: true
datasource:
url: jdbc:h2:mem:database;MODE=MySQL;
read:
jdbc-url: jdbc:h2:mem:database;MODE=MySQL;
write:
jdbc-url: jdbc:h2:mem:database;MODE=MySQL;
flyway:
enabled: false
jpa:
Expand Down

0 comments on commit bb12b49

Please sign in to comment.