본문 바로가기

SearchDeveloper/개발자를 위한 레디스

3장 레디스 기본 개념

redis-cli -h 127.0.0.1 -p 6379

string, list, set, hash, sorted set, 비트맵, hyperloglog, geospatial, stream

string

  • 한 키에 최대 512MB 저장 가능
    • 이진 데이터, JPEG 이미지 같은 바이트 값 HTTP 응답값 다양하게 저장 가능
    • 키 하나에 값도 하나 저장되는 유일한 자료 구조

SET, GET

127.0.0.1:6379> set hello world // 키 값
OK
127.0.0.1:6379> get hello
"world"

127.0.0.1:6379> set hello newval NX
(nil)
127.0.0.1:6379> get hello
"world"

127.0.0.1:6379> set hello newval XX
OK
127.0.0.1:6379> get hello
"newval"
  • NX hello 키 없을 때만 newval 값 넣기
  • XX hello 키 있을 때만 newval 값 덮어쓰기

INCR, INCRBY

127.0.0.1:6379> SET counter 100
OK
127.0.0.1:6379> INCR counter
(integer) 101
127.0.0.1:6379> INCRBY counter 50
(integer) 151
127.0.0.1:6379> DECR counter
(integer) 150
127.0.0.1:6379> DECRBY counter 50
(integer) 100
  • INCR 1 증가 / DECR 1 감소
  • INCRBY 50 증가 / DECRBY 50 감소

→ INCR 커맨드는 원자적(경쟁 상태 발생시키지 않음, 데이터 읽고-증가하고-저장하는 과정 중 다른 클라 접근 못 함)이라 동시성 이슈 없다

MSET, MGET

127.0.0.1:6379> MSET a 10 b 20
OK
127.0.0.1:6379> MGET a b
1) "10"
2) "20"
  • MSET 키-값 멀티 세팅
  • MGET 키-값 멀티 조회

→ 키들 한 번에 관리해서 네트워크 통신 시간 줄이기 때문에 속도 측면에서 쓰면 좋다

list

  • 한 list 에 최대 42억개 아이템 저장 가능
  • 커맨드 접두어가 L

LPUSH, LRANGE

127.0.0.1:6379> LPUSH my E
(integer) 1
127.0.0.1:6379> RPUSH my B
(integer) 2
127.0.0.1:6379> LRANGE my 0 -1
1) "E"
2) "B"
127.0.0.1:6379> LPUSH my A B C
(integer) 5
127.0.0.1:6379> LRANGE my 3 4
1) "E"
2) "B"
127.0.0.1:6379> LRANGE my 0 -1
1) "C"
2) "B"
3) "A"
4) "E"
5) "B"
  • LPUSH [0] 에 E 삽입
  • RPUSH [-1] 에 E 삽입
  • LPUSH my A B C list 왼쪽에 여러 요소 삽입
  • LRANGE my 3 4 [3]~[4] 출력
  • LRANGE my 0 -1 전체 출력

LPOP, LTRIM

127.0.0.1:6379> LPOP my
"C"
127.0.0.1:6379> LPOP my 2
1) "B"
2) "A"

127.0.0.1:6379> LTRIM my 0 0
OK
127.0.0.1:6379> LRANGE my 0 -1
1) "E"
  • LPOP my 맨 왼쪽 요소 하나 제거 후 반환
  • LPOP my 2 맨 왼쪽부터 2개 요소 제거 후 반환
  • LTRIM my 0 0 [0]~[0] 제외하고 모두 제거, 반환 X

→ 로그 데이터 1000개 제한하는 상황에서 쓰면 좋음

LPUSH logdata
LTRIM logdata 0 999 // 1001번째부터 삭제

주기적으로 삭제 배치 돌리는것보다 이렇게 끝에 하나만 삭제하는 게 O(1)이라 더 빠름

  • LPUSH, LPOP, RPUSH, RPOP 커맨드는 양 끝에 넣고 빼는거라 O(1)
  • list 중간 데이터 접근할 때는 O(n)

LINSERT, LSET, LINDEX

127.0.0.1:6379> LRANGE lista 0 -1
1) "3"
2) "3"
3) "2"
4) "1"

127.0.0.1:6379> LINSERT lista BEFORE 3 A
(integer) 5
127.0.0.1:6379> LRANGE lista 0 -1
1) "A" // 3이 두 개인데 중복으로 A가 들어가진 않음
2) "3"
3) "3"
4) "2"
5) "1"

127.0.0.1:6379> LSET lista 4 B
OK
127.0.0.1:6379> LRANGE lista 0 -1
1) "A"
2) "3"
3) "3"
4) "2"
5) "B"

127.0.0.1:6379> LINDEX lista 2
"3"
  • LINSERT lista BEFORE 3 A 3 앞에 A 넣어라 (AFTER 도 있음)
  • LSET lista 4 B [4]에 B로 덮어쓰기
  • LINDEX lista 2 [2]조회

hash

  • 필드-값 쌍 가진 아이템의 집합
  • 필드는 하나의 hash내에서 유일하다
  • 필드, 값 모두 문자열로 저장된다.
  • 각 아이템마다 다른 필드를 가질 수 있다.
  • 커맨드 접두어가 H

HSET, HGET, HMGET, HGETALL

127.0.0.1:6379> HSET p:1 name "happy"
(integer) 1
127.0.0.1:6379> HSET p:2 name "hack" id 2
(integer) 2
127.0.0.1:6379> HGET p:1 name
"happy"
127.0.0.1:6379> HMGET p:2 name id
1) "hack"
2) "2"
127.0.0.1:6379> HGETALL p:2 
1) "name"
2) "hack"
3) "id"
4) "2"
  • HSET p:1 name "happy" p:1 키에 name 필드, happy 값 삽입
  • HSET p:2 name "hack" id 2 키 멀티 삽입도 가능
  • HGET p:1 name p:1 키에 name 필드 값 반환
  • HMGET p:2 name id 멀티 키 값 반환
  • HGETALL p:2 키-값 모두 반환

❓key에 : 붙이는 이유

  • 데이터 간의 계층 구조(Hierarchy)를 표현하기 위한 네이밍 컨벤션(관습)입니다.
  • UI에서선 폴더 형태로 보여줌

set

  • 정렬되지 않은 문자열 모음
  • 중복해서 저장하지 않음
  • 합집합, 교집합, 차집합 연산 커맨드 제공
  • 커맨드 접두어가 S

SADD, SREM, SMEMBERS, SPOP, SINTER, SUNION, SDIFF

127.0.0.1:6379> SADD sett 1 2 3 3 3 3
(integer) 3
127.0.0.1:6379> SMEMBERS sett
1) "1"
2) "2"
3) "3"

127.0.0.1:6379> SREM sett 2
(integer) 1
127.0.0.1:6379> SMEMBERS sett
1) "1"
2) "3"

127.0.0.1:6379> SPOP sett
"1"


127.0.0.1:6379> SADD set:111  a b c d e
(integer) 5
127.0.0.1:6379> SADD set:222 f g h d e
(integer) 5

127.0.0.1:6379> SINTER set:111 set:222
1) "d"
2) "e"
127.0.0.1:6379> SUNION set:111 set:222
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"
7) "g"
8) "h"
127.0.0.1:6379> SDIFF set:111 set:222
1) "a"
2) "b"
3) "c"
  • SADD sett 1 2 3 3 3 3 요소 여러 개 삽입. 중복 제거한 카운트 반환
  • SMEMBERS sett 전체 요소 조회
  • SREM sett 2 2 제거 (REMove)
  • SPOP sett 랜덤 제거, 반환
  • SINTER set:111 set:222 교집합
  • SUNION set:111 set:222 합집합
  • SDIFF set:111 set:222 차집합

sorted set

  • 스코어에 따라 정렬되는 고유한 문자열 집합 (문자열 데이터 중복X)
  • 모든 아이템은 스코어-값 쌍을 가진다
  • 정렬해서 저장한다.
  • 스코어 같으면 키 사전순 정렬한다.
  • 유니크 값이라 set 과 유사, 스코어 같이 저장돼서 hash와 유사, list 처럼 인덱스 접근 가능
  • 인덱스 이용해 접근하려면 list보다 sorted set이 더 빠르다
    • list: O(n)
    • sorted set: O(log(n))
      • 이유: skip list 자료구조라서 조회가 더 빠름 (블로그)
  • 커맨드 접두어가 Z

 

ZADD

127.0.0.1:6379> ZADD score:1 100 user:a 
(integer) 1
127.0.0.1:6379> ZADD score:1 150 user:b 200 user:c
(integer) 2
127.0.0.1:6379> ZADD score:1 300 user:c // user:c 이미 있어서 0
(integer) 0
  • ZADD score:1 150 user:b 200 user:c 스코어-필드 쌍 멀티로 삽입 가능
    • 필드 데이터가 이미 있으면 스코어만 업데이트 됨
    • 스코어는 배정밀도 부동소수점 숫자

ZADD 옵션

  • XX 아이템 이미 존재할 때만 스코어 업데이트
  • NX 아이템 존재하지 않을 때만 신규 삽입. 기존 아이템 스코어 업데이트하지 않는다
  • LT (업데이트<기존) 업데이트하려는 스코어가 기존 스코어보다 작을 때만 업데이트 함. 기존 값 없으면 신규 삽입
  • GT (업데이트>기존) 업데이트하려는 스코어가 기존 스코어보다 클 때만 업데이트 함. 기존 값 없으면 신규 삽입

 

ZRANGE

ZRANGE start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count] [WITHSCORES]
  • BYSCORE start, stop을 점수 범위로 인식
  • BYLEX start, stop을 사전 문자열로 인식
  • REV 쓰면 점수 내림차순으로 정렬
  • WITHSCORES 스코어도 차례대로 출력됨

 

인덱스로 조회 ZRANGE

127.0.0.1:6379> ZRANGE score:1 0 -1 WITHSCORES
1) "user:a"
2) "100"
3) "user:b"
4) "150"
5) "user:c"
6) "300"
127.0.0.1:6379> ZRANGE score:1 0 -1 WITHSCORES REV
1) "user:c"
2) "300"
3) "user:b"
4) "150"
5) "user:a"
6) "100"

 

점수로 조회 ZRANGE BYSCORE

127.0.0.1:6379> ZRANGE score:1 100 299 BYSCORE WITHSCORES 
1) "user:a"
2) "100"
3) "user:b"
4) "150"
127.0.0.1:6379> ZRANGE score:1 100 (300 BYSCORE WITHSCORES 
1) "user:a"
2) "100"
3) "user:b"
4) "150"
127.0.0.1:6379> ZRANGE score:1 -inf +inf BYSCORE WITHSCORES 
1) "user:a"
2) "100"
3) "user:b"
4) "150"
5) "user:c"
6) "300"
127.0.0.1:6379> ZRANGE score:1 +inf -inf BYSCORE WITHSCORES REV
1) "user:c"
2) "300"
3) "user:b"
4) "150"
5) "user:a"
6) "100"
  • (300 3000 미만
  • -inf +inf 무한대
  • ZRANGE score:1 +inf -inf BYSCORE WITHSCORES REV REV 붙이려면 역순이라 범위도 역순이어야함

 

사전순으로 조회 ZRANGE BYLEX

127.0.0.1:6379> ZRANGE score:1 - +  BYLEX
1) "user:a"
2) "user:b"
3) "user:c"

127.0.0.1:6379> ZRANGE score:1 [u [u BYLEX
(empty array)

127.0.0.1:6379> ZRANGE score:1 [u [v BYLEX
1) "user:a"
2) "user:b"
3) "user:c"

127.0.0.1:6379> ZRANGE score:1 [user:a (user:c BYLEX
1) "user:a"
2) "user:b"
  • - + 사전 순에서 모든 데이터 조회 (LEXicon)
  • [u [u 정확히 u인 데이터만 조회 (부분 문자열이 아니라)
  • [u [v u로 시작해서 v포함되는 데이터 조회
  • [user:a (user:c user:a 포함 부터 user:c 미포함까지 데이터 조회
  • [( 반드시 써줘야 함

비트맵

  • string 자료구조에 bit 연산 수행되게 확장한 형태
  • BITFIELD by set u1 6 1 set u1 10 1

SETBIT, GETBIT, BITFIELD, BITCOUNT

127.0.0.1:6379> SETBIT myy 2 1
(integer) 0
127.0.0.1:6379> GETBIT myy 2
(integer) 1
127.0.0.1:6379> GETBIT myy 0
(integer) 0
127.0.0.1:6379> STRLEN myy
(integer) 1

127.0.0.1:6379> BITFIELD myyy SET u1 6 1 SET u1 10 1 SET u1 14 1
1) (integer) 0
2) (integer) 0
3) (integer) 0

127.0.0.1:6379> BITCOUNT myyy
(integer) 3
  • SETBIT myy 2 1 [2]번째 비트를 1로 바꿔라 (최소 8비트)
  • STRLEN myy 몇 바이트인지 (1 → 8비트)
  • BITFIELD myyy SET u1 6 1 SET u1 10 1 SET u1 14 1 [6], [10], [14]번 인덱스를 1로
    • u1: unsigned 1-bit 데이터 타입. 0, 1만 다룸
  • BITCOUNT myyy 값이 1인 비트 개수

hyperloglog

  • 집합의 카디널리티 추정할 때 쓰는 자료구조(블로그)
  • 키의 고유한 값 집계할 때 유용하다
  • 데이터 그 자체를 저장하지 않고 자체적으로 변경해 처리하기 때문에 개수에 구애받지 않고 일정한 메모리 유지 가능
  • 한 hyperloglog에 최대 12KB, 최대 264개 저장 가능

PFADD, PFCOUNT

127.0.0.1:6379> PFADD m 1
(integer) 1
127.0.0.1:6379> PFADD m 2
(integer) 1
127.0.0.1:6379> PFADD m 3
(integer) 1
127.0.0.1:6379> PFCOUNT m
(integer) 3
  • PFADD: 저장
  • PFCOUNT: 카디널리티 추정 (오차 0.81%)

geospatial

  • 경도, 위도 쌍 저장하는 자료구조
  • 내부적으로 sorted set으로 저장된다그래서 내부 키는 중복 저장 안 된다.

GEOADD

127.0.0.1:6379> GEOADD seoul 127.027 37.497 "Gangnam"
(integer) 1
127.0.0.1:6379> TYPE seoul
zset
127.0.0.1:6379> ZSCORE seoul "Gangnam" // sorted set score 구하기
"4077553489551351"
  • GEOADD seoul 127.027 37.497 "Gangnam" seoul sorted set 안에 Gangnam이 키고 score 가 geohash인 값(4077553489551351)이 있음
    • XX 이미 아이템 있는 경우에만 저장
    • NX 아이템 없는 경우에만 저장
127.0.0.1:6379> GEOPOS seoul Gangnam
1) 1) "127.02700227499008179"
   2) "37.49700078681933491"

127.0.0.1:6379> GEODIST seoul Gangnam Gangnam KM
"0.0000"
  • GEOPOS 위경도 조회
  • GEODIST 두 점 사이 거리 구하기
  • GEOSEARCH 한점으로 부터 거리 반경 내 아이템 검색 (BYRADIUS: 거리 기준, BYBOX: 직사각형 거리 기준) [4장에서 계속]

stream

  • 메시지 브로커로서 사용가능한 자료구조
  • 컨슈머 그룹 도입
  • append-only 방식
  • [7장에서 계속]

<키 관리하기>

키 자동 생성과 삭제

  • set, sorted set, stream 같이 한 키에 여러 아이템 갖고 있는 자료구조는 명시하지 않아도 알아서 생성, 삭제된다.
  • 규칙 3가지를 따른다.

1. 키 미존재해도 아이템 넣으면 key의 빈 자료구조 먼저 생성한다.

127.0.0.1:6379> DEL myy
(integer) 1

127.0.0.1:6379> LPUSH myy 1 2 3
(integer) 3

127.0.0.1:6379> EXISTS myy
(integer) 1
  • EXISTS myy myy key 존재 여부

2. 모든 아이템 삭제하면 key도 자동 삭제된다.

  • stream은 예외
127.0.0.1:6379> LPOP myy
"3"
127.0.0.1:6379> LPOP myy
"2"
127.0.0.1:6379> LPOP myy
"1"
127.0.0.1:6379> LPOP myy
(nil)

127.0.0.1:6379> EXISTS myy
(integer) 0

 

3. 키 없는 상태에서 키/아이템 삭제, size 조회같은 읽기 전용 커맨드 수행하면 에러 반환이 아니라 아이템 없는 것처럼 동작한다.

127.0.0.1:6379> DEL myy
(integer) 0
127.0.0.1:6379> LLEN myy
(integer) 0
127.0.0.1:6379> LPOP myy
(nil)

 

키 관련 커맨드

EXISTS

127.0.0.1:6379> EXISTS myy
(integer) 0

key 존재 여부

KEYS

  • 전체 키 조회
  • 얼마나 걸릴지 모르기 때문에 쓰면 안되는 커맨드! 대신 SCAN 사용

SCAN

SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
  • count: 한 번에 몇 개 키 반환
27.0.0.1:6379> SCAN 0
1) "2"
2)  1) "2382784ddd6cadf0de2740aaa3699820"
    2) "score:1"
    3) "p:1"
    4) "lista"
    5) "m"
    6) "counter"
    7) "8999826031ddc85858b2351b57e79457"
    8) "d3f806e8d1b81f3d54376fc11aa928e6"
    9) "af1025bfa37ae4cbd68e5da207dff730"
   10) "hello"
   11) "set:222"
127.0.0.1:6379> SCAN 2 COUNT 2
1) "42"
2) 1) "b"
   2) "llist"
  • 1) “2” 다음 커서 인수 값
    • 0이면 더 이상 검색할 키가 없다.
  • SCAN 2 COUNT 2 한번에 2개 반환인데 효율성에 따라 1~2개 더 반환될 수도 있다.

match

127.0.0.1:6379> SCAN 0 match *total*
1) "2"
2) 1) "total:2382784ddd6cadf0de2740aaa3699820"
   2) "total:d3f806e8d1b81f3d54376fc11aa928e6"
   3) "total:af1025bfa37ae4cbd68e5da207dff730"
127.0.0.1:6379> SCAN 2 match *total*
1) "21"
2) 1) "total:8ef013b98083028b8353ada7e98b39b8"
   2) "total:ef1c511c9efb9259438f098aff940740"
   3) "total:1c86fde60c0c8b21828259de8f0ecf01"
   4) "total:ab5e47bb06ab521a2bebf2477d26bec9"
127.0.0.1:6379> SCAN 21 match *total*
1) "47"
2) 1) "total:e77a64f388e198f2b7ea13d15debf765"
   2) "total:ed1b04537ab1839667c5f4d42b2e0d34"
   3) "total:798fdcc0abbcfdd5d4ac88efa61acab2"
   4) "total:1118b991bdf0405180d94a59ab3a1584"

match로 key 필터할 수 있는데 커서의 범위 안에서만 필터하는 거라 커서를 다 돌려야 모든 필터된 값 알 수 있다.

type

127.0.0.1:6379> SCAN 0 TYPE zset
1) "2"
2) 1) "score:1"

127.0.0.1:6379> SCAN 2 TYPE zset
1) "21"
2) 1) "location:data:1746942989373"

자료구조 종류로 필터링하기

 

SSCAN - set 에서 SMEMBERS 대체해서 서버 영향 끼치지 않고 전체 키 조회

HSCAN - hash 에서 HGETALL 대체해서 서버 영향 끼치지 않고 전체 키 조회

ZSCAN - sorted set 에서 ZRANGE WITHSCORE 대체해서 서버 영향 끼치지 않고 전체 키 조회

127.0.0.1:6379> ZSCAN score:1 0
1) "0"
2) 1) "user:a"
   2) "100"
   3) "user:b"
   4) "150"
   5) "user:c"
   6) "300"

SORT

  • list, set, sorted set 에서만 사용 가능
  • 블로그
SORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]

 

RENAME / RENAMENX

  • RENAME a aa key a 를 aa 로 변경
  • RENAMENX a aa 변경할 키 aa가 없을 때만 변경해줌

COPY

  • COPY b bb 키 b를 bb로 복사. 이미 key bb가 있으면 에러 반환.
  • COPY b bb REPLACE dest key 를 삭제하고 복사

TYPE

  • TYPE key 자료구조 타입 반환

OBJECT

  • 키 상세 정보 반환
127.0.0.1:6379> OBJECT ENCODING score:1
"listpack"
127.0.0.1:6379> OBJECT IDLETIME score:1
(integer) 419

FLUSHALL

FLUSHALL [ASYNC | SYNC] 
  • 저장된 모든 키 삭제
    • SYNC: 동기적으로 삭제해서 다른 커맨드 요청은 작업 끝날 때까지 기다려야함
    • ASYNC: 백그라운드로 삭제 실행. 작업 중 새로 생성된 키는 삭제 안 된다.

DEL

DEL key [key …]
  • 키와 키에 저장된 모든 아이템 삭제. 동기로 실행

UNLINK

UNLINK key [key …] 
  • DEL과 비슷하게 키 삭제
  • 백그라운드로 실행
  • 키와 연결된 데이터 우선 끊음
  • set, sorted set 처럼 한 키 안에 몇 백만개 아이템 있으면 DEL은 서버 영향 미칠 수 있어서 UNLINK가 안전함

EXPIRE

EXPIRE key seconds [NX|XX|GT|LT]
  • 키 만료될 시간 초단위로 설정
  • NX 키에 만료 시간 없으면 커맨드 수행
  • XX 키에 만료 시간 있으면 커맨드 수행
  • GT 새로 입력한 초가 기존 초보다 클 때만 수행
  • LT 새로 입력한 초가 기존 초보다 작을 때만 수행

EXPIREAT

EXPIREAT key unix-time-seconds [NX|XX|GT|LT]
  • 만료될 시간을 유닉스 타임스탬프로 직접 지정

EXPIRETIME

EXPIRETIME key
  • 키가 삭제되는 유닉스 타임스탬프 반환
127.0.0.1:6379> EXPIRETIME f
(integer) -2
127.0.0.1:6379> EXPIRETIME score:1
(integer) -1
  • -1: 키 존재하지만 만료 시간 없음
  • -2: 키 없음

TTL

TTL key
  • 키가 몇 초 뒤에 만료되는지 반환
    • -1: 키 존재하지만 만료 시간 없음
    • -2: 키 없음

PEXPIRE, PEXPIREAT, PEXPIRERIME, PTTL : 밀리 초 단위 설정

 

레퍼런스

(책) 개발자를 위한 레디스

글 읽어주셔서 언제나 감사합니다. 좋은 피드백, 개선 피드백 너무나도 환영합니다.