Redis 야무지게 사용하기 정리

이영은·2025년 5월 12일
0

기술면접

목록 보기
7/7

영상을 보면서 점점 의식을 잃어가서 냅다 쓰기~~

  1. Redis 캐시로 사용하기
  2. Redis 데이터 타입 야무지게 활용하기
  3. Redis에서 데이터를 영구 저장하려면? (RDB vs AOF)
  4. Redis 아키텍처 선택 노하우(Replication vs Sentinel vs Cluster)
  5. Redis 운영 꿀팁 + 장애 포인트

1. Redis 캐시로 사용하기

캐시 : 데이터의 원래 소스보다 더 빠르고 효율적으로 액세스할 수 있는 임시 데이터 저장소

대부분의 어플리케이션에서 속도 향상을 위해 캐시를 사용합니다.
캐시가 유용하게 사용될려면 원본보다 빠르게 접근 가능해야 합니다.
그리고 동일한 데이터에 대해 반복적으로 접근하는 경우가 많을 때 캐시를 사용하는 것이 좋습니다.
즉, 데이터 재사용 횟수가 1번 이상이여야 캐시가 의미 있게 됩니다.
또한 잘 변하지 않은 데이터일 때, 캐시를 사용하는 것이 효율적입니다.

레디스는 캐시를 사용하기 좋은 이상적인 솔루션입니다.
우선 사용이 간편합니다. 단순한 key-value 구조로 저장할 수 있기 때문에 어떤 데이터라도 쉽게 저장할 수 있습니다.
또한, 레디스는 모든 데이터를 메모리에 올려놓는 In-Memory data store입니다. 즉, 굉장히 빠르다는 것을 의미합니다.

평균 읽기 및 쓰기 작업 속도가 1ms 미만이기에 초당 수백만 건의 작업 처리가 가능합니다.
이렇게 빠른 속도를 가지고 있기에 지연 속도도 감소하고 처리 속도도 증가합니다.

캐싱전략

레디스를 캐시로 사용할 때, 어떻게 배치하는지에 따라 시스템 성능에 큰 영향을 끼칩니다. 이를 캐싱 전략이라고 합니다. 캐싱 전략은 데이터의 유형과 해당 데이터에 대한 접근 패턴을 잘 고려해서 선택해야 합니다.

  • 읽기 전략, look-Aside, Lazy Loading
    먼저, 어플리케이션에서 데이터를 읽는 작업이 많을 때 사용하는 look-aside 작업에 대해 설명하겠습니다.

    이 구조는 레디스를 읽는 작업으로 사용할 때 많이 사용하는 구조입니다. 어플리케이션은 데이터를 찾을 때 캐시를 먼저 확인합니다. 캐시에 데이터가 있으면 캐시에서 데이터를 가져오는 작업을 반복합니다. 만약 레디스에 찾는 키가 없으면 db에 접근해 데이터를 가져온 뒤 레디스에 다시 저장합니다.
    따라서 캐시는 찾는 데이터가 없는 경우에만 입력되기에 이를 lazy loading 이라고 합니다.
    이는 레디스가 다운되더라도 바로 장애로 이어지지 않고 db에서 데이터르 ㄹ가져올 수 있습니다. 대신 캐시로 붙어 있던 연결이 많았다면, 그 연결이 모두 db로 연결되기 때문에 db에 갑자기 많은 부하가 몰릴 수 있습니다.
    그래서 이런 경우에 캐시를 새로 투입하거나 db에만 새로운 데이터를 저장했다면, 처음에 캐시미스가 엄청 발생해서 성능에 저하가 올 수 있습니다. 이럴 땐 미리 db에서 캐시로 미리 데이터를 밀어넣을 수 있습니다. 이를 캐시 월밍(cache warming)이라고 합니다. 실제로 상품 오픈 전, db에서 캐시로 상품에 대한 정보를 미리 올려두는 작업을 하고 있습니다.

  • 쓰기 전략
    왼쪽의 방식은 db에만 데이터가 저장됩니다. 일단 db에만 데이터가 저장되고 캐시 미스가 발생하는 경우, 캐시에 데이터를 끌어오게 됩니다. 이 경우에 캐시 내 데이터와 db의 데이터가 다른 문제가 발생할 수 있습니다. 오른쪽 전략은 db에 데이터를 저장할 때, 캐시에도 같이 저장하는 방법입니다. 캐시는 항상 최신 정보를 가지고 있다는 장점이 있지만, 저장할 때마다 두 단계를 거쳐야 하기에 상대적으로 느리다고 볼 수 있습니다. 그리고 저장하는 데이터가 재사용되지 않을 수 도 있는데 무조건 저장하여 리소스 낭비로도 이어질 수 있습니다. 따라서 이렇게 데이터를 저장할 때 몇 분만 저장하겠다는 expire를 설정하는 것이 좋습니다. 그런데 이 값의 관리를 어떻게 하는지가 장애 포인트가 될 수 있습니다.

2. Reids의 데이터 타입 야무지게 활용하기

레디스는 자체적으로 많은 자료구조르 ㄹ제공하고 있습니다. 특정 상황에서 이런 자료구조들을 어떻게 효율적으로 사용할 수 있는지 사례와 함께 알아보겠습니다.

String

string은 제일 기본적인 타입입니다. set 명령어를 통해 저장되는 데이터는 모두 string 형태로 저장됩니다. Bitmap은 string의 변형이라고도 볼 수 있고, 비트 단위의 연산이 가능합니다. 데이터를 순서대로 저장하는 list는 큐로 사용하기 적절합니다. 해시는 하나의 키 안에 또 다시 여러 개의 필드와 밸류 쌍으로 데이터를 저장합니다. set은 중복되지 않은 문자열의 집합입니다. sorted set은 set 처럼 중복되지 않은 값을 저장하지만 모든 값은 score라는 숫자 값으로 정렬됩니다. 데이터가 저장될 때부터 score 순으로 정렬되며 만약 score가 같을 때는 사전 순으로 정렬되어 저장됩니다. HyperLogLogs는 굉장히 많은 데이터를 다룰 때 사용하며 중복되지 않은 값을 카운트할 때 사용됩니다. Stream은 로그를 저장하기 가장 좋은 자료구조입니다.
이제 몇 가지 상황에서 레디스의 자료구조를 어떻게 사용하면 좋을 지 비교해보겠습니다. 먼저 여러가지 카운팅 상황을 생각해보겠습니다. 레디스에서 카운팅하기 가장 쉬운 방법은 키 하나를 만들어서 카운팅할 상황마다 하나씩 증가시키는 겁니다. 이는 string의 increment 함수를 사용하면 됩니다. 위의 예제를 보겠습니다. a라는 키에 10을 저장한 뒤 increment함수를 사용하면 1이 증가된 11이 됩니다. incr by 함수를 사용하여 incr by score:a 4라고 하면 15로 증가합니다. 보시다시피 아주 간단하게 카운팅 할 수 있는 방법입니다.

bits

두 번째 방법은 bit 연산을 사용하는 방법입니다. 이르 ㄹ이용하면 저장공간을 굉장하게 절약할 수 있습니다. 예를들어 오늘 웹 사이트에 접속한 유저 사용자 수를 조회하고 싶다면 날짜 키 하나를 만들어서 유저 아이디에 대한 값을 1로 올려줍니다. 한 개의 비트가 한 명을 의미하므로 만약 천 만명의 유저라면 천 만개의 비트로 표현할 수 있고, 이는 1.2 메가 바이트 정도 밖에 차지하지 않습니다. 예제에서처럼 set비트를 통해 bit를 설정할 수 있고 비트카운트를 통해 1로 설정된 값을 도무 카운팅할 수 있습니다. 하지만 이 방법을 이용할려면 모든 데이터를 정수로 표현할 수 있어야 합니다. 즉, userId와 같은 값이 0 이상의 정수 값일 때에만 가능하며 그런 sequential한 값이 없을 때에는 이 방법을 사용할 수 없다.

HyperLogLogs

마지막으로 알아볼 카운팅 방법은 HyperLogLogs를 사용하는 것입니다. 모든 string 데이터 값을 유니크하게 구분할 수 있습니다. 이는 set과 비슷하지만 대량의 값을 카운팅할 때 훨씬 유리합니다. 왜냐하면 저장되는 데이터의 갯수에 상관없이 모든 값이 12KB로 고정되어 저장되기 때문입니다. 대신 한 번 저장된 값은 다시 불러올 수 없는데, 경우에 따라 보호하기 위한 목적으로 적절합니다.
예를 들어 우리 웹 사이트에 방문한 ip가 유니크한 값이 몇 개 인지, 혹은 하루종일 크롤링한 url의 객수는 몇 개인지, 우리 검색 엔진에서 검색된 유니크한 단어는 몇 개가 되는지 엄청 크고 유니크한 값을 저장할 때 아주 유요합니다. PFADD 명령어로 데이터를 저장하고 PFCOUNT 명령어로 유니크하게 저장된 값을 조회할 수 있습니다. 만약 나는 일별로 데이터를 저장했는데 일주일 데이터를 취합해서 보고싶다면 PFMERGE 명령어로 키들을 머지해서 확인할 수 있습니다.
이번에는 메시징 하는 상황에 대해 알아보겠습니다. 리스트는 메시지 큐로 사용하기 적절합니다. 특히 자체적으로 Blocking 기능을 제공하기에 이를 적절히 사용하면 불필요한 polling 프로세스를 막을 수 있습니다.

List

클라이언트 A가 BRPOP 커맨드를 통해 myqueue에서 데이터를 꺼내오려하는데 현재 리스트 안에는 데이터가 없어 대기를 하고 있는 상황입니다. 이 때 클라이언트 B가 hi라는 값을 넣어주면 클라이언트 A에서 바로 이 값을 확인할 수 있습니다. 또한, LPUSHX나 RPUSHX 명령어를 사용하면 키가 존재할 때만 Lists에 데이터를 추가하는데 이 기능도 잘 사용하면 굉장히 유용하게 사용할 수 있습니다.
키가 이미 존재한다면 예전에 사용했던 큐라는 것이고, 사용했던 큐에만 메세지를 넣어줄 수 있기 때문에 비효율적인 데이터의 이동을 막을 수 있습니다.
인스타그램, 페이스북, 트위터 등과 같은 SNS에는 각 유저별로 타임라인이 존재하고 그 타임라인에 내가 팔로우한 사람들의 데이터가 보여지게 됩니다. 트위터에서는 각 유저의 타임라인에 보일 트윗을 캐싱하기위해 redis의 Lists를 사용하는데 이 때, RPUSHX 명령어를 사용하여 트위터를 자주 이용하던 유저의 타임라인에만 새로운 데이터를 미리 캐시해 놓을 수 있습니다. 자주 사용하지 않는 유저는 캐싱 키 자체가 존재하지 않기 때문에 자주 사용하지 않는 유저를 위해 데이터를 미리 쌓아놓는 것 같은 비효율적인 작업을 방지할 수 있습니다.

stream


stream은 로그를 저장하는 가장 적절한 자료구조라고 볼 수 있습니다. 실제 서버에 로그가 쌓이는 것처럼 모든 데이터는 append-only 방식으로 저장되며 중간에 데이터가 바뀌지 않습니다. 예제에서는 XADD 명령어를 이용해 mystream이라는 키에 데이터를 저장합니다. 키 이름 옆에 는 ID 값을 의미하며 ID 값을 직접 저장할 수도 있지만 일반적으로 로 입력하면 redis가 알아서 저장하고 ID 값을 반환해줍니다.
반환되는 ID 값은 데이터가 저장된 시간을 의미합니다. 이 값 뒤로는 hash처럼 key-value 쌍으로 데이터가 저장되는데, 예제에서는 sensor-id 값에 1234를 온도에는 19.8을 저장한 것을 의미합니다. 스트림의 데이터를 읽어오는 방법은 다양한데, ID값을 이용해 시간 대역대로 저장된 값을 검색할 수 있고 실제 서버에서 로그를 읽을 때 tail -f 를 사용하는 것 처럼 새로 들어오는 데이터만 리스닝 할 수 있습니다. 또한 kafka 처럼 소비자 그룹이라는 개념이 존재하기에 원하는 소비자만 특정 데이터를 읽을 수 있습니다. 스트림에서는 kafka 개념을 차용했는데요 레디스 공식 문서에서는 스트림을 메세징 브로커가 필요할 때 kafka를 대체해서 간단하게 사용할 수 있는 자료구조라 소개하고 있습니다.

3. Redis에서 데이터를 영구 저장하려면? (RDB vs AOF)


redis는 In-memory data store입니다. 모든 데이터가 메모리에 저장되어 있기 때문에 서버나 redis 인스턴스가 재시작되면 모든 데이터는 유실됩니다.
복제 구조를 사용하고 있더라도 데이터 유실에 있어 안전하다고 볼 수는 없습니다.
코드상의 버그가 있거나 혹은 휴먼 에러로 데이터를 날린 경우에는 바로 복제본에도 똑같이 적용되기 때문에 이런 경우에는 데이터를 복원할 수 없습니다.
따라서 redis를 캐시 이외의 용도로 사용한다면 적절한 데이터의 백업이 필요합니다.

redis에서는 데이터를 영구적으로 저장하는 두 가지 방법을 제공합니다. AOF는 데이터를 변경하는 명령어가 들어오면 명령어를 그대로 모두 저장합니다. RDB는 스냅샷 방식으로 동작하기 때문에 저장 당시 메모리에 있는 데이터를 사진찍듯이 찍어서 그대로 파일로 저장합니다.
그림을 살펴보면 AOF에는 key1에 a가 저장되었다가 apple로 변경되었고, key2가 들어왔다가 삭제된 기록 모두 남아있습니다. 하지만 RDB에는 key1이 apple인 값만 남아있습니다.
AOF 파일은 Append Only하게 동작하기 때문에 데이터가 추가되기만 해서 대부분 RDB 파일보다 커지게 됩니다. 따라서 AOF 파일은 주기적으로 압축해서 재작성되는 과정을 거쳐야 합니다.

자동 / 수동 파일 저장 방법

RDB와 AOF 파일 모두 명령어를 이용해 직접 파일을 생성할 수 있으며, 원하는 시점에 파일이 자동 생성되도록 설정할 수 도 있다.

  • AOF (Append Only File)
    데이터 변경 명령어까지 모두 저장합니다.
    자동 저장시 redis.conf 파일에서 auto-aof-rewrite-percentage 옵션으로 크기 기준으로 저장 가능합니다.
    수동 저장시 BGREWRITEAOF 명령어를 이용해 CLI 창에서 수동으로 AOF 파일 재작성이 가능합니다.
  • RDB (Snapshot)
    저장 당시 메모리에 있던 데이터들만 그대로 저장합니다.
    자동 저장시 redis.conf 파일에서 save 옵션으로 시간 기준으로 저장할 수 있습니다.
    수동 저장시 BGSAVE 명령어를 이용해 CLI 창에서 수동으로 RDB 파일을 저장할 수 있습니다.

RDB VS AOF 선택 기준

  • 백업은 필요하지만 어느 정도의 데이터 손실이 발생해도 괜찮은 경우 RDB를 단독으로 사용합니다. redis.conf 파일에서 SAVE 옵션을 적절히 사용합니다. SAVE 900 1은 900초 동안 한 개 이상의 키가 변경되었을 때, RDB 파일을 재작성하라는 의미입니다.
  • 장애 상황 직전까지의 모든 데이터가 보장되어야 할 경우

출처 : https://www.youtube.com/watch?v=92NizoBL4uA

0개의 댓글