Redis

From 탱이의 잡동사니
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Overview

Redis 사용법 소개

Data types

Redis 에는 5가지의 데이터 타입이 존재한다(Strings, Lists, Sets, Sorted sets, Hashes)

Strings

일반적인 key-value 이다.

- String 이라고 해서 문자열만 저장할 수 있는게 아니라, 이진 데이터도 저장이 가능하다.(정수, 실수형이 따로 없다). 
- Key 에 넣을 수 있는 데이터의 최대 크기는 512 MB이다.

Lists

Array 형태로 key 1개에 n개의 값을 가지며, 중복 값도 가능하다.

- 배열이라고 생각해도 된다. 
- 한 key 에 넣을 수 있는 요소의 최대 개수는 4,294,967,295 개이다. 
- 데이터 형의 값은 설정파일에서 정해준 조건보다 큰 경우 linkedlist 아니면 ziplist로 encoding 된다.

Sets

Group 형태로 key 1개에 n 개의 중복되지 않는 값을 가진다.

- 정렬되지 않은 집합형으로 key에 중복된 데이터는 존재하지 않는다.
- 추가, 제거 및 존재 체크 시 소모되는 시간이, sets 에 포함되 ㄴ요소의 수와 관계없이 일정하다.
- 한 key 에 넣을 수 있는 요소의 최대 개수는 4,294,967,295 개이다.
- 데이터 형의 값은 설정파일에 정해준 조건보다 큰 경우 hashtable 아니면 intset 으로 encoding 된다.

Sorted sets

Group 형태이나 각 member에 score 값을 가진다. keye-member-score

- Sorted sets 는 가잔 진보한 Redis 데이터 형이라고도 한다.
- 요소의 추가, 제거, 업데이트는 매우 빠른 방법으로 진행되는 데, 이는 "요소의 개수의 로그"에 비례하는 시간이 사용된다.
- 랭킹 시스템 등에서 사용되기 좋다.
- sets의 각 요소마다 score 라는 실수 값을 가지고 있는 형태로 score 값으로 오름차순 정렬된다.
- key에 중복된 데이터는 존재하지 않지만 score 값은 중복 가능하다.

example

redis>  ZADD myzset 1 "one"
(integer) 1

redis>  ZADD myzset 1 "uno"
(integer) 1

redis>  ZADD myzset 2 "two" 3 "three"
(integer) 2

redis>  ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"

Hashes

Obejct 형태의 key-field-value

- list 와 비슷한데, "필드명", "필드값"의 연속으로 이루어져 있다.
- 한 key 에 포함할 수 있는 field-value 쌍의 최대 개수는 4,294,967,295 개이다.
- 데이터 형의 값은 설정파일에서 정해준 조건보다 큰 경우는 hashtable 아니면 zipmap 으로 encoding 된다.

KEYS vs SCAN

KEYS 는 Redis 명령어 중에서 가장 편리하면서도 가장 위험한 명령어이다.

왜냐하면, KEYS 를 사용할 경우 redis 내에 Lock 을 만들기 때문에, 해당 명령어가 완료되기 전까지는 redis 에서 작업이 불가능하게 된다.

이 때문에, KEYS 보다는 SCAN, SSCAN, ZSCAN, HSCAN 와 같은 명령어를 사용하는 것을 추천한다.

KEYS 와 비슷한 기능을 수행하지만 KEYS와는 달리 Table lock 을 생성하지 않는다.

SCAN cursor [MATCH pattern] [COUNT count]
SSCAN key cursor [MATCH pattern] [COUNT count]
ZSCAN key cursor [MATCH pattern] [COUNT count]
HSCAN key cursor [MATCH pattern] [COUNT count]

얼핏보기에는 KEYS 의 문제점을 모두 해결한 것 같지만, 다음과 같은 한계를 가진다.

  • 기본적으로 SCAN의 경우 table 의 한 블럭을 가져오는 것이라서, 여기에 갯수가 많으면 시간이 많이 걸릴 수도 있다(다만, re-hashing 테이블이 bitmasking 크기만큼 커지므로, 한 블럭이 극단적으로 커질 가능성은 높지 않다).
  • SET/SORTED_SET/HASH 의 내부 구조가 hash table 이나 skiplist 가 아닐 경우(ziplist 로 구현되어 있을 경우), 한 컬렉션의 모든 데이터를 가져오므로, KEYS 명령과 비슷한 문제가 그대로 발생할 수 있다.
  • 명령의 옵션으로 count 값을 지정할 수 있지만, 정확히 그 갯수를 보장하지는 않는다.
  • 순회가 시작(cursor 값을 0으로 지정한 SCAN 명령)된 이후에 추가된 항목은 전체 순회(full iteration; scan 명령의 반환된 cursor 값이 0)가 끝날 때까지 반환되지 않는다(Cursor 가 이미 지나갔으므로).
  • HASH table 이 확장/축소/re-hashing 될 때 다시 스캔하지 않기 때문에 같은 항목이 여러번 반환될 수 있다. 반환된 키 값으로 다른 명령을 실행하려면 주의해야 한다.

Errors

Cannot allocate memory

Redis 는 기본적으로 In-memory database 이다. 이 말은 모든 데이터베이스 정보들을 메모리에 저장한다는 뜻이다. 그런데, 만약 Redis 에 쌓여가는 데이터는 늘어만가고, 더이상 할당 가능한 메모리가 없다면 어떻게 될까?

속도가 엄청나게 느려진다. 보통은 1초안에 끝나는 검색이 10초 이상이 소요되게 된다.

그리고 로그 파일에는 다음과 같은 로그가 나타나게 된다.

[16451] 18 Jun 13:53:02 # Can't save in background: fork: Cannot allocate memory
[16451] 18 Jun 13:53:02 * 1 changes in 900 seconds. Saving... 

해결방법으로는 이곳<ref>http://pydelion.com/2013/05/27/redis-cant-save-in-background-fork-cannot-allocate-memory/</ref>을 참조하면 된다. 간단히, 아래 명령어를 사용하면 문제를 해결할 수 있다.

$ sysctl -w vm.overcommit_memory=1

하지만 이는 어디까지나, 단편적이고, 일회용적인 해결 방법이다. 재부팅을 하게되면 원래 설정대로 돌아간다. 주의하자.

보다, 근본적인 문제는, In-Memory DB 에서 저장해야 할 데이터는 많은데, 사용가능한 메모리가 부족하다는 것이다. 저장되는 데이터를 줄이거나, 메모리 크기를 늘리는 것이 해답이다.

See also

References

<references />