Skip to content

Commit

Permalink
feat: 데이터베이스 Replication 구성에 따른 Read / Write 분리하기 (#592)
Browse files Browse the repository at this point in the history
* feat: DataSource 연결 안됨.

* feat: prod 환경에 Read, Write Datasource 구분하여 연결

* feat: prod 환경에 Read, Write Datasource 구분하여 연결

* fix: rds 연결 불가 버그 수정

* feat: 서버 증가로 인한 CD 수정

---------

Co-authored-by: Arachneee <[email protected]>
  • Loading branch information
kunsanglee and Arachneee authored Sep 24, 2024
1 parent 243cd0d commit 0290f46
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 1 deletion.
38 changes: 38 additions & 0 deletions .github/workflows/backend-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,41 @@ jobs:

- name: Docker run
run: sudo docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=dev -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }}

deploy-prod-1:
needs: build
runs-on: [ self-hosted, backend-prod-1 ]
steps:
- name: Docker remove
run: |
CONTAINER_IDS=$(sudo docker ps -qa)
if [ -n "$CONTAINER_IDS" ]; then
sudo docker rm -f $CONTAINER_IDS
else
echo "No running containers found."
fi
- name: Docker Image pull
run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }}

- name: Docker run
run: sudo docker run -d -p 80:8080 -e SPRING_PROFILES_ACTIVE=prod -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }}

deploy-prod-2:
needs: build
runs-on: [ self-hosted, backend-prod-2 ]
steps:
- name: Docker remove
run: |
CONTAINER_IDS=$(sudo docker ps -qa)
if [ -n "$CONTAINER_IDS" ]; then
sudo docker rm -f $CONTAINER_IDS
else
echo "No running containers found."
fi
- name: Docker Image pull
run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }}

- name: Docker run
run: sudo docker run -d -p 80:8080 -e SPRING_PROFILES_ACTIVE=prod -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }}
1 change: 1 addition & 0 deletions server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ dependencies {

compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'

runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.mysql:mysql-connector-j'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package server.haengdong.infrastructure;

import com.zaxxer.hikari.HikariDataSource;
import jakarta.persistence.EntityManagerFactory;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
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.context.annotation.Profile;
import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

@Profile("prod")
@Configuration
public class DataSourceConfig {

private static final String PRIMARY = "primary";
private static final String SECONDARY = "secondary";

@ConfigurationProperties(prefix = "spring.datasource.hikari.primary")
@Bean
public DataSource primaryDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}

@ConfigurationProperties(prefix = "spring.datasource.hikari.secondary")
@Bean
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}

@DependsOn({"primaryDataSource", "secondaryDataSource"})
@Bean
public DataSource routingDataSource(
@Qualifier("primaryDataSource") DataSource primary,
@Qualifier("secondaryDataSource") DataSource secondary) {
DynamicRoutingDataSource routingDataSource = new DynamicRoutingDataSource();

Map<Object, Object> dataSourceMap = new HashMap<>();

dataSourceMap.put(PRIMARY, primary);
dataSourceMap.put(SECONDARY, secondary);

routingDataSource.setTargetDataSources(dataSourceMap);
routingDataSource.setDefaultTargetDataSource(primary);

return routingDataSource;
}

@DependsOn({"routingDataSource"})
@Primary
@Bean
public DataSource dataSource(DataSource routingDataSource) {
return new LazyConnectionDataSourceProxy(routingDataSource);
}

@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
return jpaTransactionManager;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package server.haengdong.infrastructure;

import static org.springframework.transaction.support.TransactionSynchronizationManager.isCurrentTransactionReadOnly;

import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

@Slf4j
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {

private static final String PRIMARY = "primary";
private static final String SECONDARY = "secondary";

@Override
protected Object determineCurrentLookupKey() {
return isCurrentTransactionReadOnly() ? SECONDARY : PRIMARY;
}
}
2 changes: 1 addition & 1 deletion server/src/main/resources/config

0 comments on commit 0290f46

Please sign in to comment.