- 0) Redis 란?
- REmote DIctionary System
- 고성능 In-Memory Key-Value Document Storage.
- Single-Thread 기반의 처리보장.
- 영속성(Persistance) 지원. (disk-snapshot 및 journaling)
- 수평적 확장을 위한 Scale-Out 지원.
- Read 성능을 위한 Master-Slave 지원
- Write 성능을 위한 Master Sharding 지원.
- Key만료(expiration), 트랜잭션, Pub/Sub 기능제공.
- (모든 커맨드에) 비동기-콜백옵션 기능제공.
- // TODO : https://redis.io/documentation
- // TODO : https://www.youtube.com/watch?v=xMSVlUnBy6c
- 1-1) 설치
- wget http://download.redis.io/releases/redis-5.0.5.tar.gz
- tar xzf redis-5.0.5.tar.gz -> cd redis-5.0.5 -> sudo make install
- redis-server : 레디스 서버 (실데이터 저장소) (stand-alone 및 cluster모드 제공)
- redis-cli : 레디스 클라이언트 (커맨드라인 인터페이스)
- redis-lib : 레디스 라이브러리 (다양한 언어 모두지원)
- 1-2) 지원
- Persistence(저장)
- RDB(Redis Database)
- 특정시점의 데이터 "바이너리 파일". (disk-snapshot)
- LZF 압축 사용. (적은 메모리로 빠른압축 및 적당한? 압축률)
- SAVE 또는 BGSAVE 커맨드로 수행. (다양한 옵션 제공...)
- redis.conf 를 통해서, 주기적인 스냅샷 정책 설정 가능.
- 복구속도 면에서, 유리함.
- AOF(Append Only File)
- 커맨드히스토리 "로그 파일". (journaling)
- 완벽한 내구성의 전략으로 사용.
- 레디스 설정에서 다양한 지시자... 제공.
- 저장안정성 및 내구성 면에서, 유리함.
- RDB(Redis Database)
- Replication(복제)
- Master-Slave 구조로 쓰기/복제 지원 함.
- 레디스 인스턴스를 Slave화 하는 3가지 방법... 제공.
- 단순히 레디스 싱글-인스턴스가 자체적으로~ Master 장애시, '자동 fail-over'는 지원 안함.
- Partitioning(분산)
- 데이터를 멀티-인스턴스에 나누는 법.
- 캐시 용도이면, 단순히 Hit-Rate이슈이지만~ Vs 스토리지 용도이면, 아주 어려운 Clustering이슈 다.
- 수직 파티션 : value를 나누어서 분산 (예 : RDBMS에서 컬럼을 쪼개서, 다른 테이블로~)
- 수평 파티션 : 샤딩. (key를 분산)
- 범위함수 : 단순히 key를 범위로 나누어 분산. (당연히 분포가 고르지 않고, 인스턴스 갯수에 영향)
- 해시함수 : key를 MD5 나 SHA1 등에 고른 분포의 함수를 사용. (여전히 인스턴스 갯수변화에 영향)
- 일관적(consistent) 해시함수 : Hash-Ring으로 인스턴스 갯수변화에 영향을 최소화 한다.
- 태깅 : 그냥 명시적으로 특정 인스턴스 지정. ( {key}:{tag} , {value} 으로 지정)
- 샤딩 구현
- 클라이언트 구현 : 단순히 로직으로 개발자가 직접 구현.
- 프록시 구현 : twemproxy 등의 외부프로그램으로 손쉽게 구현. (nutcracker)
- [twemproxy 1대] -/\> [redis-master 3대] 는 twemproxy 장애에 취약함.
- [LB 1대] -/\> [twemproxy 2대] -/\> [redis-master 3대] 는 안전.
- 질의(query) 라우터 : ???
- Persistence(저장)
- 1-3) 분산 시스템
- 초장기 레디스는 'Master-Slave 토포로지'의 가볍고 빠른 목적에 프로젝트. ('자동 fail-over' 및 '샤딩' X)
- 2011년쯤 '레디스 클러스터' 프로젝트를 시작했지만... 대실패! (2015년초 3.0에서 안정화)
- 이후, '자동 fail-over' 만이라도 해결하기위해~ '레디스 센티널' 프로젝트를 출시. (2013년말 2.8에서 안정화)
- CAP : (레디스는 네트워크 장애시, C-A 에 문제가 생기고... 최소화하는 설정은 존재)
- NetworkPartition이 혼돈상황에는, 약한(?) '일관성' 제공. (Consistency : ?)
- NetworkPartition이 발생하더라도, 어느정도(?) '가용성' 제공. (HA, Availability : ?)
- 기본적으로 3대 이상으로 구성하고, '분할 내성' 제공 (Partition Tolerance : O)
- 1-4) sentianl 모드
- 하나의 '레디스 인스턴스'마다, 하나의 '센티널 인스턴스'를 띄우는 식.
- 복제
- ...
- // TODO : ...
- 1-5) cluster 모드
- 샤딩
- '해시슬롯'이라는 함수로 16,384개의 고정된 슬롯값을, 각 Partition들이 1/n씩 사용함. (CRC-16)
- 슬롯을 할당받지 못하면, 말 그대로 어떤 데이터 키값도 전달되지 않는다.
- 슬롯의 자동 재분포는 없다. x개의 슬롯을 수동으로 재할당 해야 한다고 한다. (?뭔말?)
- 클라이언트는 자신의 데이터 키값을 가지는 슬롯을 잘 찾아아서, 쿼리 하면 된다. (Lib가 알아서 하겠지?)
- 서버당 하나의 redis 프로세스가 클라이언트Port으로 서비스 하게 됨.
- 10000 더한 Port으로 노드 내부간 버스통신. (health-check:문제탐지, fail-over:M/S교체, re-sharding:샤드이동)
- 모든 데이터는 Master단위로 저장되고, Slave단위로 복제된다. (참고로 fail-over시, 해당 M/S는 모두 블락 됨)
- 예)
- 서버1 : M1:6379 - S3:6380
- 서버2 : M2:6379 - S1:6380
- 서버3 : M3:6379 - S2:6380
- 예) redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes1.conf --cluster-node-timeout 5000 --cluster-slave-validity-factor 10 --cluster-migration-barrier 1 --cluster-require-full-coverage yes --dbfilename dump1.rbd --daemonize yes
- cluster-enabled yes : // cluster 모드
- cluster-config-file nodes1.conf : // cluster에서 발생하는 모든 변경사항을 관리하는 설정로그파일
- cluster-node-timeout 5000 : // cluster의 node의 헬스체크 판단시간 (M장애->S승격)
- cluster-slave-validity-factor 10 : // timeout에 factor를 곱한 시간만큼, 기다려준후~ 최종판단
- cluster-migration-barrier 1 : // Master에 연결해야 할 최소 Slave 갯수
- (M/S 1:1 구조는 fail-over이후엔 M/S 1:0 이 되어서... 아주 불안한 상황이 됨)
- (그래서 모든 M/S 1:2는 좀 과하니, 하나만 M/S 1:2로 하고~ 'barrier 1' 하면~ "S빌려오기" 가능함)
- cluster-require-full-coverage : // Master가 장애일때, Slave가 없을경우의 정책
- yes : 전체 클러스터 블락 (따라서, 전체슬롯 16,384개가 모두 할당 되있어야 함)
- no : 해당 Master가 담당하는 슬롯만! 에러처리!!!
- 예) 각 서버에 Master를 띄운 후, redis-cli -c -p 6379 으로 접속
- CLUSTER INFO : 해당 cluster 모드의 상태확인.
- CLUSTER ADDSLOTS {0..5460}
- CLUSTER ADDSLOTS {5461..10922}
- CLUSTER ADDSLOTS {10923..16383} : 각 서버에 슬롯할당.
- CLUSTER SET-CONFIG-EPOCH 1
- CLUSTER SET-CONFIG-EPOCH 2
- CLUSTER SET-CONFIG-EPOCH 3 : 각 서버에 처음 한번만, 'cluster 상태표시숫자'인 에포크값을 셋팅.
- CLUSTER MEET {ip} {port} : 서버가 서로를 인식. (서버1에서 2,3을 하면... 다 됨)
- CLUSTER INFO : 확인
- 예) 각 서버에 Slave를 띄운 후, redis-cli -c -p 6380
- CLUSTER MEET {ip} {port} : cluster 중 아무 서버의 ip 와 port으로 일단 들어감.
- CLUSTER NODES : 자신이 복제할 Master의 node_id를 찾는다. (cluster의 모든서버 다 나옴)
- CLUSTER REPLICATE {node_id} : Master 지정. (자신이 Slave으로 바뀜)
- (참고적으로 Slave를 READONLY 커맨드하면, Slave도 읽기쿼리를 처리해서~ Master 부하 줄여줌)
- 예) 신규 서버 Node 추가 -> 샤드이동(re-sharding)
- 일단 CLUSTER MEET으로 들어가면, '해시슬롯'이 없는 Master으로 시작 함.
- 기존의 Node에서 -> 신규 Node으로 '해시슬롯'을 옮기고, 기존의 모든 키값도 옮겨야 함.
- 1. 기존 Node의 '해시슬롯'을 import 지정
- 2. 신규 Node의 '해시슬롯'으로 export 지정
- 3. 기존 Node --'해시슬롯의 모든 키값'--> 신규 Node
- 4. 모든 Node에 공유
- (신규Node에서) CLUSTER SETSLOT {hashslot} IMPORTING {기 node_id} : '해시슬롯' 상태를 importing
- (기존Node에서) CLUSTER SETSLOT {hashslot} MIGRATING {신 node_id} : '해시슬롯' 상태를 migrating
- (기존Node에서) MIGRATE {ip} {port} {key} {db} {timeout} : '키값'을 옮김.
- (모든Node에서) CLUSTER SETSLOT {hashslot} NODE {신 node_id} : '해시슬롯'을 옮김.
- CLUSTER SETSLOT {hashslot} STABLE : '해시슬롯' 상태를 정리함. (재샤딩 롤백 처리시 유용)
- 예) 기존 서버 Node 삭제
- 일단... 기존 '해시슬롯' 재샤딩 및 해당 모든 '키값'을 옮긴다. 그리고...
- CLUSTER FORGET {기 node_id} : 60초 이내에 모든 Node에서, 금지목록에 추가 하도록 해주면 된다.
- 샤딩
- 2-1) 기본 데이터-타입
- String : int, float, text(json등등), binary 데이터. 예) GET-SET, MGET-MSET, SETEX, EXPIRE, TTL, INCR-DECR, ...
- List : Linked-List 구조로~ collection , stack , queue 으로 사용가능. 예) LPUSH-RPUSH, LLEN, LINDEX, LRANGE, LPOP-RPOP, RPOPLPUSH, B옵션(polling 고민없이 블록킹 대기가능), ...
- Hash : *객체단위 정보저장*. ZipList(메모리최적화) 혹은 HashTable(검색최적화) 구조. 예) HGET-HSET, HMGET-HMSET, HDEL, HKEYS-HVALS, HSCAN, ...
- 2-2) 고급 데이터-타입
- Set : 필터링,그룹핑,체킹 등에 활용. 예) SADD, SINTER, SDIFF, SUNION, SRANDMEMBER, SISMEMBER, SREM, SMEMBERS, ...
- SortedSet : 점수기반으로 정렬이되는 Set. 예) ZADD, ZRANGE, ZREM, ZSCORE, ZRANK, ...
- Bitmap : 내부적으로 String의 비트연산자. 예) SETBIT, GETBIT, BITCOUNT, BITOP(OR-AND-XOR-NOT), ...
- Hyperlog : 확률성의 알고리즘. 100%는 아니지만, 거의 근사치 값을 O(1)으로 제공함. 특정 방문자수 및 특정 검색어수 등에 활용. 예) PFADD, PFCOUNT(근사치), PFMERGE(근사치 합), ...
- 2-3) 타임시리즈
- 흔히 시간에 따라 변하는 그래프를 String, Hash, SortedSet, Hyperlog 으로 각각 구현하는 예제.
- 예) 실시간 주식시장 그래프. 일일 순방문자 추이 혹은 동영상 재생 횟수. 등등등.
- String 구현 :
- "event:sec:{시간}","event:min:{시간}","event:hour:{시간}","event:day:{시간}" 으로 key 구성.
- SET(key,value) -> EXPIRE(key,ttl) -> GET(key)
- Hash 구현 :
- Hash+SortedSet 구현 :
- String+Hyperlog 구현 :
- String 구현 :
- 2-4) 기능성 커맨드
- Pub/Sub : ...
- Transaction :
- RDBMS 같은 '자동 roll-back' 이 되는 트랜잭션은 아님. (무효화만 존재)
- Application단의 '커맨트 큐' 같은 역할. (명령어를 묶는 기능)
- ...
- Pipeline : ...
- 스크립트 : ...
- 관리 : ...
- 2-5) 보안&팁
- Java-Client :
- Jedis 나 Lettuce 추천.
- Jedis는 싱글쓰레드라, Jedis-Pool을 관리해야 함.
- Lettuce는 멀티쓰레드이고, 당연히 쓰레드세이프 하다고 함.
- // TODO : ...
- Java-Client :
- 3) 활용 예시
- SNS
- 예) app1:following:A = {B,C}
- 예) app1:follower:A = {C}
- Key에 특정값을 포함시키는것을 망설이지 마라
- 세션 저장소
- 웹서버간 세션정보 공유
- 예) session id, 정보, ttl expired
- Tag 검색
- 예) blogtag:갬성 = {contentsId1, contentsId2, ...}
- 예) blogtag:움프 = {contentsId2, contentsId3, ...}
- 특정 tag에 contentsId들로 DB 쿼리.
- API Key 일별 호출제한
- 예) api:gmap:{api키}:{일날짜} = 2411회
- 최근 조회 상품목록
- Sorted Set을 사용하여, Key-Score-Value 구조로 한상품을 유니크 하게 자동정렬
- ZRemRangeByRank 혹은 ZRemRangeByScore 으로 목록갯수 제어함.
- 예) view:recently:kim , {날짜} , {상품번호}
- SNS
-끝-
'NoSQL' 카테고리의 다른 글
HBase (0) | 2019.05.18 |
---|---|
Cassandra (0) | 2019.05.18 |
MongoDB (0) | 2019.05.18 |
MariaDB (SQL) (0) | 2019.04.24 |
PostgreSQL (작성예정) (0) | 2019.04.10 |