무지를 아는 것이 곧 앎의 시작

Redis

Redis 입문용 기본지식 채워봅시다

Alex96 2022. 10. 26. 20:31

우아한테크세미나 191121 우아한레디스 by 강대명님 영상 토대로 작성한 내용입니다.

Cache

레디스를 알기 전에 Cache에 대해 먼저 알 필요가 있다.

캐시는 나중에 요청올 결과를 미리 저장해두었다가 빠르게 서비스를 해주는 것을 의미한다.

ex) Factorial같은 경우 10!을 계산한다면 1부터 10까지 다 곱하는게 아니라, 이전 값 즉 9!을 어딘가에 저장해두었다가 10만 곱해서 반환하면 된다. 즉 접근 속도에 이점이 있다.

CPU Cache

CPU Cache

메모리는 디스크보다 용량은 훨씬 적지만, 접근 속도는 디스크보다 훨씬 빠르다.

레디스는 이 메모리에 데이터를 저장한다.

Cache 사용 패턴

Look Aside

  1. Server는 데이터가 존재하는지 Cache를 먼저 확인
  2. Cache에 데이터가 있으면 Cache에서 가져온다.
  3. Cache에 데이터가 없다면 DB에서 읽어온다.
  4. DB에서 읽어온 데이터를 Cache에 다시 저장한다.

장점: 읽기 성능 향상

Write Back

  1. Server는 모든 데이터를 Cache에만 저장
  2. Cache에 틀정 시간동안의 데이터가 저장
  3. Cache에 있는 데이터를 데이터를 DB에 저장
  4. Cache에 있는 데이터를 삭제

장점: 쓰기 성능 향상

단점: 데이터를 캐시에 저장해두고 일정 시간마다 DB에 옮겨쓰기 때문에 그 사이에 장애가 발생하거나 하는 상황이 생기면 캐시에 있는 데이터가 유실될 수 있다.


Collection

Collection이 가지는 장점

  • 개발의 편의성
    • 랭킹 서버를 직접 구현한다면?
      • 일반적인 방법으로는 DB에 유저의 Score를 저장하고 order by로 정렬 후 읽어오기
        • 개수가 많아지면 속도에 문제가 발생할 수 있다. 디스크를 사용하므로.
      • Redis의 Sorted Set을 이용하면, 너무 쉽게 랭킹을 구현할 수 있음.
  • 개발의 난이도
    • 레디스의 자료구조는 Atomic하기 때문에 자체적으론 동시성 이슈가 발생하지 않음.
      • 그래도 잘못 짜면 발생함.
        • ex) 레디스 내에서 싱글 스레드로만 자료구조에 접근해서 아토믹 한거지 서버 어플리케이션 단에서 꼬이려면 꼬임.

Collection을 잘 이용하는 것으로, 여러가지 개발 시간을 단축시키고, 문제를 줄여줄 수 있기 때문에 Collection이 중요하다.


Redis 사용처

  • Remote Data Store
    • 여러 서버에서 데이터를 공유하고 싶을 때
  • 주로 많이 사용하는 예시
    • 인증 토큰 등을 저장(Strings 또는 hash)
    • Racking 보드로 사용(Sorted Set)
    • 유저 API Limit
    • 작업 큐 (list)

Redis Collections

  • Strings
    • key / value 저장 방식
  • List
    • 연결 리스트 형태. 맨 앞이나 맨 뒤에서의 삽입 삭제는 빠른데 중간 삽입 삭제는 느림
  • Set
    • 중복 데이터 X, 데이터가 있는지 없는지만 체크하는 용도
    • ex) 특정 유저를 follow하는 목록을 저장해둔다면
  • Sorted Set
    • Set은 순서가 없는데, Sorted Set은 Score라는걸 줘서 그 값 기준으로 정렬됨. 랭킹에 따라 순서가 바뀌길 바란다면 사용.
    • sorted set의 score는 double타입이기 때문에, 값이 정확하지 않을 수 있다.
  • Hash
    • Key 밑에 sub key가 존재

Collection 주의 사항

  • 하나의 컬렉션에 너무 많은 아이템을 담으면 좋지 않음.
    • 10000개 이하 몇 천개 수준으로 유지하는게 좋음
  • expire는 Collection의 item 개별로 걸리지 않고 전체 Collection에 대해서만 걸림
    • 즉 해당 10000개의 아이템을 가진 Collection에 expire가 걸려있다면 그 시간 후에 10000개의 아이템이 모두 삭제.

Redis 운영

메모리 관리를 잘하자

  • Redis는 In-Memory Data Store
  • Physical Memory 이상을 사용하면 문제가 발생
    • Swap이 있다면 Swap 사용으로 해당 메모리 Page접근시 마다 늦어짐
  • Maxmemory를 설정하더라도 이보다 더 사용할 가능성이 큼.
  • RSS(Resident set size)값을 모니터링 해야함.
    • 많은 업체가 현재 메모리를 많이 사용해서 Swap을 쓰고 있다는 것을 모를 때가 많다고 한다. 그냥 레디스가 느려졌어요~ 한다고 함
  • 메모리 파편화가 발생할 수 있음.
    • 다양한 사이즈를 가지는 데이터 보다는 유사한 크기의 데이터를 가지는 경우가 유리하다.

메모리가 부족할 때는?

  • Cache is Cash
    • 더 메모리가 큰 장비로 Migration
    • 메모리가 빡빡하면 Migration중에 문제가 발생할 수도 있다.
    • 60 ~ 70 프로정도 사용중일 때 더 큰 메모리 장비로 옮겨야 한다.
  • 있는 데이터 줄이기
    • 데이터를 일정 수준에서만 사용하도록 특정 데이터를 줄임
    • 다만 이미 Swap을 사용중이라면, 프로세스를 재시작 해야함.
  • 메모리를 줄이기 위한 설계
    • 기본적으로 Collection들은 다음과 같은 자료구조를 사용
      • Hash → HashTable을 하나 더 사용
      • Sorted Set → Skiplist와 HashTable을 이용
      • Set → HashTable 사용
      • 해당 자료구조들은 메모리를 많이 사용함.
    • Ziplist를 이용하자
      • ziplist
        • In Memory특성 상, 적은 개수라면 선형 탐색을 하더라도 빠르다.
        • List, hash, sorted set 등을 ziplist로 대체해서 처리를 하는 설정이 존재

O(n)관련 명령어는 주의하자.

  • Redis는 Single Threaded
    • 그러면 Redis가 동시에 여러 개의 명령을 처리할 수 있을까?
    • 참고로 단순한 get / set의 경우, 초당 10만 TPS이상 가능 (CPU 속도에 영향받음)
    • 한번에 하나의 명령만 수행 가능
      • 긴 시간이 필요한 명령을 수행하면, 뒤에 들어오는 명령들도 다 그 시간만큼 대기해야해서 망함
  • 대표적인 O(n) 명령들
    • keys
    • flushall, flushdb
    • delete collections
    • get all collections
  • 대표적인 실수 사례
    • 모니터링 스크립트가 주기적으로 keys를 호출…
    • 아이템이 몇만개 든 hash, sorted set, set에서 모든 데이터를 가져오는 경우
  • keys는 어떻게 대체할 것인가?
    • scan 명령을 사용하는 것으로 하나의 긴 명령을 짧은 여러 번의 명령으로 바꿀 수 있다.
      • 그 사이사이에 다른 명령들이 수만건씩 처리 가능
  • Collection의 모든 item을 가져와할 때?
    • Collection의 일부만 가져오거나
      • sorted set
    • 큰 Collection을 작은 여러 개의 Collection으로 나눠서 저장 (샤딩)
      • 하나당 몇천개 안쪽으로 저장하는게 좋음

Redis Replication

  • Async Replication
    • Replication Lag이 발생할 수 있다.
  • ‘Replicaof’(≥ 5.0.0) or ‘slaveof’ 명령으로 설정 가능
    • replicaof hostname port
  • DBMS로 보면 statement replication이 유사
  • Replication 설정 과정
    • Secondary에 replicaof or slaveof 명령을 전달
    • Secondary에 Primary에 sync 명령 전달
    • Primary는 현재 메모리 상태를 저장하기 위해 Fork
    • Fork한 프로세서는 현재 메모리 정보를 disk에 dump
    • 해당 정보를 secondary에 전달
    • Fork이후의 데이터를 secondary에 계속 전달
  • Replication 주의사항
    • Repliaction 과정에서 fork가 발생하므로 메모리 부족이 발생할 수 있다.
    • redis-cli —rdb 명령은 현재 상태의 메모리 스냅샷을 가져오므로 같은 문제를 발생시킴
    • AWS나 클라우드의 Redis는 좀 다르게 구현되어서 좀더 해당 부분이 안정적

redis.conf 권장 설정

  • maxclient 설정 50000
  • RDB / AOF 설정 off
  • 특정 commands disable
    • keys
    • 전체 장애의 90프로 이상이 keys와 save설정을 사용해서 발생
  • 적절한 ziplist 설정

Redis 용도?

  • 데이터의 특성에 따라서 선택할 수 있는 방법이 달라진다.
  • Cache 용도로 사용할 경우 문제가 적게 발생
    • Redis가 문제가 있을 때 DB 등의 부하가 어느 정도 증가하는지 확인 필요
  • Persistent Store의 경우
    • 무조건 Primary / Secondary 구조로 구성이 필요함
    • 메모리를 절대로 빡빡하게 사용하면 안됨
    • 정기적인 migration이 필요
    • 가능하면 자동화 툴 만들어서 이용
    • RDB / AOF 가 필요하다면 Secondary에서만 구동