Postgres क्यू तकनीक का चयन
(adriano.fyi)- अलग क्यू सिस्टम लाने से पहले, अगर पहले से इस्तेमाल हो रहे Postgres से ही background job queue बनाई जा सकती है, तो ऑपरेशन की सरलता और टीम की परिचितता का बड़ा फायदा मिल सकता है
- Postgres 9.5 के बाद से
NOTIFY/LISTENऔरFOR UPDATE SKIP LOCKEDनए कामों की सूचना और workers के बीच duplicate processing रोकने दोनों समस्याओं को हल करते हैं - Redis, Kafka, RabbitMQ, Amazon SQS मजबूत विकल्प हैं, लेकिन नई dependency development, testing और operations environments में failure modes और learning cost जोड़ती है
- Postgres queue भी सर्वगुण-संपन्न नहीं है; Redis की तुलना में push/pop धीमा हो सकता है, और अलग queue database या server, अधिक बार
VACUUMजैसी operational costs आ सकती हैं - background job code को queue backend से बंधा न रहने दें; परिचित तकनीक जरूरतें पूरी न कर पाए तभी दूसरी queue technologies पर विचार करना अधिक सुरक्षित है
Postgres queue कैसे काम करती है
- Postgres queue तकनीक दो तत्वों से मिलकर बनी है
- नए कामों की सूचना देने और प्राप्त करने वाला pub/sub
- कई workers को एक ही काम process करने से रोकने वाला row locking
- दोनों features 2016 में जारी Postgres 9.5 से built-in उपलब्ध हैं
NOTIFYऔरLISTENको साथ इस्तेमाल करने पर application में pub/sub जोड़ा जा सकता हैFOR UPDATE SKIP LOCKEDशर्तों से मेल खाने वाले records पर row lock लगाता है और पहले से locked records को छोड़ देता है- इसे job records पर लागू करने से
SELECT * FROM jobs ORDER BY created_at FOR UPDATE SKIP LOCKED LIMIT 1जैसी queue processing query बनाई जा सकती है
- इसे job records पर लागू करने से
SKIP LOCKEDdata का “inconsistent” view देता है, लेकिन queue में यह विशेषता उपयोगी है- जो काम पहले से process हो रहा है, वह row lock के कारण दूसरे workers को दिखाई नहीं देता
- इस behavior से distributed mutual exclusion संभव हो जाता है
NOTIFYके जरिएLISTENकर रहे workers को नए कामों की सूचना देकर periodic batch processing और real-time job processing दोनों बनाई जा सकती हैं
Redis कैसे background jobs का default बना
- लंबे समय तक चलने वाले jobs को कैसे handle करना है, यह कई trade-offs वाला technical choice है
- व्यापक रूप से इस्तेमाल होने वाले queue/message broker विकल्प ये हैं
- Redis: in-memory data store और कई background job libraries का backend
- Apache Kafka: Apache Foundation द्वारा maintain किया जाने वाला distributed event streaming platform
- RabbitMQ: व्यापक रूप से deployed message broker के रूप में परिचित
- Amazon SQS: highly scalable queues प्रदान करने वाला Amazon SaaS
- GitHub के background jobs topic में top 5 popular libraries सभी Redis-based हैं
- Redis data को memory में store करता है, इसलिए inserts और lookups तेज होते हैं; यह pub/sub API और
list,setdata structures देता है, इसलिए queue implementation के लिए अच्छी तरह फिट बैठता है - Redis की scalability कई developers के लिए default choice की तरह काम करती है, और technology selection में defaults का असर बहुत मजबूत होता है
scalability से पहले देखने लायक मानदंड
- tech industry का “scale” obsession simplicity, maintainability और developer cognitive load कम करने जैसी बातों को पीछे धकेल सकता है
- कई applications को Google, Facebook, Uber स्तर की scaling की जरूरत नहीं होती
- किसी project या business की शुरुआत करते समय शुरू से ही scalability को optimize करने के बजाय पहले ये मानदंड देखने चाहिए
- ऐसी technology जिसे टीम अच्छी तरह जानती हो
- ऐसी काफी अच्छी technology जो user needs पूरी करती हो
- ऐसा solution जो team capability के अनुकूल हो और सबसे कम मेहनत वाला हो
- Postgres असल में अच्छी तरह scale करता है, लेकिन queue use cases में यह सबसे ज्यादा scale करने वाला specialized queue system नहीं है
- general-purpose software होने के नाते Postgres कई काम काफी अच्छी तरह करता है, और queue को भी उनमें से एक के रूप में संभाल सकता है
“boring technology” के आधार पर निर्णय लेना
- queue technology चुनते समय सबसे अहम सवाल है कि अभी कौन-सी technology इस्तेमाल हो रही है और टीम उसे कितनी अच्छी तरह समझती है
- जो technology पहले से इस्तेमाल में है और अच्छी तरह जानी-पहचानी है, वह software stack पर कम बोझ जोड़ती है
- अगर relational database पहले से इस्तेमाल हो रहा है और वह database Postgres है, तो अन्य software से पहले Postgres queue पर विचार किया जा सकता है
- “boring technology” कोई fixed list नहीं है; यह इस बात पर निर्भर करती है कि अभी कौन-सी technology इस्तेमाल हो रही है
- message delivery-centric application के लिए RabbitMQ boring technology हो सकती है
- caching-centric application के लिए Redis boring technology हो सकती है
- बहुत relational data वाली application के लिए Postgres boring technology हो सकती है
- Redis, Kafka, RabbitMQ, SQS को सिर्फ background jobs के लिए नया introduce करने पर लागत बढ़ जाती है
- development, testing और production environments में नई system dependency जुड़ती है
- भविष्य में Developers, DBAs, SREs को नए system के failure modes और configuration समझने होंगे
- failure recovery, troubleshooting और performance monitoring का ज्ञान चाहिए
- टीम को अभी जो नहीं पता, वे unknown unknowns risk बने रहते हैं
Postgres queue की कीमत और चयन मानदंड
- boring technology सर्वगुण-संपन्न नहीं होती, और Postgres भी अपवाद नहीं है
- Postgres queue चुनने पर परिचितता, known failure modes और cost distribution जैसे फायदे मिलते हैं, लेकिन बदले में ये कीमतें चुकानी पड़ सकती हैं
- Postgres queue का push/pop Redis की तुलना में काफी धीमा है
- single relational database के बजाय application database और queue database की जरूरत पड़ सकती है
- background jobs को independently scale करने के लिए अलग database server की जरूरत पड़ सकती है
- ज्यादा बार
VACUUMकी जरूरत हो सकती है, जिससे performance overhead बन सकता है
- Postgres, Redis, Kafka, RabbitMQ, SQS में से कोई भी automatic default नहीं होना चाहिए
- technology selection लगातार चलने वाला trade-off है, और इसे team व application requirements के हिसाब से तय करना चाहिए
- संदेह होने पर यह मानदंड लागू किया जा सकता है: “alternatives पर तभी विचार करें जब यह साबित हो जाए कि boring technology जरूरतें पूरी नहीं कर पा रही”
queue बदल सकने वाली background job संरचना
- background job processing code किसी specific queue technology पर निर्भर नहीं होना चाहिए
- application के बढ़ने पर जरूरत के अनुसार memcached या Redis जैसी technologies जोड़ी जा सकती हैं, और समय के साथ वे भी टीम के लिए परिचित “boring technology” बन सकती हैं
- queue technology को abstract करने से users काम के हिसाब से queue चुन सकते हैं
- GitHub की top popular background job libraries में Hangfire को छोड़कर कोई भी Redis के अलावा किसी queue technology की ओर निकलने का escape hatch नहीं देती
- ऐसी structure में queue बदलने के लिए application code फिर से लिखना पड़ता है
- Neoq इसी philosophy के तहत बनाई गई Go library है
- queue backend के रूप में in-memory, Postgres, Redis इस्तेमाल किए जा सकते हैं
- users application code बदले बिना दूसरे queue backend से initialize कर सकते हैं
- in-memory और Postgres implementations first-class हैं, और Redis implementation asynq का इस्तेमाल करता है
- Redis, Kafka, RabbitMQ, SQS शानदार technologies हो सकती हैं, लेकिन वे हमेशा उस job के लिए सही queue या उचित complexity नहीं होतीं
1 टिप्पणियां
Hacker News की रायें
अब तक मैंने distributed job system तीन बार बनाए हैं, और कई सालों से मेरी सुझाई हुई rule of thumb यह है: “मौजूदा scale के 10 गुना को आधार मानकर design करो”
अगर 70 requests प्रति सेकंड हैं तो 700 requests को, और अगर 20 batch job servers चाहिए तो 200 को आधार मानो। हर साल 100% बढ़ने वाला startup भी 3 साल बाद 8 गुना scale पर होगा, इसलिए बढ़ते हुए फिर से लिखने का समय मिल जाता है
पहले बनाए गए system में “scalability” की वजह से SQL से बचा था, लेकिन transaction integrity की जरूरत वाले बहुत-से edge cases मिलने पर काफी परेशानी हुई
बाद में बनाए गए दो distributed job systems में PostgreSQL को coordinator की तरह इस्तेमाल किया, और सचमुच
SELECT FOR UPDATE SKIP LOCKEDके इर्द-गिर्द बनाया। एक आम तौर पर 350 workers को control करता है, और दूसरा हजारों jobs पर complex priorities लागू करता हैदोनों सालाना कई मिलियन डॉलर revenue के scale तक बिना दिक्कत टिकेंगे, और उदाहरण के लिए 350 workers वाला system थोड़ी tweaking से करीब 2,000 CPUs तक scale हो सकता है
जब तक आपको यह एहसास न हो कि transactions चाहिए, hyperscale technology काफी सस्ती लगती है। लेकिन उसी क्षण से eventually consistent store के ऊपर transaction semantics की नकल करना engineering nightmare बन जाता है
इसलिए बैठकर हिसाब लगाना चाहिए। अगर company सालाना 100 million डॉलर कमाए तो distributed system कितना बड़ा होना चाहिए, क्या उस load को handle करने वाला PostgreSQL instance आसानी से मिल सकता है, या client-wise sharding काफी है—यह सब देखकर, अगर संभव हो तो PostgreSQL पर गंभीरता से विचार करने लायक है। सौ छोटी-छोटी चीजें आसान हो जाती हैं
SQL solution आम तौर पर ज्यादा simple होता है, compute resources भी कम खाता है, और operational support भी आसान होता है
हालांकि इसे चलाने के लिए database को इतना अच्छे से जानना पड़ता है कि
SELECT FOR UPDATE SKIP LOCKEDजैसी feature शुरू से मौजूद है, यह पता हो। आजकल कई engineers ऐसे environment में बढ़ रहे हैं जहां भारी ORM, DBMS की असली क्षमता के रास्ते में आ जाते हैं, इसलिए यह knowledge काफी rare होती जा रही हैsystem को peak load संभालना होगा, और अगर peak नहीं पता तो safety margin रखें या जरूरत पड़ने पर jobs को drop करने या पीछे धकेलने का तरीका रखें
सब कुछ trade-off है, और optimization सिर्फ उन्हीं चीजों की करनी चाहिए जिन्हें इसकी जरूरत है; कौन-सी चीजें उस category में आती हैं, यह पहचानने की क्षमता अच्छे engineer की निशानी है
अगर यह आपके लिए नया है, तो आपने अभी काम के समय HN एक हफ्ता पढ़ने की कीमत वसूल कर ली है; इसे कागज पर लिखकर ATM card पर चिपका देने लायक है
कई projects में मैंने ज्यादा simple approach चुनी: normal table और
SELECT FOR UPDATE SKIP LOCKEDका इस्तेमाल, जो हर language के ORM/query DSL framework में सीधे काम करता हैhttps://www.pgcasts.com/episodes/the-skip-locked-feature-in-...
“web scale” तो नहीं है, लेकिन मेरे अनुभव में हजारों background jobs तक आसानी से scale हो जाता है
बड़े organization के काम में भी यह तरीका बिना समस्या इस्तेमाल किया। कोई special deployment या नया infrastructure नहीं चाहिए, बस app के अंदर कुछ worker threads चला दो। abandoned jobs को reset करने वाला thread भी रखा जा सकता है
हालांकि 3 साल में सच में ऐसी स्थिति आई ही नहीं, और सब कुछ
try/catchके अंदर था, इसलिए fail होने पर queue में वापस डाल दिया जाता था; Java app भी बहुत stable थाdelete from taskwhere task_id in( select task_idfrom taskorder by random() -- use tablesample for better performancefor updateskip lockedlimit 1)returning task_id, task_type, params::jsonb as params[1] https://taylor.town/pg-task
“हजारों background jobs” कहा गया, लेकिन queues को आम तौर पर Little's law के आधार पर देखना चाहिए, और average job enqueue rate प्रति सेकंड व average job duration जैसे ratios बताने चाहिए। raw count अपने-आप में ज्यादा मायने नहीं रखता
शुरुआत में naive
UPDATE ... SETसे भी काम चल जाता है, लेकिन यह बहुत ज्यादा locks लेता है।UPDATEमेंSELECTsubquery इस्तेमाल करके याSELECT FOR UPDATE SKIP LOCKEDसे dequeue lock को efficient बनाया जा सकता है, फिर भी अंततः dequeue queries एक-दूसरे के locks को block करके queue रोक सकती हैंउस समय DB को सांस लेने का मौका देने के लिए ingestion बंद कर सकते हैं, लेकिन खोई हुई ingestion से data loss होता है, और आम तौर पर core problem यही होती है कि dequeues आपस में एक-दूसरे को block कर रहे होते हैं
jobs table को जल्दबाजी में shard करके locks से बचा जा सकता है, लेकिन कई workers में deploy करना fragile होता है और data loss तक ले जा सकता है। कुछ random jobs drop भी कर सकते हैं, लेकिन वह जाहिर तौर पर data loss है
production के दौरान ऐसे options बेहद stressful होते हैं, और ground-up redesign के बिना recovery भी बहुत मुश्किल होती है। अगर सिर्फ कुछ customers हैं और पक्का है कि हमेशा प्रति सेकंड कुछ दर्जन jobs के level पर ही रहेंगे, तो अलग बात है; ऐसी situation खुद झेलने के बाद मैं जहां संभव हो database के बजाय असली queue technology चुनता हूं
“इंजीनियर अपनी ज़रूरत से बिल्कुल अलग होने के बावजूद cool दिखने के लिए FAANG infrastructure की नकल करते हैं” जैसी आलोचना अक्सर दिखती है, लेकिन मेरे हिसाब से इसका बड़ा हिस्सा ज्ञान और documentation की समस्या है
अगर आप FAANG या दूसरे startups को follow करके अनंत रूप से scalable queue-based architecture बनाना चाहते हैं, तो Redis, SQS जैसे scalable solutions को कुछ घंटों में set up करने में मदद करने वाली दर्जनों high-quality guides, tutorials और white papers मौजूद हैं
maintenance cost ज़्यादा होती है, लेकिन अच्छी प्रतिष्ठा वाले sources से commands, code और configuration copy-paste करके शुरुआत की जा सकती है
इसके उलट, अगर आप PostgreSQL का
NOTIFYइस्तेमाल करना चाहते हैं और “SQLALchemy notify listen postgres” search करते हैं, तो बस कुछ unanswered Stack Overflow questions और context के बिना GitHub Gist जैसे results मिलते हैंकिसी side project में मैं यह तरीका सच में आज़माना चाहता हूँ, लेकिन अकेले 2–3 दिन लगाकर इसे समझने की फुरसत नहीं है
बाहर से यह “सरल लेकिन scale नहीं होता, यानी सिर्फ PostgreSQL इस्तेमाल करना” और “complex लेकिन scale होता है, यानी Redis/SQS आदि” के चुनाव जैसा दिखता है, और तब बात ऐसी बनती है कि मैं fancy technology और FAANG से प्रभावित होकर ऐसी scalability चुन रहा हूँ जिसकी ज़रूरत नहीं है
लेकिन guides और resources को भी ध्यान में रखें तो असली विकल्प “complex और scalability भी unpredictable, क्योंकि मुझे implementation और pitfalls नहीं पता” और “सरल और scalable, जिसे असल में सब अपनाते हैं” के करीब हैं। तब FAANG को follow करने वाले engineer का चुनाव कहीं ज़्यादा rational दिखता है
NOTIFYइस्तेमाल करना हो तो बस https://www.postgresql.org/docs/current/sql-notify.html पढ़ लें, search skills की ज़रूरत नहींउदाहरण के लिए, low-load PostgreSQL इस्तेमाल करने पर schema migration, नए constraints जोड़ना, analytics आदि लगभग मामूली काम बन जाते हैं
SQS, Cassandra आदि इस्तेमाल करने पर scalability/availability मिलती है, लेकिन जब पता चलता है कि मूल design fit नहीं बैठ रहा, तो उसे बदलने में कहीं ज़्यादा समय लगता है। जैसे business कहे कि “foo type के users को bar values को साथ में combine नहीं करना चाहिए” जैसा constraint जोड़ना है
PostgreSQL के बिना भी implementation संभव है, लेकिन खासकर बदलाव चाहिए हो तो यह आसान या सरल नहीं होता
इसलिए flexibility बनाए रखनी हो तो PostgreSQL इस्तेमाल करना, और जब पता हो कि चीज़ नहीं बदलेगी तब PostgreSQL के ऊपर कुछ और साथ में इस्तेमाल करना बेहतर लगता है। बेशक इस case में infrastructure और maintenance overhead जुड़ता है
आखिरकार यह हमेशा trade-off है, और यह जानना पड़ता है कि क्या, कब, किसके बदले छोड़ना है
हर किसी का अपने application में PostgreSQL backend हो या कोई और queue, custom background job worker खुद implement करना ideal नहीं लगता
background jobs में कई subtle बातें और implementation details होती हैं जिनमें गलती आसानी से हो सकती है, इसलिए आम तौर पर इन्हें किसी ज़्यादा comprehensive dedicated library या framework को संभालना बेहतर होता है
अगर हर Rails application में Sidekiq/Active Jobs न होते और सभी अपने custom background workers implement करते, तो reliability के मामले में Rails apps की reputation शायद आज से कहीं खराब होती
ऐसा solution चुनना चाहिए जो main goal से बहुत दूर न ले जाते हुए सबसे बड़ा benefit दे
मैंने एक startup देखा था जहाँ developers अपना लगभग 80% समय tools और infrastructure से लड़ने में लगा रहे थे। runway 3 महीने की थी, और अब उसके अंत में बस एक बड़ा गड्ढा बचा है। सोचकर आज भी सिहरन होती है
लगता है complexity के प्रति सम्मान पर्याप्त नहीं है
PostgreSQL को publish/subscribe bus के तौर पर
LISTEN/NOTIFYके साथ इस्तेमाल करते समय सबसे बड़ा नुकसान यह है किLISTENsession feature है, इसलिए यह statement-level connection pooling के साथ fit नहीं बैठताअगर यह तरीका अपनाते हैं तो advisory locks इस्तेमाल करना बेहतर है। दूसरे explicit locks database पर ज़्यादा बोझ डालते हैं, लेकिन advisory locks को जानबूझकर बहुत lightweight बनाया गया है
मेरा पसंदीदा implementation example que है, जिसे कई भाषाओं में port किया गया है
NOTIFY/LISTENपसंद न करने की एक वजह यह है कि समस्या आने पर इसे diagnose करना मुश्किल होता हैहाल ही में भी एक issue था जहाँ कुछ समय बाद सभी
NOTIFY/LISTENरुक जाते थे, और database restart करने पर ही समाधान होता था, इसलिए इसका use बंद करना पड़ा https://dba.stackexchange.com/questions/325104/error-could-n...Skype ने कई साल पहले सभी CDR प्रोसेस करने के लिए एक छोटे plugin के साथ PostgreSQL को queue के रूप में इस्तेमाल किया था। पता नहीं वे अभी भी करते हैं या नहीं, लेकिन 10 साल पहले के हिसाब से यह “web scale” था, और जब इंटरनेट पर लोग database को queue की तरह इस्तेमाल करने को anti-pattern बताकर बहस कर रहे थे, तब यह बस अच्छी तरह चल रहा था
transactions होना काफी सुविधाजनक है
https://wiki.postgresql.org/wiki/SkyTools
काम में इसे काफी इस्तेमाल किया था, इसलिए Sydpy में इस विषय पर कुछ presentations भी दिए थे। अगर आप पहले से PostgreSQL को अच्छी तरह operate और support कर रहे हैं तो यह उपयोगी है
हालांकि आज के समय में शायद मैं dedicated queue इस्तेमाल करूंगा, और RabbitMQ से जरूर बचूंगा
vendor lock-in की चिंता हो तब भी queue के basic operations असल में push/pop जैसे छोटे ही होते हैं, इसलिए जरूरत पड़ने पर migrate करना आसान रहे, ऐसा लिखना भी तुलनात्मक रूप से आसान है
अगर आपने पहले से database चल रहा है इसलिए queue भी database में डाल दी, तो यह logic दोधारी तलवार है। बधाई की बात तो नहीं है, लेकिन queue की गड़बड़ी अब primary data store को भी नीचे गिरा सकती है
PostgreSQL को application queue के रूप में इस्तेमाल करने का एक सबसे बड़ा फायदा यह है कि schedule किए गए सभी asynchronous jobs को transactionality का लाभ मिलता है
उदाहरण के लिए, signup के बाद email भेजने वाला कोई जटिल backend change है, और email भेजने का job डालने के बाद उसी transaction के बाद वाले हिस्से में failure होकर rollback हो जाता है, तो वह email job शुरू से queue में गया ही नहीं होगा
email के मामले में, अगर भेजने की confirmation का इंतजार करते हुए failure हो, तो आपको चुनना होगा कि transaction fail करके duplicate email की संभावना स्वीकार करें, या आगे बढ़कर email खो जाने की संभावना स्वीकार करें
बड़ा फायदा उन code paths से आता है जो asynchronously DB को modify करते हैं। job consumption और DB update एक ही transaction के अंदर होते हैं, इसलिए exactly-once semantics को पूरी तरह transactionally handle किया जा सकता है
PostgreSQL में एक transaction log table रखता हूं जिसमें triggered event और उस transaction का
pg_current_xact_id()होता है। row का built-inxminभी इस्तेमाल किया जा सकता है, लेकिन transaction wraparound का ध्यान रखना पड़ता है। इस row में insert करने परNOTIFYहोता हैएक background process बार-बार चलता है, और पिछले run के
xminऔर मौजूदाpg_snapshot_xmin(pg_current_snapshot())के बीच transaction IDs वाली सभी rows transaction table से चुनता है। उन events को jobs में map करके SQS में submit करता है,xminrecord करता है, फिर अगलेNOTIFYके लिएLISTENकरता हैPostgreSQL queue में email भेजने का job डालने के बाद बाद में transaction fail हो जाए तो email queue में नहीं जाएगा—यह बात सही है
database code जिसे पूरी तरह अलग होना चाहिए, उसे अलग transactions में बांटना worthwhile है। उल्टा, अगर user DB में बना ही नहीं है तो आप signup email भी नहीं भेजना चाहेंगे, इसलिए यह स्थिति पर निर्भर करता है
Redis-based queue या असल में लगभग किसी भी दूसरी queue में आप जल्दी ही ऐसी स्थिति देखेंगे जहां database record मौजूद है मानकर job चल जाता है, जबकि transaction अभी commit नहीं हुआ होता। इसे ठीक करने वाला code आमतौर पर awkward और complex हो जाता है
Kafka में मुझे जो बात पसंद है वह यह है कि यह बस append-only log है, और clients मूल रूप से सिर्फ offsets रखते हैं
conceptually समझना बहुत आसान है, persistent है और failures के खिलाफ काफी मजबूत भी है, क्योंकि आप किसी भी offset पर लौटकर फिर से पढ़ सकते हैं
दुर्भाग्य से Kafka अपनी distributed nature की वजह से पर्याप्त complexity साथ लाता है, इसलिए ज्यादातर use cases में आखिरकार उसकी कीमत वसूल नहीं होती
निजी तौर पर, अच्छा होगा अगर ऐसा ही कुछ हो जो operate करने में ज्यादा आसान हो। single node पर प्रति सेकंड सैकड़ों, शायद हजारों events handle कर सकेगा, और distributed complexity न हो तो काफी अच्छा होगा
theory में PostgreSQL से भी यह किया जा सकता है, बस rows कभी delete न करें। शायद वही answer हो सकता है
अगर consumer groups, partitions जैसी पूरी feature set की जरूरत नहीं है, तो consumer setup भी बहुत सरल हो जाएगा
Windmill में बिल्कुल यही तरीका इस्तेमाल हो रहा है। Windmill एक open-source Retool alternative और modern Airflow जैसा tool है, और हम रोज benchmarks चलाते हैं
एक ठीक-ठाक GitHub CI instance पर Windmill worker और PostgreSQL को containers में चलाने पर benchmark 1,200 jobs per second process करता है। workers जोड़ने पर यह स्थिर रूप से 5,000 jobs per second तक scale करता है
multi-tenant instance में 5,000 jobs per second की बाधा पार करने के लिए Citus इस्तेमाल करने पर विचार कर रहे हैं
https://github.com/windmill-labs/windmill/tree/benchmarks
जब प्रति सेकंड लगभग 10 messages का स्तर था, तब कुछ queues के लिए PostgreSQL इस्तेमाल किया था और वह काफ़ी scale भी हुआ। लेकिन सच कहें तो AWS, GCP, Azure में SQS या कोई दूसरा queue stack सेट करना बेहद आसान है, वे इसी उद्देश्य के लिए बने हैं, और DLQ जैसी चीज़ें भी built-in होती हैं
मुझे समझ नहीं आता कि जानबूझकर ऐसा रास्ता क्यों चुनें जिसमें यह चिंता रहे कि अगर वह system गिरा तो बाकी DB state पर भी असर पड़ेगा
“सबसे सरल tool इस्तेमाल करो” वाला सिद्धांत मुझे पसंद है, लेकिन कभी-कभी लगता है कि engineers इसे बहुत दूर ले जाते हैं, और जब mainstream विकल्प अपेक्षाकृत सस्ते और सरल होते हैं तब भी अस्पष्ट caveats वाले सबसे बेवकूफ़ tool तक ही सीमित रह जाते हैं
job state को DB में store करने से state को अच्छे से query किया जा सकता है। भले ही वह actual state को बिल्कुल सही न दिखाए, production में incidents analyze करते समय मदद मिलती है। खासकर क्योंकि ज़्यादातर job queues processed records को बस delete कर देती हैं
और अगर सभी background jobs को idempotent बनाया जाए, तो “इस job को process करने के लिए job queue में message भेजना” जैसा तरीका लगभग हमेशा safe होता है
सिर्फ़ message queue पर निर्भर रहने पर performance problem आने पर क्या हो रहा है, यह समझना अक्सर मुश्किल होता है। उदाहरण के लिए RabbitMQ queue size बता सकता है, लेकिन internal data inspect करने की सुविधा लगभग नहीं होती या बहुत सीमित होती है
कुछ software के बारे में उम्मीद की जा सकती है कि वह PostgreSQL की क्षमता से कभी आगे नहीं जाएगा, और अगर गया भी तो उसे किसी दूसरी service पर ले जाना आसान बनाया जा सकता है
और आप PostgreSQL के अंदर ही transactions वाला job system सरल तरीके से बनाना चाह सकते हैं
हम Elixir के Oban का उपयोग करके PostgreSQL के अंदर हर दिन लाखों से लेकर कई मिलियन jobs process करते हैं
transaction सफल होने पर ही email schedule करने जैसी चीज़ों के लिए background jobs के आसपास transactional semantics होना बेहद सुविधाजनक है
autovacuumकी थोड़ी tuning करनी पड़ती है, लेकिन साफ़-सुथरा कर लेने के बाद यह हमारे लिए बहुत अच्छा fit रहा