SSD Nodes Learn 🎉 VPS $5.50/மாதம் முதல்
கல்வி வழிகாட்டிகள் Matt Connorஆல் Matt Connor · புதுப்பிக்கப்பட்டது 2026-08-16

ஒரே VPS-ல் NATS, RabbitMQ அல்லது Kafka: எது சிறந்தது?

ஒரே சர்வரில் message queue பயன்படுத்தும்போது கவனிக்க வேண்டிய delivery guarantees, memory பயன்பாடு மற்றும் restart சிக்கல்கள் குறித்து அறியுங்கள். Postgres எப்போது சிறந்த தேர்வாகும்?

ஒரே server-க்கான சுருக்கமான பதில்

ஒரே VPS-ல் message queue-ஐப் பயன்படுத்துவது என்பது வேகத்தைப் பற்றியது அல்ல, அது delivery guarantees பற்றிய முடிவாகும். ஒரே கணினியில் broker பெரும்பாலும் ஒரு தடையாக இருப்பதில்லை, ஏனெனில் உங்கள் application code, database மற்றும் disk ஆகியவையே முதலில் தடையாக மாறும். எந்தக் கருவியின் தோல்விச் செயல்பாட்டை (failure behaviour) நீங்கள் ஏற்றுக்கொள்ள முடியுமோ அதைத் தேர்வு செய்யுங்கள், பின்னர் உங்களிடம் உள்ள கணினியின் செயல்திறனை அளவிடுங்கள்.

வாசகர்கள் கவனிக்க வேண்டிய வரிசையில் நான்கு விருப்பங்கள் கீழே கொடுக்கப்பட்டுள்ளன:

  • ஏற்கனவே நீங்கள் பயன்படுத்தும் database-ஐப் பயன்படுத்துங்கள். Postgres மற்றும் SELECT ... FOR UPDATE SKIP LOCKED ஒரு சிறந்த job queue-ஆகச் செயல்படும், மேலும் இதற்காகக் கண்காணிக்க வேண்டிய புதிய process எதுவும் தேவைப்படாது.
  • ஒவ்வொரு message-ம் ஒரு குறிப்பிட்ட வேலை (unit of work) என்றும், அதை உறுதிப்படுத்த வேண்டும் (acknowledged), குறிப்பிட்ட எண்ணிக்கையிலான முறை மீண்டும் முயற்சி செய்ய வேண்டும் (retried), பின்னர் மனிதர்கள் சரிபார்க்கும் வகையில் எங்காவது சேமிக்க வேண்டும் என்றும் இருந்தால் RabbitMQ-ஐப் பயன்படுத்துங்கள்.
  • messages என்பவை உங்கள் system-ன் பல பகுதிகள் எதிர்வினையாற்றும் நிகழ்வுகள் (events) என்றால் NATS-ஐப் பயன்படுத்துங்கள். மறுதொடக்கத்திற்குப் பிறகும் (restart) நிலைத்திருக்க வேண்டிய நிகழ்வுகளுக்கு JetStream-ஐ இயக்கவும்.
  • downstream கருவி Kafka protocol-ஐ மட்டுமே ஆதரித்தால் Kafka-வைப் பயன்படுத்துங்கள். ஒரே server-ல் இதைப் பயன்படுத்துவதற்கு இதுவே பெரும்பாலும் ஒரே காரணமாக இருக்கும்.

இந்த வழிகாட்டியின் மீதமுள்ள பகுதி இதற்கான காரணங்களை விளக்குகிறது: ஒரு சிறிய VPS-ல் ஒவ்வொரு விருப்பத்திற்கும் எவ்வளவு memory மற்றும் disk தேவைப்படும், கணினி reboot ஆகும்போது அது எவ்வாறு செயல்படும், மற்றும் பயனர்களுக்குத் தெரிவதற்கு முன்பே backlog-ஐக் கண்டறிய உதவும் துல்லியமான கட்டளைகள் என்னென்ன என்பதை இது விவரிக்கிறது.

டெலிவரி உத்தரவாதம் (delivery guarantee) என்பதன் உண்மையான பொருள்

At most once என்பது, broker செய்தியை அனுப்பிவிட்டு அதை மறந்துவிடும் என்பதைக் குறிக்கும். நுகர்வோர் (consumer) யாரும் இணைக்கப்படவில்லை என்றாலோ அல்லது வேலை முடியும் முன்பே நுகர்வோர் செயலிழந்துவிட்டாலோ, அந்தச் செய்தி தொலைந்துவிடும்; இதைப் பற்றி எந்தத் தகவலும் கிடைக்காது.

At least once என்பது, வேலை வெற்றிகரமாக முடிந்த பிறகு நுகர்வோர் ஒரு acknowledgement (ack) அனுப்புவதைக் குறிக்கும். அந்த ack வரும் வரை, broker அந்தச் செய்தியைத் தன்வசம் வைத்திருக்கும்; மீண்டும் அனுப்பும். மீண்டும் மீண்டும் செய்தி வருவதால், உங்கள் handlers idempotent-ஆக இருக்க வேண்டும்: ஒரே செய்தியை இரண்டு முறை செயலாக்கினாலும், அது கார்டில் இரண்டு முறை கட்டணத்தை வசூலிக்கக்கூடாது. Exactly once என்பது broker வழங்கும் வசதி அல்ல; இது உங்கள் database-ல் உள்ள தனித்துவமான key (unique key) மூலம் மட்டுமே சாத்தியமாகும்.

Replay என்பது ஒரு தனிப்பட்ட பண்பு. ஒரு queue-ல் செய்தி acknowledged ஆனவுடன் அது நீக்கப்படும். ஆனால், ஒரு log அந்தச் செய்தியை ஒரு குறிப்பிட்ட காலத்திற்கு (retention window) வைத்திருக்கும்; எனவே, ஒரு புதிய நுகர்வோர் தொடக்கத்திலிருந்தே முழு வரலாற்றையும் படிக்க முடியும். Kafka மற்றும் NATS JetStream ஆகியவை logs ஆகும். RabbitMQ என்பது ஒரு queue ஆகும். இந்த வேறுபாடே throughput-ஐ விட அதிகப்படியான கட்டமைப்புகளைத் தீர்மானிக்கிறது.

Dead lettering என்பது தொடர்ந்து தோல்வியடையும் செய்திகளுக்கு நடக்கும் செயலாகும். இது இல்லையென்றால், ஒரு poison message முடிவில்லாமல் சுழன்று கொண்டே இருக்கும்; இந்தச் சுழற்சி, ஒரு worker பழுதடைந்திருப்பதை விட, அது பிஸியாக இருப்பது போன்ற தோற்றத்தையே கொடுக்கும்.

Postgres-உடன் தொடங்கி, broker-ன் திறனை உறுதிப்படுத்துதல்

பெரும்பாலான ஒற்றை-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-களைத் தவிர்த்துவிடுகிறது. இதனால் இரண்டு worker-கள் ஒரே job-ஐ ஒருபோதும் கோர முடியாது. ஒரு worker செயலிழந்தால் (crash), Postgres அதன் transaction-ஐ abort செய்யும், lock விடுவிக்கப்படும், அந்த row அடுத்த worker-க்குத் தெரியும். இதன் மூலம் at-least-once delivery கிடைக்கிறது, attempts-ஐ அதிகரிப்பதன் மூலம் retries செய்ய முடியும், மேலும் dead letter table-ஐயும் பராமரிக்கலாம். இவை அனைத்தும் நீங்கள் ஏற்கனவே பணம் செலுத்தும் durability-ல் கிடைக்கின்றன. backlog-ஐக் கண்டறிய இந்த ஒரே query போதும்: SELECT count(*) FROM job WHERE run_after <= now();

இது எங்கு வேலை செய்யாது என்பது முக்கியம். ஒவ்வொரு claim மற்றும் delete-ம் ஒரு write என்பதால், அதிகப்படியான job rate இருக்கும்போது dead row versions தேங்கிவிடும். queue table என்பது autovacuum-ஐ விட bloat வேகமாக வளரும் ஒரு பொதுவான சூழலாகும். நீண்ட நேரம் எடுக்கும் jobs நிலைமையை மோசமாக்கும், ஏனெனில் வேலையின் கால அளவு வரை திறந்திருக்கும் transaction, முழு database-ன் vacuum horizon-ஐயும் தடுத்து நிறுத்தும். Polling தாமதத்தை (latency) உருவாக்குகிறது, LISTEN மற்றும் NOTIFY மூலம் polling-ஐ நீக்கலாம், ஆனால் write-களைக் குறைக்க முடியாது. job table உங்கள் database-ல் மிகவும் பரபரப்பான table-ஆக மாறினாலோ அல்லது இரண்டாவது service-க்கு அதே events தேவைப்பட்டாலோ, இந்த வேலையை வெளியே மாற்ற வேண்டும். அந்தத் தேர்வு database எவ்வாறு deploy செய்யப்பட்டுள்ளது என்பதைப் பொறுத்தது, எனவே database Docker-ல் இயங்குகிறதா அல்லது host-ல் இயங்குகிறதா என்பதை முடிவு செய்த பிறகு, அதனுடன் ஒரு broker-ஐச் சேர்க்கவும்.

Redis என்பது நீங்கள் ஏற்கனவே பயன்படுத்தக்கூடிய மற்றொரு கருவி. Redis Streams உங்களுக்கு XADD மற்றும் XREADGROUP கொண்ட consumer groups-ஐ வழங்குகிறது. இதில் ஒவ்வொரு group-க்கும் ஒரு pending list உள்ளது, மேலும் செயலிழந்த consumer-விடமிருந்து பணியைத் திரும்பப் பெற XAUTOCLAIM உள்ளது. இது சிறியது மற்றும் வேகமானது. ஒரே server-ல் இதைப் பயன்படுத்தும்போது கவனிக்க வேண்டிய உண்மை: பொதுவான appendfsync everysec அமைப்பில், மின்சாரம் துண்டிக்கப்பட்டால் சுமார் ஒரு வினாடி வரையிலான write-கள் இழக்கப்படலாம். cache invalidation-க்கு இது சரி, ஆனால் payments-க்கு இது தவறு. உங்கள் application SQLite in production on a VPS அடிப்படையில் உருவாக்கப்பட்ட ஒற்றை process என்றால், அதே claim-and-delete முறையைப் பயன்படுத்தலாம். இருப்பினும், SQLite-ல் SKIP LOCKED-க்கு இணையான வசதி இல்லை, மேலும் ஒவ்வொரு worker-ம் ஒரே write lock-க்காக வரிசையில் காத்திருக்க வேண்டியிருக்கும்.

NATS core: நினைவகம் இல்லாத subject routing

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

ஆகஸ்ட் 2026 நிலவரப்படி, தற்போதைய server line 2.14 ஆகும். -m 8222 என்பது HTTP monitoring port-ஐத் திறக்கும்; இது இயல்பாகவே முடக்கப்பட்டிருக்கும் மற்றும் இதில் authentication கிடையாது, எனவே மேலே குறிப்பிட்டது போல இதை localhost-ல் மட்டும் bind செய்யவும்.

Core NATS என்பது 'at most once' முறையில் இயங்குகிறது மற்றும் இது எதையும் சேமிப்பதில்லை. ஒரு publisher orders.created போன்ற ஒரு subject-க்குச் செய்தியை அனுப்பினால், அதன் filter-உடன் பொருந்தும் அனைத்து subscriber-களுக்கும் ஒரு நகல் கிடைக்கும். யாரும் subscribe செய்யவில்லை என்றால், அந்தச் செய்தி நீக்கப்படும்; server அந்த bytes-ஐப் பெற்றுக்கொண்டவுடன் publisher-ன் பணி முடிந்துவிடுவதால், அவருக்கு எந்தப் பிழையும் காட்டப்படாது. ஒரு queue group (ஒரே group பெயரைப் பகிரும் பல subscriber-கள்) பயன்படுத்தினால், server ஒவ்வொரு செய்திக்கும் ஒரு உறுப்பினரை மட்டும் தேர்ந்தெடுக்கும்; இது செய்திகளைச் சேமிக்காமல் வேலைப்பகிர்வைச் செய்யும்.

இதன் footprint என்பது subscription நிலை மற்றும் ஒவ்வொரு connection-க்கும் ஒரு write buffer மட்டுமே; எனவே இது செய்திகளின் அளவை விட connection எண்ணிக்கையையே கண்காணிக்கும், வட்டில் (disk) எதுவும் சேமிக்கப்படாது. இதனாலேயே restart செய்யும் போது: செயல்பாட்டில் இருந்த செய்திகள் அழிந்துவிடும், clients தாமாகவே மீண்டும் இணைந்துகொள்ளும், மேலும் காத்திருக்க வேண்டிய recovery நிலைகள் எதுவும் இல்லை.

கண்காணிக்க backlog எதுவும் இல்லாததால், இழப்புகளை (loss) கவனிக்க வேண்டும். ஒரு subscriber தனது socket-லிருந்து server எழுதும் வேகத்தை விட மெதுவாகப் படித்தால், அந்த 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 மதிப்பு தொடர்ந்து அதிகரித்துக்கொண்டே இருந்தால், செய்திகள் இழக்கப்படுகின்றன என்று அர்த்தம்; எனவே இதை ஒருமுறை மட்டும் பார்க்காமல், இதற்காக alert ஒன்றை அமைக்கவும். Core NATS என்பது விரைவாக காலாவதியாகும் செய்திகளுக்கு ஏற்றது: ஒரு metric, ஒரு presence update, அல்லது அடுத்த நிகழ்வு மாற்றியமைக்கக்கூடிய cache invalidation போன்றவை இதற்குச் சிறந்த உதாரணங்கள்.

NATS JetStream: ஒரே process-ல் நீடித்திருக்கும் streams மற்றும் replay

JetStream என்பது ஒரு தனி தயாரிப்பு அல்ல. இது அதே binary-க்குள் இருக்கும் ஒரு subsystem ஆகும், இதை ஒரு flag மூலம் இயக்கலாம்.

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

-sd /data என்பது தரவு சேமிக்கப்படும் directory-ஐ அமைக்கிறது. இதை குறிப்பிடவில்லை என்றால், JetStream தனது தரவை /tmp-ல் சேமிக்கும், இது பெயருக்கேற்றவாறு நீடித்திருக்கும் தன்மை கொண்டது. nats-box image-ல் கிடைக்கும் CLI-ஐப் பயன்படுத்தி ஒரு stream-ஐ உருவாக்கவும்.

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) முக்கியமானது. --storage file என்பது crash-க்கு பிறகும் நிலைத்திருக்கும், ஏனெனில் memory stream-ல் தரவு நிலைத்திருக்காது. --max-bytes=1073741824 என்பது stream-ன் அளவை 1 GiB ஆக byte எண்ணிக்கையில் கட்டுப்படுத்துகிறது, மேலும் --discard old என்பது அந்த வரம்பை எட்டும்போது புதிய பதிவுகளை நிராகரிப்பதற்குப் பதிலாக, பழைய செய்திகளை நீக்கிவிட்டு புதியவற்றைச் சேர்க்கிறது. இந்த வரம்பை அமைக்கவில்லை என்றால், கட்டுப்பாடற்ற publisher ஒருவரால் disk முழுவதுமாக நிரப்பப்படலாம்; அப்போது உங்கள் database-ம் இயங்குவதை நிறுத்திவிடும், ஏனெனில் அவை ஒரே disk-ஐப் பகிர்ந்து கொள்கின்றன.

ஒரு durable consumer, stream-ல் தனது நிலையைத் தக்கவைத்துக்கொள்ளும் மற்றும் restart செய்த பிறகும் அதை நினைவில் வைத்திருக்கும். consumer-ல் --max-deliver-ஐ அமைக்கவும், இதன் மூலம் தொடர்ந்து தோல்வியடையும் ஒரு செய்தி மீண்டும் மீண்டும் அனுப்பப்படுவதைத் தவிர்க்கலாம். ஒரு செய்திக்கான அனுப்பும் முயற்சிகள் தீர்ந்துவிட்டால், JetStream $JS.EVENT.ADVISORY.CONSUMER.MAX_DELIVERIES.>-ல் ஒரு advisory-ஐ வெளியிடும். அந்த subject-க்கு subscribe செய்வதன் மூலம், RabbitMQ-ல் உள்ளதைப் போன்ற dead letter path-ஐ நீங்கள் உருவாக்கலாம். இது நீங்கள் சுயமாகச் செய்ய வேண்டிய ஒரு முக்கியமான பணியாகும்.

backlog-ஐப் பார்க்க, சேமிக்கப்பட்ட செய்திகளின் எண்ணிக்கைக்கு nats stream report-ஐயும், consumer வாரியாக நிலுவையில் உள்ள acknowledgements மற்றும் செயலாக்கப்படாத செய்திகளுக்கு nats consumer report ORDERS-ஐயும் இயக்கவும். செயலாக்கப்படாத செய்திகளின் எண்ணிக்கையை வைத்தே நீங்கள் எச்சரிக்கை (alarm) அமைக்க வேண்டும். Disk பயன்பாட்டை du -sh மூலம் store directory-ல் பார்க்கலாம், retention limit-ஆல் தரவு நீக்கப்படும் வரை இது வளர்ந்துகொண்டே இருக்கும்.

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

ஆகஸ்ட் 2026 நிலவரப்படி, தற்போதைய தொடர் 4.3 ஆகும். Port 5672 என்பது AMQP (advanced message queuing protocol) க்கானது, 15672 என்பது மேலாண்மை இடைமுகத்திற்கான (management interface)து. இந்த இடைமுகத்தை localhost-ல் வைத்துக்கொண்டு, SSH tunnel வழியாக அணுகவும்.

Queue-களை x-queue-type argument-ஐ quorum என அமைத்து உருவாக்கவும்; இயல்புநிலை (default) இன்னும் classic ஆக உள்ளது. Quorum queues எப்போதும் நீடித்திருக்கும் (durable) தன்மை கொண்டவை; எதையும் செய்வதற்கு முன்பு தரவை வட்டில் (disk) எழுதும். எனவே, ஒரு node-ல் நீடித்திருக்கும் மற்றும் தற்காலிக விருப்பங்களின் சிக்கலான கலவைக்கு பதிலாக, தெளிவான செயல்பாட்டைப் பெறலாம். ஒரு policy மூலம் dead letter இலக்கை அமைக்கவும்.

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

ஒரு செய்தி நான்கு காரணங்களுக்காக dead letter செய்யப்படுகிறது: ஒரு consumer அதை basic.reject அல்லது basic.nack மற்றும் requeue ஆகியவற்றை false என அமைத்து நிராகரித்தல், அதன் per-message TTL (time to live) முடிவடைதல், queue அதன் நீள வரம்பைத் தாண்டுதல், அல்லது அது quorum queue விநியோக வரம்பை மீறுதல். RabbitMQ 4.0 முதல் அந்த வரம்பு இயல்பாக 20 ஆக உள்ளது. எனவே, பிழையை உருவாக்கி nack செய்யும் ஒரு handler, 20 முறை மீண்டும் முயற்சி செய்துவிட்டு, சுழற்சியில் (looping) சிக்காமல் செய்தியை dead letter exchange-க்கு அனுப்பிவிடும்.

சிறிய VPS-களில் RabbitMQ-வின் நினைவகப் பயன்பாடு (memory usage) பயனர்களை ஆச்சரியப்படுத்தும். இயல்புநிலை high watermark என்பது கிடைக்கக்கூடிய RAM-ல் 0.6 ஆகும். node இதைத் தாண்டும்போது, RabbitMQ வெளியிடும் (publishing) அனைத்து இணைப்புகளையும் தடுக்கும். உங்கள் application-க்கு பிழை செய்தி கிடைக்காது. மாறாக, publish செய்யும் செயல்பாடு முடிவடையாமல் அப்படியே நிற்கும், இது உங்கள் code-ல் hang ஆனது போலத் தோன்றும். startup log-ல் node கணக்கிட்ட எண்ணைக் காணலாம்:

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

இலவச இடம் இயல்பாக 50 MB-க்குக் கீழே குறையும் போது, disk alarm இதேபோல் வெளியீட்டாளர்களைத் தடுக்கும். Quorum queues இதனுடன் கூடுதல் கணக்கீடுகளைச் சேர்க்கின்றன: ஆவணங்களின்படி ஒரு செய்திக்கு குறைந்தபட்சம் 32 bytes in-memory metadata தேவைப்படுகிறது, அதாவது 30,000 செய்திகளுக்கு சுமார் 1 MB. மேலும், RAM-ல் குறைந்தபட்சம் மூன்று மடங்கு effective write-ahead log அளவு இருக்க வேண்டும் என்று பரிந்துரைக்கப்படுகிறது. WAL வரம்பு இயல்பாக 512 MiB ஆக உள்ளது, எனவே அந்தப் பரிந்துரைக்கே 1.5 GB தேவைப்படும். 2 GB server-ல், இயல்புநிலை அளவு பொருந்தும் என்று நம்புவதற்குப் பதிலாக, rabbitmq.conf-ல் அதைக்குறைக்கவும்.

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 என்பது விநியோகிக்கப்பட்டு, இன்னும் உறுதிப்படுத்தப்படாத (acked) செய்திகளைக் குறிக்கும். Ready count மாறாமல், unacknowledged count அதிகரித்துக் கொண்டே இருந்தால், உங்கள் workers வேலைகளை எடுத்துக்கொண்டு அவற்றை முடிக்கவில்லை என்று அர்த்தம். இது 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

இது Kafka 4.3.1-க்கான விரைவு வழிகாட்டி (quickstart). இது ஆகஸ்ட் 2026 நிலவரப்படி தற்போதையது. இது KRaft mode-ல் (Kafka 4.0-ல் ZooKeeper-க்கு மாற்றாக வந்த உள்ளமைக்கப்பட்ட controller) இயங்குகிறது. இதற்கான container வடிவம் apache/kafka:4.3.1 ஆகும்.

நீங்கள் export KAFKA_HEAP_OPTS="-Xmx1G -Xms1G"-ஐ அமைக்காதபோது, தொடக்க script அதை அமைத்துவிடும். இதனால் broker ஒரு செய்தியைச் சேமிக்கும் முன்பே 1 GB Java heap-ஐ ஒதுக்கிவிடும். மேலும், அது வாசிக்கும் page cache-க்காக அதற்கு அப்பால் கூடுதல் RAM தேவைப்படும். 2 GB VPS-ல், உங்கள் application மீதமுள்ள RAM-க்காக JVM-உடன் போட்டியிட வேண்டியிருக்கும்.

Retention என்பது அடுத்த ஆச்சரியம். log.retention.hours இயல்பாக 168 என இருக்கும், அதாவது ஏழு நாட்கள். log.retention.bytes இயல்பாக -1 என இருக்கும், அதாவது அளவு வரம்பு எதுவும் இல்லை. ஒவ்வொரு consumer-ம் செய்திகளை வாசித்தாலும் இல்லாவிட்டாலும், Kafka அந்த முழு காலத்திற்கும் செய்திகளை வைத்திருக்கும். இது நீங்கள் எதிர்பார்த்த வசதிதான், ஆனால் சிறிய disk-ல் இதுவே தோல்விக்கான காரணமாகவும் அமையும். எனவே, சிக்கலை எதிர்கொள்ளும் முன் ஒவ்வொரு topic-க்கும் byte வரம்பை அமைக்கவும்.

இப்போது உண்மையான நிலையை பார்ப்போம். ஒரே ஒரு broker என்பது replication factor 1 என்பதைக் குறிக்கும். எனவே acks=all ஒரு disk-ல் ஒரு fsync-ஆக மட்டுமே செயல்படும். ஒரு JVM broker மற்றும் ஒரு controller-ன் செயல்பாட்டுச் செலவுடன், ஒரு இயந்திரத்தின் நீடித்து நிலைக்கும் தன்மையை (durability) மட்டுமே நீங்கள் பெறுவீர்கள். Partitions என்பது உங்களிடம் இல்லாத பல broker-களுக்கு இடையே இணையாகச் செயல்படும் (parallelism) வசதியை வழங்கும். Replication, rack awareness மற்றும் பிற fleet வசதிகள் இங்கு செயல்படாது. JetStream அதே போன்ற நீடித்து நிலைக்கும் replay வசதியை, மிகக் குறைந்த நினைவகத்தில் அதே கணினியில் வழங்குகிறது. Kafka-வை இங்கு பயன்படுத்துவதற்கு இரண்டு காரணங்கள் மட்டுமே உள்ளன: ஒன்று, downstream கருவி Kafka protocol-ஐ மட்டுமே ஆதரிப்பது (Debezium மூலம் change data capture அல்லது analytics loader), அல்லது production சூழலைச் சிறிய அளவில் பிரதிபலிக்க முயற்சிப்பது. ஒரு cluster-ஆக வளரத் திட்டமிடுவது என்பது கூடுதல் இயந்திரங்களை வாங்குவதற்கான திட்டமாகும். அதுவரை, இது ஒரே node-ல் k3s இயக்குவது போன்றதே; ஒரு node-ன் நம்பகத்தன்மைக்காக நீங்கள் cluster-ன் சிக்கலான தன்மையைச் சுமக்கிறீர்கள்.

Kafka-வில் backlog என்பது consumer lag ஆகும்.

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

LAG நெடுவரிசையை வாசிக்கவும். இது ஒவ்வொரு partition-க்கும் LOG-END-OFFSET கழித்தல் CURRENT-OFFSET ஆகும். மற்ற partition-கள் சீராக இருக்கும்போது, ஒரு partition-ல் மட்டும் lag அதிகரித்தால், அது சீரற்ற key-யைக் குறிக்கிறது. ஏனெனில், ஒரே key கொண்ட அனைத்துச் செய்திகளும் ஒரே partition-ல் சேரும், அதை ஒரே ஒரு consumer மட்டுமே கையாளும்.

பெட்டி (box) மறுதொடக்கம் செய்யப்படும்போது என்ன நடக்கும்

Core NATS செயல்பாட்டில் இருந்த அனைத்து தரவுகளையும் இழந்து உடனடியாக மீண்டும் தொடங்கும், ஏனெனில் இதில் மீட்டெடுக்க எதுவும் இல்லை. JetStream, store directory-லிருந்து streams மற்றும் consumer நிலைகளை மீண்டும் ஏற்றும், எனவே consumers தாங்கள் நிறுத்திய offset-லிருந்து மீண்டும் தொடரும். RabbitMQ, quorum queues-ஐ வட்டில் (disk) இருந்து மீட்டெடுக்கும், ஆனால் classic transient queues மற்றும் persistent delivery mode இல்லாமல் வெளியிடப்பட்ட செய்திகள் அனைத்தும் அழிந்துவிடும். Kafka தொடங்கும் போது அதன் log segments-ஐ மீண்டும் இயக்கும்; முறையற்ற shutdown-க்கு பிறகு, broker இணைப்பை ஏற்கும் முன் சிறிய வட்டில் கூட இந்த recovery scan சில நிமிடங்கள் ஆகலாம்.

இரண்டு விஷயங்களை ஒருமுறை அமைப்பது நல்லது. Container-க்கு restart policy (restart: unless-stopped) வழங்கவும் அல்லது systemd unit-ஐ enable செய்யவும், அப்போதுதான் kernel upgrade reboot-க்கு பிறகு உங்கள் தலையீடு இன்றி broker மீண்டும் தொடங்கும். அடுத்து, வரிசையை கவனிக்கவும்: உங்கள் application-க்கு இருபது வினாடிகளுக்குப் பிறகு தயாராகும் ஒரு broker, முதல் இணைப்புகளை நிராகரிக்கும்; சில client libraries மீண்டும் முயற்சி செய்வதற்குப் பதிலாக வெளியேறிவிடும். Broker தயாராகும் வரை dependent service-ஐ நிறுத்தி வைக்கும் Compose healthchecks மூலம் application-ஐ broker-டன் இணைக்கவும்.

உங்கள் சொந்த VPS-ல் செலவு, மேற்கோள் காட்டப்படாமல் அளவிடப்படுகிறது

வெளியிடப்பட்ட throughput புள்ளிவிவரங்கள் உங்களிடம் இல்லாத வன்பொருளில் அளவிடப்படுபவை, பொதுவாக local NVMe கொண்ட multi-core server-ல் இவை அளவிடப்படும். அவற்றை ஒரு அதிகபட்ச எல்லையாகக் கருதி, உங்கள் server-ல் நீங்களே அளவிடவும்.

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

Broker idle நிலையில் இருக்கும்போது அவற்றை இயக்கவும், பின்னர் உங்கள் உண்மையான traffic-ன் கீழ் மீண்டும் இயக்கவும். இந்த இரண்டிற்கும் இடையே உள்ள இடைவெளிதான், உங்கள் application-க்கு அருகில் அந்த broker பொருந்துமா என்பதைத் தீர்மானிக்கும் எண். தோராயமான throughput அளவைக் கண்டறிய, மற்றவர்களின் blog post-களைப் பயன்படுத்துவதற்குப் பதிலாக அந்தந்த project-ன் சொந்த load generator-ஐப் பயன்படுத்தவும்: NATS-க்கு nats bench pub test --msgs 100000 --clients 2, Kafka-க்கு bin/kafka-producer-perf-test.sh, மற்றும் RabbitMQ-க்கு PerfTest. Generator-ஐ அதே VPS-ல் இயக்குவது broker மற்றும் generator ஆகிய இரண்டையும் சேர்த்தே அளவிடும்; நீங்கள் முடிவுகளைப் புகாரளிக்கும்போது இதைக் குறிப்பிடும் வரை இது தவறில்லை.

அனைத்திற்கும் ஒரு பொதுவான உச்ச வரம்பு உண்டு. இங்கே உள்ள ஒவ்வொரு durable விருப்பமும் fsync-க்காகக் காத்திருக்கும், எனவே network-attached storage கொண்ட VPS-ல் disk-தான் வரம்பைத் தீர்மானிக்கிறது, broker-களை மாற்றுவதால் இந்த வரம்பு மாறாது.

மூன்று பணிச்சுமைகள் மற்றும் ஒவ்வொன்றுக்கும் தேவையான செய்தி வரிசை (message queue)

  1. ஒரு இணையப் பயன்பாட்டிற்கான பின்னணிப் பணிகள் (background jobs), உதாரணமாக மின்னஞ்சல் அனுப்புதல், படங்களின் அளவை மாற்றுதல் அல்லது webhooks வழங்குதல். Postgres மற்றும் SKIP LOCKED உடன் தொடங்கவும். ஒவ்வொரு செய்திக்கும் உறுதிப்படுத்தல் (acks), விநியோக வரம்பு (delivery limit) மற்றும் நீங்களே தர்க்கத்தை எழுதாமல் ஆய்வு செய்யக்கூடிய dead letter queue தேவைப்படும்போது, அல்லது தரவுத்தளத்தில் உள்ள job table மிகவும் பிஸியான அட்டவணையாக மாறும்போது RabbitMQ-க்கு quorum queues உடன் மாறவும்.
  2. பல உள் சேவைகள் எதிர்வினையாற்றும் நிகழ்வுகள் (events), இதில் தொலைந்த செய்தி விரைவாகப் புதிய ஒன்றால் மாற்றப்படும். Core NATS-ஐப் பயன்படுத்தவும்; இதில் subjects என்பது routing திட்டமாகவும், வேலைப் பகிர்வு தேவைப்படும் இடங்களில் queue groups-ஆகவும் செயல்படும். மறுதொடக்கம் (restart) செய்தாலும் அழியாமல் இருக்க வேண்டிய குறிப்பிட்ட சில subjects-க்கு மட்டும் JetStream stream-ஐச் சேர்க்கவும், மற்றவற்றை நினைவகத்திலேயே (memory) விட்டுவிடவும்.
  3. தணிக்கை சுவடு (audit trail), read model-ஐ மீண்டும் உருவாக்குதல் அல்லது பிற்காலத்தில் பகுப்பாய்வு செய்தல் போன்றவற்றுக்காக, நுகர்வோர் (consumers) தொடக்கத்திலிருந்தே வாசிக்கும் நிகழ்வுப் பதிவு (event log). கோப்பு சேமிப்பகம் (file storage) மற்றும் தெளிவான byte cap கொண்ட JetStream-ஐப் பயன்படுத்தவும். ஏதேனும் ஒரு downstream கருவிக்கு Kafka protocol தேவைப்படும்போது மட்டுமே Kafka-வைத் தேர்ந்தெடுக்கவும், அந்த இணக்கத்தன்மைக்காக JVM heap-ன் பயன்பாட்டை ஏற்றுக்கொள்ளவும்.

ஒரே server-ல் தவறான தேர்வைச் செய்வதால் ஏற்படும் பாதிப்பு throughput குறைபாடு அல்ல. அதிகாலை மூன்று மணிக்கு மீட்புப் பணிகளைச் செய்யும்போது, செய்திகள் இன்னும் இருக்கிறதா என்று தெரிந்துகொள்ள வேண்டிய கட்டாயமே அது. அதைக் கருத்தில் கொண்டு தேர்வு செய்யவும்.

FAQ

2 GB VPS-ல் என்னால் Kafka-வை இயக்க முடியுமா?

இது தொடங்கும், ஆனால் மிகக் குறைந்த இடமே இருக்கும். நீங்கள் மாற்றங்களைச் செய்யாதபோது bin/kafka-server-start.sh ஆனது KAFKA_HEAP_OPTS="-Xmx1G -Xms1G"-ஐ அமைக்கிறது, எனவே எந்தவொரு செய்தியையும் சேமிப்பதற்கு முன்பே JVM 1 GB நினைவகத்தை எடுத்துக்கொள்ளும். Kafka அதற்கு மேலதிகமாக உள்ள நினைவகத்தை page cache-க்காக நம்பியிருக்கிறது. அதே server-ல் உங்கள் application மற்றும் database-ஐச் சேர்த்தால், அது swap-க்குச் சென்றுவிடும். மேலும், replication factor 1-ஐப் பயன்படுத்தும்போது, acks=all என்பது ஒரு வட்டில் ஒருமுறை மட்டுமே fsync செய்யும்; இதனால் Kafka-வின் நீடித்து நிலைக்கும் திறன் (durability model) இல்லாமலேயே அதன் செயல்பாட்டுச் செலவை நீங்கள் ஏற்க வேண்டியிருக்கும். அதே வன்பொருளில், மிகக் குறைந்த நினைவகத்தில் NATS JetStream நீடித்த மறுபதிவு (durable replay) வசதியை வழங்குகிறது.

என்னிடம் ஏற்கனவே Postgres இருக்கும்போது message queue தேவையா?

பெரும்பாலும் தேவையில்லை. ஒரு transaction-க்குள் job table-ஐ SELECT ... FOR UPDATE SKIP LOCKED மூலம் வாசிப்பது, at-least-once delivery, பாதுகாப்பான concurrent workers, retries மற்றும் dead letter table ஆகியவற்றை வழங்குகிறது. இதற்குத் தனியாக எந்தச் சேவையையும் கண்காணிக்க வேண்டியதில்லை, மேலும் நீங்கள் ஏற்கனவே எடுக்கும் backups-களே போதுமானது. இதிலிருந்து வெளியேற வேண்டிய சூழல்கள் குறிப்பிட்டவை: queue table உங்கள் அதிகப்படியான write load-ஆக மாறி autovacuum பின்தங்குதல், நீண்ட நேரம் இயங்கும் jobs-கள் transaction-களைத் திறந்து வைத்து முழு database-ன் vacuum-ஐத் தடுத்தல், அல்லது இரண்டாவது சேவை அதே நிகழ்வுகளைத் தனித்தனியாகப் பயன்படுத்த வேண்டியிருத்தல்.

பின்னணிப் பணிகளுக்கு (background jobs) நான் NATS JetStream-ஐப் பயன்படுத்த வேண்டுமா அல்லது RabbitMQ-வா?

ஒவ்வொரு செய்திக்கும் acknowledgement, delivery limit மற்றும் dead letter routing ஆகியவை உள்ளமைக்கப்பட்ட வசதியாக இருக்க வேண்டுமென்றால் RabbitMQ-வைத் தேர்வு செய்யவும். Quorum queues எப்போதும் நீடித்திருக்கும் (durable). RabbitMQ 4.0 முதல் delivery limit இயல்பாகவே 20 என உள்ளது. ஒரு policy மூலம், தீர்ந்துபோன செய்திகளை dead letter exchange-க்கு அனுப்பி, அவற்றை நீங்கள் சரிபார்க்கலாம். அதே நிகழ்வுகளைப் பிற்காலத்தில் பிற நுகர்வோர்கள் (consumers) மீண்டும் பயன்படுத்த வேண்டியிருந்தால் JetStream-ஐத் தேர்வு செய்யவும், ஏனெனில் ஒரு queue செய்திகளை நீக்கிவிடும், ஆனால் stream செய்திகளை வைத்திருக்கும். JetStream-ல் நீங்கள் --max-deliver-ஐ அமைத்து, $JS.EVENT.ADVISORY.CONSUMER.MAX_DELIVERIES.> advisory மூலம் dead letter பாதையை நீங்களே உருவாக்க வேண்டும்.

எனது நுகர்வோர்கள் (consumers) எவ்வளவு பின்தங்கியுள்ளனர் என்பதை எப்படி அறிவது?

ஒவ்வொரு broker-க்கும் ஒரு கட்டளை உள்ளது. RabbitMQ-விற்கு, rabbitmqctl list_queues name messages messages_ready messages_unacknowledged ஆனது நுகர்வோருக்காகக் காத்திருக்கும் பணிகளையும், வழங்கப்பட்டு இன்னும் ack செய்யப்படாத பணிகளையும் பிரிக்கிறது. JetStream-விற்கு, nats consumer report <stream> ஒவ்வொரு நுகர்வோருக்கும் செயலாக்கப்படாத செய்திகளையும் நிலுவையில் உள்ள acknowledgement-களையும் காட்டுகிறது. Kafka-விற்கு, kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group <group> ஒவ்வொரு partition-க்கும் LAG நெடுவரிசையை அச்சிடுகிறது. Core NATS எதையும் சேமிப்பதில்லை என்பதால், அதில் வாசிப்பதற்கு backlog எதுவும் இல்லை. அதற்குப் பதிலாக http://localhost:8222/varz-ல் உள்ள slow_consumers counter-ஐக் கவனிக்கவும்: இது பின்தங்கியதால் server துண்டித்த இணைப்புகளைக் கணக்கிடுகிறது, இது செய்தி இழப்பைக் குறிக்கும்.

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