RE:NODE

Django Celery s Valkey: broker, beat a limity paměti

Text: Tým RE:NODE
17 min čtení


Celery v Djangu jsou tři kousky zapojení a čtyři nastavení, která byste neměli nechávat ve výchozí hodnotě. Zapojení: soubor celery.py vedle settings.py, import v __init__.py a nastavení s prefixem CELERY_ načítaná z vlastního modulu nastavení Djanga. Nastavení: acks_late, násobitel prefetch, visibility timeout a strop paměti na jeden podřízený proces. Brokerem je Valkey, a protože mluví protokolem Redis, nasměruješ na něj Celery obyčejnou URL redis://.

Na malém tarifu se nepokazí konfigurace, ale aritmetika. Worker Celery je kopie tvého Django projektu, zopakovaná jednou pro rodičovský proces a jednou pro každý podřízený proces, a běží vedle gunicornu, což je ten samý projekt zopakovaný znovu. Tento článek nastaví broker a plán beat a většinu prostoru věnuje tomu, kolik procesů se vejde do zakoupené paměti a co dělat, když se nevejdou. Předpokládá, že projekt už je nasazený podle článku nasazení Djanga do produkce s gunicornem, a neopakuje srovnání knihoven z článku fronty úloh s Valkey.

Co stavíš#

Jeden Valkey sdílejí tři druhy procesů. Webový proces (gunicorn) zařadí úlohu do fronty a vrátí odpověď. Jeden nebo více workerů si úlohy z fronty bere a spouští je. Jeden proces beat, a přesně jeden, podle hodin přidává do fronty periodické úlohy. Zprávy mezi nimi drží Valkey.

task.delay()úlohy k odeslánízprávazápisy ORMčtení ORMgunicornwebový proces DjangaCelery beatjen jeden procesValkeybroker, výsledkyCelery workerprefork potomciPostgreSQLdata aplikace
Django, Celery a Valkey na malém tarifu

Dvě věci z tohoto obrázku určují vše další. Beat úlohy nikdy nespouští, jen je posílá, takže je malý. A worker potřebuje vlastní připojení k databázi, protože importuje tvé modely a s databází mluví úplně stejně jako webový proces. Výpočet, jak se tato připojení sčítají, najdeš v článku connection pooly a limity.

Instalace Celery pro Django#

Nainstaluj Celery s doplňkem pro transport Redis, který přitáhne klientskou knihovnu používanou i pro Valkey:

bash
$ pip install "celery[redis]"

Verzi připni v requirements.txt jako všechno ostatní. Názvy konfiguračních klíčů Celery se změnily v řadě 4.x a několik výchozích hodnot se posunulo mezi vydáními 5.x, takže rozsah, který plave přes minor verzi, je způsob, jak restart ve tři ráno změní chování. Zamykací soubory popisuje článek požadavky Pythonu a virtualenvy.

Integrace s Djangem jsou tři soubory. Nejprve aplikace Celery, ve stejném balíčku jako settings.py:

myproject/celery.py
import osfrom celery import Celeryos.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings.production")app = Celery("myproject")app.config_from_object("django.conf:settings", namespace="CELERY")app.autodiscover_tasks()

Pak zajisti, aby se importovala při startu Djanga, aby se dekorátory @shared_task navázaly na tuto aplikaci:

myproject/__init__.py
from .celery import app as celery_app__all__ = ("celery_app",)

namespace="CELERY" znamená, že každé nastavení Celery v settings.py nese prefix CELERY_ a píše se velkými písmeny: nastavení Celery task_acks_late se stane CELERY_TASK_ACKS_LATE. autodiscover_tasks() importuje modul tasks.py z každé aplikace v INSTALLED_APPS. Úloha, která žije jinde, se nikdy nezaregistruje a worker zaloguje Received unregistered task, jakmile pro ni dorazí zpráva.

Úlohy patří do tasks.py uvnitř aplikace a používají shared_task, aby aplikace neimportovala instanci Celery:

shop/tasks.py
from celery import shared_taskfrom .models import Order@shared_task(    autoretry_for=(ConnectionError, TimeoutError),    retry_backoff=True,    retry_backoff_max=600,    retry_jitter=True,    max_retries=5,)def send_receipt(order_id):    order = Order.objects.get(pk=order_id)    order.send_receipt_email()

Předávej primární klíč, ne instanci modelu. Úloha nesoucí celý objekt pracuje s tím, jak vypadal v okamžiku zapsání zprávy, což může být před hodinou, pokud se fronta zahlcuje.

Nastavení brokeru#

Připojení a nastavení chování patří do modulu nastavení Djanga a čtou se z prostředí, aby heslo nebylo v repozitáři:

settings/production.py
import osCELERY_BROKER_URL = os.environ["VALKEY_URL"]          # redis://:password@host:port/0CELERY_RESULT_BACKEND = os.environ["VALKEY_URL"].replace("/0", "/1")CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = TrueCELERY_TASK_ACKS_LATE = TrueCELERY_TASK_REJECT_ON_WORKER_LOST = TrueCELERY_WORKER_PREFETCH_MULTIPLIER = 1CELERY_TASK_TIME_LIMIT = 300CELERY_TASK_SOFT_TIME_LIMIT = 240CELERY_RESULT_EXPIRES = 3600CELERY_TASK_IGNORE_RESULT = TrueCELERY_BROKER_TRANSPORT_OPTIONS = {    "visibility_timeout": 3600,    "global_keyprefix": "shop:",}CELERY_TIMEZONE = "UTC"

Každé z nich tam je z nějakého důvodu.

NastaveníHodnotaProč
CELERY_BROKER_URLredis://:pw@host:port/0Prázdné uživatelské jméno je záměr: výchozí uživatel Valkey bere jen heslo
CELERY_TASK_ACKS_LATETruePotvrdit po dokončení úlohy, ne při jejím startu
CELERY_WORKER_PREFETCH_MULTIPLIER1Potomek drží jednu rezervovanou zprávu, ne čtyři
CELERY_TASK_TIME_LIMITsekundyTvrdé ukončení úlohy, která se zasekla
CELERY_RESULT_EXPIRES3600Výsledky vyprší, místo aby se hromadily jako klíče
CELERY_TASK_IGNORE_RESULTTrueNeukládat nic, dokud o to úloha nepožádá

URL vychází z přístupových údajů tvého tarifu Valkey: hostitel, port a vygenerované heslo, z nichž nic není výchozí hodnotou lokální instalace. Pokud heslo obsahuje znaky jako @, / nebo #, zakóduj je v URL procentově (@ se stane %40), jinak klient řetězec rozdělí na špatném místě a ohlásí matoucí chybu hostitele. Zvládne to urllib.parse.quote z Pythonu.

CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP je důležité při restartu. Bez něj worker, který naběhne o pár sekund dřív, než je broker dostupný, skončí, a novější vydání Celery 5.x vypisují varování o zastarání s výzvou, abys to nastavil. Hostingový panel po nasazení restartuje všechno naráz, takže pořadí startu neovlivníš.

Číslo databáze za lomítkem je logická databáze uvnitř téhož Valkey. Výsledky v databázi 1 drží mimo prostor klíčů fronty, takže jednu můžeš prohlížet nebo vyprázdnit, aniž bys sáhl na druhou. Pokud návratové hodnoty úloh nikdy nečteš, je CELERY_TASK_IGNORE_RESULT = True a žádný backend pro výsledky vůbec nejlevnější varianta a odstraní celou třídu zbylých klíčů.

Potvrzování, prefetch a visibility timeout#

Transport Redis nemá nativní potvrzování, takže si ho Celery postaví samo. Zpráva převzatá workerem přejde do skryté struktury zvané unacked. Pokud worker potvrdí v rámci visibility timeoutu, zpráva se smaže; pokud ne, vrátí se do fronty a spustí ji jiný worker.

Z toho plynou tři pravidla.

  1. Visibility timeout musí být delší než tvá nejdelší úloha, včetně odpočtů jejích opakování. Výchozí hodnota je jedna hodina. Úloha, která pod výchozí hodnotou běží devadesát minut, se doručí podruhé, zatímco první ještě běží. To je nejčastější příčina hlášení „moje úloha proběhla dvakrát“ u brokeru s protokolem Redis. Pozor: úlohy s ETA a countdown drží až do termínu worker, ne Valkey, takže úloha naplánovaná na zítřek s timeoutem jedné hodiny se doručuje znovu každou hodinu. Krátké timeouty a dlouhé odpočty se nemíchají; práci v daleké budoucnosti plánuj raději přes beat.
  2. S `acks_late` může úloha proběhnout víckrát. Když worker zabijí uprostřed úlohy, zpráva se vrátí a úloha začne znovu od začátku. Dělej úlohy idempotentní: unikátní omezení na id události nebo sloupec se stavem, který se kontroluje jako první. CELERY_TASK_REJECT_ON_WORKER_LOST to rozšiřuje i na potomka, kterého kernel zabil kvůli paměti, což je na malém tarifu ten podstatný případ.
  3. Prefetch 1 vyměňuje propustnost za férovost. Výchozí násobitel 4 znamená, že každý potomek si předem rezervuje čtyři zprávy. Pokud je jednou z nich desetiminutový report, tři za ní čekají, i když jsou ostatní potomci volní. Pro úlohy různé délky je správná 1; pro tisíce drobných stejných úloh je rychlejší výchozí hodnota.

acks_late bez reject_on_worker_lost má ještě jednu past: pokud potomka zabije OOM killer, je zpráva v některých verzích potvrzena jako neúspěšná, místo aby se zkusila znovu. Teprve nastavení obou způsobí, že se zabití kvůli paměti chová jako opakování.

Do fronty zařazuj až po potvrzení transakce, ne před ním. V požadavku obaleném databázovou transakcí se může úloha zařazená přes delay() dostat k workeru dřív, než existuje řádek, na který odkazuje, a skončí chybou DoesNotExist:

python
from django.db import transactiondef create_order(request):    order = Order.objects.create(...)    transaction.on_commit(lambda: send_receipt.delay(order.pk))

on_commit spustí callback, až se potvrdí nejvnější transakce, a při rollbacku ho zahodí, což je přesně to, co chceš u úlohy popisující práci vyvolanou daty.

Beat: periodický plán#

Beat čte plán a v daný čas posílá úlohy. Je to samostatný proces a pro každý plán musí běžet přesně jeden. Dva beaty znamenají, že se každá periodická úloha pošle dvakrát. To je nejdůležitější fakt o škálování Celery: workery můžeš přidávat libovolně, ale druhý beat nikdy.

Nejjednodušší plán žije v nastavení:

settings/production.py
from celery.schedules import crontabCELERY_BEAT_SCHEDULE = {    "clear-expired-sessions": {        "task": "accounts.tasks.clear_sessions",        "schedule": crontab(hour=3, minute=30),    },    "daily-digest": {        "task": "notifications.tasks.send_digest",        "schedule": crontab(hour=7, minute=0, day_of_week="mon-fri"),        "options": {"expires": 3600},    },    "sync-stock": {        "task": "shop.tasks.sync_stock",        "schedule": 300.0,        "args": (),    },}

Holé číslo je interval v sekundách, měřený od startu beatu. crontab se spouští v časech podle nástěnných hodin a používá CELERY_TIMEZONE; nastav ji výslovně, protože výchozí je UTC a souhrn „v 07:00“ pak neběží v 07:00 tam, kde bydlíš. Pokud je syntaxe cronu mlhavá, referencí je vysvětlení výrazů cron, s upozorněním, že crontab() v Celery bere pole jako pojmenované argumenty, ne pětidílný řetězec.

Volbu expires stojí za to opsat. Pokud workery hodinu neběží, plán spouštěný každých pět minut nechá čekat dvanáct totožných zpráv sync_stock a po návratu workerů proběhnou všechny v nárazu. S expires se zastaralé zahodí nepřečtené.

Beat spusť jako samostatný proces:

bash
$ celery -A myproject beat --loglevel=INFO -s /tmp/celerybeat-schedule

-s určuje, kam beat ukládá celerybeat-schedule, malý soubor, který zaznamenává, kdy každá položka naposledy proběhla. Výchozí je zápis do pracovního adresáře. Beatu nevadí o něj při restartu přijít; potřebné si pak zjistí z hodin, což je u položek crontab správně a u intervalových položek to znamená „začni počítat znovu“. Úloha, která má proběhnout přesně jednou denně, má být položka crontab, ne interval 86400 sekund.

Narazíš na radu spouštět beat uvnitř workeru přes celery worker -B. Ušetří to jeden proces a pro jednoho workera na malém serveru je to v pořádku, ale je to důvod, proč lidé skončí se dvěma beaty v den, kdy přidají druhého workera. Použij to vědomě, s výslovně nastaveným --concurrency a počtem workerů pevně na jedné.

Pro plány, které mají personál upravovat bez nasazení, je tu django-celery-beat, který je ukládá do databáze a přidává stránky v administraci:

bash
$ pip install django-celery-beat$ celery -A myproject beat --scheduler django_celery_beat.schedulers:DatabaseScheduler

Přidej "django_celery_beat" do INSTALLED_APPS a spusť python manage.py migrate. Cenou je další sada tabulek a plán, který už nežije ve verzovacím systému. Pro hrstku pevných úloh nech slovník výše.

Paměť a souběžnost na malém tarifu#

Tady se rozhoduje, jestli Celery na malém serveru obstojí, nebo ho zabijí. Výchozí pool Celery, prefork, spustí jednoho rodiče a pak --concurrency podřízených procesů. Výchozí souběžnost je počet jader CPU, které proces vidí, což na sdíleném hostiteli mohou být jádra celého stroje, ne tvůj podíl. Nastav si ji sám.

Každý potomek importuje tvůj Django projekt, takže stojí zhruba tolik co jeden worker gunicornu: běžně 100-200 MB u skromného projektu, více s náročnými závislostmi. Jak to změřit, vysvětluje článek kolik RAM potřebuje aplikace v Pythonu. Rodič přidává podobné množství. Worker spuštěný s --concurrency 2 jsou proto tři procesy a s gunicornem vedle se projekt načítá pětkrát až šestkrát.

RAM tarifuRozloženíPoznámky
1 GBJen web, worker jindeSamotný jeden worker gunicornu má kolem 200 MB
2 GBgunicorn 1 + Celery -c 1Těsné; před spoléháním změř
4 GBgunicorn 2 + Celery -c 2Rozumné malé produkční rozložení
6-8 GBgunicorn 3 + Celery -c 3-4Za touto hranicí jsou úlohy vázané na databázi

To jsou výchozí body postavené na údajích o jednotlivých procesech výše, ne měření tvého kódu. Spusť workera pod zátěží a přečti si resident size každého procesu pomocí ps -o pid,rss,cmd -C celery, než se na rozložení zavážeš. Na RE:NODE konzole vykresluje paměť proti limitu tarifu, zatímco to děláš, a limit je vypínač: při dosažení limitu paměti kernel kontejner zastaví a ten se čistě restartuje, místo aby swapoval. Pro workera Celery to znamená smrt všech potomků najednou, a právě proto acks_late a reject_on_worker_lost výše nejsou volitelné.

Čtyři opatření drží workera v rozpočtu.

Vyber pool podle zátěže. Prefork je správná volba pro úlohy vázané na CPU nebo těžké na knihovny a dává skutečnou izolaci. U úloh, které většinou čekají na síťové volání, používá vláknový pool jednu kopii projektu pro mnoho souběžných úloh:

bash
$ celery -A myproject worker --pool=threads --concurrency=8 --loglevel=INFO

Vlákna sdílejí proces Djanga, takže úloha s únikem paměti uniká pro všechny a na tvůj vlastní kód platí obvyklá upozornění k thread safety. U zátěže typu e-maily a webhooky je úspora velká: osm souběžných úloh zhruba za paměť jedné. Existuje také --pool=solo, jedna úloha najednou v hlavním procesu, což je nejmenší možná stopa a rozumná volba na tarifu s 1 GB a občasnými úlohami.

Recykluj potomky. Procesy Pythonu paměť operačnímu systému vracejí jen zřídka, takže potomek, který jednou zpracoval velký export, zůstane velký. Hranici určují dvě nastavení:

settings/production.py
CELERY_WORKER_MAX_TASKS_PER_CHILD = 200CELERY_WORKER_MAX_MEMORY_PER_CHILD = 300_000   # kilobajty, asi 300 MB

Po dosažení kteréhokoli limitu potomek dokončí aktuální úlohu a nahradí ho nový. Limit paměti je v kilobajtech, což lidi překvapuje. Recyklace není oprava úniku paměti, ale změní únik z výpadku na poznámku v logu.

Omez zbytečné řeči. Na malém tarifu tři přepínače odstraní provoz a procesy, které při jediném workeru nepotřebuješ:

bash
$ celery -A myproject worker --concurrency=2 -Ofair \    --without-gossip --without-mingle --without-heartbeat

-Ofair způsobí, že rodič dává práci jen potomkům, kteří jsou volní, což má smysl u dlouhých úloh a prefetch nad 1. --without-gossip, --without-mingle a --without-heartbeat zastaví výměnu stavu clusteru s ostatními workery, což se hodí, když žádní další nejsou. Bez heartbeatu jsou příkazy celery status a inspect z jiných uzlů méně vypovídající, takže ho nech zapnutý, pokud provozuješ víc workerů a na ty příkazy spoléháš.

Rozděl fronty a pak je omez. Report, který trvá pět minut, a reset hesla, který trvá vteřinu, by neměly sdílet potomky. Rozveď je:

settings/production.py
CELERY_TASK_DEFAULT_QUEUE = "default"CELERY_TASK_ROUTES = {    "reports.tasks.*": {"queue": "slow"},}
bash
$ celery -A myproject worker -Q default --concurrency=2 -n fast@%h$ celery -A myproject worker -Q slow    --concurrency=1 -n slow@%h

Pomalá fronta dostane jednoho potomka, takže těžký export může využít nejvýš podíl jednoho jádra a paměť jednoho procesu a vše naléhavé dál plyne. Cenou je další rodičovský proces. Na velmi malém tarifu je levnější nechat jednu frontu a jednoho workera a smířit se s tím, že naléhavé úlohy čekají.

CPU je samostatný limit vedle paměti. Na RE:NODE je údaj o CPU tvrdé omezení na zakoupený podíl, takže worker s --concurrency 4 na půlce jádra neběží čtyři úlohy rychlostí čtyř jader; běží je pomalu, všechny najednou. Souběžnost nad podílem CPU pomáhá jen u úloh, které tráví čas čekáním na něco jiného.

Kde procesy běží#

Webový proces, worker a beat jsou tři dlouho běžící příkazy. Aplikační server na RE:NODE má jeden startovací příkaz, takže přímočaré rozložení jsou oddělené servery Pythonu ze stejného repozitáře, každý s vlastním startovacím příkazem, všechny nasměrované na stejný Valkey a databázi přes proměnné prostředí. Webový server spouští gunicorn, server workera spouští celery -A myproject worker a proces beat se přidá do příkazu workera nebo dostane vlastní malý server. To stojí víc než jediný tarif a odstraní to otázku, který proces dostane padáka, když dojde paměť.

Pokud chceš mít všechno v jednom serveru, funguje startovací příkaz shellu, který spustí workera na pozadí a gunicorn v popředí, ale měj jasno, čeho se vzdáváš: když worker umře, nic ho nerestartuje, zatímco gunicorn běží dál, a fronta přestane odtékat bez jakéhokoli viditelného selhání. Po každém nasazení se podívej do konzole a pro cokoli důležitého dej přednost odděleným serverům.

Tarify Valkey začínají na 256 MB za $2 měsíčně a tarify Pythonu na $4. K serveru Valkey se přistupuje na jeho vlastním hostiteli a portu s vygenerovaným heslem, takže se webové servery i servery workerů připojují stejně, ať běží kdekoli. Existuje také balíček tarifu Pythonu, tarifu PostgreSQL a tarifu Valkey s 256 MB, kupovaný společně se slevou na záložce Bundles v obchodě panelu, což je přesně tvar celého tohoto článku: webová aplikace, databáze a broker.

Nasazení přes Git se aplikuje na každý server zvlášť. Push do repozitáře restartuje každý server, který má zapnuté nasazení při pushi, takže workery dostanou nový kód při stejném pushi jako webový proces. Běžící worker Celery drží starý kód v paměti až do restartu, takže na tom záleží. Restart, který přijde uprostřed úlohy, je normální zastavení a acks_late znamená, že se přerušená úloha doručí znovu. Proč má signál k zastavení nechat úlohu dokončit, popisuje článek řádné ukončení a health checky.

Nastavení Valkey, které broker Celery potřebuje#

O tom, jestli zprávy přežijí, rozhodují tři nastavení na straně serveru. Fronty úloh s Valkey je probírá pro všechny knihovny; stručně pro Celery:

  • Vytěsňování. Zkontroluj maxmemory-policy na své instanci. Cokoli kromě noeviction může smazat seznam fronty celery nebo strukturu unacked, když se zaplní paměť. Politiky vysvětluje článek paměť Valkey a politiky vytěsňování.
  • Perzistence. Tarif Valkey na RE:NODE ukládá na disk pomocí AOF a snapshotů, takže zařazené úlohy restart přežijí. Co která varianta stojí, vysvětluje článek AOF a RDB.
  • Velikost. Zpráva má od několika stovek bajtů po několik kilobajtů. Instance s 256 MB pojme velmi velkou zásobu malých zpráv; zaplní se backendem výsledků, který nikdo nevyprší, nebo velkými argumenty.

To, co Celery vytvořilo, si prohlédni přes valkey-cli:

bash
$ valkey-cli -h HOST -p PORT --askpass> KEYS *> LLEN celery> HLEN unacked> INFO memory

LLEN celery je počet čekajících zpráv ve výchozí frontě a HLEN unacked je počet převzatých, ale dosud nepotvrzených. KEYS * je na malé instanci v pořádku a na velké špatný zvyk; tam použij SCAN. Připojení popisuje článek začínáme s Valkey.

Příkazem celery -A myproject inspect active uvidíš, co který worker právě provádí, celery -A myproject inspect stats ukáže údaje o poolu a paměti a celery -A myproject purge zahodí všechno, co čeká; ptá se na potvrzení a je to rozhodnutí, které je třeba udělat vědomě.

Řešení potíží#

Worker naběhne a pak nic nedělá. Adresa brokeru je špatně způsobem, který hned nehlásí chybu, nebo jsou úlohy v jiné frontě, než jakou worker poslouchá. Zkontroluj celery -A myproject inspect registered a pak LLEN na název fronty.

`Received unregistered task of type`. Worker neimportoval modul, který úlohu definuje. Zkontroluj autodiscover_tasks(), že aplikace je v INSTALLED_APPS a že se soubor jmenuje tasks.py.

`kombu.exceptions.OperationalError` nebo `Connection refused`. Hostitel, port nebo heslo je špatně, nebo webový proces nemá síťovou cestu k Valkey. Nejprve zkus stejnou URL přes valkey-cli ze stejného serveru.

Úloha proběhne dvakrát. Visibility timeout je kratší než úloha, nebo byl potomek zabit dřív, než potvrdil. Zvyš timeout, nastav acks_late s reject_on_worker_lost a udělej úlohu idempotentní.

Periodické úlohy proběhnou dvakrát ve stejný okamžik. Dva procesy beat. Zkontroluj, jestli neběží druhý server nebo -B na více než jednom workeru.

Periodické úlohy neběží nikdy. Beat neběží, nebo běží s jiným modulem nastavení, než je ten, který obsahuje CELERY_BEAT_SCHEDULE. Když funguje, beat loguje Sending due task pro každou z nich.

Server se restartuje každých pár hodin. Zabití kvůli paměti. Porovnej přes ps součet webových workerů, rodiče a potomků s tarifem a pak použij opatření výše. Týdenní naplánovaný restart ze záložky Schedules je hrubá, ale účinná pojistka; načasování popisuje článek restartovací plány, které pomáhají.

`DatabaseError: connection already closed` uvnitř úlohy. Dlouho žijící worker si ponechal připojení, které databáze zahodila. Zavolej na začátku dlouhých úloh django.db.close_old_connections() nebo drž CONN_MAX_AGE skromné v nastavení, které worker používá.

Úlohy se hromadí, zatímco workery zahálejí. Často je to násobitel prefetch v kombinaci s jednou velmi dlouhou úlohou. Nastav ho na 1 a použij -Ofair.

FAQ#

Potřebuji Celery pro projekt v Djangu?

Často ne. Management příkaz spouštěný podle plánu pokryje noční úklidy a souhrny bez brokeru a fronta v databázi pokryje skromné objemy. Celery se vyplatí, když jsou úlohy časté, potřebují opakování s backoffem a musí přežít restart. Možnosti srovnává článek úlohy na pozadí na malém serveru.

Může Celery používat Valkey jako broker i backend pro výsledky?

Ano. Použij stejný server s jiným číslem databáze, jako v nastavení výše, nebo nastav CELERY_TASK_IGNORE_RESULT = True a backend vynech. Alternativou specifickou pro Django je django-celery-results, které ukládá výsledky do tvé databáze přes CELERY_RESULT_BACKEND = "django-db".

Kolik workerů Celery mám provozovat?

Tolik potomků, aby fronta při špičce zůstávala blízko nule, a ne víc, než dovolí paměť. Pro úlohy vázané na síť je vláknový pool o 8 až 20 vláknech v jednom procesu levnější než osm potomků prefork. Pro úlohy vázané na CPU jeden potomek na každé jádro, které skutečně máš. Správná odpověď na malém tarifu je téměř vždy méně, než je výchozí hodnota.

Proč se počet klíčů ve Valkey pořád zvětšuje?

Uložené výsledky bez expirace, nebo záznamy v unacked, které se nikdy nevyčistí, protože se úlohy nikdy nepotvrdí. Nastav CELERY_RESULT_EXPIRES, ignoruj výsledky, které nečteš, a podívej se na HLEN unacked, když byl worker opakovaně zabíjen.

Je bezpečné spouštět beat na každém serveru?

Ne. Přesně jeden proces beat na plán, jinak se každá periodická úloha pošle jednou za každý beat. Dej ho na jeden server, nebo ho vlož přes -B do jediného workeru, který nikdy nerozšiřuješ.

Co se stane se zařazenými úlohami, když se Valkey restartuje?

Při zapnuté perzistenci se fronta znovu načte z disku a workery se znovu připojí, pokud je nastaveno CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP. Bez perzistence jsou všechny čekající úlohy pryč. Úlohy, které byly v unacked, se po uplynutí visibility timeoutu vrátí do fronty.

Pomohlo vám to?