Valkey 완벽 가이드 — Redis 라이선스 변경 이후 오픈소스 포크, 실전 마이그레이션

Valkey 완벽 가이드 — Redis 라이선스 변경 이후 오픈소스 포크, 실전 마이그레이션

이 글의 핵심

Valkey는 2024년 3월 Redis가 BSD에서 SSPL/RSALv2로 라이선스를 변경한 직후 Linux Foundation 주도로 출범한 오픈소스 포크입니다. Redis 7.2.4에서 갈라져 나와 완전 BSD 3-Clause 라이선스를 유지하며 AWS·Google·Oracle·Alibaba·Ericsson·Snap 등이 공동 개발합니다. 이 글은 Valkey 선택 이유, Redis 대비 차이, 마이그레이션 절차, 프로덕션 운영 모범 사례를 정리합니다.

왜 Valkey가 생겼나

2024년 3월 20일, Redis Ltd는 7.2.4 이후 버전의 라이선스를 BSD 3-Clause → SSPL + RSALv2로 변경한다고 발표했습니다. 이는 상용 “관리형 서비스” 제공을 원천 차단하는 라이선스로, 주된 타깃은 AWS ElastiCache 같은 클라우드 벤더입니다.

일주일 뒤 Linux Foundation이 Valkey를 출범, Redis 창립자 Salvatore Sanfilippo(antirez)가 고문으로 참여하고 AWS·Google·Oracle·Alibaba·Ericsson·Huawei·Percona·Snap이 공동 개발자로 참여했습니다. 2024년 4월 Valkey 7.2.5 첫 릴리스, 9월 Valkey 8.0 GA, 2026년 현재 Valkey 8.x가 프로덕션 안정 버전입니다.

Valkey vs Redis: 기능 비교

항목Valkey 8Redis 7.4 (SSPL)Redis 8 (AGPL/SSPL)
라이선스BSD 3-ClauseSSPL + RSALv2AGPL + SSPL + RSALv2
RESP 프로토콜동일동일동일
클러스터동일동일동일
멀티스레드 I/O강화 (async)기본강화
JSON 모듈valkey-jsonRedisJSON (SSPL)기본 포함(SSPL)
Search 모듈valkey-searchRediSearch (SSPL)기본 포함(SSPL)
Bloom/TimeSeries별도RedisBloom (SSPL)기본 포함(SSPL)
클라우드 관리형AWS/GCP/Azure 지원 확장Redis Cloud 중심Redis Cloud 중심

설치

Docker

docker run --name valkey -p 6379:6379 -d valkey/valkey:8
docker exec -it valkey valkey-cli

Linux (Ubuntu)

sudo apt update
sudo apt install valkey-server valkey-tools
sudo systemctl enable --now valkey-server
valkey-cli PING

Homebrew

brew install valkey
brew services start valkey

Kubernetes (Helm)

helm repo add bitnami https://charts.bitnami.com/bitnami
helm install cache bitnami/valkey \
  --set architecture=replication \
  --set auth.password=strong-password \
  --set replica.replicaCount=2 \
  --set sentinel.enabled=true

CLI: Redis와 동일

valkey-cli
> SET user:1 "JB"
OK
> GET user:1
"JB"
> INCR counter
(integer) 1
> EXPIRE user:1 3600
(integer) 1
> TTL user:1
(integer) 3600
> INFO server
# Server
valkey_version:8.0.1
...

redis-cli 대신 valkey-cli만 바꾸면 됩니다. redis-cli도 여전히 동작합니다(동일 프로토콜).

클라이언트 라이브러리

모든 기존 Redis 클라이언트가 그대로 동작합니다.

Node.js (ioredis)

import Redis from "ioredis"

const redis = new Redis({
  host: "valkey.internal",
  port: 6379,
  password: process.env.VALKEY_PASSWORD,
})

await redis.set("key", "value", "EX", 60)
const val = await redis.get("key")

Python (redis-py)

import redis

r = redis.Redis(host="valkey.internal", port=6379, password="...", decode_responses=True)
r.set("key", "value", ex=60)
print(r.get("key"))

Go (go-redis)

rdb := redis.NewClient(&redis.Options{
    Addr: "valkey.internal:6379",
})
rdb.Set(ctx, "key", "value", time.Minute)

네이티브 Valkey 클라이언트도 개발 중이지만 기존 Redis 클라이언트로 충분합니다.

주요 사용 패턴

1) 세션 저장소

await redis.setex(`session:${token}`, 3600, JSON.stringify({ userId: 42 }))
const session = JSON.parse(await redis.get(`session:${token}`) ?? "null")

2) 레이트 리미트

const key = `rate:${userId}`
const count = await redis.incr(key)
if (count === 1) await redis.expire(key, 60)
if (count > 100) throw new Error("Rate limit exceeded")

3) 캐시 (Cache-Aside)

async function getUser(id: string) {
  const cached = await redis.get(`user:${id}`)
  if (cached) return JSON.parse(cached)
  const user = await db.users.findById(id)
  await redis.setex(`user:${id}`, 600, JSON.stringify(user))
  return user
}

4) Pub/Sub

const sub = new Redis()
await sub.subscribe("events")
sub.on("message", (channel, msg) => console.log(channel, msg))

const pub = new Redis()
await pub.publish("events", JSON.stringify({ type: "hi" }))

5) Streams (메시지 큐)

await redis.xadd("orders", "*", "userId", "42", "amount", "100")
const entries = await redis.xread("COUNT", 10, "STREAMS", "orders", "0")

6) 분산 락 (Redlock)

const lockKey = "lock:resource"
const token = crypto.randomUUID()
const acquired = await redis.set(lockKey, token, "PX", 30000, "NX")
if (acquired) {
  try {
    // critical section
  } finally {
    await redis.eval(`
      if redis.call('get', KEYS[1]) == ARGV[1] then
        return redis.call('del', KEYS[1])
      else
        return 0
      end`, 1, lockKey, token)
  }
}

프로덕션 설정

valkey.conf 요약

bind 0.0.0.0
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300

requirepass your-strong-password

# 메모리
maxmemory 8gb
maxmemory-policy allkeys-lru

# 영속성 (AOF + RDB 혼합 권장)
appendonly yes
appendfsync everysec
save 900 1
save 300 10
save 60 10000

# 멀티스레드 I/O (8 이상)
io-threads 4
io-threads-do-reads yes

# 복제
replica-read-only yes
replica-serve-stale-data yes

# 로그
loglevel notice

복제 + 센티넬 (고가용성)

Master 1 + Replica 2 + Sentinel 3의 전형적 구조. Sentinel이 master 장애 시 자동 페일오버.

# Sentinel 설정
sentinel monitor mymaster 192.168.1.10 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
sentinel parallel-syncs mymaster 1

Cluster (샤딩)

valkey-cli --cluster create \
  10.0.0.1:6379 10.0.0.2:6379 10.0.0.3:6379 \
  10.0.0.4:6379 10.0.0.5:6379 10.0.0.6:6379 \
  --cluster-replicas 1

16384개 슬롯이 3 마스터에 분산되고 각 마스터마다 1 레플리카.

Redis → Valkey 마이그레이션

시나리오 1: 인플레이스 교체

Valkey는 Redis 7.2와 바이너리 호환이므로 가장 간단:

# 기존 Redis 중지 후 Valkey로 교체
systemctl stop redis-server
apt install valkey-server
# 데이터 디렉터리(/var/lib/redis → /var/lib/valkey) 복사 또는 설정 조정
systemctl start valkey-server

AOF/RDB 파일을 그대로 로드합니다.

시나리오 2: 블루그린 (다운타임 최소)

  1. 기존 Redis를 Valkey 복제본으로 연결 (REPLICAOF old-redis 6379)
  2. 복제 완료 대기 (INFO replication에서 sync 완료)
  3. 애플리케이션을 Valkey로 전환
  4. 기존 Redis 종료

시나리오 3: ElastiCache 교체 (AWS)

aws elasticache create-replication-group \
  --replication-group-id myapp-valkey \
  --replication-group-description "Valkey replacement" \
  --engine valkey \
  --engine-version 8.0 \
  --cache-node-type cache.r7g.large \
  --num-cache-clusters 2 \
  --automatic-failover-enabled

기존 Redis ElastiCache와 동일한 API·VPC·보안그룹 설정이 가능합니다. Terraform 리소스는 aws_elasticache_replication_groupengine = "valkey" 한 줄만 바꾸면 됩니다.

모니터링

핵심 메트릭

  • used_memory / used_memory_rss: 메모리 사용량
  • connected_clients: 활성 연결 수
  • instantaneous_ops_per_sec: 초당 처리
  • keyspace_hits / keyspace_misses: 캐시 히트율
  • evicted_keys: 메모리 부족으로 제거된 키 (0이어야 이상적)
  • replication_lag: 복제 지연
  • cluster_state (클러스터): ok/fail

Prometheus exporter

docker run -d --name valkey-exporter \
  -p 9121:9121 \
  oliver006/redis_exporter \
  --redis.addr=redis://valkey.internal:6379 \
  --redis.password=$VALKEY_PASSWORD

기존 redis_exporter가 Valkey도 완벽 지원합니다. Grafana 대시보드도 Redis 대시보드 재사용.

성능 튜닝

  1. maxmemory-policy: LRU 계열 정책이 일반적, 세션이라면 allkeys-lru, 캐시 기반은 volatile-lru
  2. Pipelining: 클라이언트에서 pipeline() 사용 시 수십 배 처리량 향상
  3. Lua scripting: 여러 명령을 원자적으로, 네트워크 왕복 최소화
  4. 큰 값 회피: 단일 키에 수 MB 저장 시 블로킹. 100KB 이상은 구조 변경 고려
  5. SCAN 사용: KEYS는 운영 중 금지 — 블로킹
  6. Persistence 설정: 캐시 전용이면 appendonly no + save ""로 디스크 I/O 제거 가능

보안

  • requirepass 강한 비밀번호
  • ACL: ACL SETUSER reader on >readpass ~* &* +@read로 읽기 전용 계정
  • bind 127.0.0.1 + 내부 네트워크만 허용
  • TLS 활성: tls-port 6379, 인증서 설정
  • Redis 익스플로잇(SSRF 등)은 Valkey에도 동일 적용 → 절대 공개 노출 금지

트러블슈팅

”WRONGTYPE” 오류

같은 키에 다른 타입(예: STRING 위에 LPUSH) 작업. TYPE key로 확인.

메모리 급증

  • DEBUG OBJECT key로 큰 키 찾기
  • valkey-cli --bigkeys로 전체 스캔
  • MEMORY USAGE key로 개별 키 크기

복제 지연

  • 네트워크 대역폭 확인
  • repl-backlog-size 증가
  • Master의 client-output-buffer-limit 확인

AOF 파일 거대화

  • BGREWRITEAOF로 수동 재작성
  • auto-aof-rewrite-percentage 100·auto-aof-rewrite-min-size 64mb

클러스터 운영 팁

  • 짝수 마스터 피하기: 스플릿브레인 방지에 홀수 선호
  • 물리 분리: 마스터·레플리카를 다른 AZ/rack에
  • 재분산(reshard): 노드 추가 후 valkey-cli --cluster reshard
  • Hash tag: 특정 키들을 같은 슬롯에 두려면 {user:1}:profile, {user:1}:orders
  • 파이프라인 주의: 클러스터에서는 여러 슬롯 명령 한 번에 금지

체크리스트

  • 라이선스 컴플라이언스 팀 검토 완료
  • 기존 Redis 클라이언트 호환성 테스트
  • AOF/RDB 백업 후 마이그레이션
  • TLS + ACL + bind 설정
  • 메모리 정책과 영속성 요구사항 일치
  • Sentinel 또는 Cluster로 HA
  • Prometheus 메트릭 + 알림
  • big keys·slow log 주기 점검
  • 관리형 서비스(ElastiCache for Valkey) 고려

마무리

Valkey는 Redis 라이선스 변경이라는 위기를 오픈소스 커뮤니티가 빠르게 포크로 응답한 사례이며, Linux Foundation 거버넌스와 주요 클라우드 벤더의 전폭 지원 덕분에 안정적으로 자리잡았습니다. 2026년 현재 Redis와 기술적으로 완전 호환되면서 라이선스 리스크는 0이고 성능 개선·오픈소스 모듈 대안도 빠르게 성숙 중입니다. 신규 프로젝트는 Valkey를 기본 선택으로, 기존 Redis 운영 조직도 점진적 전환 계획을 세워두는 것이 합리적입니다. 대부분의 앱은 docker run redis 대신 docker run valkey로 한 줄만 바꿔도 무엇 하나 잃지 않습니다.

관련 글

  • Redis 완벽 가이드
  • 캐시 전략 완벽 가이드
  • Memcached vs Redis 비교
  • AWS ElastiCache 가이드