Redis의 핵심 특성
- 초고속 처리: 메모리 기반으로 구현되어 1초당 수십만 건의 읽기/쓰기 작업이 가능하며, C 언어로 작성됨.
- 단일 스레드 모델: 모든 명령은 동기적으로 처리되며, 데이터 경쟁이나 불완전한 읽기/쓰기 현상 없음.
- 지속성 지원: RDB(스냅샷)과 AOF(명령 로그) 방식 제공.
- 다양한 데이터 구조: 문자열, 해시, 리스트, 셋, 정렬된 집합 등 5가지 주요 타입.
- 다중 언어 연동: TCP 기반 통신 프로토콜을 사용해 대부분의 프로그래밍 언어와 호환.
- 풍부한 기능: 발행-구독, Lua 스크립트, 파이프라인, 트랜잭션 등.
- 간편한 관리: 외부 라이브러리 없이도 자체적으로 강력한 기능 제공.
- 마스터-슬레이브 복제: 마스터 서버에서 슬레이브 서버로 데이터를 자동 복제.
- 고가용성 및 분산 환경 지원: 클러스터링 및 장애 대비 아키텍처 구성 가능.
Linux에서의 설치 및 실행
# 1. 소스 다운로드
wget http://download.redis.io/releases/redis-6.2.9.tar.gz
# 2. 압축 해제
tar -xzf redis-6.2.9.tar.gz
# 3. 심볼릭 링크 생성 및 컴파일
ln -s redis-6.2.9 redis
cd redis
make && make install
# 4. 설치 후 확인
ls src/
# 결과: redis-server, redis-cli, redis-benchmark, redis-check-aof, redis-check-rdb, redis-sentinel 등 존재
또한 yum 또는 apt 등을 통해 단일 명령으로 설치할 수 있음.
서버 시작 방법
최소 설정 시작
redis-server
ps -ef | grep redis # 프로세스 확인
netstat -antpl | grep redis # 포트 열림 여부 확인
redis-cli -h 127.0.0.1 -p 6379 ping
동적 옵션으로 시작
redis-server --port 6380
설정 파일 기반 시작
daemonize yes
pidfile /var/run/redis.pid
port 6379
dir "/root/redis/data"
logfile "6379.log"
# 작업 디렉터리 생성
mkdir -p data
# 설정 파일 적용
redis-server myredis.conf
클라이언트 연결 및 관리
redis-cli -h 127.0.0.1 -p 6379
redis-cli -h 127.0.0.1 -p 6379 info
# 설정 조회
CONFIG GET *
# 비밀번호 설정 (임시)
CONFIG SET requirepass 123456
CONFIG REWRITE # 변경 사항을 파일에 저장 (지속적 적용)
# 인증 방법
# 1. 명령줄에서 직접 비밀번호 포함
redis-cli -a 123456
# 2. 접속 후 인증 명령 실행
AUTH 123456
주요 사용 시나리오
- 캐시 시스템: 가장 일반적인 활용. 웹 애플리케이션의 성능 향상.
- 카운터: 페이지 조회수, 공유 횟수, 댓글 수 등. 단일 스레드 보장으로 동시성 문제 없음.
- 메시지 큐: 발행-구독 모델, 블로킹 큐(예:
BLPOP)를 통해 생산자-소비자 패턴 구현. - 사회 네트워크: 팔로우 수, 팔로워 수, 간단한 추천 알고리즘.
- 실시간 시스템: 블랙리스트, 스팸 필터링, 실시간 알림.
- 위치 기반 서비스: 근처 사용자 검색, 지도 기반 정보 처리.
기본 명령어
키 조회
keys * # 모든 키 조회 (생산 환경 금지)
keys he* # 'he'로 시작하는 키
keys he[h-l] # 'he'로 시작하고 세 번째 글자가 h~l 사이인 키
키 개수 확인
dbsize # 현재 데이터베이스에 저장된 키 수
값 조작
get key
set key value [EX seconds] [PX milliseconds] [NX|XX]
exists key # 존재 여부 확인 (1=존재, 0=미존재)
del key # 삭제 (성공 시 1 반환)
expire key 3 # 3초 후 만료
ttl key # 남은 만료 시간 확인
persist key # 만료 제거
type key # 키의 데이터 유형 확인
기타 유용 명령어
info # 메모리, CPU, 복제 상태 등 정보 출력
client list # 연결된 클라이언트 목록
client kill ip:port # 특정 클라이언트 연결 종료
flushall # 전체 데이터베이스 초기화
flushdb # 현재 데이터베이스만 초기화
select 0 # DB 선택 (0~15까지 총 16개)
monitor # 모든 명령어 로깅 (디버깅용)
내부 구조 및 아키텍처
데이터 구조의 내부 인코딩
각 데이터 타입은 내부적으로 최적화된 인코딩 방식을 사용함 (예: 작은 리스트는 배열, 큰 리스트는 연결 리스트).
단일 스레드 설계의 이유
- 메모리 내 연산으로 성능 향상.
- 비차단 I/O (epoll 기반), 네트워크 대기 시간 최소화.
- 스레드 간 전환 및 경쟁 조건 발생 없음.
주의사항
- 하나의 명령어만 동시에 실행됨.
- 긴 실행 명령어 차단 금지:
KEYS,FLUSHALL,FLUSHDB, 긴 Lua 스크립트,MULTI/EXEC블록 등. - 실제로는 데이터 처리 부분만 단일 스레드, 지속성 작업은 별도 스레드 처리.
각 데이터 타입의 운영 명령어
문자열 (String)
incr age # age 키 값 +1
decr age # age 키 값 -1
incrby age 10 # age에 10 더하기
decrby age 10 # age에서 10 빼기
append key "extra" # 끝에 문자열 추가
setrange key 3 "new" # 인덱스 3부터 문자열 교체
getrange key 0 5 # 인덱스 0~5 범위 문자열 추출
strlen name # 문자열 길이 (바이트 단위)
incrbyfloat key 3.5 # 부동소수점 증가
해시 (Hash)
hset user:1001 name "leethon"
hget user:1001 name
hdel user:1001 name
hexists user:1001 name
hlen user:1001
hmset user:1001 field1 val1 field2 val2
hmget user:1001 field1 field2
hgetall user:1001 # 전체 항목 조회 (느린 명령어)
hvals user:1001 # 값만 추출
hkeys user:1001 # 키만 추출
hincrby user:1001 score 1
hsetnx user:1001 name "new" # 기존 값이 없을 때만 설정
hincrbyfloat user:1001 score 0.5
리스트 (List)
rpush mylist a b c # 오른쪽 삽입
lpush mylist x y z # 왼쪽 삽입
linsert mylist before a new_val
lpop mylist # 왼쪽 삭제
rpop mylist # 오른쪽 삭제
lrem mylist 2 "value" # 처음 2개 일치하는 항목 삭제 (2: 왼쪽부터, -2: 오른쪽부터)
ltrim mylist 0 4 # 인덱스 0~4만 유지
lrange mylist 0 9 # 인덱스 범위 항목 가져오기
lindex mylist 2 # 인덱스 2의 값 가져오기
llen mylist # 리스트 길이
blpop mylist 5 # 5초 동안 블로킹 대기 (시간 초과 시 무효)
brpop mylist 5
셋 (Set)
sadd users 1001 1002 1003
srem users 1001
sismember users 1002
srandmember users 3
spop users
smembers users
sdiff set1 set2 # 차집합
sinter set1 set2 # 교집합
sunion set1 set2 # 합집합
정렬된 셋 (ZSet)
zadd ranking 90 "alice" 85 "bob" 95 "charlie"
zrem ranking alice
zscore ranking bob
zincrby ranking 5 "bob"
zcard ranking # 요소 수
zrank ranking bob # 순위 (오름차순)
zrange ranking 0 2 # 순위 0~2 범위 요소
zrange ranking 0 2 withscores
zrangebyscore ranking 80 95
zcount ranking 80 95
zremrangebyrank ranking 0 2
zremrangebyscore ranking 80 90
zrevrank ranking bob # 내림차순 순위
zrevrange ranking 0 2
zrevrangebyscore ranking 100 80
zinterstore result set1 set2
zunionstore result set1 set2
고급 기능
느린 명령어 감시 (Slow Log)
단일 스레드 환경에서 느린 명령어는 전체 성능 저하 유발. Redis는 느린 명령어를 별도 큐에 기록해 분석 가능하게 함.
config set slowlog-log-slower-than 1000 # 1ms 이상 수행 시 로깅
config set slowlog-max-len 100 # 최대 100개 저장
config rewrite # 설정 파일에 반영
# 확인 및 관리
slowlog len
slowlog reset
slowlog get
파이프라인 및 트랜잭션
여러 명령어를 한 번의 네트워크 요청으로 전송하여 성능 향상. 트랜잭션도 함께 사용 가능.
import redis
pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
r = redis.Redis(connection_pool=pool)
pipe = r.pipeline(transaction=True)
pipe.set('name', 'leethon')
pipe.execute()
옵티미스트틱 락 (Optimistic Locking)
with r.pipeline() as pipe:
pipe.watch('count')
pipe.multi()
time.sleep(2)
pipe.decr('count')
pipe.execute() # count 값 변경 시 예외 발생
발행-구독 (Pub/Sub)
publish channel1 "Hello World"
subscribe channel1
pubsub numsub channel1 # 구독자 수 확인
pubsub channels # 구독 중인 채널 목록
비트맵 (Bitmap)
문자열 타입을 이용해 비트 단위 조작 가능.
set xx "hi" # "hi" → 01101000 01101001
getbit xx 0 # 0번 비트 값 확인
setbit xx 7 1 # 7번 비트를 1로 설정
bitcount xx 0 0 # 첫 번째 바이트에서 1의 개수
bitcount xx 0 1 # 두 바이트에서 1의 개수
HyperLogLog
매우 적은 메모리로 중복되지 않은 원소 수를 추정.
pfadd visits user1 user2 user3
pfcount visits # 중복 없는 사용자 수
GEO 지리정보
경도/위도 기반 위치 데이터 저장 및 쿼리.
geoadd person:location 116.28 39.55 lee 116.30 38.67 lily
geopos person:location lee
geodist person:location lee tianjin km
georadiusbymember person:location lee 150 km
지속성 전략
RDB (Snapshot)
save 60 1000 # 60초 내 1000회 변경 시 스냅샷 생성
save 300 10 # 300초 내 10회 변경 시 스냅샷 생성
dbfilename dump.rdb
dir "/data/redis"
특징: 빠른 백업, 하지만 충돌 시 데이터 손실 가능성 있음.
AOF (Append Only File)
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite yes
전략: 매번 또는 1초마다 디스크에 기록. 성능 저하 우려 있으나 재시작 시 데이터 완전 복원 가능.
혼합 지속성 (Redis 4.0+)
aof-use-rdb-preamble yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
save ""
기존 RDB + AOF의 장점을 결합, 복구 속도 향상 및 공간 절약.
캐시 최적화 전략
캐시 업데이트 정책
- LRU: 가장 최근에 사용되지 않은 항목 우선 삭제.
- LFU: 특정 기간 동안 가장 적게 사용된 항목 삭제.
- FIFO: 먼저 들어온 항목부터 삭제.
캐시 문제 해결
캐시 뚫기 (Cache Penetration)
존재하지 않는 키에 대한 반복 요청. 공격 가능성 있음.
- 입력 유효성 검사 (ID ≤ 0 등 거부).
- 없는 키는
key-null형태로 임시 캐시. HyperLogLog로 잘못된 키 추적.
캐시 격차 (Cache Breakthrough)
핫 컨텐츠의 캐시 만료 시 동시 접근으로 데이터베이스 과부하.
- 핫 데이터는 영구적으로 캐시.
캐시 폭탄 (Cache Avalanche)
대량 캐시가 동시에 만료되어 데이터베이스에 대규모 요청 폭주.
- 만료 시간을 랜덤하게 설정.
- 분산 캐시에서 핫 데이터 균형 배포.
- 핵심 데이터는 영구 캐시.