책, 세미나, 컨퍼런스 후기/Seminar

우아한 Redis - Redis 톺아보기

TwinParadox 2021. 11. 28. 21:53
728x90

세미나 영상

우아한 Redis

 

 

내용 정리


Redis란 무엇인가?

  • In-Memory Data Structure Store이면서 오픈소스
  • String, Set, Sorted-Set, Hash, List 등의 타입을 지원한다.
  • 캐시(Cache)로 자주 사용한다.
    • Look Aside Cache, 캐시에 자료가 없으면 DB 접근 후 캐시에 갱신한다.
    • Write Back, 캐시에 쓰고 이걸 모아서 DB에 저장한다.

Redis에서의 Collection

  • 개발의 편의성을 끌어올리고 난이도를 대폭 낮춰준다.
  • 모든 것들이 그렇듯, 적합한 컬렉션을 고르고 잘 이용하는 것이 무엇보다 중요하다.\
  • 랭킹 서버의 예시
    • DB에 넣고 Score를 처리하는 시스템은 유저가 많아진다면?
    • Redis를 도입하고 Sorted Set을 사용해서 랭킹 시스템을 구현해낼 수 있다.

 

  • Redis의 친구 리스트를 Key-Value로 저장하는 경우
    • 서로 다른 클라이언트에서 친구를 추가하는 상황이 있다고 하자.
    • 현재 두 클라이언트의 친구 리스트에는 A만 있는데, 각각 B와 C를 추가하면, 최종적으로 A, B, C가 있어야 한다.
    • 동시성 이슈가 발생하면, A, B, C가 모두 없을 수 있다.
    • 하지만, Redis는 자료구조의 Atomic을 보장하여 Race Condition을 피할 수 있다.

Redis 사용처

  • 원격 데이터 저장소, 그 외 인증 토큰 저장소, 랭킹 시스템, API Limit, Job Queue(Celery)...

Redis Collections

Strings

  • Key-Value
  • Key의 설계 방식이 상당히 중요해진다. 어떻게 Key를 설정하느냐에 따라 데이터의 분산 정도가 달라진다.

 

List

  • Lpush, Rpush를 통해 컬렉션의 시작과 끝에 데이터 추가 가능.
  • 동일한 방식으로 LPOP, RPOP을 제공

 

Set

  • 중복 X, 순서 X -> 탐색이 빠름
  • SADD, SMEMBERS, SISMEMBERS
  • 특정 유저를 팔로우하는 목록을 저장할 때

 

Sorted Set

  • Score를 포함한 순서가 있는 Set
  • ZADD key score value
  • 범위를 대상으로 데이터 조회 가능
    • ZRANGE, ZREVERAGE, ZRANGEBYSCORE

 

  • Score는 Double 타입
    • 실수형, 값의 정확성에 문제가 있을 수 있다.
    • 자바스크립트에서 유저 ID를 보낸다고 할 때, Long 정수형을 보내면 문제가 발생할 수 있음.

 

Hash

  • Key-Value 안에 Sub Key-Value가 존재

 

Collection 주의사항

  • 하나의 컬렉션에는 너무 많은 아이템을 넣지 않는 게 좋다.
  • 많은 아이템을 집어넣어야 한다면, 여러 컬렉션에 분산 저장하는 걸 고려해보자.
  • Expire는 컬렉션 내 아이템 개별이 아닌, 컬렉션 자체에 해당한다.

Redis 운영 팁

메모리 관리를 잘하자.

  • 메모리가 꽉 차서 뻗는다면?
  • 또는 메모리가 부족해서 Memory Swap이 발생하면?
  • 위 사례들이 발생하면 Redis를 사용하는 효과를 많이 잃는다.

 

Maxmemory 옵션

  • 이건 건드리지 않는 게 좋다.
  • 할당 대상의 메모리 사이즈를 완벽히 예측할 수 있을까?
  • 더 사용하게 되면 실제 필요한 용량보다 더 큰 용량이 필요해진다.

 

모니터링

  • 일단 Swap이 발생하는지 봐야 한다.

 

하드웨어 단계에서 고려할 부분

  • 24GB 크기의 인스턴스 하나보다, 8GB 인스턴스 3대가 더 안정적이다.
  • Read에서는 문제없지만 Write의 경우 필연적으로 메모리가 2배 늘어나는 경우가 있을 수 있다.

 

여러 가지를 고려했음에도 메모리 부족이 발생하면?

  • 일단 가장 쉬운 건 돈으로 해결하기 = 더 크고 더 강력한 장비
    • 보통 60 ~ 70% 정도의 메모리를 사용하면 장비 이전을 고려해야 한다.

 

  • 컬렉션에 대해 고민해보기
    • Hash는 Hash Table을 사용
    • Sorted Set은 Skip List와 HashTable을 사용
    • Set 은 Hash Table
    • Hash, Sorted Set, Set은 메모리들을 많이 사용해서 Ziplist를 고려해볼 수 있다.
      • 선형 저장, In-Memory라서 선형 탐색해도 적은 개수에서는 효과적

 

 

O(N)은 당연히 주의해야 한다.

  • 싱글 스레드 환경에서 요청 처리 과정의 병목을 신경 써야 한다.
  • 단순한 GET/SET이라면 10만 TPS까지 가능하다고 한다.

 

O(N) 명령어

  • KEYS, FLUSHALL, FLUSHDB, DELETE COLLECTIONS, GET ALL COLLECTIONS
  • KEYS는 SCAN을 쓰고, 조회 대상을 나누자.
  • GET ALL을 하는 것도, 일부만 가져오던지 컬렉션 자체를 쪼개자.

Redis Replication

  • Async Replication으로 Replication Lag이 발생할 수 있다.
  • DBMS에서의 Statement Replication과 유사하다. 쿼리가 직접!

 

 

Replication 과정

  • Secondary에 replicaof, slaveof 명령 전달
  • Secondary는 Primary에 sync 명령 전달
  • Primary는 현재 메모리 상태 저장을 위해서 Fork 수행
    • 이 과정에서 Copy On Write 발생

 

  • Fork한 프로세서는 현재 메모리 정보를 디스크에 Dump, 이때 메모리에 바로 줄 수도 있다.
  • Fork 이후 데이터를 Secondary에 지속적으로 전달

 

 

주의사항

  • Fork 발생으로 메모리 부족이 발생할 수 있다.
    • Fork하다가 메모리가 터지고, 데이터가 사라지면?
    • 그 데이터는 영영 못 만난다.

 

  • Redis-cli의 --rdb는 현재 상태의 메모리 스냅샷을 가져오는데, 이것이 치명적인 문제를 발생시킬 수 있다.
  • AWS 등의 클라우드 서비스에서는 조금 다르게 구성되어 문제가 덜하다.
  • 여러 Replica를 동시에 만들면 대역 초과로 네트워크 연결이 끊어질 수 있다.

 

 

redis.conf에서의 권장 설정

  • Maxclient 50000, 기본값보다 높이자
    • Maxclient 숫자만큼 접속 가능
  • RDB/AOF 설정은 비활성화. 특히 Primary에서는 무조건.
  • 특정 커맨드를 비활성화
    • 전체 장애 중 90% 이상은 KEYS, SAVE를 사용하면서 발생한다.

Redis 데이터 분산 방법

Consistent Hashing

  • 일반 모듈러 방식의 문제는 서버의 장애와 추가 시점에 여러 서버에 걸쳐 리밸런싱이 발생하면 취약하다는 것
    • 50% 이상의 데이터가 움직이게 되면...

 

  • Consistent Hashing은 자기 해시보다 크고, 가장 근접한 해시를 가진 서버를 찾아간다.
    • 서버 장애/추가 시점에 N분의 1 정도만 리밸런싱이 발생한다.
    • 세미나 영상에서는 실제 참석자분들이 움직이며 예시를 보여준다.

 

 

Sharding

  • 데이터를 어떻게 나누고 어떻게 찾을 것인가?

 

Range

  • 특정 Range를 정의하고 그에 속하는 Range에 저장한다.
  • 데이터가 일정 Range에 몰릴 수 있다.
  • 확장 단계에는 편할지 몰라도, 결국 쏠림 현상이 특정 서버의 부하를 유발한다.

 

Modular

  • 서버 한 대 추가하면 리밸런싱이 많아진다.
  • 한 번 서버를 늘릴 때 *2로 늘린다거나.. 좀 줄일 순 있는데...

 

Indexed

  • Key가 어디에 저장될지 처리할 서버가 따로 존재
  • 장애 포인트가 생기는 문제

 

 

Redis Cluster

  • Hash 기반, Slot 16384로 구분
    • slot = crc16(key) % 16384
    • key값 설정으로 보낼 서버를 선택할 수 있다.
    • Redis 서버는 slot range를 가지고 있고 이 slot 단위의 데이터를 다른 서버로 전달하게 된다.
    • 자기 slot 외의 데이터가 오면 -Moved {Server} 에러를 보내고, 이 에러를 받으면 해당 서버로 옮긴다.

 

  • 장점
    • 자체적인 Primary/Secondary Failover
    • Slot 단위의 데이터 관리

 

  • 단점
    • 메모리 사용량이 늘어난다.
    • Migration 자체는 관리자가 시점을 결정한다.
    • 라이브러리 구현이 필요하다.

Redis Failover

Redis Cluster Failover

 

Coordinator 기반 Failover

  • Zookeper, etcd 등의 Coordinator 사용
  • 이를 기반으로 설정을 관리하면 동일 방식으로 관리가 가능하다.
  • 다만, 해당 기능을 이용하게끔 개발이 필요하다.

 

VIP, DNS 기반 Failover

  • 서버가 죽으면 승격된 Redis에 죽은 서버의 VIP를 할당해준다.
  • Health Checker는 죽은 서버의 연결을 모두 끊어, 클라이언트 쪽의 재접속을 유도한다.
    • 클라이언트 추가 구현은 필요 없다.

 

  • DNS 기반은 DNS Cache TTL 관리 필요
    • 클라이언트가 DNS 캐싱하는 경우 접속 불가 상태가 있을 수 있다.

 

  • VIP 기반은 외부 서비스가 필요한 경우 유리하다.

모니터링 지표

  • Redis Info 제공 정보
  • RSS
    • 피지컬 메모리를 얼마나 쓰고 있는지, OS가 보는 지표
  • Used Memory
    • Redis에서 인지하는 현재 사용 중인 메모리
  • Connection 수
  • 초당 처리 요청 숫자
  • CPU, Disk, Network RX/TX 등...

결론


Redis는 매우 좋은 툴이다.

  • Memory를 빡빡하게 사용하면 관리가 어려울 수 있다.
    • 스펙 대비 75% 이상 사용하면 장비 증설을 고려하자.
    • 쓰기 작업 용량이 크면 Migration도 주의하자.

 

Cache로써의 Redis

  • Redis에 이슈가 있는 경우, DB 등 다른 쪽의 부하를 확인해야 한다.
  • Consistent Hashing도 부하를 완벽하게 분산시키는 건 아니다.
    • 여기도 이슈가 있다면, Adaptive Consistent Hashing에 대해 알아보자.

 

Persistent Sotre로써의 Redis

  • 무조건 Primary/Secondary 구조를 가져가자.
  • 메모리는 절대 빡빡하게 가져가면 안 된다.
    • 정기적인 Migration을 수행해야 하고, 이를 위한 자동화 툴을 준비하자.

 

  • RDB나 AOF가 필요한 경우 Secondary에서만 구동한다.

영상 후기


  • 기본적인 Redis에 대한 내용들은 공식 문서에서 파악을 해야겠지만, 이것을 어떻게 사용하고 어떤 이슈들을 고려해야 하는지에 대한 내용은 문서에서 딱딱한 문체로 보면 크게 와닿지 않는 경우가 있다. 이 강의에서 약 1시간 40분 정도의 영상에서 Redis가 무엇인지에 대한 내용에서부터 시작해서, 실무에서의 사용 방식, 운영 시 장애 관리 방법 등에 대해 한 번 맛볼 수 있어서 입문자에게도 좋은 영상이었던 것 같다.
728x90