본문 바로가기
데이터베이스

Redis BSL락인·싱글스레드 끝낸 Valkey 8.1 멀티-IO

by forward error correction Circle 2026. 6. 11.
반응형

Ⅰ. Valkey 기술이란?

 ⅰ. 기존 방식의 한계와 필요한 이유
Redis는 20년 가까이 사실상의 인메모리 스토어 표준이었습니다. 그러나 두 가지 문제가 동시에 터졌습니다. 첫째, 라이선스 락인입니다. 2024년 3월 Redis Inc.는 Redis 7.4부터 BSD 3-Clause에서 SSPL/RSALv2 듀얼로 전환했고, 이는 AWS·GCP·Alibaba 같은 매니지드 서비스 사업자에게는 사실상 상업 라이선스 협상을 강제하는 조항이었습니다. 둘째, 싱글스레드 데이터플레인입니다. 코어가 32개여도 명령어 처리는 1개 코어에서만 돌았고, GET/SET 같은 가벼운 명령에서 CPU의 60%가 read()/write() 시스템콜과 네트워크 I/O에서 소모됐습니다.

 ⅱ. 기술 정의
 Linux Foundation 산하 OSS 프로젝트로, Redis 7.2.4(마지막 BSD 버전) 시점에서 분기된 RESP3 프로토콜 호환 인메모리 키밸류 스토어입니다. 기존 Redis 클라이언트·자료구조·명령어 셋을 100% 유지하면서, 멀티-IO 스레딩·메모리 효율·RDMA 같은 신규 기능을 BSD 3-Clause로 공개합니다. AWS·Google·Oracle·Ericsson·Snap이 창립 스폰서이며, AWS ElastiCache for Valkey, GCP Memorystore for Valkey가 정식 출시되어 매니지드 생태계도 갖추어졌습니다.

Ⅱ. Valkey 기술 특징

영역 핵심 변화 기존 Redis 대비 효과
라이선스 BSD 3-Clause 유지, CLA 없음 (DCO 서명만)  SSPL 락인 회피
멀티-IO 8.0 비동기 IO 스레딩, 명령 처리는 메인 스레드 유지 동일 코어 수에서 처리량 2–3배
메모리 embedded key, robj 슬림화, listpack 확장 동일 데이터 RAM 사용량 약 20% 감소
클러스터 슬롯별 dict 분리, atomic slot migration  리샤딩 중 latency spike 제거
전송 8.1 RDMA(RoCE/IB) 트랜스포트 모듈 tail latency p99 60%↓ (실측 의존)
호환성 RESP2/RESP3, 명령어 셋, AOF/RDB 포맷 동일 기존 클라이언트 무수정 교체

Ⅲ. Valkey 기술 동작방식

 ⅰ. 구성 요소
Valkey의 프로세스 모델은 "단일 명령처리 스레드 + N개의 IO 스레드" 구조로 정리됩니다. 메인 스레드는 여전히 명령을 직렬로 실행해 원자성을 자료구조 수준에서 보장합니다. 그 앞단에 IO 스레드 풀(io-threads)이 붙어 소켓 read·파싱·write를 병렬화합니다. 데이터는 per-slot dict(클러스터 모드)와 jemalloc 슬랩 위에 배치되며, 만료 처리는 active expire + lazy expire의 2단으로 동작합니다.

 ⅱ. 데이터 흐름
클라이언트가 RESP3 프레임을 보내면, IO 스레드가 epoll로 받아 파싱 큐에 넣고, 메인 스레드가 큐를 드레인하며 dict·listpack·skiplist를 조작한 뒤 응답 객체를 IO 스레드의 출력 큐로 돌려보냅니다. AOF 로깅은 BIO(background I/O) 스레드가 fsync를 분리해 처리하고, RDB 스냅샷은 fork된 자식이 COW로 떠갑니다. 클러스터 모드에서는 gossip 채널이 슬롯 상태를 전파하고, 8.1 atomic slot migration이 키 이전 중에도 -MOVED 응답을 막아 클라이언트 재시도 폭주를 차단합니다.

Ⅳ. Valkey 기술 구성 및 흐름도

 ⅰ. 구성도


 ⅱ. 실제 처리 흐름
SET user:1 hyunsi EX 60 한 줄을 따라가면 이렇습니다. IO 스레드가 TCP 세그먼트를 모아 RESP3로 디코딩해 명령 큐에 적재합니다. 메인 스레드가 dispatch table에서 setCommand를 찾아 슬롯(예: 3245번) dict에 객체를 삽입하고 expire dict에 절대 timestamp를 박습니다. AOF가 켜져 있다면 appendonly 버퍼에 시리얼라이즈해 두고, BIO 스레드가 appendfsync everysec 정책에 따라 fsync합니다. 마지막으로 +OK 응답이 IO 스레드의 writeQ로 들어가 클라이언트에 회신됩니다. 이 한 명령에서 fsync·복제·만료가 모두 비동기 경로로 분리되어 있다는 점이 latency 안정성의 핵심입니다.

Ⅴ. Valkey 기술 설치 방법

Ubuntu 24.04 /기준, Valkey 8.1.x 안정 채널

# 1) APT 저장소 등록 (Valkey 공식 또는 배포판 기본)
sudo apt-get update
sudo apt-get install -y valkey-server valkey-tools

# 2) 또는 소스 빌드 (RDMA 모듈 필요 시)
git clone https://github.com/valkey-io/valkey.git
cd valkey && git checkout 8.1
make BUILD_WITH_MODULES=yes BUILD_RDMA=module -j$(nproc)
sudo make install

# 3) 컨테이너
docker run -d --name vk -p 6379:6379 \
  -v vk-data:/data valkey/valkey:8.1 \
  valkey-server --appendonly yes --io-threads 4

# 4) 동작 확인
valkey-cli ping        # PONG
valkey-cli INFO server # valkey_version:8.1.x

※ 설치 시 주의
redis-server 패키지가 이미 설치되어 있다면 systemd unit 이름이 충돌합니다. apt-get remove --purge redis-server 후 /etc/redis/ 디렉터리를 백업하고 /etc/valkey/valkey.conf로 옮겨야 합니다. 포트가 동일(6379)하기 때문에 동시 기동 시 한쪽이 silent fail합니다.

Ⅵ. Valkey 기술 사용 방법

코드 / 설정

# /etc/valkey/valkey.conf  (운영 기준 핵심 6줄)
bind 0.0.0.0 -::*
port 6379
io-threads 4                  # vCPU 절반 권장, 8 초과 비추천
io-threads-do-reads yes       # 8.0 기본 yes, 읽기까지 병렬
maxmemory 12gb
maxmemory-policy allkeys-lru
appendonly yes
appendfsync everysec          # 안전·성능 균형
cluster-enabled yes
cluster-config-file nodes.conf

// Java (lettuce) — Redis 클라이언트가 그대로 동작
RedisURI uri = RedisURI.builder()
    .withHost("valkey-primary.svc").withPort(6379)
    .withTimeout(Duration.ofMillis(200)).build();
try (StatefulRedisConnection<string, string> conn =</string, string>
        RedisClient.create(uri).connect()) {
    RedisCommands<string, string> cmd = conn.sync();</string, string>
    cmd.setex("sess:" + sid, 300, payload);
}


※ 운영 시 고려사항

항목 권고
io-threads 값 vCPU의 절반, 최대 8. 그 이상은 context switch 손해
maxmemory 시스템 RAM의 75%까지만. RDB fork 시 COW 폭증 대비
persistence  캐시 용도면 AOF off, 세션·큐 용도면 everysec
swap vm.swappiness=1, transparent_hugepage never
client output buf  pub/sub·replica는 hard 256mb, soft 64mb/60s
모듈 호환 RedisStack(RediSearch, RedisJSON 등)은 SSPL이므로 Valkey 측 대체 모듈(Valkey-Search 등) 사용

Ⅶ. Valkey 기술 자주 쓰는 명령어

명령 용도와 실무 사례
INFO memory used_memory_rss / used_memory 비율이 1.5 넘으면 단편화 의심
SLOWLOG GET 50 10ms 이상 명령 추적. KEYS * 범인 잡을 때 1순위
LATENCY DOCTOR 자동 진단 리포트. fork·AOF·expire 원인 분류
MEMORY DOCTOR / MEMORY USAGE key 키 단위 RAM, 큰 키(big key) 사냥
CLIENT LIST TYPE normal 유휴·장기 커넥션·output buf 폭주 클라이언트 색출
SCAN 0 COUNT 1000 MATCH user:* KEYS 대체. 운영 중 키 점검 표준
CLUSTER NODES / CLUSTER SLOTS 샤드 상태 확인, MOVED 폭주 시 토폴로지 점검
CONFIG SET maxmemory-policy allkeys-lru OOM 직전 응급 처치. 재기동 없이 정책 변경
DEBUG SLEEP 0.5 스테이징에서 timeout 동작 검증, 운영 절대 금지
valkey-cli --bigkeys / --memkeys 전체 스캔으로 핫키·빅키 리포트. 야간 점검 스크립트 1번 항목

Ⅷ. Valkey 기술 활용방안

ⅰ. 대안 기술 비교

제품 라이선스 강점 약점 / 트레이드오프
Valkey 8.1 BSD 3-Clause Redis 100% 호환, 멀티-IO, RDMA, 매니지드 풍부 RedisStack 모듈 직접 호환 안 됨
Redis 7.4+ SSPL/RSALv2 RedisStack(Search/JSON/TS) 1급 지원, Redis Inc. 상용 매니지드 재판매 사실상 금지, 라이선스 리스크
KeyDB BSD 멀티마스터, full multithread Snap 인수 후 사실상 정체, 호환성 격차
Dragonfly BSL 1.1 샤딩된 코어, 단일 노드에서 극단적 처리량 BSL이라 라이선스 락인은 동일 이슈
Garnet (MS) MIT .NET 기반, 디스크 티어드 스토리지 자료구조 셋 일부 결손, 운영 노하우 적음
Memcached BSD 단순·가볍고 빠름 자료구조 없음, 영속·복제 없음


ⅱ. 언제 쓰면 안 되는가
 1) 주 저장소로는 부적합 : RAM 가격이 SSD 대비 비싸고, 데이터 셋이 RAM을 넘어가는 순간 eviction이 발생

 2) 대용량 트랜잭션 처리(은행 원장, 다중 행 ACID) : PostgreSQL·TigerBeetle 같은 OLTP가 정답입니다.

 3) 대형 객체 캐시(수 MB 이상 단일 키)는 메인 스레드를 점유해 다른 클라이언트의 latency를 끌어올립니다.

 

이런 경우 CDN·MinIO 등 별도 저장소가 더 낫습니다. 넷째, 일관성을 양보할 수 없는 분산 락은 Redlock 알고리즘만으로는 안전성 논쟁이 있으므로 Zookeeper·etcd를 검토해야 합니다.

Ⅸ. Valkey 기술 주의 사항

 ⅰ. io-threads를 무작정 늘리지 마라.

vCPU 16개에 io-threads 16 박은 적이 있는데, context switch가 폭증해 오히려 처리량이 떨어졌습니다. 반은 메인 스레드와 BIO·fork 자식에게 남겨두세요. 경험적으로 io-threads = min(vCPU/2, 8)이 가장 안전합니다.
 ⅱ. RDB fork가 메모리를 두 배로 먹는다는 것을 잊지 말 것.

COW라고는 하지만 쓰기 워크로드가 많으면 결국 메모리 페이지가 복제됩니다. maxmemory를 OS RAM의 75%로 잡지 않으면 fork 시점에 OOM Killer가 valkey-server를 정확하게 노리고 죽입니다.
 ⅲ. THP(transparent hugepage)는 반드시 never. hugepage 위에서 COW가 일어나면 한 페이지가 2MB라 fork 지연이 수초까지 튑니다. /sys/kernel/mm/transparent_hugepage/enabled를 never로 박고 부팅 시 적용되도록 systemd unit에 박아두세요.
 ⅳ. RedisStack 모듈 그대로 못 옮긴다.

RediSearch·RedisJSON·RedisTimeSeries는 SSPL입니다. Valkey-Search, Valkey-JSON 같은 OSS 대체가 있긴 하지만 인덱스 포맷·쿼리 문법이 100% 호환되지는 않습니다. 마이그레이션 전에 비호환 명령 목록을 먼저 뽑으세요.
 ⅴ. 스왑은 빠른 SSD라도 켜지 마라.

swappiness=1로도 부족합니다. Valkey가 swap된 페이지를 건드리는 순간 단일 명령이 수십 ms 튑니다. 클라우드 인스턴스라도 swap 파티션 0이 정답입니다.
 ⅵ. pub/sub 구독자가 늦으면 메모리가 터진다.

client-output-buffer-limit가 기본값(pubsub 32mb hard / 8mb soft 60s)이면 폭주 시 valkey-server 메모리가 즉시 폭발합니다. 구독자 수 × 평균 메시지율로 한계를 다시 계산하세요.
 ⅶ. Sentinel과 Cluster를 섞지 마라. 같이 운영하면 failover 신호가 충돌해 split brain 흉내가 납니다. HA는 둘 중 하나로 통일하고, 멀티 AZ가 필요하면 Cluster + replica per shard로 가는 게 트러블이 적습니다.

Ⅹ. Valkey 트러블 슈팅 케이스

증상 진단 도구  해결
p99 latency 갑자기 200ms LATENCY DOCTOR
SLOWLOG GET
대부분 KEYS * 또는 SMEMBERS 대형 셋. SCAN으로 교체
used_memory_rss/used 1.7  INFO memory의 mem_fragmentation_ratio activedefrag yes, 주말 새벽 시간 트래픽 분산해 가동
fork hang 5초 dmesg, latency-monitor-threshold THP off, RDB save 빈도 ↓, replica로 diskless replication
MOVED 응답 폭주 CLUSTER NODES 슬롯 이전 중 클라이언트 캐시 stale. 8.1 atomic migration으로 완화, 클라 측 slot map refresh 주기 단축
OOM 직후 자동 재기동 journalctl, systemd OOMScoreAdjust  maxmemory 하향, fork 시 COW 여유 확보, vm.overcommit_memory=

 

반응형