ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Redis] Redis 기초 정리하기
    Engineering/Database 2021. 8. 8. 20:43
    반응형

    https://www.youtube.com/watch?v=mPB2CZiAkKM&t

     본 포스트는 우아한테크 세미나의 우아한 Redis 영상을 정리한 내용입니다.

     

    Redis?

     레디스는 In-Memroy 기반의 Data Structure Store이다. 인메모리 기반의 특성으로 인하여 고성능이며, 주로 캐시 용도로 많이 사용된다. 인메모리 기반이기 때문에 서버가 재시작되면 휘발된다. (Redis Persistence를 통해서 일정 주기마다 데이터들을 디스크에 스냅샷 형태로 백업이 가능하다.)

     

    Redis에서 지원하는 자료구조

    Redis는 Key-Value Store 구조로써 아래와 같은 자료구조를 지원한다.

    • Strings
    • Sets
    • Sorted Sets
    • Lists
    • Hashes
    • Bitmaps
    • Bitfields
    • HyperLogLog
    • Geospatial indexes
    • Streams

    자세한 설명은 아래 링크를 참조한다.

    https://redis.io/topics/data-types

     

    Data types – Redis

    *Data types *Strings Strings are the most basic kind of Redis value. Redis Strings are binary safe, this means that a Redis string can contain any kind of data, for instance a JPEG image or a serialized Ruby object. A String value can be at max 512 Megabyt

    redis.io

    https://redislabs.com/redis-enterprise/data-structures/

     

    Data Structures | Redis Labs

    Strings One of the most versatile of Redis’ building blocks, Redis Strings is a binary-safe data structure. It can store any kind of data–a string, integer, floating point value, JPEG image, serialized Ruby object, or anything else you want it to carry

    redislabs.com

     

     이처럼 레디스는 풍부한 자료구조를 지원하기 때문에 개발의 편의성과 생산성을 높여준다.

     

    Cache 의 활용 - 1 (Look aside Cache)

     흔하게 많이 쓰이는 방법이다. 같은 데이터에 대해서 Read가 빈번할 경우에 RDB에 Read 부하를 줄여줄 수 있다.

     

    Cache 의 활용 -2 (Write Back)

     일정 시간동안 모든 데이터를 캐시 서버에 저장해두고, 주기적으로 RDB에 캐싱된 데이터를 일괄적으로 Write 하는 패턴이다. 모든 요청마다 RDB에 Write 하는 것보다 캐싱된 데이터를 벌크 Insert로 한꺼번에 Write 해주는 것이 훨씬 빠르다.

     

     캐시 서버라는 특성상, 서버가 장애 등의 이유로 리부팅되면 모두 휘발되기 때문에 데이터가 유실될 위험이 있으므로 중요도가 큰 데이터를 처리하기엔 부적합하다.

     

     이러한 패턴은 로그를 DB에 저장할 때 많이 사용된다.

     

    Cache 의 활용 -3 (Session Clustering)

     다중 서버를 운영하는 환경에서는 보통 웹 서버 앞단에 로드밸런서를 두게 된다. 이러한 구조에서 웹서버에서 각자의 메모리에 세션을 관리한다면 클라이언트는 서빙되는 웹서버에 따라 세션이 존재하거나 존재하지 않는 문제가 발생한다. 이러한 문제를 레디스 같은 캐시 서버를 통해서 클러스터링하여 해결할 수 있다.

     

    그 외에..

    • 레디스에서 제공하는 Sorted Set 자료구조를 활용하면 랭킹 서버를 손쉽게 구현이 가능
    • 인증 토큰 등의 저장소로 사용 (Strings 또는 Hash)
    • 유저 API Limit

     

    Collection 주의 사항

    • 하나의 Collection에 너무 많은 Item을 담지 않도록 한다.
    • Expire는 Collection의 Item 개별로 동작하지 않고, 전체 Collection에 대해서 동작한다.
      • 10,000개의 Item을 가진 Collection이 expire되면 10,000개의 Item이 모두 expire된다.

     

    Redis 운영

    메모리 관리

    • In-Memory Data Store 이므로 물리적인 크기 이상의 메모리를 사용하게 되었을 때, virtual memory 기능을 활성화 했다면 디스크와의 swap이 발생하여 퍼포먼스가 상당히 느려진다.
      (https://stackoverflow.com/questions/5068518/what-does-redis-do-when-it-runs-out-of-memory/5163220#5163220)
    • Maxmemory를 설정하더라도 이보다 더 사용할 가능성이 크다. (메모리의 단편화로 인하여)
    • 큰 메모리를 사용하는 인스턴스 하나보다는 적은 메모리를 사용하는 인스턴스 여러 개가 안전하다.
      • Redis는 Master/Slave로 레플리케이션을 운영하는 경우에 Write를 하면 fork를 하게 된다. 이러한 점은 Read 시에는 문제가 없지만 Write가 상당히 많은 경우에 Copy on Write 로 인하여 메모리를 더 많이 쓰게 된다.
    • RSS 값을 모니터링 해야한다.
      • RSS 값은 운영체제의 관점에서 Redis에 할당한 메모리 크기이다.
      • 이 값은 실제로 사용하고 있는 used_memory 값보다 크다.
      • Redis에서 INFO 명령을 통해 구체적인 지표들을 확인할 수 있다. (https://redis.io/commands/INFO)
    •  jemalloc 을 사용하여 메모리를 관리하며, 사용하는 버전에 따라 메모리 파편화 정도가 달라짐.
    • 다양한 사이즈를 가지는 데이터 보다는 유사한 크기의 데이터를 가지는 경우가 유리하다.

     

    O(N) 관련 명령어는 주의한다.

    • Redis는 Single Thread이기 때문에 한 번에 하나의 명령만 수행이 가능하기 때문이다.
    • 대표적인 O(N) 명령 (KEYS, FLUSHALL, FLUSHDB, Delete Collections, Get All Collections)
    • KEYS 명령어는 SCAN 명령을 사용하는 것으로 하나의 긴 명령을 짧은 여러 번의 명령으로 바꿀 수 있다.
    • Collection의 모든 Item을 가져와야 할 때
      • Sorted Set 같은 경우에는 Collection의 일부만 가져올 수 있음
      • 큰 Collection을 작은 여러 개의 Collection으로 나눠서 저장한다.
        • UserRanks -> UserRank1, UserRank2, UserRank3
        • 하나당 몇 천 개 안쪽으로 저장하는게 좋다.

     

    메모리가 부족할 경우

    • Scale Up
    • 현재 유지중인 데이터를 줄이기
    • 기본적으로 Collection들은 다음과 같은 자료구조를 사용한다.
      • Hash -> HashTable을 하나 더 사용
      • Sorted Set -> Skiplist와 HashTable을 이용
      • Set -> HashTable 사용
      • 위 자료구조들은 메모리를 많이 사용한다.
    • 메모리 사용량을 줄이기 위해 Zip List 자료구조를 이용할 수 있다.
      • 데이터를 선형적으로 적재하기 때문에 일반적인 자료구조들보다 상대적으로 느릴 수는 있지만 데이터의 개수가 적다면 선형 탐색을 하더라도 빠르고, 메모리 사용량을 줄 일 수 있다.
      • List, Hash, Sorted Set 등을 Zip List 로 대체해서 처리하는 설정을 이용하여 적용할 수 있다.

     

    Replication

    • Redis의 Replication은 Async Replication 이므로 Replication Lag이 발생할 수 있다.
    • 'Replicaof'(5.0.0 버전 이상) 또는 'slaveof' 명령으로 설정 가능하다.
      • Replicaof hostname port
    • DBMS로 보면 statement replication과 유사하다.
      • RDB에서 now() 라는 함수를 이용하여 저장할 경우 Primary에서 저장되는 시간과 Secondary에서 저장되는 시간이 다른 경우
    • Replication 설정 과정
      • Secondary에 replicaof 또는 slaveof 명령을 전달
      • Secondary는 Primary에 Sync 명령 전달
      • Primary는 현재 메모리 상태를 저장하여 전달하기 위해 Fork
      • Fork 한 프로세서는 현재 메모리 정보를 disk에 dump
      • 해당 정보를 secondary에 전달
      • Fork 이후의 데이터를 Secondary에 지속적으로 전달
    • Replication 과정에서 fork가 발생하므로 메모리 부족이 발생할 수 있다.
    • Redis-cli --rdb 명령은 현재 상태의 메모리 스냅샷을 가져오므로 같은 문제를 발생시킬 수 있다.
    • AWS나 클라우드의 Redis는 좀 다르게 구현되어서 좀 더 해당 부분이 안정적이다.
    • 네트워크 이슈나 사람의 작업으로 많은 대수의 Redis 서버가 동시에 Replication을 재시도 하지 않도록 주의해야함.
      • 네트워크 Bandwidth 보다 큰 트래픽이 대량으로 발생하여 네트워크 이슈가 발생할 수 있음.

     

    권장 설정 Tip

    • Maxclient 설정 50,000
    • RDB/AOF 설정 off 가 성능, 안정성 면에서 유리
    • 특정 command 는 disable (ex. KEYS)
    • 전체 장애의 90% 이상이 KEYS와 SAVE 설정을 사용해서 발생한다.
    • 적절한 ziplist 설정

     

    데이터 분산 방법

    Application 레벨에서 분산

    • Consistent Hashing
      • 단순히 모듈러 연산을 통해서 분산시키면 서버의 수를 늘리거나 줄이는 경우에 분산된 데이터들이 대량으로 rebalancing 되어야 한다.
      • Consistent Hashing을 사용하면 서버 수의 증감된 데이터 분량만 rebalancing 하도록 줄일 수 있다. (ex. 서버가 4대인 상황에서 데이터의 rebalancing으로 1/4 만 바뀜)
    • Sharding
      • Range
        • Range를 정의하고 해당 Range에 속하면 저장
        • 특정 Range 서버에만 부하가 몰릴 가능성이 높다.
      • Modular
        • Range 보다는 균등하게 분배한다.
        • 서버 수의 증감에 따라 rebalancing할 데이터가 많아진다.
      • Indexed
        • 해당 Key가 어디에 저장되어야 할지 관리 서버가 따로 존재
        • Index 서버에 대해서 장애 포인트가 늘어난다.

     

    Redis Cluster 사용

    • Hash 기반으로 Slot 16384 로 구분
      • Hash 알고리즘은 CRC16을 사용
      • Slot = crc16(key) % 16384
      • Key가 Key{hashKey} 패턴이면 실제 crc16에 hashKey가 사용된다.
      • 특정 Redis 서버는  slot range를 가지고 있고, 데이터 migration은 이 slot 단위의 데이터를 다른 서버로 전달하게 된다. (migrateCommand 이용)
    • 장점
      • 자체적인 Primary, Secondary Failover
      • Slot 단위의 데이터 관리
    • 단점
      • 메모리 사용량이 더 많음
      • Migration 자체는 관리자가 시점을 결정해야 함.
      • Library 구현이 필요함.

     

    Redis Failover

    • Coordinator 기반 Failover
    • VIP/DNS 기반 Failover
    • Redis Cluster 의 사용

    Coordinator 기반

    • Zookepper, etcd, consul 등의 Coordinator 사용
    • Health Checker가 Redis 서버의 상태를 주기적으로 체크하고, Primary에 장애가 발생하면 Secondary를 Primary로 승격 시키고 Coordinator에 업데이트 한다. Coordinator는 Api Server에 Primary 서버의 변경 사실을 알린다.
    • Coordinator 기반으로 설정을 관리한다면 동일한 방식으로 관리가 가능하다.
    • 해당 기능을 이용하기 위한 개발이 필요하다.

     

    VIP/DNS 기반

     

    • 클라이언트에 추가적인 구현이 필요없다.
    • VIP 기반은 외부로 서비스를 제공해야 하는 서비스 업자에 유리하다. (ex. 클라우드 업체)
    • DNS 기반은 DNS Cache TTL을 관리해야 한다.
      • 사용하는 언어별 DNS 캐싱 정책을 잘 알아야 한다.
      • DNS 솔루션에 따라서 한 번 가져온 DNS 정보를 다시 호출하지 않는 경우도 존재한다.

     

    Monitoring

    • Redis Info를 통한 정보
      • RSS
      • Used Memory
      • Connection 수
        • Redis는 Single Thread이기 때문에 Connection의 연결과 끊김이 빈번하면 자원을 여기에 많이 사용하게 된다.
      • 초당 처리 요청 수
        • 짧은 명령에 대해서는 CPU에 영향을 받는다.
    • System
      • CPU
      • Disk
      • Network rx/tx
        • Redis는 네트워크로 통신하므로 대량의 트래픽으로 인하여 앞 단의 스위치에서 버티지 못하고 패킷을 드랍시키는 경우 이슈가 생길 수 있다.
    • CPU가 100%를 칠 경우 
      • 처리량이 매우 많다면 CPU 성능이 좀 더 좋은 서버로 이전
    • O(N) 계열의 특정 명령이 많은 경우
      • Monitor 명령을 통해 특정 패턴을 파악하는 것이 필요
      • Monitor 명령을 잘못 사용하면 부하로 해당 서버에 더 큰 문제를 야기할 수 있음. (짧게 쓰는 것이 좋음)

     

    마무리

    • 메모리를 넉넉하게 사용하지 않으면 관리하기 어려움
      • 32기가 장비에서 24기가 이상 사용하면 장비 증설을 고려하는 것이 좋음
      • Write가 Heavy 할 때는 migration도 주의해야함.
    • Client-output-buffer-limit 설정이 필요.

     

    Cache Store로 사용하는 경우

    • Redis가 문제가 있을 때 DB등의 부하가 어느정도 증가하는지 확인 필요.
    • Consistent Hashing도 실제 부하를 아주 균등하게 나누지는 않음. Adaptive Consistent Hashing을 이용해 볼 수 있음.

     

    Persistent Store로 사용하는 경우

    • 무조건 Primary/Secondary 구조로 구성이 필요함
    • 메모리를 무조건 넉넉하게 사용해야 함
      • 정기적인 Migration이 필요
      • 가능하면 자동화 툴을 만들어서 이용하는 것이 좋음
    • RDB/AOF가 필요하면 Secondary에서만 구동
      • RDB보다는 AOF가 IO 발생이 조금 더 균등하게 일어나기 때문에 안정적이다.

     


    참고자료

    https://www.youtube.com/watch?v=mPB2CZiAkKM 

    https://www.slideshare.net/charsyam2/redis-196314086

     

    Redis

    Redis, Redis Failover, Consistent Hashing, Commands, Failures

    www.slideshare.net

     

    반응형

    댓글

Designed by Tistory.