Why “just use Redis” is no longer a safe answer
A few years ago, cache-layer meetings lasted five minutes. One line — “let’s put Redis in front of it” — closed the discussion. That changed in March 2024, when Redis moved from BSD 3-Clause to a RSALv2/SSPLv1 dual license. The fallout did not stay inside the source tree.
- Major Linux distros started pulling Redis out of their default package repos and replacing it with a fork (e.g. Fedora, openSUSE, and Debian-family packaging-policy discussions).
- Valkey, the community fork backed by AWS, Google Cloud, Oracle, and others, moved under the Linux Foundation and showed up as a separate engine option in cloud managed services.
- Cloud vendors are pushing the fork at a lower unit price. License is now both a legal issue and a billing issue.
- In 2025 Redis added AGPLv3 as a license option, but that is not a rollback — it is an extra choice. Depending on the organization, AGPL itself can be more burdensome than RSAL.
This is not a concepts primer. It is a decision document that scores Redis / Valkey / Memcached on six axes and names a single winner per scenario. If you need a similar judgment, read Terraform vs OpenTofu in Practice: What to Use After BSL and When to Move with the same frame.
30-second scorecard: use this when…
Grab the conclusion without scrolling.
| # | Our situation | Verdict | One-line rationale |
|---|---|---|---|
| ① | Simple string/byte cache only, horizontal scale first | Memcached | Slab allocation is memory-efficient + multithreading is native; smallest ops surface |
| ② | Depends on Sorted Set, Stream, HyperLogLog, Bitmap, etc. | Valkey (keeping Redis is also viable) | Memcached has no data structures. Valkey is Redis 7.2 API compatible |
| ③ | Used as Pub/Sub or a lightweight queue stand-in | Valkey, but a real queue needs a real broker | Streams can hold, but if you need reprocessing and a DLQ, Kafka/SQS/RabbitMQ is the answer |
| ④ | Per-core throughput is the bottleneck; need vertical scale on a single node | Valkey or Memcached | Valkey 8 multithreaded I/O, Memcached native multithreading — both use the cores |
| ⑤ | Avoiding license risk is contractually mandatory | Valkey | Stays BSD 3-Clause + Linux Foundation governance |
| ⑥ | No one to run a cluster | Managed service + single shard (1 replica) | Who operates it is a bigger risk variable than which engine you pick |
The three variables that actually flip the verdict
The axes that reverse the table are really just three.
- Value-size distribution — large values saturate NIC bandwidth first and wash out engine differences.
- Data-structure dependence — if you only use
SETEX/GET, Memcached is a serious candidate. A singleZADDknocks it out. - Whether you resell — offering cache as a service to customers is the only knockout punch on the license axis.
The sections below validate each of those three.
License judgment: what is actually a problem for your company
Timeline
| When | Event | What gets constrained |
|---|---|---|
| ~2024.02 | Redis: BSD 3-Clause | Effectively none. Resell, modify, bundle freely |
| 2024.03 | Redis 7.4~: RSALv2 / SSPLv1 dual | Restricts offering Redis “as a managed service to third parties.” Choosing SSPL raises the whole-stack source-disclosure debate |
| 2024.03~ | Valkey fork, Linux Foundation transfer | Based on Redis 7.2.4-era code, stays BSD 3-Clause |
| 2024~2025 | Distro package swaps, cloud engine split | apt install redis may no longer mean latest Redis |
| 2025 | Redis 8: AGPLv3 option added | Relicensing is eased, but AGPL’s network-distribution clause is still a burden for some orgs |
Risk by usage pattern
| Usage pattern | Risk | Verdict and what to check |
|---|---|---|
| (a) Internal infra, cache only | Low | Fine in practice. Still refresh the license entry in your software BOM |
| (b) Internal component of your own SaaS | Medium | The fight is “are we providing Redis itself, or our service that happens to use Redis?” The clause is ambiguous — legal review required |
| (c) Reselling cache itself as a managed service | High | Exactly the shape RSALv2 targets. Commercial license or move to Valkey |
| (d) Bundled in an appliance / on-prem package | High | Distribution happens, so source-disclosure / notice obligations must be reviewed |
Internal-docs checklist to pull before the meeting
- Open-source clause in customer contracts — any “no GPL-family or similar copyleft licenses” language?
- Software BOM (SBOM) — is the Redis version pre-relicense (7.2 or earlier) or after?
- Redis binaries baked into container image bases (including sidecars and bundled images)
- License-table consistency in the open-source notice docs you filed for public-sector / financial deliveries
⚠️ This section is not legal advice. Final interpretation and application of license terms must go through in-house counsel or outside counsel. What you get here is a list of what to ask.
Remember one principle. Do not migrate because “licenses are scary.” An (a)-type org that rushes a migration and pages itself loses far more. Conversely, if you are (c) or (d), you need a date on the calendar now.
Features, performance, and cost — three-way comparison
Feature comparison
| Item | Redis 8 | Valkey 8 | Memcached 1.6 |
|---|---|---|---|
| String / Hash / List / Set | ✅ | ✅ | String (bytes) only |
| Sorted Set / Stream / Bitmap / HyperLogLog | ✅ | ✅ | ❌ |
| Multithreaded I/O | ✅ (io-threads) | ✅ (improved async I/O) | ✅ multithreaded by default |
| Cluster mode | ✅ | ✅ | ❌ (client-side sharding) |
| Replication | ✅ | ✅ | ❌ |
| Persistence (RDB/AOF) | ✅ | ✅ | ❌ (full loss on restart) |
| TLS / ACL | ✅ | ✅ | TLS yes; ACL is SASL-level |
| Modules (Search/JSON/TimeSeries) | ✅ official bundle | Separate modules (e.g. valkey-search); ecosystem still early | ❌ |
| Memory efficiency | jemalloc, object overhead exists | Same + key-offload improvements | Slab allocation; lowest overhead for plain KV |
| License | RSALv2/SSPL or AGPLv3 | BSD 3-Clause | BSD 3-Clause |
| Governance | Redis Ltd. | Linux Foundation | Community |
Where Memcached clearly wins: operational simplicity (far fewer knobs), memory efficiency on pure KV, multithreading by default, and a stateless design where “on failure, just drop it” is correct. If this is a DB query-result cache rather than a session store, Memcached is still the right answer.
Where Memcached loses: no persistence, no data structures, no replication, no compound ops beyond atomic counters.
Benchmarks: use our values, not someone else’s numbers
Vendor benches are mostly measured under small values + high pipelining. Change the conditions and the conclusion changes. Reproduce it yourself with memtier_benchmark.
# 1) 기준선: 파이프라이닝 없음, 작은 값(32B) — 지연 시간 중심
memtier_benchmark -s 10.0.1.10 -p 6379 \
--protocol=redis --clients=50 --threads=4 \
--data-size=32 --ratio=1:9 --pipeline=1 \
--test-time=60 --hide-histogram# 2) 처리량 상한: 파이프라이닝 16 — 엔진의 I/O 스레드 효과가 드러나는 구간
memtier_benchmark -s 10.0.1.10 -p 6379 \
--clients=50 --threads=8 \
--data-size=32 --ratio=1:9 --pipeline=16 \
--test-time=60# 3) 큰 값 구간: 100KB — 여기서부터는 NIC 대역폭이 먼저 포화된다
memtier_benchmark -s 10.0.1.10 -p 6379 \
--clients=20 --threads=4 \
--data-size=102400 --ratio=1:4 --pipeline=1 \
--test-time=60How to read the results
| Condition | Dominating variable | Practical implication |
|---|---|---|
| value ≤ 1KB + pipeline ≥ 8 | I/O thread count, CPU cores | The band where Valkey multithreaded I/O gains show up most |
| value ≤ 1KB + pipeline = 1 | RTT (network round trip) | AZ placement and connection pools matter more than the engine |
| value ≥ 100KB | NIC bandwidth | Engine gap washes out. Compression / value splitting help more |
| mostly GET/SET | Memory efficiency | Memcached holds more keys in the same RAM |
How to extract our value-size distribution (on a production node, always run this on a replica or a snapshot-restored instance. --bigkeys / MEMORY USAGE add load):
# 큰 키 상위 목록 (샘플링, 부하 낮음)
redis-cli -h <host> --bigkeys
# 랜덤 샘플 200개의 실제 메모리 사용량 히스토그램
for i in $(seq 1 200); do
k=$(redis-cli -h <host> RANDOMKEY)
redis-cli -h <host> MEMORY USAGE "$k"
done | sort -n | awk '{a[NR]=$1} END {
print "p50:", a[int(NR*0.5)];
print "p90:", a[int(NR*0.9)];
print "p99:", a[int(NR*0.99)];
}'If p90 is over 10KB, “multithreaded benchmark numbers” are irrelevant to our workload.
Real cost math: the formula, in the open
💰 The unit prices below are example figures as of an August 2026 lookup and change constantly by region, commitment, and engine. Re-check the latest rates on the official AWS ElastiCache pricing page, then plug them into the formula.
The formula is simple.
월 노드 비용 = 시간당 온디맨드 단가(USD) × 노드 수 × 730시간Seoul region (ap-northeast-2), cache.r7g.large × 2 nodes (1 primary + 1 replica) template:
| Engine | Hourly rate (USD, fill in lookup) | Formula | Monthly total (USD) |
|---|---|---|---|
| Redis OSS | $A | $A × 2 × 730 | = $A × 1,460 |
| Valkey | $B (typically priced below A) | $B × 2 × 730 | = $B × 1,460 |
| Memcached | $C (no replication → re-count nodes) | $C × N × 730 | = $C × N × 730 |
Put the savings rate in the meeting deck as-is.
절감률(%) = (A - B) / A × 100If Valkey is priced 20% below Redis OSS, monthly savings on 2 nodes is A × 1,460 × 0.20. It scales linearly with node count, so if you already run 10+ shards, cost alone is enough reason to evaluate a move — license aside.
Rough TCO: ElastiCache vs self-managed on EC2 (same spec, 2 nodes)
| Cost item | ElastiCache | Self-managed on EC2 |
|---|---|---|
| Compute | node rate × 730h | instance rate × 730h (cheaper with RI/SP) |
| Storage | included | EBS gp3 volume extra |
| Backup | snapshot charges (after free allowance) | S3 storage + script upkeep |
| Failover | automatic (Multi-AZ) | Sentinel/Cluster you build yourself |
| Ops hours | ≈ 2–4h/month | ≈ 8–16h/month (patches, monitoring, failover drills) |
| Hours converted | hourly loaded cost × hours above | same math |
Multiply those hours by your team’s loaded hourly rate and the instance-price gap usually flips. If you run failover yourself, the procedure in Redis Sentinel — High Availability and Automatic Failover applies to Valkey as-is (config syntax is compatible).
Migration runbook: Redis 7.2 → Valkey 8 with zero downtime
Valkey is based on Redis 7.2.4 code, so protocol and command compatibility is very high. “Very high” is not “complete.”
Stage 0: pre-inventory (can we even cut over?)
# 서버 정보 및 모듈 목록
redis-cli -h <host> INFO server
redis-cli -h <host> MODULE LIST
# 지원 명령어 수 (전후 비교용)
redis-cli -h <host> COMMAND COUNT
# 실제로 어떤 명령을 쓰고 있는지 (짧게, 부하 주의)
redis-cli -h <host> --stat
timeout 30 redis-cli -h <host> MONITOR | awk '{print $4}' | sort | uniq -c | sort -rn | head -30Expected healthy result: MODULE LIST is an empty array ((empty array)) → proceed.
Branch: if Redis Stack modules such as search, json, timeseries, bloom show up, this is not a simple cutover. Your options are ① keep Redis (re-read the license terms) ② split that capability onto OpenSearch/PostgreSQL/etc. ③ validate the Valkey-side counterpart module, then migrate. For ③, budget validation effort as its own line item.
Procedure
- Bring up a new Valkey 8 node (same subnet as existing Redis, same spec or better)
Bash
valkey-server /etc/valkey/valkey.conf --port 6379 --daemonize yes - Point it at existing Redis as master
Bash
valkey-cli -h <valkey-host> REPLICAOF <redis-host> 6379 # 인증이 있다면 valkey-cli -h <valkey-host> CONFIG SET masterauth "<password>" - Confirm replication — these values must be healthy before you continue.
Expected healthy result:Bash
valkey-cli -h <valkey-host> INFO replicationmaster_link_status:up,master_sync_in_progress:0, andlag:0on the master’sINFO replication. Branch: ifmaster_link_status:downpersists, check security groups /bind/protected-mode/requirepassfirst. Ifmaster_sync_in_progress:1hangs around, an RDB transfer is in flight — wait proportional to dataset size. - Optionally shift a slice of read traffic to Valkey — canary 5–10%, watch latency and error rate.
- Flip the client endpoint — DNS CNAME or a config switch. Drop TTL to 30 seconds or less ahead of time.
- Promote
Bash
valkey-cli -h <valkey-host> REPLICAOF NO ONE - Observation window (minimum 24 hours) — hang the rollback thresholds below on the dashboard.
- Retire old Redis — keep it stopped, with snapshots, for at least 7 days (stay on 3-2-1 backup).
Client-library checkpoints
| Library | What to check | Common failure point |
|---|---|---|
| redis-py (Python) | HELLO 3 RESP3 handshake, decode_responses behavior, CLUSTER SLOTS parsing if you use Cluster | Custom code that regex-parses the server version string |
| Lettuce / Spring Data Redis (Java) | Command-support logic keyed off server version, Sentinel topology refresh interval, ClientResources reconnect policy | Assuming the engine-name string in Sentinel INFO |
| go-redis (Go) | Options.Protocol (RESP2/3), cluster topology refresh, ReadTimeout tuning | MOVED retry handling on pipeline + cluster |
Common check command:
valkey-cli -h <valkey-host> INFO server | grep -E "redis_version|valkey_version|server_name"Some clients assume a redis_version field exists. Valkey keeps that field for compatibility, but grep your homegrown health-check and monitoring scripts for hardcoded strings.
Rollback conditions (quantitative thresholds)
If any one of these holds for 5+ minutes, immediately revert the step-5 endpoint.
| Metric | Threshold |
|---|---|
| Cache-read p99 latency | >+30% vs pre-cutover baseline |
| Client error rate | >+0.1 pp vs baseline |
Replication lag (lag) | >10 seconds and not recovering |
| Cache hit ratio | >−5 pp vs baseline |
| Node CPU | sustained 80% |
Rollback procedure: point DNS back at old Redis → put Valkey back as a replica with REPLICAOF → if you had already promoted, check whether both sides took writes first (if dual-write happened, invalidate and reload is the safe path).
Constraints when you are on ElastiCache
ElastiCache sometimes cannot in-place change a cluster’s engine (whether the console offers an upgrade path depends on the engine/version combo — confirm in the console and official docs). If there is no path, the workaround is:
- Take a manual snapshot of the existing cluster
- Create a new Valkey-engine cluster from that snapshot (seed RDB restore)
- Catch up the post-snapshot delta via application-level warming, or via
REPLICAOFagainst the source (through a self-managed node) - Flip the endpoint → observe → delete the old cluster
If this is a pure cache and delta catch-up is hard, natural warming via TTL expiry is simpler. Right after cutover the origin DB will get slammed, so put cache-stampede protection (request coalescing or jittered TTLs) in place first.
Conclusion: final recommendation by three scenarios
① Startup, single instance (low traffic, 1–2 infra people)
Verdict: Valkey (managed, single shard + 1 replica)
Simple: feature-parity with Redis, cheaper managed rates, and you will not think about the license again. No need to rush if you already run Redis, but when you create a new cluster, create it as Valkey.
- One thing to do today: change the default engine on the next cache cluster you create to Valkey, and update the
enginevalue in the IaC template (Terraform module, etc.) at the same time.
② High-traffic SaaS (multi-tenant, some resale element)
Verdict: Valkey (full cutover)
Multi-tenant SaaS sits on the (b)–(c) boundary of the license table. Shard count is high enough that savings are material. Nodes keep growing while legal interpretation is still pending.
- Cutover priority: ① no modules + pure cache clusters (safest) → ② session store → ③ rate limiter / distributed lock → ④ module-dependent clusters (split out as a separate project)
- Anything tied to Redis Stack modules comes off the cutover list and gets redefined as “move the capability to another store.”
③ Regulated-industry on-prem (air-gapped, vendor-audit response)
Verdict: Valkey (or Memcached if it is pure KV)
This is where bundled distribution and open-source notice obligations bite, so the simplicity of BSD 3-Clause is audit-cost reduction.
- License evidence pack: ① copy of the LICENSE file for the version in use ② refreshed SBOM (CycloneDX/SPDX) ③ open-source notice (NOTICE) ④ package provenance (official release URL / checksum) on record
Our team’s decision checklist (copy this)
[ ] 1. 우리는 캐시를 고객에게 "서비스로" 제공하거나 제품에 번들 배포하는가? (Yes → Valkey 필수)
[ ] 2. Sorted Set / Stream / Bitmap 중 하나라도 쓰는가? (No → Memcached 후보 진입)
[ ] 3. Redis Stack 모듈(Search/JSON/TimeSeries)에 의존하는가? (Yes → 단순 전환 불가, 별도 과제)
[ ] 4. 값 크기 p90이 10KB를 넘는가? (Yes → 멀티스레드 성능 마케팅은 무시)
[ ] 5. 캐시 노드가 10개를 넘는가? (Yes → 라이선스와 무관하게 비용만으로 전환 검토)Three data points you must have before the decision meeting
- Value-size distribution — p50/p90/p99 from the
MEMORY USAGEsampling script above - Commands actually in use — top 30 from a 30-second
MONITORsample +MODULE LIST - Current monthly cache bill — last 3 months actuals from Cost Explorer, tagged to ElastiCache
Without those three, the meeting ends at “but Redis is more stable, right?” With numbers, you close in 30 minutes.
FAQ
Q. Is Valkey 100% compatible with Redis? A. Valkey forked from Redis 7.2.4, so compatibility is very high at the command, protocol, config-file, and replication-protocol level. Separately verify ① Redis Stack modules (Search/JSON/TimeSeries, etc.) ② features added after Redis 8 ③ homegrown scripts that hardcode the server version string. The two projects are evolving independently, so the gap will widen over time.
Q. We only use Redis as an internal cache. Do we need to move to Valkey urgently? A. In most cases, no. Internal-infra-only use is pattern (a) on the license table and is fine in practice. The rational order is: create new clusters as Valkey, then evaluate a cutover when the managed-price gap becomes material (node count grows). Make the final call after legal reviews the open-source clause in customer contracts with you.
Q. Can we use Memcached as a session store? A. Not recommended. Memcached has no persistence and no replication, so a node restart wipes everything and every user is logged out. Data whose loss immediately breaks UX — sessions — belongs on Valkey/Redis, which have replication and persistence. Memcached is optimal for “we can recompute it” DB query-result caches.
Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.
Comments
Be the first to comment.