• 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)
        • 완벽한 내구성의 전략으로 사용.
        • 레디스 설정에서 다양한 지시자... 제공.
        • 저장안정성 및 내구성 면에서, 유리함.
    • 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) 라우터 : ???
  • 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 구현 : 
  • 2-4) 기능성 커맨드
    • Pub/Sub : ... 
    • Transaction : 
      • RDBMS 같은 '자동 roll-back' 이 되는 트랜잭션은 아님. (무효화만 존재)
      • Application단의 '커맨트 큐' 같은 역할. (명령어를 묶는 기능)
      • ...
    • Pipeline : ...
    • 스크립트 : ...
    • 관리 : ...
  • 2-5) 보안&팁
    • Java-Client :
      • Jedis 나 Lettuce 추천.
      • Jedis는 싱글쓰레드라, Jedis-Pool을 관리해야 함.
      • Lettuce는 멀티쓰레드이고, 당연히 쓰레드세이프 하다고 함.
    • // TODO : ...
  • 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 , {날짜} , {상품번호}

-끝-

'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

+ Recent posts