[오늘의코딩] Step3. 백엔드 - 데이터베이스 연결
Machine translation — switch to KO for the original.
JAVA 17, Spring Boot 3.0.2, Gradle, MySQL, Redis로 만드는
'오늘의코딩' 메일링 서비스
데이터베이스 연결방식
이번 프로젝트의 큰 목표는 Redis와 MySQL을 둘 다 사용하는 부분이기 때문에 Redis Cache를 Write-Through 방식으로 사용하기로 했다. 프로젝트에서 두 데이터베이스에 업데이트를 한다고 해도 그 비중이 크지 않고, 예상되는 타겟층도 크지 않아서 성능상에 무리가 없을 것으로 예측하고 진행했다.
서비스 리스트를 한 번에 가져와서 Redis Cache를 이용하는게 RDB를 거치지 않아도 빠르게 접근가능한 부분을 많이 만들고 싶었고, 그 외에도 Cache에 두지 않고 RDB에 접근해야 하는 부분들도 있었기에 Write-Through 방식이 적합했다.
MySQL, Redis Connection Test
MySQL과 Redis 연결 test를 진행했다. 둘 다 잘 연결이 되어 있는지 확인하기 위해서 다음 코드들을 사용했고, 나와 같은 고민이 있던 사람들에게 도움이 되었으면 좋겠다.
build.gradle
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
runtimeOnly 'com.mysql:mysql-connector-j'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
MySQL Connection Test
package com.toco.trialService.databaseTest;
import org.junit.jupiter.api.*;
import java.sql.Connection;
import java.sql.DriverManager;
public class DatabaseConnectionTest {
private static final String URL = "jdbc:mysql://127.0.0.1:3306/world";
private static final String User = "root";
private static final String Password = "0000"; // 임의의 패스워드
@Test
public void rdbConnectionTest() {
try(Connection conn = DriverManager.getConnection(URL, User, Password)) {
System.out.println(conn);
// com.mysql.cj.jdbc.ConnectionImpl@3697186
}catch(Exception e){
System.out.println(e.getMessage());
}
}
}
Redis Connection Test
package com.toco.trialService.databaseTest;
import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import org.junit.jupiter.api.*;
import static org.springframework.test.util.AssertionErrors.assertTrue;
public class RedisConnectionTest {
private RedisClient redisClient;
private StatefulRedisConnection connection;
private RedisCommands redisCommands;
@BeforeEach
public void beforeConnectDatabase(){
redisClient = RedisClient.create("redis://localhost:6379");
connection = redisClient.connect();
redisCommands = connection.sync();
}
@AfterEach
public void afterConnectDatabase(){
connection.close();
redisClient.shutdown();
}
@Test
public void inMemoryConnectionTest() {
assertTrue("Redis connection test failed", redisCommands.ping().equals("PONG"));
}
}
※
Lettuce version 3.0.5에서는 더 이상 DefaultClientResources 클래스를 사용하지 않고, 새 Redis 클라이언트 객체 생성으로 RedisClient를 사용한다. 생성시에는 위 코드와 같이 create([url])을 사용하고, 사용이 끝난 시점에서는 shutdown(); 처리를 해주자.
Redis Caching 전략에 따른 고찰
Caching 전략으로 이걸 사용하는게 맞을까?
프로젝트를 만들면서 이런 고민을 제일 많이 했던 것 같다.
Redis Caching을 어떻게 활용할 것인가에 대한 고민이 많았다. 현업과 서비스에 따라 방식이 달라져야겠지만, 지금 만들고자 하는 프로젝트는 동시성을 제공해야 하며 데이터 유실을 최대한 막고 싶었고 그래서 선택하게 된 방식이 Write-Through 였다.
하지만 Write-Around 방식도 있고, 이 경우에는 대용량 서비스 처리에서는 유실가능성을 고려해야한다. RDBMS Data가 최신이 아닐 수 있기 때문에 RDBMS Data를 in-memory 로 정기적으로 Pushing 처리해주는 방식을 같이 사용된다.
Caching 전략에 따라 불필요한 캐쉬 데이터를 가지고 있는 건 메모리 낭비로 이어질 수 있기 때문에 오히려 성능을 떨어뜨릴 수 있다.
따라서 적절한 TTL처리와 성능 개선에 필요한 주요데이터(UPDATE가 많이 발생하지 않는)만을 @RedisCache 처리해서 사용했다. 이번 프로젝트에서는 Program, ProgramDetail, Categories 처럼 update가 많지 않을 것으로 예상되는 항목만에만 적용했다.
Comments
No comments yet. Be the first!
318 posts in 테크
- 341Migrating from Permanent Access Tokens to Token Exchange — Why Order Matters
- 326Startup & Product Glossary: Terms Every Solo Founder Should Know
- 325Context Management — How I Do It Now
- 324Claude Code Routines vs Cowork Schedule — What's the Difference?
- 323로컬 LLM + Claude Code로 PM 업무 자동화 에이전트 만들기