Ⅰ. 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= |
'데이터베이스' 카테고리의 다른 글
| SQLite의 한계를 넘다: libSQL과 Turso가 여는 엣지 분산 데이터베이스의 미래 (0) | 2026.05.28 |
|---|---|
| DB 변경도 Git처럼: Bytebase로 구현하는 데이터베이스 CI/CD (0) | 2026.05.10 |
| Redis 의 진정한 오픈소스 후계자, 인메모리 데이터스토어의 새로운 표준 Valkey 에 대해 알아보겠습니다. (0) | 2026.05.04 |
| 왜 PrestoSQL이 Trino가 되었을까? 특징부터 기본 실행까지 총 정리 (0) | 2026.04.30 |
| B-Tree (Balanced Tree) 에 대해 알아보겠습니다. (0) | 2026.01.07 |