728x90
세미나 영상
내용 정리
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