PJT
PJT - 티어 갱신 1분 단위일 때의 기술 정리
1. Redis 관련 핵심 개념 (Memory & Concurrency)
- 동시성 제어
- 데이터 유실 방지
📌 Write-Behind (Write-Back) 패턴
- 개념: 데이터를 DB에 즉시 쓰지 않고(Write-Through), 캐시(Redis)에 모았다가 나중에 한꺼번에 DB에 저장하는 방식
- PJT 적용: 1분 동안 발생한 공부 시간/점수를 Redis에 모아두었다가 스케줄러가 DB에 한 번만
UPDATE합니다. - 면접 질문: Redis가 죽으면 데이터 다 날아가는 거 아니에요?
- 맞음. Write-Behind는 정합성(Consistency)보다 처리량(Throughput)을 중시하는 패턴
- 그럼 어떻게 해결? Redis의 AOF(Append Only File)나 RDB(Snapshot) 설정을 통해 데이터 유실을 최소화하는 방향 존재
📌 Redis의 단일 스레드(Single Thread)와 원자성(Atomicity)
- 개념: Redis는 기본적으로 싱글 스레드 이벤트 루프 모델임. 따라서 한 번에 하나의 명령어만 처리함.
- →
synchronized키워드 없이도 동시성 문제가 발생하지 않음 (Race Condition 방지).
- →
- PJT 적용:
increment(HINCRBY) 명령어는 원자적- Consumer가 값을
+1하는 순간과, Scheduler가 값을10하는 순간이 절대 겹치지 않음
- 주의할 점:
- Java 코드 레벨에서
get하고 값을 수정한 뒤set을 하면 동시성 문제 생김 - ✅ Redis 명령어 자체(
increment)를 써야만 안전합니다.
- Java 코드 레벨에서
📌 자료구조: Hash vs String
- 개념:
- String: Key-Value 1:1 매핑. (
study:session:{sessionId}:info) - Hash: 하나의 Key 안에 여러 Field-Value 존재. (
study:member:{id}:delta)
- String: Key-Value 1:1 매핑. (
- 왜 Hash를 썼는가?
- 멤버 ID 하나에
time_min,score_point,buffer등 관련 데이터를 그룹화해서 관리하기 위함 - 메모리 효율이 좋고,
HMGET으로 한 번에 가져올 수 있어 네트워크 왕복(RTT)을 줄일 수 있음
- 멤버 ID 하나에
2. Kafka 관련 핵심 개념 (Messaging & Ordering)
- 순서 보장
- 처리 효율
📌 배치 리스너 (Batch Listener)
- 개념
- Kafka Consumer가 메시지를 하나씩(
Record) 처리하는 게 아니라, 설정된 개수나 시간만큼 모아서List<Record>형태로 한 번에 처리하는 방식
- Kafka Consumer가 메시지를 하나씩(
- PJT 적용:
List<StudyLogRequest> logs로 받아서 루프를 돌리는 중 - 장점: Redis와의 네트워크 통신 횟수를 획기적으로 줄일 수 있음 (건건이 통신 vs 모아서 통신)
📌 파티션(Partition)과 순서 보장 (매우 중요 ⭐️)
- 개념
- Kafka는 전체 토픽의 순서는 보장하지 않지만, 하나의 파티션 내에서는 순서를 보장
- 위험 포인트
- 만약 AI 서버가 로그를 보낼 때
sessionId나memberId를 Key로 지정하지 않고 보내면, 로그가 여러 파티션에 라운드 로빈으로 뿌려질 수 있음
- 만약 AI 서버가 로그를 보낼 때
- 해결책
- AI 서버에서 Kafka로 보낼 때 반드시
sessionId를 Key로 설정해서 보내야 함 - 그래야 같은 세션의 로그는 무조건 같은 파티션으로 들어가서 순서가 지켜짐
- AI 서버에서 Kafka로 보낼 때 반드시
📌 Offset과 Commit
- 개념: 어디까지 읽었는지 표시하는 책갈피
- PJT 적용: 배치 처리를 하다가 중간에 에러가 나면 어떻게 할 것인가?
- Batch Listener는 기본적으로 배치가 전부 성공해야 커밋을 진행함. 하나라도 터지면 배치가 다시 들어올 수 있음(재처리).
- 이 때문에 Redis 연산은 멱등성(여러 번 해도 결과가 같음)이 보장되거나, 재처리 되어도 괜찮은지 고민해봐야 함
3. Java & Spring 개념
📌 더티 체킹 (Dirty Checking) vs 명시적 쿼리
- 개념
- JPA는 엔티티 조회 후 값만 바꾸면 트랜잭션 종료 시 알아서
UPDATE를 날림
- JPA는 엔티티 조회 후 값만 바꾸면 트랜잭션 종료 시 알아서
- PJT 적용
- 나는
@Modifying과 JPQL(UPDATE ... SET ...)을 사용함
- 나는
- 이유
- 조회 없는 업데이트를 위해서임
- 현재는 1000명의 데이터가 있다고 가정하고 있음.
- 따라서 1,000명의 데이터를 업데이트하려면 1,000번
SELECT후UPDATE하는 것보다, 그냥 바로UPDATE쿼리만 날리는 게 성능상 훨씬 이득임