CS

🎯 Redis

늦은산책 2024. 4. 26. 12:10

🎲 레디스란?

  • Key-Value 구조를 가진 형태로 다양한 형태의 자료구조를 제공하고 데이터를 저장한다
  • 레디스 클러스터 모드를 가지고 있어 다중 노드에 데이터를 분산 저장하여 안정성 & 고가용성을 제공한다
  • 다양한 목적으로 사용된다 ( e.g. Pub/Sub패턴, 블랙리스트 등등)
  • 모든 데이터를 In-Memory인 RAM에 저장하기 때문에 굉장히 빠른 작업 처리 속도를 가지고 있다
    • 데이터 영속성을 위한 SSD나 HDD에 저장하는 방식도 사용하고 있다
장점 정리
메모리에 데이터를 저장하면서 매우 빠른 읽기와 쓰기 속도를 보장하고 다양한 데이터 타입을 저장할 수 있다

 

Redis의 persistence

Redis는 RAM에 데이터를 저장하기 때문에 휘발성 데이터라고 생각하면 된다. 그래서 Redis는 이를 보완하고자 데이터를 디스크에 백업하는 RDB 방식 혹은 AOF방식으로 영속성을 제공한다

 

  • RDB 방식 : 메모리에 있는 데이터 전체에서 스냅샷을 작성하고 이를 디스크로 저장하는 방식이다
    • 특정 시간마다 여러 개의 스냅샷을 생성하고, 데이터를 복원해야 한다면 스냅샷 파일을 그대로 로딩만 하면 된다
    • 하지만 한번 변경된 데이터는 이후 다시 복구가 불가능하다
  • AOF(Append Only File) : 데이터가 변경되는 이벤트가 발생하면 모두 로그에 저장한다
    • 데이터를 생성, 수정, 삭제하는 이벤트를 초단위로 취합 및 호그 파일에 작성
    • 모든 데이터의 변경 기록들을 보관하고 있기 때문에 최신 데이터 정보를 백업 할 수 있다
    • RDB 방식에 비해 데이터 유실의 량이 적다
    • RDB보다 로딩이 느리고 파일의 크기가 크다
  • 사용방법
    • 일부 데이터 손실에 영향을 받지 않는 경우 즉, 캐시로만 사용될때는 RDB
    • 장애 상황 직전까지의 모든 데이터가 보장되어야 하는 경우에는 AOF
    • 강력한 내구성이 필요하다면 RDB + AOF

 


 

🎲 레디스의 스레드

 

레디스는 사용자들이 실행한 명령어들을 이벤트 루프 방식으로 처리한다. 즉, 클라이언트가 실행한 명령어들을 Event Queue에 적재하고 싱글 스레드를 통해 하나씩 처리한다.

 

  • 장점
    • 멀티 스레드가 아니라서 Context switch 가 발생하지 않고 이로 인해 효율적인 시스템 리소스 사용이 가능하다
    • Context switch가 발생하지 않기 때문에 데드락또한 걱정이 없다
  • 단점
    • 오버헤드가 큰 명령어를 처리하는 동안 다른 명령어를 처리 할 수 없다.
    • 앞의 명령어를 처리해야 다음 명령어를 처리할 수 있기 때문에 다른 명령어들이 이벤트 큐에 저장되어 있는 시간이 길어진다.

 


 

🎲 레디스 자료 구조

 

  • String : 문자열 데이터를 저장 및 조회 할 수 있는 기본 자료 구조이다
    • 증감 연산으로 사용도 가능하다 : INCR, INCRBY, INCRBYFLOAT, HINCRBY, HINCRBYFLAOT, ZINCRBY
  • Bitmap : 비트 연산을 사용할 수 있다
  • List : LinkedList의 형태로 연결되어 있다. 때문에 Push, Pop의 속도가 O(1)이 된다.
    • 이를 통해 Queue 와 Stack도 구현 할 수 있다
  • Hash : field-value이다. 명심해야한다 Key와 Value가 아닌 Field-Value이다. 이 데이터는 레디스의 키와 매핑되어 있다
  • Set : Set 과 매우 흡사하다 중복을 허용하지 않는다 두개의 Set을 비교하는 것도 가능하다
  • Sorted Sets : ZSET의 명령어를 통해 사용하며 SET과 비슷한 명령어 이다. 중복을 허용하지 않고 데이터는 스코어와 함께 저장 할 수 있다. 내부적으로 Skip List + HashTable로 이루어져있기에 해당 스코어의 값을 기준으로 정렬하게 되고 만약 값이 같다면 사전 순으로 정렬한다
  • Stream : append-only log에 consumer groups과 같은 기능을 더한 자료 구조이다. 카프카와 유사하다 데이터가 수정 삭제는 없고 오로지 추가만 된다. 
    • XADD events * action like user_id 1 product_id 1 
    • events라는 큐에 userId 1이 ProductId 1을 좋아요를 눌렀다는 메세지가 담긴것이다.
  • HyperLogLog : 집합의 데이터 갯수를 추정할 수 있는 알고리즘이자 이를 사용할 수 있는 레디스의 자료 구조이다. 이 알고리즘은 비트 패턴을 분석하여 비교적 정확한 추정 값을 계산한다 오차는 0.81%만큼 작다 또한 저장 공간이 크지 않아서 카운트에 적합하다

 

🎲 레디스의 주의 사항

  • O(N) 명령어 : 레디스는 싱글스레드이기에 O(N) 명령어처럼 성능의 저하가 일어날 수 있는 명령어는 가급적 피해야한다 
    • KEYS : 모든 키를 조회하는 것이다 → SCAN 명령어로 대체
    • SMEMBERS : Set에 모든 member를 반환, 하나의 Set에 member갯수를 조절하는 것이 좋다
    • HGETALL : Hash의 모든 field를 반환한다. 이또한 마찬가지 이다.
    • SORT : item을 정렬하는 행위또한 같은 시간 복잡도를 같기에 주의해야한다.
  • Thendering herd Problem : 병렬 요청이 공유 자원에 대해서 접근시 급격한 과부하가 발생한다
    • Redis에 캐싱되어 있는 데이터가 만료로 인해 사라졌을때 수많은 사용자가 동시에 요청을 한다면 레디스는 이를 DB를 통해 데이터를 가져오게 되는데 동시에 요청을 한 상황이기에 모든 요청이 DB로 몰리게 된다
    • 이를 방지하기 위해 캐시를 주기적으로 최신화를 시켜주는 방법을 사용할 수 있다.
  • Stale Cache Invalidation : 캐시는 원본이 아니기에 유효성이 손실되거나 변경되었을때 캐시를 변경하거나 삭제해야한다
    • 이 또한 캐시를 주기적으로 최신화 시켜주는 방법이 있을 수 있다.

 


 

🎲 레디스 특수 명령어

♬ 데이터 만료(Expiration)

  • 데이터를 특정 시간 이후에 만료시키는 기능
  • TTL(Time To Live)은 데이터가 유효한 시간(초단위)
  • 데이터는 조회 요청시에 만료된 데이터는 조회되지 않는다 또한 데이터가 만료되었다고 바로 삭제하지않고 표시만 바꿔주었다가 백그라운드에서 주기적으로 삭제한다.
  • 명령어
    • EXPIRE greeting 10 ▶ 10초의 만료 시간을 준다
    • TTL greeting ▶ 데이터 만료 설정 여부
    • SETEX greeting 10 hello ▶ 데이터를 SET으로 꾸미고 10초라는 만료시간을 준다

 

♬ SET NX/XX

  • NX : 해당 Key가 존재하지 않는 경우에만 SET
  • XX : 해당 Key가 이미 존재한다면 SET
  • Null Reply : SET이 동작하지 않은 경우 (nil)을 응답한다
  • 만약 이러한 명령어가 없다면 데이터가 존재하는지 계속해서 확인해야한다
  • 명령어
    • SET greeting (value) NX ▶ 해당 key가 없다면 OK를 반환하고 value를 SET해준다 하지만 있다면 nil을 반환
    • SET greeting (value) XX ▶ 해당 Key가 있다면 OK를 반환하고 value의 내용을 바꾼다 하지만 없다면 nil을 반환

 

♬ Pub/Sub

  • publisher와 Subscriver가 서로 알지 못해도 통신이 가능하도록 decoupling 된 패턴이다
  • publisher는 Subscriber에게 직접 메세지를 보내지 않고 Channel에 publish
  • Subscriber는 관심이 있는 Channel을 필요에 따라 Subscribe하며 메세지를 수신한다
  • Stream 메세지가 보관되는 Stream과는 달리 Pub/Sub는 Subscribe하지 않을 때 발생된 메세지 수신이 불가능 하다

  • 명령어
    • SUBSCRIBE ch:order ch:payment
    • PUBLISH ch:order ner-order
    • PUBLISH ch:payment new-payment

 

♬ Pipeline

  • 다수의 commands를 한 번에 요청하여 네트워크 성능을 향상 시키는 기술이다
  • Round-Trip Times 최소화 : Requset/Response 모델에서 발생하는 네트워크 지연 시간
  • 대부분의 클라이언트 라이브러리에서 지원한다.

 

♬ Transaction

  • 다수의 명령을 하나의 트랜잭션으로 처리되면서 원자성이 보장된다
  • 중간에 에러가 발생하면 모든 작업이 rollback된다
  • 하나의 트랜잭션이 처리되는 동안 다른 클라이언트의 요청이 중간에 끼어들수 없다
  • 원자성(Automicity)
    • All or Nothing : 모든 작업이 적용되거나 하나도 적용되지 않거나
  • Pipeline은 네트워크 퍼포먼스 향상을 위해 여러개의 명령어를 한 번에 요청
  • Transaction은 작업의 원자성을 보장하기 위해 다수의 명령을 하나처럼 처리하는 기술
  • 두개는 다르고 동시에 사용도 가능하다
  • 명령어
    • MULTI : 트랜잭션의 시작
    • DISCARD : rollback
    • EXEC : 트랜잭션 적용

 


 

🎲 레디스 다양한 데이터 타입의 활용

♬ One-Time Password(임시 비밀번호[String])

  • 인증을 위해 사용되는 임시 비밀번호

 

♬ Distributed Lock(분산락[String])

  • 분산 환경의 다수의 프로세스에서 동일한 자원에 접근할 때 동시성 문제를 해결한다

  • 해당 공유 자원을 표현하는 이름으로 Key를 설정하고 NX를 통해 key가 없다면 lock을 획득
  • 이미 존재한다면 nil을 리턴한다
  • lock을 획득한 자원이 해결되면 delete를 하고 다음 요청이 lock을 다시 진행한다

 

♬ Rate Limiter(비율 계산기[String])

  • 시스템 안정성/보안을 위해 요청의 수를 제한하는 기술
    • IP, USER, Application 등등을 기준으로 제한한다.
  • Fixed-window Rate Limiting
    • 고정된 시간(e.g. 1분)안에 요청 수를 제한하는 방법

  • 10분에 서버에 요청을 하면 1.1.1.1:10 이라는 key를 만든다. 이뜻은 10분부터 11분까지의 요청한 횟수를 체크한다
  • 만약 한계를 20으로 잡았다면 20이 넘어가면 429 오류를 발생시킨다. 하지만 그 전까진 정상적인 응답을 한다
  • 최악의 경우
    • 10분 59초에 20번의 요청이 오고 11분이 되면서 20개의 요청이 오면 2초안에 40개의 요청을 처리해야한다

 

♬ SNS Activity Feed(소셜 네트워크 활동 피드[List])

  • 사용자 또는 시스템과 관련된 활동이나 업데이트를 시간순으로 정렬하여 보여주는 기능
  • Fan-Out : 단일 데이터를 한 소스에서 여러 목적지로 동시에 전달하는 메시징 패턴 

  • user1 이 어떠한 게시물에 좋아요를 누르면 해당 이벤트는 피드를 관리하는 서비스로 전달되고
  • 레디스는 이것에 흥미가 있을만한 사람들의 피드에 해당 이벤트를 전달한다.
  • 이후 자신의 피드를 조회한 user2 는 0 ~ 9index 즉 10개의 피드 내용을 순서대로 보여주게 되면서 확인한다

 

♬ Shopping Cart(장바구니[Set])

  • 사용자가 구매를 원하는 상품을 임시로 모아두는 가상의 공간
  • 수시로 변경이 발생할 수 있고, 실제 구매로는 이어지지 않을 수 있다

  • 상품을 추가하면 SADD 로 해당 SET데이터인 cart에 item이 담기고
  • 이후에 조회를 할때는 SMEMBERS를 통해 조회하여 가져온다.

 

♬ Login Session(로그인[Hash])

  • 사용자의 로그인 상태를 유지하기 위한 기술
  • 로그인시 세션의 갯수를 제한하여, 동시에 로그인 가능한 디바이스 갯수를 제한한다 - 동시 로그인 제한

  • 인증을 완료하면 유저의 정보를 SET의 이름을 담아 저장하고 set-cookie에 해당 SET의 이름을 담아 전달한다
  • 이후엔 cookie에 데이터를 담아 전달한다. 그럼 저장된 SET을 확인하고 처리한다

 

♬ Sliding Window Rate Limiter(비율 계산기2[SortedSet])

  • 시간에 따라 window를 이동시켜 동적으로 요청 수를 조절하는 기술
  • Fixed Window : window의 시간마다 허용량이 초기화 된다
  • Sliding Window : 시간이 경과함에 따라 window가 같이 움직인다

 

 

♬ Geofencing(반경 탐색[Geospatial])

  • 위치를 활용하여 지도 상의 가상의 경계 또는 지리적 영역을 정의하는 기술
  • 만약 내가 있는 범위내로 특정 가게만 찾고자 한다는 요청이 있다면
  • 명령어를 이렇게 작성하면 나온다.

 

♬ Online Status(온라인 상태 표시[Bitmap])

  • 사용자의 현재 상태를 표시하는 기능
  • 실시간성을 완벽히 보장하지 않는다. 수시로 변경되는 값이기 때문이다.

 

♬ Visitors Count(방문자 수 계산[HyperLogLog])

  • 방문자 수를 대략적으로 추정하는 경우 정확한 횟수를 셀 필요 없이 대략적인 어림치만 알고자 하는 경우

 

♬ Unique Events(중복 이벤트 제거[BloomFilter])

  • 동일한 요청이 중복으로 처리되지 않게 하기 위해 빠르게 해당 Item이 중복인지 확인한다.