본문 바로가기
[개발] 데이터베이스/Redis

Redis 소개

by Devsong26 2024. 9. 2.
반응형

Redis(레디스)는 오픈 소스 비관계형(NoSQL) 데이터베이스로, 주로 인메모리 데이터 구조 서버로 사용됩니다. 즉, 데이터를 메모리(RAM)에 저장하고 관리하며, 매우 빠른 속도를 자랑합니다.

 

Redis의 주요 특징

  1. 인메모리 데이터 저장:
    • Redis는 데이터를 메모리에 저장하므로, 매우 낮은 지연 시간과 높은 처리량을 제공합니다. 이는 실시간 애플리케이션이나 캐시 서버로 사용하기 적합합니다.
  2. 다양한 데이터 구조 지원:
    • Redis는 단순한 키-값 저장소 이상으로, 다양한 데이터 구조를 지원합니다. 예를 들어, 문자열(Strings), 리스트(Lists), 집합(Sets), 정렬된 집합(Sorted Sets), 해시(Hashes), 비트맵(Bitmaps), 하이퍼로그로그(HyperLogLogs), 지오스페이셜 인덱스(Geospatial Indexes) 등이 있습니다.
  3. 영속성 옵션:
    • Redis는 데이터를 디스크에 영속적으로 저장할 수 있는 옵션도 제공합니다. 이는 RDB (Redis Database Backup) 방식과 AOF (Append-Only File) 방식이 있으며, 이를 통해 서버 재시작 후에도 데이터를 복구할 수 있습니다.
    • RDB: 특정 시간 간격으로 메모리의 스냅샷을 디스크에 저장합니다.
    • AOF: 모든 쓰기 작업을 로그로 기록하여 복구 시 이 로그를 재생합니다.
  4. 복제와 고가용성:
    • Redis는 마스터-슬레이브(Master-Slave) 구조로 복제를 지원합니다. 여러 슬레이브가 하나의 마스터로부터 데이터를 복제할 수 있으며, 슬레이브는 읽기 작업을 처리하여 부하를 분산시킬 수 있습니다.
    • Redis Sentinel을 통해 자동 장애 조치(failover)를 설정할 수 있으며, 클러스터 모드를 통해 수평적으로 확장(scale-out)할 수 있습니다.
  5. 고급 기능:
    • Lua 스크립트: Redis는 Lua 스크립트를 지원하여 복잡한 작업을 원자적으로 실행할 수 있습니다.
    • 트랜잭션: MULTI, EXEC, DISCARD, WATCH 명령어를 통해 트랜잭션을 지원합니다.
    • Pub/Sub: Redis는 발행/구독(Publish/Subscribe) 모델을 통해 메시징 시스템으로도 사용될 수 있습니다.

 

Redis의 사용 사례

  1. 캐시(Cache):
    • 주로 데이터를 빠르게 액세스할 수 있도록 캐싱 레이어로 사용됩니다. 예를 들어, 데이터베이스의 쿼리 결과를 캐싱하여 응답 시간을 줄일 수 있습니다.
  2. 세션 저장소:
    • 사용자 세션 데이터를 관리하기 위해 Redis를 사용합니다. 메모리 기반 저장소이기 때문에 빠른 세션 조회 및 업데이트가 가능합니다.
  3. 실시간 분석:
    • 실시간 로그 처리나 실시간 통계 계산에 사용됩니다. Redis의 데이터 구조를 활용해 카운터, 랭킹 시스템 등을 구현할 수 있습니다.
  4. 메시지 큐:
    • 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