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"
NXhello 키 없을 때만 newval 값 넣기XXhello 키 있을 때만 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
INCR1 증가 /DECR1 감소INCRBY50 증가 /DECRBY50 감소
→ 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 Clist 왼쪽에 여러 요소 삽입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 A3 앞에 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 namep: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 22 제거 (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 자료구조라서 조회가 더 빠름 (블로그)

- 이유: 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]
BYSCOREstart, stop을 점수 범위로 인식BYLEXstart, 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"
(3003000 미만-inf +inf무한대ZRANGE score:1 +inf -inf BYSCORE WITHSCORES REVREV 붙이려면 역순이라 범위도 역순이어야함
사전순으로 조회 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 [vu로 시작해서 v포함되는 데이터 조회[user:a (user:cuser: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 myymyy 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 aakey a 를 aa 로 변경RENAMENX a aa변경할 키 aa가 없을 때만 변경해줌
COPY
COPY b bb키 b를 bb로 복사. 이미 key bb가 있으면 에러 반환.COPY b bb REPLACEdest 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 : 밀리 초 단위 설정
레퍼런스
(책) 개발자를 위한 레디스

글 읽어주셔서 언제나 감사합니다. 좋은 피드백, 개선 피드백 너무나도 환영합니다.
'SearchDeveloper > 개발자를 위한 레디스' 카테고리의 다른 글
| 2장 레디스 시작하기 (1) | 2026.01.16 |
|---|---|
| 1장 마이크로서비스 아키텍처와 레디스 (1) | 2026.01.16 |