SSD Nodes Learn Hosting plans →
मार्गदर्शक Matt Connorद्वारे Matt Connor

एका VPS वर NATS, RabbitMQ की Kafka?

एका सर्व्हरवरील queue निवडताना delivery guarantees, memory व disk खर्च, restart नंतरचे वर्तन, backlog तपासणी आणि कधी Postgres अधिक योग्य ठरते हे जाणून घ्या.

एका सर्व्हरसाठी थोडक्यात

एका VPS वरील message queue ही गतीबद्दलची नव्हे, तर delivery guarantees बद्दलची निवड आहे. एकाच box वर broker क्वचितच bottleneck ठरतो, कारण तुमचा application code, database आणि एकमेव disk यांच्यावरच आधी मर्यादा येतात. ज्या tool चे failure behaviour तुम्ही स्वीकारू शकता ते निवडा. त्यानंतर तुमच्याकडे प्रत्यक्षात असलेल्या box चे मोजमाप करा.

बहुतेक वाचकांनी विचारात घ्यावयाचे चार पर्याय पुढील क्रमाने आहेत.

  • तुम्ही आधीपासून चालवत असलेला database वापरा. SELECT ... FOR UPDATE SKIP LOCKED सह Postgres ही कार्यक्षम job queue आहे आणि monitor करण्यासाठी नवीन process जोडत नाही.
  • प्रत्येक message हा acknowledge करणे आवश्यक असलेला work unit असेल, त्यावर मर्यादित वेळा retry करायचा असेल आणि त्यानंतर मानवी तपासणीसाठी एखाद्या ठिकाणी ठेवायचा असेल, तर RabbitMQ वापरा.
  • तुमच्या system चे अनेक भाग ज्या messages वर प्रतिक्रिया देतात ते events असतील, तर NATS वापरा. Restart नंतर टिकून राहणे आवश्यक असलेल्या events साठी JetStream सुरू करा.
  • downstream tool फक्त Kafka protocol वापरत असेल, तर Kafka वापरा. एका server वर उरलेले जवळजवळ एकमेव कारण हेच आहे.

या मार्गदर्शकाच्या उर्वरित भागात त्यामागील कारणमीमांसा दिली आहे: लहान VPS वर प्रत्येक पर्यायासाठी memory आणि disk ची किती आवश्यकता असते, box reboot झाल्यावर तो कसा वागतो आणि users ना त्याचा परिणाम जाणवण्यापूर्वी backlog दाखवणारी अचूक command कोणती.

वितरणाची हमी प्रत्यक्षात काय दर्शवते

जास्तीत जास्त एकदा याचा अर्थ broker संदेश consumer कडे सोपवतो आणि तो विसरतो. कोणताही consumer जोडलेला नसेल किंवा काम अर्ध्यावर असताना consumer बंद पडला, तर संदेश नष्ट होतो आणि त्याची कोणतीही नोंद होत नाही.

किमान एकदा याचा अर्थ काम यशस्वी झाल्यानंतर consumer acknowledgement (ack) पाठवतो. तो ack मिळेपर्यंत broker संदेश जतन करतो आणि तो पुन्हा वितरित करतो. पुन्हा वितरणामुळे तुमचे handlers idempotent असणे आवश्यक आहे: एकाच संदेशावर दोनदा प्रक्रिया झाली, तरी कार्डवर दोनदा शुल्क आकारले जाऊ नये. सुरुवातीपासून शेवटपर्यंत तंतोतंत एकदाच प्रक्रिया होण्याची हमी broker देत नाही. ती तुमच्या स्वतःच्या database मधील unique key मुळे मिळते.

Replay हा स्वतंत्र गुणधर्म आहे. संदेश acknowledged झाल्यावर queue तो टाकून देते. log तो retention window पर्यंत जतन करतो. त्यामुळे नवीन consumer सुरुवातीपासून सुरू होऊन संपूर्ण इतिहास वाचू शकतो. Kafka आणि NATS JetStream हे logs आहेत. RabbitMQ ही queue आहे. या फरकामुळे throughput पेक्षा अधिक architectures प्रभावित होतात.

Dead lettering म्हणजे सतत अपयशी ठरणाऱ्या संदेशाचे काय होते ते. ही व्यवस्था नसल्यास poison message अंतहीनपणे पुन्हा process होत राहतो. हा loop बिघाड झाल्यासारखा न दिसता व्यस्त worker सारखा दिसतो.

Postgres पासून सुरुवात करा आणि broker ने स्वतःची उपयुक्तता सिद्ध करू द्या

बहुतेक single-application workloads मध्ये दररोज काही हजार background jobs असतात. हे प्रमाण एका table मध्ये सहज हाताळता येते.

CREATE TABLE job (
  id        bigserial   PRIMARY KEY,
  payload   jsonb       NOT NULL,
  run_after timestamptz NOT NULL DEFAULT now(),
  attempts  int         NOT NULL DEFAULT 0
);
CREATE INDEX job_ready_idx ON job (run_after, id);

एक worker transaction च्या आत एक job claim करतो.

BEGIN;
SELECT id, payload
  FROM job
 WHERE run_after <= now()
 ORDER BY id
   FOR UPDATE SKIP LOCKED
 LIMIT 1;
-- run the work, then remove the row
DELETE FROM job WHERE id = $1;
COMMIT;

FOR UPDATE SKIP LOCKED हाच संपूर्ण उपाय आहे. तो परत करत असलेल्या row वर lock लावतो आणि दुसऱ्या transaction ने आधीच lock केलेल्या row वगळतो. त्यामुळे दोन workers एकाच job ला claim करत नाहीत. एखादा worker crash झाल्यास Postgres त्याचा transaction abort करतो, lock release होतो आणि ती row पुढील worker ला दिसू लागते. तुम्हाला at-least-once delivery, attempts ची value वाढवून retries आणि dead letter table मिळतात. यासाठी तुम्ही आधीच भरत असलेल्या durability चाच वापर होतो. Backlog तपासण्यासाठी एकच query पुरेशी आहे: SELECT count(*) FROM job WHERE run_after <= now();

हे कुठे अयशस्वी होऊ लागते. प्रत्येक claim आणि delete ही write operation आहे. त्यामुळे job rate जास्त असल्यास मागे dead row versions साचतात आणि queue table मध्ये bloat autovacuum पेक्षा वेगाने वाढणे ही नेहमीची समस्या ठरते. Jobs दीर्घकाळ चालत असल्यास समस्या वाढते. कारण काम पूर्ण होईपर्यंत उघडा ठेवलेला transaction संपूर्ण database साठी vacuum horizon पुढे जाण्यापासून रोखतो. Polling मुळे latency वाढते. LISTEN आणि NOTIFY वापरल्यास polling दूर होते, पण writes दूर होत नाहीत. तुमच्याकडील सर्वांत व्यस्त table job table झाली असेल किंवा दुसऱ्या service ला त्याच events ची गरज असेल, तर काम database च्या बाहेर हलवा. हा निर्णय database स्वतः कसा deploy केला आहे याच्याशी संबंधित आहे. त्यामुळे broker शेजारी जोडण्यापूर्वी database Docker मध्ये चालतो की host वर हे निश्चित करा.

Redis ही दुसरी गोष्ट आहे जी तुम्ही आधीपासून चालवत असू शकता. Redis Streams मध्ये XADD आणि XREADGROUP सह consumer groups, प्रत्येक group साठी pending list आणि मृत झालेल्या consumer कडून काम परत घेण्यासाठी XAUTOCLAIM उपलब्ध असते. ते लहान आणि जलद आहे. मात्र एका server वरची महत्त्वाची मर्यादा स्पष्टपणे समजून घ्या: सामान्य appendfsync everysec setting वापरल्यास power loss मुळे सुमारे एक सेकंदाच्या writes गमावल्या जाऊ शकतात. Cache invalidation साठी हे स्वीकार्य आहे, पण payments साठी अयोग्य आहे. तुमचे application production मध्ये VPS वर SQLite भोवती तयार केलेला single process असल्यास हाच claim-and-delete pattern कार्य करतो. मात्र SQLite मध्ये SKIP LOCKED चा समतुल्य पर्याय नाही आणि प्रत्येक worker एकाच write lock वर serialise होतो.

NATS core: स्मरणशक्तीशिवाय subject routing

docker run -d --name nats \
  -p 4222:4222 -p 127.0.0.1:8222:8222 \
  nats:2.15 -m 8222

October 2026 पर्यंत सध्याची server line 2.15 आहे. -m 8222 मुळे HTTP monitoring port सुरू होतो. हा port default ने बंद असतो आणि त्यावर authentication नसते. त्यामुळे वर दिल्याप्रमाणे तो localhost ला bind करा.

Core NATS मध्ये संदेश जास्तीत जास्त एकदाच वितरित केला जातो आणि कोणतीही माहिती साठवली जात नाही. Publisher orders.created सारख्या subject वर संदेश पाठवतो आणि ज्यांचा filter जुळतो अशा प्रत्येक subscriber ला त्याची एक प्रत मिळते. कोणताही subscriber नसल्यास संदेश टाकून दिला जातो आणि publisher ला कोणतीही error दिसत नाही, कारण server ने bytes स्वीकारताच publisher चे काम पूर्ण झालेले असते. Queue group मध्ये अनेक subscribers एकच group name वापरतात. अशा वेळी server प्रत्येक संदेशासाठी एक member निवडतो. संदेश साठवण्यासाठी queue न ठेवता काम वाटले जाते.

संसाधन वापरामध्ये subscription state आणि प्रत्येक connection साठी write buffer यांचा समावेश होतो. त्यामुळे तो message volume ऐवजी connection count नुसार वाढतो आणि disk वर काहीही साचत नाही. Restart नंतरचे वर्तन यावरून स्पष्ट होते: in-flight messages नष्ट होतात, clients स्वतःहून पुन्हा connect होतात आणि recovery साठी प्रतीक्षा करण्याची कोणतीही पायरी नसते.

पाहण्यासाठी backlog नसल्यामुळे loss वर लक्ष ठेवा. Server एखाद्या client च्या socket वर ज्या वेगाने write करतो त्यापेक्षा client ज्या वेगाने read करतो तो वेग कमी असल्यास त्या client साठीचा server buffer भरतो. Write deadline संपेपर्यंत client ने मागे राहिलेला डेटा वाचून पूर्ण केला नाही, तर server संपूर्ण connection बंद करतो आणि एक counter वाढवतो.

curl -s http://localhost:8222/varz | jq '.slow_consumers, .connections, .in_msgs, .out_msgs'

सतत वाढणारे slow_consumers value संदेश टाकून दिले जात असल्याचे दर्शवते. त्यामुळे ते एकदाच वाचण्याऐवजी त्यावर alert द्या. ज्याचे मूल्य लवकर कालबाह्य होते अशा संदेशासाठी Core NATS योग्य आहे: metric, presence update किंवा cache invalidation, ज्यावर पुढील event चा परिणाम होणार असतो.

NATS JetStream: त्याच process मधील durable streams आणि replay

JetStream हे दुसरे product नाही. ते त्याच binary मधील subsystem आहे आणि एकाच flag ने enable करता येते.

docker run -d --name nats \
  -p 4222:4222 -p 127.0.0.1:8222:8222 \
  -v nats-data:/data \
  nats:2.15 -js -sd /data -m 8222

-sd /data store directory सेट करते. ते वगळल्यास JetStream आपला data /tmp अंतर्गत साठवते. तेवढीच durability त्याला मिळते, जितकी त्या नावावरून अपेक्षित आहे. CLI वापरून stream तयार करा. हा CLI nats-box image मध्ये उपलब्ध असतो.

docker run --rm -it --network host natsio/nats-box:latest \
  nats stream add ORDERS \
    --subjects 'orders.>' \
    --storage file \
    --retention limits \
    --max-age 72h \
    --max-bytes=1073741824 \
    --discard old \
    --defaults

छोट्या server वर येथे दिलेली प्रत्येक limit उपयुक्त आहे. Crash नंतर टिकून राहणारा data --storage file मुळे मिळतो, कारण memory stream टिकत नाही. --max-bytes=1073741824 stream ची कमाल मर्यादा byte count म्हणून 1 GiB ठेवते. मर्यादा गाठल्यावर नवीन writes नाकारण्याऐवजी --discard old सर्वांत जुने messages काढून टाकते. ही मर्यादा न ठेवल्यास एखादा नियंत्रणाबाहेर गेलेला publisher disk भरू शकतो. त्या वेळी database देखील थांबतो, कारण दोन्ही एकाच disk चा वापर करतात.

durable consumer stream मधील आपली स्वतंत्र position ठेवतो आणि restart नंतरही ती जपतो. सतत fail होणारा message कायम redeliver होऊ नये यासाठी consumer वर --max-deliver सेट करा. एखाद्या message साठी deliveries ची मर्यादा संपल्यावर JetStream $JS.EVENT.ADVISORY.CONSUMER.MAX_DELIVERIES.> वर advisory publish करते. त्या subject ला subscribe करून dead letter path तयार करता येतो. RabbitMQ हे feature म्हणून देते; येथे ते काम तुम्हालाच लिहावे लागते.

Backlog पाहण्यासाठी stored message counts साठी nats stream report चालवा. प्रत्येक consumer साठी outstanding acknowledgements आणि unprocessed messages पाहण्यासाठी nats consumer report ORDERS चालवा. Alarm साठी unprocessed संख्या वापरा. Store directory चा disk वापर du -sh ने पाहता येतो. Retention limit लागू होऊन data कमी होईपर्यंत हा वापर वाढत राहतो.

RabbitMQ: प्रत्येक संदेश acknowledge करा, अपयशी संदेश वेगळे ठेवा

docker run -d --name rabbitmq \
  -p 5672:5672 -p 127.0.0.1:15672:15672 \
  -v rabbitmq-data:/var/lib/rabbitmq \
  rabbitmq:4-management

October 2026 पर्यंत सध्याची series 4.3 आहे. Port 5672 हा AMQP (advanced message queuing protocol) साठी आहे आणि 15672 हा management interface साठी आहे. Interface localhost वरच ठेवा आणि SSH tunnel द्वारे त्याचा वापर करा.

Queues घोषित करताना x-queue-type argument चे मूल्य quorum ठेवा; default अजूनही classic आहे. Quorum queues नेहमी durable असतात आणि इतर कोणतीही प्रक्रिया करण्यापूर्वी data disk वर लिहितात. त्यामुळे एका node वर durable आणि transient पर्यायांच्या अनेक संयोजनांऐवजी एकच स्पष्ट वर्तन मिळते. Dead letter target policy द्वारे सेट करा.

docker exec rabbitmq rabbitmqctl set_policy DLX ".*" \
  '{"dead-letter-exchange":"my-dlx", "dead-letter-routing-key":"my-routing-key"}' \
  --apply-to queues --priority 7

एखादा message dead letter होण्याची चार कारणे आहेत: consumer तो basic.reject किंवा basic.nack सह reject करतो आणि requeue चे मूल्य false असते; त्या message चा per-message TTL (time to live) संपतो; queue ची length limit ओलांडली जाते; किंवा quorum queue ची delivery limit ओलांडली जाते. RabbitMQ 4.0 पासून ही limit default म्हणून 20 आहे. त्यामुळे handler ने exception टाकून nack दिल्यास message वीस वेळा retry होतो आणि नंतर loop होण्याऐवजी dead letter exchange कडे पाठवला जातो.

लहान VPS वर RabbitMQ च्या memory वापरामुळे अनेकदा अनपेक्षित समस्या येतात. उपलब्ध RAM पैकी 0.6 हा default high watermark आहे. Node ने ही मर्यादा ओलांडल्यावर publishing करणारे प्रत्येक connection RabbitMQ block करते. तुमच्या application ला error मिळत नाही. त्याऐवजी publish call पूर्णच होत नाही आणि तुमच्या code मध्ये तो hang झाल्यासारखा दिसतो. Startup log मध्ये node ने मोजलेली संख्या दिसते:

Memory high watermark set to 1024 MiB (1073741824 bytes) of 8192 MiB (8589934592 bytes) total

Free space default 50 MB पेक्षा कमी झाल्यावर disk alarm देखील publishers ला याच प्रकारे block करते. Quorum queues यावर स्वतःची अतिरिक्त गणना लागू करतात: documentation नुसार प्रत्येक message साठी memory मधील metadata साठी किमान 32 bytes, म्हणजे सुमारे 30,000 messages साठी 1 MB, आणि effective write-ahead log size च्या किमान तीनपट RAM आवश्यक आहे. WAL limit चे default मूल्य 512 MiB आहे. त्यामुळे केवळ या शिफारसीसाठी 1.5 GB RAM लागते. 2 GB server वर default पुरेसा असेल अशी अपेक्षा ठेवण्याऐवजी rabbitmq.conf मध्ये ही limit कमी करा.

raft.wal_max_size_bytes = 64000000
vm_memory_high_watermark.relative = 0.5

Backlog दोन संख्यांनी दर्शवला जातो. या दोन्ही संख्या एकत्र पाहिल्यास कोणती समस्या आहे हे समजते.

docker exec rabbitmq rabbitmqctl list_queues name messages messages_ready messages_unacknowledged

messages_ready consumer ची वाट पाहत आहे. messages_unacknowledged deliver झाला आहे, पण त्याला ack मिळालेला नाही. Ready count स्थिर असताना unacknowledged count वाढत असेल, तर तुमच्या workers ने jobs स्वीकारल्या आहेत पण त्या पूर्ण करणे थांबवले आहे. हे केवळ मागे पडलेल्या queue पेक्षा वेगळे bug आहे.

एका बॉक्सवर Kafka, आणि ते वापरणे कुठे अर्थपूर्ण राहत नाही

KAFKA_CLUSTER_ID="$(bin/kafka-storage.sh random-uuid)"
bin/kafka-storage.sh format --standalone -t $KAFKA_CLUSTER_ID -c config/server.properties
bin/kafka-server-start.sh config/server.properties

ऑक्टोबर 2026 पर्यंत अद्ययावत असलेला Kafka 4.3.1 चा हा quickstart आहे. तो KRaft mode मध्ये चालतो. KRaft म्हणजे Kafka Raft; Kafka 4.0 मध्ये ZooKeeper ची जागा घेणारा अंगभूत controller. Container मधील समतुल्य पर्याय apache/kafka:4.3.1 आहे.

तुम्ही स्वतः export KAFKA_HEAP_OPTS="-Xmx1G -Xms1G" सेट केलेले नसल्यास start script ते सेट करते. त्यामुळे एकही message साठवण्यापूर्वी broker 1 GB Java heap राखून ठेवतो. तसेच तो ज्या page cache मधून वाचतो, त्यासाठी यापेक्षा अधिक मोकळी RAM अपेक्षित असते. 2 GB VPS वर उरलेल्या RAM साठी तुमचा application आणि JVM स्पर्धा करतात.

Retention हा पुढील अनपेक्षित मुद्दा आहे. log.retention.hours चे default मूल्य 168 आहे, म्हणजे सात दिवस. log.retention.bytes चे default मूल्य -1 आहे, म्हणजे आकारावर कोणतीही मर्यादा नाही. प्रत्येक consumer ने message वाचले आहेत किंवा नाहीत, याची पर्वा न करता Kafka संपूर्ण retention window दरम्यान ते message ठेवतो. Kafka वापरण्याचे हेच कारण आहे. पण एका लहान disk वर हेच failure mode ठरू शकते. त्यामुळे ते लक्षात येण्यापूर्वी प्रत्येक topic साठी byte limit सेट करा.

आता व्यवहार्य मुद्दा. Single broker असल्याने replication factor 1 असतो. त्यामुळे acks=all एका disk वर एका fsync पर्यंत मर्यादित राहते. तुम्हाला एका machine ची durability मिळते आणि त्यासोबत JVM broker आणि controller चालवण्याचा operating cost येतो. तुमच्याकडे नसलेल्या अनेक brokers मध्ये partitions मुळे parallelism मिळतो. Replication, rack awareness आणि fleet साठीची इतर वैशिष्ट्ये निष्क्रिय राहतात. त्याच box वर JetStream कमी memory वापरून तितकाच durable replay देते. तरीही येथे Kafka निवडण्याची दोन कारणे आहेत: एखादे downstream tool फक्त Kafka protocol वापरते, जसे Debezium सह change data capture किंवा analytics loader; किंवा production topology ची लहान आवृत्ती पुन्हा तयार करायची आहे. भविष्यात cluster वाढवण्याचे नियोजन म्हणजे अधिक machines खरेदी करण्याचे नियोजन. तोपर्यंत हा trade-off single node वर k3s चालवण्यासारखाच असतो: एका node ची reliability मिळवण्यासाठी cluster complexity स्वीकारावी लागते.

Kafka मधील backlog ला consumer lag म्हणतात.

bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group my-group

LAG column वाचा. प्रत्येक partition साठी ते LOG-END-OFFSET मधून CURRENT-OFFSET वजा केल्यावर मिळते. इतर partitions स्थिर असताना एका partition मधील lag वाढत असेल, तर key चे वितरण असमान असण्याची शक्यता आहे. समान key असलेले सर्व messages त्याच partition मध्ये जातात आणि ते एकटाच consumer हाताळतो.

रीबूट झाल्यावर काय होते

Core NATS मधील उड्डाणावस्थेतील सर्व माहिती नष्ट होते आणि सेवा त्वरित पुन्हा सुरू होते, कारण पुनर्प्राप्त करण्यासाठी काहीही नसते. JetStream streams आणि consumer positions store directory मधून पुन्हा लोड करते. त्यामुळे consumers ज्या offset वर होते तिथून पुढे सुरू होतात. RabbitMQ quorum queues डिस्कवरून पुनर्प्राप्त करते. मात्र classic transient queues आणि persistent delivery mode शिवाय प्रकाशित केलेला कोणताही message नष्ट होतो. Kafka startup वेळी त्याचे log segments पुन्हा वाचते. अस्वच्छ shutdown नंतर broker connection स्वीकारण्यापूर्वी ही recovery scan लहान डिस्कवर काही मिनिटे चालू शकते.

दोन गोष्टी एकदाच निश्चित करणे उपयुक्त ठरते. Container ला restart policy (restart: unless-stopped) द्या किंवा systemd unit enable करा. त्यामुळे kernel upgrade नंतर reboot झाल्यावर broker तुमच्या हस्तक्षेपाशिवाय पुन्हा सुरू होईल. त्यानंतर startup order हाताळा. तुमच्या application पेक्षा broker वीस सेकंद उशिरा ready झाल्यास तो पहिल्या connections नाकारेल. काही client libraries retry करण्याऐवजी बंद होतात. broker ready होईपर्यंत dependent service ला थांबवणारे Compose healthchecks वापरून application ला broker वर अवलंबून ठेवा.

तुमच्या VPS वरील खर्च, उद्धृत आकड्यांऐवजी प्रत्यक्ष मोजलेला

प्रकाशित throughput चे आकडे तुमच्याकडे नसलेल्या hardware वर मोजलेले असतात. साधारणपणे हे local NVMe असलेले multi-core server असते. त्यामुळे त्यांना कमाल मर्यादा समजा आणि तुमच्या box वर मोजमाप करा.

docker stats --no-stream
free -m
sudo du -sh /var/lib/docker/volumes/*/_data

ही मोजमापे broker idle असताना चालवा. त्यानंतर तुमच्या प्रत्यक्ष traffic अंतर्गत पुन्हा चालवा. या दोन मोजमापांमधील फरकावरून broker तुमच्या application सोबत चालू शकतो की नाही हे ठरते. अंदाजे throughput floor साठी कोणाच्यातरी blog post ऐवजी प्रत्येक project चा स्वतःचा load generator वापरा: NATS साठी nats bench pub test --msgs 100000 --clients 2, Kafka साठी bin/kafka-producer-perf-test.sh आणि RabbitMQ साठी PerfTest. त्याच VPS वर generator चालवल्यास broker आणि generator या दोघांचे एकत्रित मोजमाप होते. अहवालात हा आकडा सांगताना ते स्पष्ट केले, तर ही पद्धत योग्य आहे.

या सर्वांसाठी एकच कमाल मर्यादा लागू होते. येथे प्रत्येक durable option fsync पूर्ण होण्याची प्रतीक्षा करते. त्यामुळे network-attached storage असलेल्या VPS मध्ये disk ही मर्यादा ठरवते. Broker बदलल्याने ही मर्यादा बदलणार नाही.

तीन workload आणि प्रत्येकाला आवश्यक असलेली message queue

  1. एका web application साठी background jobs, जसे की email पाठवणे, images चा आकार बदलणे किंवा webhooks वितरित करणे. सुरुवात Postgres आणि SKIP LOCKED ने करा. प्रत्येक message साठी ack, delivery limit आणि dead letter queue हवी असेल, तसेच हे logic स्वतः लिहिल्याशिवाय dead letter queue तपासता यावी असे वाटत असेल, किंवा database मधील job table सर्वाधिक व्यस्त table झाली असेल, तर quorum queues असलेल्या RabbitMQ कडे जा.
  2. अनेक internal services ज्या events वर प्रतिक्रिया देतात आणि हरवलेला message लवकरच नवीन message ने बदलला जातो, अशा परिस्थितीसाठी Core NATS वापरा. Routing scheme म्हणून subjects वापरा आणि कामाचे वाटप आवश्यक असेल तेथे queue groups वापरा. रीबूटनंतर टिकून राहणे आवश्यक असलेल्या मर्यादित subjects संचासाठी JetStream stream जोडा आणि उर्वरित messages memory मध्ये ठेवा.
  3. Consumers सुरुवातीपासून वाचतात असा event log, audit trail साठी, read model पुन्हा तयार करण्यासाठी किंवा नंतर analytics ला data पुरवण्यासाठी. File storage आणि स्पष्ट byte cap असलेले JetStream वापरा. Downstream tool ला Kafka protocol आवश्यक असेल तेव्हाच Kafka निवडा आणि या compatibility ची किंमत म्हणून JVM heap स्वीकारा.

Single server वर चुकीची निवड केल्याची किंमत throughput नसते. पहाटे 3 वाजता recovery करताना messages अजून उपलब्ध आहेत का, हे तपासण्याची वेळ आली की खरी अडचण समजते. त्यामुळे त्यानुसार निवड करा.

FAQ

मी 2 GB VPS वर Kafka चालवू शकतो का?

ते सुरू होईल, पण उपलब्ध संसाधने अत्यंत मर्यादित राहतील. तुम्ही bin/kafka-server-start.sh बदलले नसल्यास ते KAFKA_HEAP_OPTS="-Xmx1G -Xms1G" सेट करते. त्यामुळे कोणताही संदेश साठवण्यापूर्वीच JVM 1 GB मेमरी घेते. याशिवाय Kafka ला page cache साठी मोकळी मेमरी आवश्यक असते. त्याच सर्व्हरवर तुमचे अॅप्लिकेशन आणि database चालू केल्यास प्रणाली swap वापरू लागेल. तुम्हाला replication factor 1 देखील मिळतो. याचा अर्थ acks=all एका disk वर एक fsync इतकेच असते. त्यामुळे Kafka चा operating cost येतो, पण त्याचे durability model मिळत नाही. त्याच hardware वर NATS JetStream खूप कमी मेमरीमध्ये durable replay देते.

मी आधीच Postgres चालवत असल्यास message queue आवश्यक आहे का?

बहुतेक वेळा नाही. Transaction मध्ये SELECT ... FOR UPDATE SKIP LOCKED सह job table वाचल्यास at-least-once delivery, सुरक्षित concurrent workers, retries आणि dead letter table मिळतात. यासाठी monitor करण्यासाठी अतिरिक्त सेवा आवश्यक नसते आणि तुम्ही आधीच घेत असलेले backups वापरता येतात. वेगळ्या queue कडे जाण्याची कारणे विशिष्ट असतात: queue table वरील write load सर्वाधिक होतो आणि autovacuum मागे पडते, दीर्घकाळ चालणारी jobs transactions उघडी ठेवतात आणि संपूर्ण database साठी vacuum अडवतात, किंवा दुसऱ्या सेवेला त्याच events स्वतंत्रपणे consume करण्याची आवश्यकता असते.

Background jobs साठी NATS JetStream वापरावे की RabbitMQ?

प्रत्येक message साठी acknowledgement, delivery limit आणि dead letter routing अंगभूत स्वरूपात हवे असल्यास RabbitMQ वापरा. Quorum queues नेहमी durable असतात. RabbitMQ 4.0 पासून delivery limit चे default मूल्य 20 आहे. Policy मुळे मर्यादा संपलेल्या messages ना dead letter exchange कडे पाठवता येते; तेथून तुम्ही ते drain आणि inspect करू शकता. त्याच events चे replay नंतर इतर consumers ना आवश्यक असल्यास JetStream वापरा. Stream मध्ये acknowledgement नंतरही messages राहतात, तर queue मध्ये ते राहत नाहीत. JetStream मध्ये तुम्ही --max-deliver सेट करता आणि $JS.EVENT.ADVISORY.CONSUMER.MAX_DELIVERIES.> advisory वरून dead letter path स्वतः तयार करता.

माझे consumers किती मागे आहेत हे कसे समजेल?

प्रत्येक broker साठी यासाठी एक command आहे. RabbitMQ मध्ये rabbitmqctl list_queues name messages messages_ready messages_unacknowledged consumer ची वाट पाहणारे work आणि deliver झालेले पण ack न झालेले work वेगळे दाखवते. JetStream मध्ये nats consumer report <stream> प्रत्येक consumer साठी unprocessed messages आणि outstanding acknowledgements दाखवते. Kafka मध्ये kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group <group> प्रत्येक partition साठी LAG column दाखवते. Core NATS मध्ये read करण्यासाठी backlog नसतो, कारण ते काहीही store करत नाही. त्यामुळे त्याऐवजी http://localhost:8222/varz वरील slow_consumers counter monitor करा. Consumer मागे पडल्यामुळे server ने बंद केलेल्या connections ची संख्या हा counter दाखवतो. याचा अर्थ message loss आहे.

हा लेख उपयुक्त होता का?

#nats#rabbitmq#kafka#message-queue#architecture