One self-hosted console to run your entire business — commerce, ERP, HRM, CRM & manufacturing

भाग 2: दो Load Balancer, दो Pool, और क्यों सिर्फ़ सर्वर जोड़ना काफ़ी नहीं था

Exam platform के application layer को कैसे rebuild किया: दो load balancer, दो autoscale pool, हर node में दो container के साथ Next.js frontend, tag-based backend, 5-8 मिनट का CPU metric lag, और 219 probe 0 error का rollout।

Author

Anichur Rahaman

5 दिन पहले13 min read8 views
भाग 2: दो Load Balancer, दो Pool, और क्यों सिर्फ़ सर्वर जोड़ना काफ़ी नहीं था

हमने DNS को नए frontend पर switch करने के एक घंटे बाद, पुराना सर्वर अब भी लगभग 36% traffic receive कर रहा था। हमने TTL को 300 seconds तक कम किया था। हमने नए setup को एक hosts-file entry से test किया था। और अब भी visitor का एक तिहाई नए सामने के दरवाज़े को skip करके सीधा चला गया, क्योंकि उनके resolver पुराने address को याद रख गए थे।

यह नंबर इसी वजह है कि पुराना सर्वर हमारा rollback तरीका alive रहा। यह भी summarize करता है यह stage: हर कदम कागज़ पर simple दिखता था, और हर कदम एक measured surprise छुपाता था।

Part 1 में हमने पाया कि हमारे पहले bottleneck एक rate limiter और Valkey connection का एक flood था, सर्वरों की कमी नहीं। सिर्फ़ उसके बाद ज़्यादा सर्वर add करना सही tool बन गया, और यहाँ भी इसे एक architecture की ज़रूरत थी। यह article इसे cover करता है: दो load balancer, दो autoscale pool, एक rebuilt frontend, एक backend जहाँ कोई भी node replace किया जा सकता है, और एक deploy method जो request drop नहीं करता। उस method के पहले version ने किया था।

यह "From One Server to Exam-Day Ready" five-part case study का हिस्सा 2 है। NovaCommerce एक काल्पनिक नाम है; architecture, संख्याएँ और गलतियाँ वास्तविक हैं।

क्यों ज़्यादा सर्वर पहला जवाब नहीं था

Part 1 में bottleneck तीन बार moved। पहले एक rate limiter जो विद्यार्थियों को IP से गुन रहा था, तो एक पूरा school एक bucket share करता था और HTTP 429 पाता था। फिर Valkey, जहाँ एक load test 2,854 application error दे गया क्योंकि हर request ने Valkey को एक fresh TLS connection खोला जो accept नहीं कर सकता था। सिर्फ़ तीसरा, plain backend CPU, वह है जो ज़्यादा सर्वर solve करते हैं: एक 4 vCPU / 8 GB node लगभग 65 to 70 requests per second के real API mix को serve करता है।

पहले दोनों में nodes add करना इन्हें ख़राब करता। हर नया node same limiter code चलाता और Valkey को same अपने connections खोलता। हम ज़्यादा सर्वर के लिए pay करते और same error faster देखते। तो यह article तीसरे bottleneck के बारे में है, सही से किया गया।

दो load balancer, एक नहीं

हमारा पहला sketch सब कुछ के लिए एक single load balancer इस्तेमाल करता था। एक दो से सस्ता है, और देखभाल के लिए कम होता है। Status: Considered, फिर Rejected।

एक DigitalOcean load balancer host name या URL path से route नहीं कर सकता, और हर एक exactly एक tag को target करता है, जिसका मतलब एक group server। Frontend और backend node अलग group हैं, अलग size, health check और scaling rules के साथ। एक reception desk है जो हर visitor को rooms की same list देता है।

DNS ने पहले से website और API को अलग domain में split किया था, तो split free आया: एक load balancer per tier, हर एक अपने pool के सामने। Status: Implemented। दोनों together $48 एक महीने में cost करते हैं।

कोई warm pool नहीं, तो हमने kitchen में cooks को रखा

शुरुआत में हमने एक attractive requirement लिख दिया: एक warm standby जो 3 to 4 seconds में traffic ले सके। यह यहाँ exist नहीं करता। DigitalOcean autoscale pool के पास कोई warm pool नहीं है, और एक नया droplet minutes चाहिए created, booted, checked और load balancer द्वारा admitted होने के लिए। एक taxi आपके door पर idle खड़ी आपको call करने वाली taxi से एक अलग product है।

तो हमने दो boring चीज़ें किएं।

  • Spare capacity जो पहले से ही serve कर रहा है। दोनों pool के पास 2 node का minimum है, और दोनों load balancer के अंदर पूरे समय बैठे हैं। एक खोने से दूसरा already traffic ले रहा है।
  • Pre-scaling। एक बड़े exam से लगभग 45 मिनट पहले हम pool minimum raise करते हैं, तो extra node boot, checked और serve करने वाले हैं पहले से ही जब पहला विद्यार्थी Start click करता है। एक extra backend node लगभग $0.08 per hour cost करता है।

हमने Kubernetes (DOKS) भी consider किया seconds-level scaling के लिए। इसका मतलब चलाने के लिए बहुत अधिक होता, तो हमने इसे बाद के लिए छोड़ दिया। Status: Considered, not implemented।

Frontend: आठ CPU और एक cashier

पुराना frontend एक 8 vCPU / 16 GB droplet था एक Next.js container चला रहा, TLS droplet पर certbot से, और कोई load balancer नहीं। अगर यह मरता, तो site down होता। यह भी quietly पैसे बर्बाद कर रहा था: एक Node.js process लगभग एक core पर render करता है, तो उन आठ CPU में से ज़्यादातर कुछ नहीं करते। एक supermarket आठ checkout counter के साथ और एक cashier।

नया design कई छोटे, identical nodes चलाता है एक बड़े की जगह। Figure 1 पूरी application layer दिखाता है; हम बाएँ से चलते हैं।

Architecture diagram: विद्यार्थी एक frontend load balancer और एक frontend autoscale pool को reach करते हैं जिसके nodes हर एक nginx और दो Next.js container चलाते हैं; API call एक backend load balancer और एक backend pool को जाती हैं जिसके nodes nginx और php-fpm चलाते हैं; managed data service और एक fixed worker दोनों pool के बाहर बैठते हैं
दो tier, हर एक के साथ अपना load balancer और pool। Worker दोनों pool के बाहर एक fixed server है।

एक frontend node

हर node nginx चलाता है दो identical Next.js container के सामने, एक per vCPU। Settings जो मायने रखते हैं:

  • Container port सिर्फ़ localhost को bind होते हैं, तो सिर्फ़ nginx एक container को reach कर सकता है।
  • nginx दोनों container के बीच balance करता है least_conn से: हर request fewest active connection वाले container को जाता है।
  • हर container के पास 1.5 GB memory cap है, restart: always और rotating log।
  • nginx real client IP load balancer से लेता है, तो per-student limit काम करते हैं हर किसी को एक address देखने की जगह।
  • एक micro-cache static file, image और home page serve करता है बिना Next.js को wake किए।
  • /lb-health सिर्फ़ pass करता है जब Next.js answer दे, तो एक node एक dead app के साथ rotation से निकलता है यहाँ तक कि nginx alive है।

HTTPS frontend load balancer पर ख़त्म होता है, और cloud firewall एक frontend node को सिर्फ़ port 80 accept करने दे private network पर load balancer से।

DNS switch करना, एक way back के साथ

हमने नया frontend पुराने server के बगल में build किया और इसे अपने ही machines पर hosts-file entry से test किया, तो real domain हमारे लिए नए load balancer पर point करता था और और कोई नहीं। हमने 12 real page पुराने server के साथ compare किए, DNS TTL को 300 seconds तक कम किया और switch किया।

पुराना server rollback के लिए रहा, क्योंकि DNS को back point करना पूरी undo होती। हमने इसे उससे लंबा चाहिए: एक घंटा बाद यह अब भी लगभग 36% traffic cached DNS से receive कर रहा था। एक TTL एक request है, एक order नहीं। Server को जल्दी destroy करना लगभग एक तिहाई visitors को एक address भेजता जो अब answer नहीं दे रहा।

Load test, और एक सस्ता node

दो frontend node लगभग 356 requests per second serve करते थे p95 के साथ 0.05 seconds और 0 error, 55 to 60% CPU पर। Pool पहले dedicated-CPU droplet इस्तेमाल करता था। वह test headroom दिखाता था, तो हमने shared AMD droplet 2 vCPU / 4 GB के साथ move किए, लगभग $28 एक महीने में हर एक। एक measurement, guess नहीं, सस्ते node को safe बनाता था।

पहलेअब
Server1 droplet, 8 vCPU / 16 GB, 1 Next.js container2 to 10 node का Pool, 2 vCPU / 4 GB shared AMD, 2 container हर एक
अगर एक server मरेSite down हैदूसरा node serve करते रहता है
2 node के साथ MeasuredRendering लगभग एक core तक limited हैलगभग 356 request/s, p95 0.05 s, 0 error, CPU 55 to 60%

Backend: droplet ID से एक tag तक

पहले, backend load balancer दो droplet को ID से point करता था। एक तीसरा server कभी अपने आप join नहीं कर सकता, क्योंकि load balancer सिर्फ़ दो नाम जानता था। हमने target को ID से tag में बदला। एक guest list और staff badge के बीच का फ़र्क़ है: badge पहनने वाला कोई भी अंदर आता है।

Change एक API update था जो load balancer की हर दूसरी setting को रखता था, switch के दौरान 0 error के साथ। फिर से, कोई भी pool बनाता है tag ले जाता है, load balancer पर अपने आप join करता है, और same tag-based firewall और database access rule के अंतर्गत गिरता है। HTTPS end to end चलता है: load balancer private network पर हर backend को re-encrypt करता है। हर node एक golden snapshot से boot करता है।

Frontend poolBackend pool
Node2 vCPU / 4 GB shared AMD, लगभग $28 एक महीने में4 vCPU / 8 GB, लगभग $56 एक महीने में
Minimum / maximum2 / 102 / 10
Scale-out rule70% average CPU, cooldown 5 मिनट70% average CPU (बाद में 55%), cooldown 5 मिनट
Health check/lb-health pass करता है जब Next.js answer दे/lb-health nginx alone द्वारा answered

Stateless node, और वह एक server जो नहीं है

Web node पहले से ही stateless थे, और हमने फिर से check किए इससे पहले pool को trust करने से। Sessions, cache और queue managed Valkey में रहते हैं, log stderr को जाते हैं, और upload, written-answer PDF सहित, Spaces object storage में जाते हैं। 7 अक्टूबर को हमने verify किया: backend node ने 24 घंटे में 0 file disk में लिखे। यही वजह है कि कोई भी node किसी भी समय delete किया जा सकता है।

हर backend node सिर्फ़ web (nginx) और app (php-fpm) चलाता है। Queue, scheduler, WebSocket server और OMR web node पर switch off हैं, तो extra server कभी एक job दो बार नहीं चलाते। वे सब एक single fixed worker पर रहते हैं दोनों pool के बाहर, एक known single point of failure जो Part 4 return करता है।

Health check और draining

Backend पर, /lb-health nginx अकेले द्वारा answered है और कभी framework boot नहीं करता, तो health check PHP या database से slow नहीं हो सकता। यह भी हमें एक drain switch देता है। एक node को service से निकालने के लिए, हम /lb-health को 503 return करते हैं। Load balancer लगभग 30 seconds में इसे नए request भेजना बंद करता है, और पहले से ही running request normally finish होते हैं।

Autoscale test और five-minute lie

5 अक्टूबर को, 21:17 और 21:33 के बीच, हमने autoscaling अपने आप को test किया। k6 ने real exam-peak request mix replay किया, सिर्फ़ GET request तो कुछ नहीं लिखा गया: 300 to 450 requests per second, फिर लगभग 750 requests per second 6 मिनट के लिए।

हमने क्या देखाResult
Backend pool21:29 पर 2 to 3 node, जब pool average 75% तक पहुँचा
Frontend pool21:30 पर 2 to 3 node, 71% पर
Error और timeout0 server error, 0 timeout; नए node अपने आप load balancer में join किए
Overall p95132 to 153 ms
API p95320 to 705 ms, जबकि backend 90% के पास बैठा तीसरे node के join करने से पहले
HTTP 429लगभग 4%: सब load एक test IP से आया, तो per-IP limit अपना काम करते थे

API p95 को देखें, 320 to 705 ms। यह waiting की क़ीमत है। Backend 90% CPU के पास बैठा तीसरे node join होने तक, क्योंकि DigitalOcean का CPU metric real load से 5 to 8 मिनट से lag करता है। पहले backend test में, पहला extra node लगभग 7 मिनट बाद appear हुआ CPU 99% को hit करने के बाद। Autoscaler broken नहीं है। यह पुरानी खबर पढ़ रहा है।

Lag दूसरी direction में भी काम करता है। जब load stop हुआ, metric अब भी high लग रहा था, और backend briefly 4 node scale किया। यह एक shower tap है: आप further turn करते क्योंकि कुछ अभी नहीं बदला, और फिर hot water एक साथ आती है।

Schematic chart: real load t0 पर step up करता है, CPU metric सिर्फ़ 5 to 8 मिनट बाद catch up करता है, तीसरा node join करता है metric crossing target के बाद, और चौथा node add होता है load के बाद यह पहले से ही stop हो चुका है
Load एक step है, metric एक slow curve है, और autoscaler curve को follow करता है। Effect का schematic, एक recording नहीं।

General argument Autoscaling for Traffic Spike में है; यहाँ इसके पीछे हमारे अपने नंबर हैं। एक scheduled exam के लिए हम minimum को लगभग 45 मिनट पहले raise करते हैं और सिर्फ़ बाद में lower करते हैं। Autoscaling safety net के रूप में on रहता है unplanned के लिए। Test का Status: Tested।

Replacing द्वारा deploy, कभी editing द्वारा नहीं

Pool node disposable हैं, तो कोई भी एक को hand edit नहीं करता: यह अगले scale-in पर vanish होगा, और अगला नया node snapshot से boot होगा, edit से नहीं। हमारा flow:

  1. एक node change करो और test करो।
  2. इसका एक snapshot लो।
  3. Pool template को snapshot पर point करो।
  4. DigitalOcean नए node create करता है, फिर पुराने को delete करता है।

हम last 3 अच्छे image rollback के लिए रखते हैं और कभी template को exam hours के दौरान roll नहीं करते। हम pool update पर हर setting pass करते हैं, तो कुछ silently reset नहीं होता। Account की droplet limit को 25 पर भी raise करना पड़ा दोनों pool अपने maximum तक reach करने से पहले rollout के दौरान, जब old और new node एक साथ exist करते हैं।

503 blip, और guarded rollout

पहला backend rollout एक plain template change था, और यह 503 error का एक short burst produce किया। DigitalOcean पुराने droplet delete कर रहा था जबकि load balancer अब भी उन्हें requests route कर रहा था। पुराने dining room को close करने जैसे है जबकि host अब भी guest को वहाँ seat कर रहा है।

Fix provider के event order पर rely करना बंद करना और rollout को एक guarded sequence के रूप में run करना था। Figure 2 इसे दिखाता है।

Guarded rollout का timeline पाँच step में: सिर्फ़ image change करो, हर नए node के /lb-health pass करने का wait करो, लगभग 40 second का wait करो, पहले old node drain करो, फिर provider उन्हें delete करता है; नीचे, lane पुराने node को show करते हैं serving, draining और गए हुए जबकि नए node boot, wait और serve करते हैं
पुराने node delete होने से पहले drain किए जाते हैं, तो load balancer एक node को request भेजता जो disappear होने वाला है।
  1. Pool template पर सिर्फ़ image change करो।
  2. हर नए node के /lb-health को answer देने तक wait करो।
  3. Load balancer को उन्हें admit करने के लिए लगभग 40 seconds के लिए wait करो।
  4. पुराने node drain करो पहले: उनका /lb-health 503 return करता है।
  5. DigitalOcean पुराने node अपने cooldown के बाद remove करता है, कुछ serve करने के लिए बचा हुए नहीं।

7 अक्टूबर पर दोनों pool का later full rollout real page पर हर 2 second एक uptime probe के साथ run किया। Result: 219 probe और 0 error। Status: Tested, फिर fixed।

हर node पर Swap और hardening

Memory frontend पर quiet risk था। उन node के पास कोई swap नहीं था, और हर container लगभग 1.5 GB एक 4 GB node का use कर सकता है। 7 अक्टूबर को हमने एक 2 GB swap file add किया swappiness 10 के साथ, तो kernel RAM prefer करता है, और इसे frontend image में baked किया। Backend node के पास पहले से ही 4 GB swap। हर node पर hardening को भी same set of change cover किया।

Areaक्या in place है
AccessKey-only SSH और सब node पर Fail2Ban
NetworkCloud firewall by tag: frontend node सिर्फ़ port 80 accept करते हैं उनके load balancer से; backend node 80 और 443 सिर्फ़ अपने से
ProcessContainer अपने request-serving process non-root user के रूप में चलाते हैं
SecretSecret env file mode 600 के साथ
DatabaseApp user को सिर्फ़ SELECT, INSERT, UPDATE और DELETE है, कोई DDL नहीं

Firewall tag को follow करते हैं, तो एक node जो pool midnight में create करता है अपने rule लगता है moment यह exist करता है। कोई को कुछ याद नहीं रखना पड़ता। Status: Implemented 7 अक्टूबर को।

हमने क्या सीखा

  • Server add करना architecture नहीं है। Limiter और Valkey को एक code change और data-tier fix की जरूरत थी; ज़्यादा node सिर्फ़ problem copy करते।
  • कोई warm pool? Warmth अपने आप build करो। Spare capacity पहले से ही serve करता है, plus एक raised minimum लगभग 45 मिनट एक बड़े exam से पहले।
  • Scheduled exam के लिए Pre-scale करो। CPU metric 5 to 8 मिनट से lag करता है, तो reactive autoscaling safety net है, plan नहीं।
  • Node को disposable बनाओ। Stateless web node, ID की जगह tag, image से replace करके edit नहीं।
  • Delete करने से पहले drain करो। Guarded rollout एक procedure है, hope नहीं: 219 probe, 0 error।
  • पुरानी चीज़ जब तक traffic अपने को छोड़ देता है। TTL एक request है; एक घंटा बाद पुराने server के पास अब भी 36% था।

एक और rule, एक real exam evening पर सीखा गया और एक बाद में बताया गया: scale-in अपने आप drain नहीं करता।

जहाँ हर piece stands

PieceStatus
दो load balancer, दो autoscale pool, golden-image deploy, swap और hardeningImplemented
लगभग 750 requests/s पर autoscale test; पहला rollout और इसका 503 blipTested, फिर fixed
दोनों tier के लिए एक load balancerRejected
Second में warm standby; Kubernetes (DOKS)Considered; DOKS later के लिए
CDN से Static asset; Frontend node पर Fluent Bit, जिसका nginx log node के साथ vanish हो जाते हैंPlanned

Application layer अब grow कर सकता है और बिना किसी को notice किए replace किया जा सकता है। अगला सवाल क्या एक विद्यार्थी का answer survive करता है: database। Part 3 में हम MySQL को एक planned 26-minute window में move करते हैं, और हम legacy admin panel से मिलते हैं जो गलत database को write कर रहा था।

About the Author

Anichur Rahaman

Continue Reading