Przejdź do treści

Cache z ElastiCache for Valkey na Dragonfly na EC2 z 64 GB RAM

Cache aplikacji SaaS przeniosłem z ElastiCache for Valkey na Dragonfly postawiony na zwykłej instancji EC2 z 64 GB RAM. Powody były trzy: koszt, wydajność i zwykła ciekawość, bo Dragonfly od dawna obiecuje, że na tym samym sprzęcie zrobi więcej niż Redis i Valkey. Jeśli Twoja aplikacja przeżyje przez chwilę pusty cache, przełączenie zajmuje jedną noc, a według cennika AWS rachunek spada o ponad 200 USD miesięcznie na jednym węźle.

Punkt wyjścia

  • Aplikacja SaaS, jedna instancja cache, bez klastra.
  • Cache trzymał dane, które da się odtworzyć z bazy. Nic, czego utrata oznaczałaby utratę danych klienta.
  • ElastiCache for Valkey, czyli zarządzana usługa AWS. Wygodna, ale płaci się za tę wygodę.
Architektura przed i po migracjiPrzed: aplikacja SaaS łączy się z ElastiCache for Valkey, cache.r7g.2xlarge, około 39,6 GiB na dane. Po: aplikacja łączy się z Dragonfly na instancji EC2 r7g.2xlarge, około 54 GiB na dane, w tym samym VPC.PRZEDVPCAplikacja SaaSodczyt i zapis cache:6379ElastiCache for Valkeycache.r7g.2xlarge (52,82 GiB)ok. 39,6 GiB na dane (25% rezerwy)POVPCAplikacja SaaSodczyt i zapis cache:6379Dragonfly na EC2r7g.2xlarge (64 GiB)ok. 54 GiB na dane (--maxmemory)

Dlaczego nie zostać na ElastiCache

ElastiCache nie daje Ci całej pamięci, za którą płacisz. W grupie parametrów dla Redisa i Valkey reserved-memory-percent ma domyślnie 25%. AWS rezerwuje tę pamięć m.in. na copy-on-write przy bgsave, który robi fork() całego procesu. Dokumentacja wprost prosi, żeby tej wartości nie zmniejszać. Węzeł cache.r7g.2xlarge ma 52,82 GiB, więc na dane zostaje około 39,6 GiB.

Dragonfly robi snapshot bez fork(), więc nie trzeba trzymać tak dużego zapasu. Na EC2 r7g.2xlarge z 64 GiB RAM zostawiam system i bufory na swoim miejscu i daję Dragonfly około 54 GiB. To ta sama klasa procesora (Graviton3) i te same 8 vCPU, a miejsca na dane jest wyraźnie więcej.

Do tego dochodzi cena. Cennik AWS dla Frankfurtu, ceny on-demand, 730 godzin w miesiącu, stan na wrzesień 2026:

Wariant Za godzinę Za miesiąc
ElastiCache for Valkey, cache.r7g.2xlarge 0,84 USD 613,20 USD
EC2 r7g.2xlarge + 100 GB gp3 na snapshoty 0,5168 USD + dysk 386,78 USD
Różnica 226,42 USD (ok. 37%)
Koszt miesięczny: ElastiCache for Valkey a EC2 z DragonflyElastiCache for Valkey cache.r7g.2xlarge: 613,20 USD miesięcznie. EC2 r7g.2xlarge z Dragonfly i dyskiem 100 GB gp3: 386,78 USD miesięcznie.Koszt miesięczny według cennika AWS0 USD200 USD400 USD600 USDElastiCache for Valkeycache.r7g.2xlarge613,20 USDEC2 + Dragonflyr7g.2xlarge + 100 GB gp3386,78 USDRegion eu-central-1 (Frankfurt), ceny on-demand, 730 h w miesiącu, wrzesień 2026. Różnica: 226,42 USD (ok. 37%).

To są ceny z cennika, nie z faktury klienta. Obie strony mają też rezerwacje na rok lub trzy lata. Sama instancja EC2 z rocznym Reserved Instance bez opłaty z góry kosztuje 0,3419 USD za godzinę, czyli z dyskiem około 259 USD miesięcznie. Jeśli ktoś wciąż siedzi na ElastiCache for Redis OSS, ten sam węzeł kosztuje we Frankfurcie 1,05 USD za godzinę, czyli 766,50 USD miesięcznie, i różnica robi się jeszcze większa.

Policz dla swojej liczby węzłów

Cennik AWS (Price List API), region eu-central-1, ceny on-demand, wrzesień 2026, 730 godzin w miesiącu. Bez rezerwacji po obu stronach.

ElastiCache for Valkey
613,20 USD
Dragonfly na EC2
386,78 USD

Różnica: 226,42 USD miesięcznie, czyli 2 717 USD rocznie (37% taniej).

Miejsce na dane w jednym węźle: ok. 39,6 GiB w ElastiCache i ok. 54 GiB w Dragonfly. Po stronie EC2 dochodzi Twoja praca: łatanie, monitoring, kopie.

Co mówią benchmarki

Własnych pomiarów z tego wdrożenia nie publikuję, więc podaję liczby z benchmarku producenta. W czerwcu 2026 zespół Dragonfly porównał go z Valkey 9.0 na instancjach Graviton. Najbliższa mojej jest m7g.2xlarge: 8 vCPU, tyle samo co r7g.2xlarge, tylko mniej pamięci.

m7g.2xlarge, 8 vCPU Dragonfly Valkey 9.0
Zapis, operacji na sekundę 816 tys. 548 tys.
Odczyt, operacji na sekundę 848 tys. 811 tys.
Zapis, p99 787 µs 3 283 µs
Odczyt, p99 887 µs 951 µs
Pamięć na jeden wpis 127 B 149 B
Benchmark Dragonfly i Valkey 9.0 na m7g.2xlargeZapis: Dragonfly 816 tys., Valkey 548 tys. operacji na sekundę. Odczyt: Dragonfly 848 tys., Valkey 811 tys. operacji na sekundę.Operacje na sekundę, m7g.2xlarge (8 vCPU)DragonflyValkey 9.00 tys.200 tys.400 tys.600 tys.800 tys.Zapis816 tys.Dragonfly548 tys.ValkeyOdczyt848 tys.Dragonfly811 tys.ValkeyŹródło: benchmark producenta (blog Dragonfly, czerwiec 2026). SET/GET, wartości 64 B, bez persystencji i replikacji.

Na odczytach przy 8 rdzeniach różnica jest niewielka i sami autorzy piszą, że Valkey 9 mocno ją zmniejszył. Duża przewaga jest na zapisach i na opóźnieniu zapisu. Test dotyczył prostych SET/GET z wartościami 64 B, bez persystencji, bez replikacji i bez trybu klastra. Twoja aplikacja zachowa się inaczej, więc przed migracją puść ruch testowy na własnych danych.

Dla mnie ważniejsza od szczytowej przepustowości jest pamięć: 127 B zamiast 149 B na wpis to około 15% mniej RAM-u na te same dane.

Jak przebiegła migracja

Przyjąłem najprostszy wariant: zimny start cache. Bez replikacji danych i bez podwójnego zapisu. Aplikacja obsługiwała pusty cache, więc po przełączeniu po prostu przez chwilę częściej pytała bazę, aż cache się zapełnił. Przełączenie zrobiłem w nocy, kiedy ruch jest najmniejszy.

Przełączenie krok po kroku

VPCAplikacja SaaSBaza danychElastiCache for Valkeycache.r7g.2xlargeDragonfly na EC2r7g.2xlargeobciążeniezapełnienie cacheVPCAplikacja SaaSBaza danychobciążenieElastiCachefor Valkeycache.r7g.2xlargeDragonflyna EC2r7g.2xlargezapełnienie cache
  1. Przed: aplikacja czyta i zapisuje cache w ElastiCache for Valkey.
  2. Obok, w tym samym VPC, staje instancja EC2 z Dragonfly. Najpierw test aplikacji na stagingu.
  3. W nocy zmiana adresu cache i deploy. Cache jest pusty, więc więcej zapytań trafia do bazy.
  4. Cache się zapełnia, a obciążenie bazy wraca do normy.
  5. Po kilku dniach spokoju stary klaster ElastiCache zostaje usunięty.

Kolejność kroków:

  1. Instancja EC2 r7g.2xlarge w tym samym VPC co aplikacja. Security group przepuszcza port 6379 tylko z security group aplikacji, bez publicznego IP.
  2. Dragonfly z jawnie ustawionymi flagami (niżej).
  3. Test aplikacji na stagingu z Dragonfly w miejscu ElastiCache.
  4. W nocy zmiana adresu cache w konfiguracji aplikacji i deploy.
  5. Obserwacja obciążenia bazy i trafień w cache, dopóki cache się nie rozgrzeje.
  6. Stary klaster ElastiCache usunąłem dopiero po kilku dniach spokoju, żeby w razie problemów wrócić jedną zmianą w konfiguracji.

Konfiguracja startowa, od której zaczynam:

dragonfly \
  --bind=0.0.0.0 --port=6379 \
  --requirepass="$DRAGONFLY_PASSWORD" \
  --maxmemory=54gb \
  --cache_mode=true \
  --dir=/var/lib/dragonfly \
  --dbfilename=dump \
  --snapshot_cron="0 */6 * * *"

Na co uważać

To lista z dokumentacji i zgłoszeń z GitHuba. Przejdź ją przed migracją. W tym wdrożeniu aplikacja nie używała skryptów Lua ani BullMQ, więc dwa pierwsze punkty w tym projekcie odpadły. W wielu aplikacjach będą najważniejsze.

Skrypty Lua i niezadeklarowane klucze

Dragonfly domyślnie blokuje skrypty, które dotykają kluczy nieprzekazanych w KEYS, i zwraca błąd script tried accessing undeclared key. Redis i Valkey na to pozwalają, więc część bibliotek z tego korzysta. Można to wyłączyć flagą --default_lua_flags=allow-undeclared-keys, ale wtedy Dragonfly zatrzymuje wszystkie inne operacje na czas wykonania skryptu. Dokumentacja sama ostrzega, że to mocno spowalnia.

Kolejki BullMQ

To najczęstszy przypadek powyższego problemu. Zalecane ustawienie to --cluster_mode=emulated --lock_on_hashtags i nazwy kolejek z hashtagiem, np. {emails} zamiast emails. Wtedy każda kolejka jest obsługiwana przez jeden wątek i nie trzeba blokować całej bazy.

Pamięć i usuwanie kluczy

Domyślnie --maxmemory ma wartość 0, czyli Dragonfly sam ustala limit, a --cache_mode jest wyłączone. Bez --cache_mode=true Dragonfly nie usuwa kluczy przy zbliżaniu się do limitu, tylko zaczyna odrzucać zapisy. Z tą flagą usuwa klucze, po które aplikacja najpewniej już nie sięgnie, własnym algorytmem zamiast klasycznego LRU. Na ElastiCache miałeś politykę usuwania w grupie parametrów i łatwo o niej zapomnieć.

Nikt za Ciebie nie zrobi failoveru

ElastiCache sam łata system, robi backupy i przełącza na replikę. Pojedyncza instancja EC2 to pojedynczy punkt awarii. Przy cache, który aplikacja umie odbudować, to akceptowalne. Przy danych, których nie da się odtworzyć, już nie. Potrzebujesz alertów na stan instancji i pamięć oraz planu, kto aktualizuje system.

TLS

ElastiCache ma zwykle włączone szyfrowanie połączeń, czyli TLS z adresem rediss://. Jeśli aplikacja łączy się przez TLS, włącz --tls z certyfikatem albo świadomie zmień adres na redis:// w prywatnej podsieci.

Stare jądro Linuksa

Dragonfly korzysta z io_uring. Na jądrach starszych niż 5.10 trzeba go uruchamiać z --force_epoll. Na aktualnym Amazon Linux 2023 czy Ubuntu 24.04 ten problem nie występuje.

Licencja

Dragonfly jest na Business Source License 1.1. Możesz go używać jako części własnego produktu, o ile ten produkt nie jest bazą danych w pamięci i nie udostępniasz samego Dragonfly jako usługi. 1 listopada 2030 kod przechodzi na Apache 2.0. Dla SaaS, który używa go jako cache, to nie problem.

Komu bym tego nie polecał

  • Jeśli cache jest jedynym miejscem, gdzie leżą jakieś dane (sesje bez kopii, liczniki rozliczeniowe), a nie masz czasu na zaprojektowanie replikacji i backupów.
  • Jeśli rachunek za ElastiCache to kilkadziesiąt dolarów miesięcznie. Oszczędność nie pokryje czasu poświęconego na utrzymanie własnej instancji.
  • Jeśli nikt w zespole nie chce odpowiadać za łatanie i monitoring serwera.

W pozostałych przypadkach, czyli przy dużym cache, stabilnym ruchu i aplikacji odpornej na pusty cache, to jedna z prostszych oszczędności na AWS. Inne miejsca, w których rachunek AWS bywa za wysoki, sprawdzisz w 8 pytaniach.

Źródła

3 sposoby, w jakie mogę pomóc