728x90
반응형

Redis

 

- 오픈소스로서 데이터베이스(NoSQL DBMS - Key/Value 형식으로 동작)로 분류되기도 하고 Memcached와 같이 인메모리 솔루션으로 분류되기도 하는데 메모리 기반으로 구성됨 (여러대의 서버로 구성 가능)

 

- 성능은 Memcached에 버금가면서 다양한 데이터 구조체를 지원함으로써 Message Queue, Shared Memory, Remote Dictionary 용도로 사용될 수 있음 (대규모 메세지를 실시간으로 처리하기 위해 사용)

 

- 디스크가 아닌 메모리 기반 데이터 저장소 (In-Memory data Structure Store)로 데이터 베이스로도 사용될 수 있으며 Cache로도 사용될 수 있는 기술임

 

- 안전한 데이터의 보관과 백업을 위해 두 가지 방법을 제공 (메모리를 활용하면서 데이터 보존)

  • 다른 서버의 메모리에 실시간으로 복사본 남김

  • 디스크에 직접 저장하는 방법

 

- 레디스의 NoSQL 특징

  • 데이터 저장소로 I/O가 가장 빠른 메모리 채택

  • 단순한 구조의 데이터 모델인 Key-Value 방식을 통해 빠른 속도

  • 캐시 및 데이터 스토어에 유리

  • 다양한 API 지원

 

- 인메모리 캐시 

  • 캐시 방식을 통해 DB Read의 부하를 감소

  • 서비스 요청이 증가하여 DB 요청이 많아지면 DB 서버 부하가 증가하는데 메모리 캐시가 적용되면 성능 및 처리 속도가 향상

 

- 레디스는 인메모리 캐시방식 중 Global Cache 방식을 사용

  • Global Cache 방식은 네트워크 트래픽이 발생하기 때문에 java heap 영역에서 조회되는 local cache의 성능이 더 낫지만 WAS 인스턴스가 증가할 경우엔 캐시에 저장되는 데이터 크기가 커질수록 레디스 방식이 더 유리

  • 급격한 사용자가 집중되는 상황이나 대규모의 확장이 예정되어 있는 환경에 적합

  • Global Cache 방식이 적용되어 WAS 인스턴스 확장에는 유리하지만 Cache 및 Redis Session 등 관리 포인트가 늘어난다는 단점이 있음

 

- Key / Value 저장소

 

 

  • 레디스는 기본적으로 Key-Value 저장소이며 특정 키 값에 값을 저장하는 구조로 되어 있고 기본적인 PUT/GET Operation을 지원

  • 모든 데이터는 메모리에 저장되고 이로 인해 매우 빠른 Read/Write 속도를 보장

  • 전체 저장 가능한 데이터 용량은 물리적인 메모리 크기를 넘을 수 있음 (OS 영역의 Swap을 사용하는 것인데 성능이 급격히 떨어지기 때문에 의미 없음)

  • 데이터 액세스는 메모리에서 일어나지만 서버 재부팅 상황에서 메모리에 있는 데이터가 모두 지워지기 때문에 이런 상황에서 데이터 저장을 보호하기 위해 Disk를 Persistence Store로 사용

 

- Reids는 여러 프로세스에서 동시에 같은 Key에 대한 갱신을 요청할 경우 Atomic한 처리로 데이터 부정합 방지 Atomic 처리 함수를 제공함

 

- 리스트 배열형식의 데이터 처리에 특화되어 있으며 리스트형 데이터의 입력과 삭제가 mysql에 비하여 10배정도 빠름

 

- 여러대의 서버 구성이 가능한데 Consistent Hashing 혹은 Master-Slave 형식으로 구성 가능

 

 

 

사용 가능한 데이터형

 

- 단순하게 Key-Value 타입기반이라면 이미 Memcached가 존재한다. Redis는 Key-Value Store이기는 하지만 저장되는 Value가 단순한 Object가 아니라 자료 구조를 갖기 때문에 큰 차이를 보인다.

 

 

1. String (일반적인 Key-Vaule)

 

- 일반적인 문자열로 최대 512MByte 길이까지 지원

 

- Text 문자열 뿐만 아니라 Integer와 같은 숫자나 JPEG같은 Binary File까지도 저장할 수 있음

 

- 데이터형의 값은 정수인 경우 int로 아니면 raw로 encoding 됨

 

 

2. Lists (Array 형태로 Key 1개에 N개의 값을 가짐, 중복 값 가능)

 

- List는 String들의 집합으로 저장되는 데이터 형태는 Set과 유사하지만 일종의 양방향 Linked List라고 생각하면 됨

 

- List 앞과 뒤에서 PUSH/POP 연산을 이용해서 데이터를 넣거나 뺄 수 있고 지정된 Index 값을 이용하여 지정된 위치에 데이터를 넣거나 뺄 수 있음

 

 

- 배열이라고 생각해도 되며 한 Key에 넣을 수 있는 요소의 최대 개수는 4,294,967,295개

 

- 데이터형의 값은 설정파일에서 정해준 조건보다 큰 경우 Linkedlist 아니면 Ziplist 로 Encoding 됨

 

 

3. Sets (Group 형태로 Key 1개에 N개의 중복되지 않은 값을 가짐)

 

- Set은 String의 집합

 

- 여러개의 값을 하나의 Value 내에 넣을 수 있다고 생각하면 되며 블로그 포스트의 태깅(Tag)등에 사용될 수 있음

 

- Set 간의 연산을 지원하는데 집합인 만큼 교집합, 합집합, 차이(Differences)를 매우 빠른 시간내에 추출할 수 있음

 

 

- 정렬되지 않은 집합형으로 Key에 중복된 데이터는 존재하지 않음

 

- 추가, 제거 및 존재 체크 시 소모되는 시간이 Sets에 포함된 요소의 수에 관계없이 일정함

 

- 한 Key에 넣을 수 있는 요소의 최대 개수는 4,294,967,295개

 

- 데이터형의 값은 설정파일에서 정해준 조건보다 큰 경우 Hashtable 아니면 intset로 Encoding 됨

 

 

4. Sorted Set (Group 형태이나 각 Member에 score 값을 가짐, Key-Member-Score)

 

- Set에 “score”라는 필드가 추가된 데이터형으로 score는 일종의 가중치 정도로 생각하면 됨

 

- Sorted Set에서 데이터는 오름차순으로 내부 정렬되며 정렬이 되어 있는 만큼 score 값 범위에 따른 쿼리(Range Query), Top Rank에 따른 Query 등이 가능

 

 

- 가장 진보한 Redis 데이터형이라 불리며 랭킹 시스템 등에서 사용하기 좋음

 

- 요소의 추가, 제거, 업데이트는 매우 빠른 방법으로 진행되는데 이는 요소 갯수의 로그에 비례하는 시간이 사용

 

- Key에 중복된 데이터는 존재하지 않지만 score 값은 중복 가능

 

- 데이터형의 값은 설정파일에서 정해준 조건보다 큰 경우 skiplist 아니면 ziplist로 Encoding 됨

 

 

5. Hashs (Object 형태의 Key-Field-Value)

 

- Value 내에 Field/String Value 쌍으로 이루어진 테이블을 저장하는 데이터 구조체

 

- RDBMS에서 PK 1개와 String 필드 하나로 이루어진 테이블이라고 이해하면 됨 

 

 

- List와 비슷한데 “필드명”, “필드값”의 연속으로 이루어져 있음

 

- 한 Key에 포함할 수 있는 Field-Value 쌍의 최대 개수는 4,294,967,295개

 

 

6. 데이터 구조체 정리

 

- Value가 일반적인 String뿐만 아니라 Set, List, Hash와 같은 집합형 데이터 구조를 지원

 

- 저장된 데이터에 대한 연산이나 추가 작업 가능 (합집합, 교집합, Range Query 등)

 

- Set은 일종의 집합, Sorted Set은 오름차순으로 정렬된 집합, hash는 키 기반의 테이블, List는 일종의 링크드 리스트와 같은 특성을 가짐

 

- 이러한 집합형 데이터 구조(Set, List, Hash) 등은 Redis에서 하나의 키당 총 2^32개의 데이터를 이론적으로 저장할 수 있으나 최적의 성능을 낼 수 있는 것은 일반적으로 1000-5000개 사이로 알려져 있음

 

- 데이터 구조에 따른 저장 구조의 정리

 

 

 

 

데이터 관리

 

1. Persistence

 

- Redis는 데이터를 디스크에 저장할 수 있는데 Memcached의 경우 메모리에만 데이터를 저장하기 때문에 서버가 종료된 후에는 데이터가 삭제되지만 Redis는 서버가 리부팅 되더라도 디스크에 저장해놓은 데이터를 다시 읽어서 메모리에 Loading하기 때문에 데이터가 유실되지 않음

 

- Redis에는 데이터를 저장하는 방법이 Snapshotting 방식과 AOF(Append on file) 두가지가 있음

 

 

1-1) Snapshotting (RDB) 방식

 

- 순간적으로 메모리에 있는 내용을 Disk에 전체를 옮겨 담는 방식

 

- 저장파일은 보통 .rdb 확장자 사용

 

- Save와 BGSave 두가지 방식이 있음

  • Save (동기적) : Blocking 방식으로 순간적으로 Redis의 모든 동작을 정지시키고 그때의 Snapshot을 디스크에 저장

  • BGSave (비동기적) : Non-Blocking 방식으로 별도의 Process를 띄운 후, 명령어 수행 당시의 메모리 Snapshot을 디스크에 저장하며 저장 순간에 Redis는 동작을 멈추지 않고 정상 동작

 

- 장단점

  • 장점

    • 메모리의 Snapshot을 그대로 뜬 것이기 때문에 서버 재부팅시 Snapshot만 Load하면 되므로 재부팅이 빠름

    • Redis-Server 디스크에 저장하는 시점까지 Disk I/O가 일어나지 않으므로 성능 극대화

  • 단점

    • Snapshot을 추출하는데 시간이 오래걸리며 Snapshot 추출된 후 서버가 다운되면 Snapshot 추출 이후 데이터는 유실 (백업 시점의 데이터만 유지)

    • 백업시 Fork()로 자식 프로세스를 생성해서 백업 작업을 수행하는데 이때 데이터가 크다면 순간적으로 CPU 부하가 발생

 

- BGSave 프로세스

  1. Redis는 Fork로 자식 프로세스 생성

  2. 자식 프로세스는 임시 rdb 파일에 data를 씀

  3. 자식 프로세스가 임시 rdb 파일에 data 쓰기를 마치면, 임시 rdb 파일로 옛날 rdb파일을 덮어 씌움

 

- 명령어로는 save와 bgsave를 실행할 수 있음

 

 

1-2) AOF 방식

 

- Redis의 모든 Write/Update 연산 자체를 모두 Log 파일에 기록하는 형태 (Mysql의 바이너리 로그와 비슷)

 

- 서버가 재시작될때 기록된 Write/Update Operation을 순차적으로 재실행하여 데이터를 복구

 

- Operation이 발생할 때마다 매번 기록하기 때문에 RDB 방식과는 달리 특정 시점이 아니라 항상 현재 시점까지의 Log를 기록할 수 있으며 기본적으로 Non-Blocking Call

 

- 장단점

  • 장점

    • Log file에 대해서 Append만 하기 때문에 Log Write 속도가 빠르며 어느 시점에 Server가 다운되더라도 데이터 유실이 발생하지 않음

    • AOF파일은 포맷이 단순하며 문제가 있는 쿼리만 삭제하고 복구에 사용하는 작업이 가능

  • 단점

    • 모든 Write/Update Operation에 대해서 Log를 남기기 때문에 Log 데이터 양이 RDB 방식에 비해서 거대하게 큼

    • 복구시 저장된 Write/Update Operation을 다시 Replay하기 때문에 재부팅 속도가 느림 (fsync 정책)

 

- 명령어로는 bgrewriteaof를 실행할 수 있음 (쓰기 내용이 많아져서 불필요할 정도로 AOF 파일이 커진 경우 해당 명령의 실행에 의해 데이터 내용을 살릴 수 있는 짧은 명령을 쓰게 됨)

 

- AOF 손상 확인 방법 (AOF 파일을 쓰는 중 정전등의 문제로 파일이 손상될 수 있음, 이 경우 redis-check-aof 툴로 복구가 가능)

  1. AOF 파일을 복사

  2. redis-check-aof —fix <AOF 복사본 파일> 을 실행해 복사본 파일을 복구

  3. diff -u 명령으로 두 파일을 비교

  4. 수정된 파일을 이용해 Redis-Server를 다시 시작

 

 

2. Expriation

 

- Redis는 데이터에 대해 생명주기를 정해서 일정 시간이 지나면 자동으로 삭제될 수 있게 하는데 Redis가 Expire된 데이터를 삭제하는 정책은 내부적으로 Active와 Passive 두 가지 방법을 사용

  • Active : Client가 Expired 된 데이터에 접근하려고 했을 때 그때 체크해서 지우는 방법

  • Passive : 주기적으로 Key들을 Random으로 100개만 스캔해서 지우는 방식

 

- Expired Time이 지난 후 Client에 의해서 접근되지 않은 데이터는 Active 방식으로 인해서 지워지지 않고 Passvie 방식으로 지워져야 하는데 Passive 방식의 경우 전체 데이터를 스캔하는 것이 아니기 때문에 Redis에는 항상 Expired 되었으나 지워지지 않은 쓰레기 데이터가 존재할 수도 있음

 

- 메모리가 Full 상태에서 Limits 설정에서 선택한 정책에 따라 Expired가 지정되지 않거나 남은 Key라도 삭제될 수 있음

 

 

 

Pub/Sub Model

 

- Redis는 JMS나 IBM MQ 같은 메세징에 활용할 수 있는데 1:1 형태의 Queue 뿐만 아니라 1:N 형태의 Publish/Subscribe 메시징도 지원 (Publish/Subscribe 구조에서 사용되는 Queue를 일반적으로 Topic이라 함)

 

- 하나의 Client가 메시지를 Publish하면 이 Topic에 연결되어 있는 다수의 Client가 메세지를 받을 수 있는 구조

 

 

- 일반적인 Pub/Sub (게시/구독) 시스템의 경우 Subscribe하는 하나의 Topic에서만 Subscribe 하는데 반해서 Redis에서는 pattern matchng을 통해서 다수 Topic에 메시지를 subscribe할 수 있음

(Ex. Topic 이름이 music.pop, music.classic 라는 두개의 Topic이 있을때 PSUBSCRIBE.music.* 라고 하면 두개의 Topic에서 동시에 메시지를 subscribe할 수 있음)

 

 

 

Replication Topology

 

Master/Slave Replication

 

- Redis의 Master Node에 Write된 내용을 복제를 통해 Slave Node에 복제하는 것을 정의

 

- 1개의 Master Node는 N개의 Slave Node를 가질 수 있으며 각 Slave Node도 그에 대한 Slave Node를 가질 수 있음

 

 

- Master/Slave 간의 복제는 Non-Blocking 상태로 이루어짐 (즉 Master Node에서 Write나 Query 연산을 하고 있을 때도 Background로 Slave Node에 데이터를 복사 중)

 

- 이 방식은 Node간의 데이터 불일치성을 유발할 수 있는데 Master Node에 Write한 데이터가 Slave Node에 복제중이라면 Slave Node에서 데이터를 조회할 경우 이전의 데이터가 조회될 수 있음

 

 

Query Off Loading을 통한 성능 향상

 

- 데이터 저장 용량을 늘릴 수 없어도 동시접속자 수나 처리 속도를 늘릴 수 있도록 Query Off Loading이라는 기법을 사용

 

- Master Node는 Write only, Slave Node는 Read only로 사용하는 기법 (Redis 뿐만아니라 Orcle, Mysql과 같은 RDBMS에서도 많이 사용하는 아키텍쳐 패턴)

 

- 대부분의 DB 트랜잭션은 웹 시스템의 경우 Write가 10-20%, Read가 70-90%선이기 때문에 Read 트랜잭션을 분산 시킨다면 처리시간과 속도를 비약적으로 증가시킬 수 있음

 

- Redis의 경우 Value에 대한 여러가지 연산 등을 수행하기 때문에 단순 Put/Get만 하는 NoSQL이나 Memcached에 비해서 Read에 사용되는 Resource의 양이 상대적으로 높기때문에 Redis의 성능을 높이기위해서 효과적인 방법

 

 

 

Redis 설정 옵션

 

Memory 

 

- maxclients 128

  • Redis 서버에서 클라이언트의 접속을 동시에 몇개까지 받아들일지 설정하는 부분

  • 0으로 설정할 경우 무제한으로 접속을 받아들임

  • 설정된 수를 초과하여 클라이언트 접속이 시도되는 경우 에러를 반환

 

- maxmemory 1gb

  • 서버에서 사용할 물리적 메모리 양을 결정

  • 이 메모리양에는 실제 데이터는 물론 각종 설정 상태를 기억하는 부분까지 포함

  • 그냥 숫자만 쓰면 바이트단위로 표기

 

- maxmemory-policy volatile-lru

  • volatile-lru : 기본값으로 만기 시각이 설정된 Key들 중에서 LRU 알고리즘에 의해 Key를 골라 삭제

  • allekey-lru : LRU 알고리즘에 의해 Key를 골라 삭제

  • volatile-random : 만기 시각이 설정된 Key들 중에서 랜덤하게 Key를 골라 삭제

  • allkets-random : 랜덤하게 key를 골라 삭제

  • volatile-ttl : 만기 시각이 설정된 key들 중에서 만기 시각이 가장 가까운 key를 골라 삭제

  • noeviction : 어떤 key도 삭제하지 않고 error on write operations를 돌려줌

 

 

클러스터 구성

 

- slave-serve-stale-data yes

  • 마스터 노드와 연결이 끊겼을 경우 슬레이브 노드로 들어오는 명령에 어떻게 대처할지 설정하는 부분

    • Yes : 슬레이브 노드에서 읽기나 쓰기 명령을 모두 받고 처리

    • No : 슬레이브 노드로 들어오는 모든 명령에 에러상태를 되돌려줌 (읽기/쓰기 모두 처리 안함)

 

- repl-ping-slave-period 10

  • 슬레이브 노드에서는 주기적으로 마스터 노드에 ping 명령을 날려 마스터 노드와의 접속상태를 확인하는데 그 주기(초단위)를 설정하는 부분, 기본값은 10초

 

- repl-timeout 60

  • 이 값은 대량의 I/O와 data에 대한 timeout을 설정해주는 부분인데 repl-ping-slave-period 값보다 크게 설정해줘야함, 기본 단위는 초단위고 기본값은 60초

 

- Master/Slave 구조에서 마스터가 죽을 경우 처리할 수 있게 하려면 Redis에서 제공하는 Sentinel 설정을 통하여 서버 상태를 모니터링하다가 master가 slave 중 1대를 마스터로 설정하는 처리를 할 수 있음

 

https://www.letmecompile.com/redis-cluster-sentinel-overview/

 

 

 

 

 

 

 

참조 URL

 

https://brownbears.tistory.com/43

https://ojava.tistory.com/70

https://goodgid.github.io/Redis/

https://bcho.tistory.com/654

https://mydb.tistory.com/210

반응형

'Other' 카테고리의 다른 글

Git  (0) 2019.04.09
Gradle  (0) 2019.04.09
Memcached  (0) 2019.04.09
Sharding (샤딩)  (0) 2019.04.09
AAA Protocol  (0) 2019.04.09

+ Recent posts