반응형
Redis(레디스)는 오픈 소스 비관계형(NoSQL) 데이터베이스로, 주로 인메모리 데이터 구조 서버로 사용됩니다. 즉, 데이터를 메모리(RAM)에 저장하고 관리하며, 매우 빠른 속도를 자랑합니다.
Redis의 주요 특징
- 인메모리 데이터 저장:
- Redis는 데이터를 메모리에 저장하므로, 매우 낮은 지연 시간과 높은 처리량을 제공합니다. 이는 실시간 애플리케이션이나 캐시 서버로 사용하기 적합합니다.
- 다양한 데이터 구조 지원:
- Redis는 단순한 키-값 저장소 이상으로, 다양한 데이터 구조를 지원합니다. 예를 들어, 문자열(Strings), 리스트(Lists), 집합(Sets), 정렬된 집합(Sorted Sets), 해시(Hashes), 비트맵(Bitmaps), 하이퍼로그로그(HyperLogLogs), 지오스페이셜 인덱스(Geospatial Indexes) 등이 있습니다.
- 영속성 옵션:
- Redis는 데이터를 디스크에 영속적으로 저장할 수 있는 옵션도 제공합니다. 이는 RDB (Redis Database Backup) 방식과 AOF (Append-Only File) 방식이 있으며, 이를 통해 서버 재시작 후에도 데이터를 복구할 수 있습니다.
- RDB: 특정 시간 간격으로 메모리의 스냅샷을 디스크에 저장합니다.
- AOF: 모든 쓰기 작업을 로그로 기록하여 복구 시 이 로그를 재생합니다.
- 복제와 고가용성:
- Redis는 마스터-슬레이브(Master-Slave) 구조로 복제를 지원합니다. 여러 슬레이브가 하나의 마스터로부터 데이터를 복제할 수 있으며, 슬레이브는 읽기 작업을 처리하여 부하를 분산시킬 수 있습니다.
- Redis Sentinel을 통해 자동 장애 조치(failover)를 설정할 수 있으며, 클러스터 모드를 통해 수평적으로 확장(scale-out)할 수 있습니다.
- 고급 기능:
- Lua 스크립트: Redis는 Lua 스크립트를 지원하여 복잡한 작업을 원자적으로 실행할 수 있습니다.
- 트랜잭션: MULTI, EXEC, DISCARD, WATCH 명령어를 통해 트랜잭션을 지원합니다.
- Pub/Sub: Redis는 발행/구독(Publish/Subscribe) 모델을 통해 메시징 시스템으로도 사용될 수 있습니다.
Redis의 사용 사례
- 캐시(Cache):
- 주로 데이터를 빠르게 액세스할 수 있도록 캐싱 레이어로 사용됩니다. 예를 들어, 데이터베이스의 쿼리 결과를 캐싱하여 응답 시간을 줄일 수 있습니다.
- 세션 저장소:
- 사용자 세션 데이터를 관리하기 위해 Redis를 사용합니다. 메모리 기반 저장소이기 때문에 빠른 세션 조회 및 업데이트가 가능합니다.
- 실시간 분석:
- 실시간 로그 처리나 실시간 통계 계산에 사용됩니다. Redis의 데이터 구조를 활용해 카운터, 랭킹 시스템 등을 구현할 수 있습니다.
- 메시지 큐:
- Redis의 리스트(List)와 Pub/Sub 기능을 활용하여 메시지 큐로 사용될 수 있습니다. 이는 간단한 작업 큐나 알림 시스템 등에 적합합니다.
Redis의 단점
- 메모리 의존성: 데이터가 메모리에 저장되므로, 대용량 데이터를 처리할 때 메모리 부족이 문제가 될 수 있습니다.
- 복잡한 데이터 처리: Redis는 단순하고 빠른 데이터 처리를 목표로 하므로, 복잡한 관계형 데이터베이스 기능을 제공하지 않습니다.
E-Commerce에서 레디스 활용
생성 | 만료 |
장바구니 : 비 로그인 시 임시로 저장되는 정보 | 특정 시간 이후 만료 |
할인정보 : 특정 기간 * 특정 상품의 할인정보 | 할인기간 종료 후 만료 |
쿠폰정보 : User 별, 제품별 할인을 위한 정보 | 로그아웃이나 쿠폰행사 종료 시 만료 |
배송정보 : 배송현황 제공을 위한 정보 | 배송완료 후 n일 후 만료 |
토큰정보, 세션정보 : 로그인 시, 로그인 상태 유지를 위함 | 로그인 후 소멸, 로그아웃 시 만료 |
광고 : User별, 상품별, Seller 별 | 광고계약시점 이후 만료 |
채팅정보 : 채팅시 ~ 채팅 종료시까지 | 채팅 종료 시 만료 |
그 밖의 Cache | 기타 소멸기한이 정해져있을 시 만료 |
레디스와 MySQL 질의 시간 비교
1. 반복 질의
레디스와 mysql의 데이터를 3개씩 셋팅하여 n 번 반복했을 때 시간 차이를 알아보는 실험을 했습니다.
@Test
public void speedComparison(){
final int n = 100;
final StopWatch redisStopWatch = new StopWatch();
redisStopWatch.start();
for(int i=0; i<n; i++){
redisTemplate.opsForValue().get(WelfareCategory.DISABLED.name());
}
redisStopWatch.stop();
System.out.println("redis 조회 시간(초) >> " + redisStopWatch.getTotalTimeSeconds());
final StopWatch mysqlStopWatch = new StopWatch();
mysqlStopWatch.start();
for(int i=0; i<n; i++) {
welfareCardRepository.findTop3ByCategoryOrderByIdDesc(WelfareCategory.DISABLED);
}
mysqlStopWatch.stop();
System.out.println("mysql 조회 시간(초) >> " + mysqlStopWatch.getTotalTimeSeconds());
}
결과는 다음과 같습니다.
n | redis 조회 시간 | mysql 조회 시간 |
1 | 0.73 | 0.34 |
10 | 0.75 | 0.33 |
100 | 0.77 | 0.64 |
1000 | 1.25 | 2.75 |
10000 | 3.01 | 10.53 |
반복 횟수가 100 이하일 경우 redis가 더 느려보이나 그 이상으로 횟수가 증가할 경우 redis가 훨씬 빠른 성능을 보여줍니다. mysql에도 동일한 쿼리의 결과에 대한 캐시를 생성하는데도 불구하고 이 정도로 유의미한 차이가 발생할 지는 몰랐습니다.
성능 개선률 (%)=(이전 시간−개선 후 시간 / 이전 시간)×100
n = 1_000일 때는 54.55% 성능이 개선되었고,
n= 10_000 일 때는 71.41% 성능이 개선되었습니다.
2. 저장
@Test
public void speedComparisonV2(){
int seq = 1;
final long inquiryId = 1L;
final Inquiry parentInquiry = new Inquiry();
parentInquiry.setId(inquiryId);
final List<InquiryAnswer> inquiryAnswerList = new ArrayList<>(100_000);
final List<InquiryAnswer> inquiryAnswerListRedis = new ArrayList<>(100_000);
for(int i=0; i<100_000; i++){
final InquiryAnswer inquiryAnswer = new InquiryAnswer();
inquiryAnswer.setAnswer("ANSWER" + seq++);
inquiryAnswer.setInquiry(parentInquiry);
inquiryAnswer.setCreatedBy("TESTER");
inquiryAnswer.setCreatedAt(LocalDateTime.now());
inquiryAnswer.setModifiedBy("TESTER");
inquiryAnswer.setModifiedAt(LocalDateTime.now());
inquiryAnswerList.add(inquiryAnswer);
final InquiryAnswer inquiryAnswer2 = new InquiryAnswer();
inquiryAnswer2.setAnswer("ANSWER" + seq++);
inquiryAnswer2.setInquiry(parentInquiry);
inquiryAnswer2.setCreatedBy("TESTER");
inquiryAnswer2.setModifiedBy("TESTER");
inquiryAnswerListRedis.add(inquiryAnswer2);
}
StopWatch stopWatch = new StopWatch();
stopWatch.start();
for(InquiryAnswer redisIA : inquiryAnswerListRedis){
redisTemplate.opsForList().leftPush("inquiry:1:answer", redisIA);
}
stopWatch.stop();
System.out.println("REDIS 10만건 저장 시간(초) >> " + stopWatch.getTotalTimeSeconds());
stopWatch = new StopWatch();
stopWatch.start();
inquiryAnswerRepository.saveAll(inquiryAnswerList);
stopWatch.stop();
System.out.println("RDB 10만건 저장 시간(초) >> " + stopWatch.getTotalTimeSeconds());
}
REDIS 1만건 저장 시간(초) >> 4.1529318
RDB 1만건 저장 시간(초) >> 8.9688153
REDIS 10만건 저장 시간(초) >> 16.6945214
RDB 10만건 저장 시간(초) >> 58.4224896
3. 대용량 데이터 조회
@Test
public void 조회_테스트_해보자(){
StopWatch stopWatch = new StopWatch();
stopWatch.start();
redisTemplate.opsForList().leftPop("inquiry:1:answer");
stopWatch.stop();
System.out.println("REDIS 10만건 조회 시간(초) >> " + stopWatch.getTotalTimeSeconds());
stopWatch = new StopWatch();
stopWatch.start();
inquiryAnswerRepository.findByInquiryId(1L);
stopWatch.stop();
System.out.println("RDB 10만건 조회 시간(초) >> " + stopWatch.getTotalTimeSeconds());
}
REDIS 10만건 조회 시간(초) >> 1.0064242
RDB 10만건 조회 시간(초) >> 2.3960754
왜 이런 차이가 발생할까?
- MySQL은 관계형 데이터베이스로, 데이터를 디스크에 저장하며 데이터를 조작할 때 디스크 I/O가 많이 발생합니다. 이러한 디스크 기반 데이터 저장 방식은 대량의 데이터를 효율적으로 관리할 수 있지만, 디스크 액세스는 메모리 액세스보다 상대적으로 느립니다.
- Redis는 메모리 기반 데이터 구조 저장소로, 데이터를 주로 RAM에 저장합니다. 따라서 데이터에 대한 읽기 및 쓰기 작업이 매우 빠릅니다
- 그러므로 Redis의 읽기 쓰기 작업이 MySQL에 비해 상대적으로 훨씬 빠릅니다.
반응형
'[개발] 데이터베이스 > Redis' 카테고리의 다른 글
[Redis] 분산락 처리하기 (1) | 2025.01.05 |
---|