7 पॉइंट द्वारा GN⁺ 2024-09-03 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • डिस्ट्रिब्यूटेड सिस्टम की मुख्य कठिनाई latency से ज्यादा partial failure है, और एक मशीन पर साधारण exception handling भी कई मशीनों में protocol design का हिस्सा बन जाती है
  • मजबूत डिस्ट्रिब्यूटेड सिस्टम में ऐसे bugs होते हैं जो असल में कई मशीनों, datacenter network conditions और बड़े datasets में ही सामने आते हैं, इसलिए इनकी लागत single-machine system से ज्यादा होती है
  • चलाने लायक system बनाने के लिए coordination घटानी और independence बढ़ानी चाहिए, और backpressure, partial availability, metrics व percentile indicators को बुनियादी tools बनाना चाहिए
  • feature flags, ID space design, data locality और service extraction, migration और scaling के दौरान failure scope और coordination cost कम करने की practical techniques हैं
  • CAP theorem system बनाने का शुरुआती बिंदु होने से ज्यादा design critique tool जैसा है, और distributed systems में technical problems जितनी ही team और organization के बीच social coordination भी कठिन होती है

डिस्ट्रिब्यूटेड सिस्टम पहली बार सीखते समय जिन बातों को चूकना आसान है

  • distributed systems engineers के कई सबक production traffic में हुई गलतियों और operational scars से आते हैं, लेकिन शुरुआती engineers को ज्यादा सीधे और actionable context की जरूरत होती है
  • Fallacies of Distributed Computing और CAP theorem self-learning में मददगार हैं, लेकिन कम अनुभव वाले engineer के लिए तुरंत काम शुरू करने के लिहाज से ये abstract हैं
  • distributed systems में ज्यादा machines और capital की जरूरत होती है, इसलिए ज्यादा teams और बड़े organizations के जुड़ने की संभावना रहती है
    • social problems आम तौर पर software developers के काम का सबसे कठिन हिस्सा होते हैं, और distributed systems development में ये खास तौर पर उभर सकते हैं
    • कभी-कभी social solutions, technical solutions से ज्यादा efficient और satisfying होते हैं, लेकिन background, education और experience engineers को technical solutions की ओर झुका देते हैं

failure और cost को मानकर design करना

  • distributed systems अक्सर fail होते हैं, और उससे भी बुरा, वे partially fail होते हैं
    • single process में mutex unlock failure हो तो process crash कराना पर्याप्त हो सकता है, लेकिन distributed mutex में unlock failure को lock protocol के अंदर शामिल करना पड़ता है
    • “दोनों machines पर write भेज दो” या “success होने तक retry करो” वाला तरीका उस स्थिति को पर्याप्त रूप से नहीं संभालता जहां एक तरफ write सफल हो और दूसरी तरफ fail हो जाए
    • switch failure, GC pause की वजह से leader गायब होना, successful दिखने वाली socket write का remote failure, या एक slow disk से पूरे cluster communication protocol का धीमा पड़ जाना जैसी स्थितियां बनती हैं
  • मजबूत distributed solution की लागत single-machine solution से ज्यादा होती है
    • कुछ failures केवल कई machines पर ही होते हैं, और VM व cloud लागत कम करते हैं, लेकिन वे पहले से मौजूद एक computer पर design, implement और test करने जितने सस्ते नहीं होते
    • dataset size जो shared machine में रखना मुश्किल हो, या datacenter network conditions में ही दिखने वाले failures के लिए असली distributed environment चाहिए
    • simulation उपयोगी है, लेकिन distributed system bugs की पूरी जगह नहीं ले सकती
  • मजबूत open source distributed systems, मजबूत single-machine systems की तुलना में कहीं ज्यादा दुर्लभ हैं
    • कई machines को लंबे समय तक चलाने की लागत open source community पर बोझ बनती है
    • hobby developers और dilettantes अपने पास मौजूद machines और खाली समय से open source बनाते हैं, इसलिए कई machines चलाने, maintain करने और उनका खर्च उठाने वाले developers ढूंढना कठिन है
    • corporate engineers कुछ gaps भरते हैं, लेकिन उनके organization की priorities users के organization की priorities से मेल न खा सकती हैं

coordination घटाना और failures absorb करना

  • machines के बीच coordination से जहां तक हो सके बचना चाहिए
    • horizontal scalability का core यह है कि data को इतना independently रखा जाए कि machines को आपस में communicate और agree करने की जरूरत न्यूनतम हो
    • जब भी दो machines को किसी चीज पर agree करना पड़े, service implementation और कठिन हो जाता है
    • information transfer की speed की एक upper bound होती है, network communication अपेक्षा से ज्यादा unreliable होता है, और consensus के बारे में intuitions गलत हो सकती हैं
    • Two Generals, Byzantine Generals, और Paxos implementation की कठिनाई को समझना मददगार है
  • अगर समस्या memory में fit हो जाती है, तो distributed systems engineer के लिए वह आम तौर पर trivial problem के करीब होती है
    • जब data कुछ pointer hops के बजाय कुछ switches के पार हो, तो उसे तेजी से process करना ज्यादा कठिन होता है
    • single-machine algorithms और implementations भरपूर हैं, लेकिन distributed systems के लिए literature और implementations कहीं कम हैं
  • “slow है” debug करने की सबसे कठिन समस्या है
    • user request में शामिल कई systems में से एक या अधिक slow हो सकते हैं, या कई machines से गुजरने वाली transformation pipeline का कोई हिस्सा slow हो सकता है
    • problem description खुद defect location के बारे में बहुत कम clues देता है, और सामान्य graphs में न दिखने वाला partial failure छिपा हो सकता है
    • performance degradation बहुत स्पष्ट होने तक time, money और tools जैसे resources पर्याप्त रूप से मिलना कठिन होता है
    • Dapper और Zipkin इसी वजह से बनाए गए
  • पूरे system में backpressure implement करना चाहिए
    • backpressure वह तरीका है जिसमें service देने वाला system requesting system को failure signal करता है, और requesting system उस failure को handle करके खुद और सामने वाले system को overload से बचाता है
    • overload या system failure के दौरान resource usage limit करना मजबूत distributed system का बुनियादी building block है
    • implementation अक्सर resource constrained होने या failure होने पर नए messages drop करने या user को error लौटाने के रूप में होती है, और दोनों cases में metrics increment होने चाहिए
    • दूसरे systems के connections और requests के लिए timeouts और exponential backoff जरूरी हैं
    • backpressure न हो तो cascading failure या unintended message loss आसानी से हो सकता है
  • partial availability देने का तरीका खोजना चाहिए
    • partial availability वह क्षमता है जिसमें system का कुछ हिस्सा fail होने पर भी कुछ results लौटाए जा सकें
    • search system results quality और user को wait कराने के समय के बीच trade-off करता है, और time limit गुजरने पर केवल collected results लौटा सकता है
    • private messaging में कुछ users के लिए ही outage होना, सभी users के कुछ messages गायब होने से बेहतर हो सकता है
    • यह तय करना होगा कि private messaging failure का public image upload जैसी unrelated feature पर असर न पड़े, इसके लिए failure domains को कितना अलग किया जाए

observation, capacity और deployment को operational tools बनाना

  • metrics, production में system वास्तव में क्या कर रहा है, यह जानने का essential means हैं
    • latency percentiles, किसी खास behavior के increment counters, और rate of change जैसे metrics, system behavior के बारे में आपके विश्वास और असल behavior के बीच gap घटाते हैं
    • 20वें दिन system behavior 15वें दिन से कैसे अलग है, यह जानना successful engineering और failed ritual के बीच फर्क करता है
    • metrics problems और behavior समझने के लिए जरूरी हैं, लेकिन आगे क्या करना है यह बताने के लिए पर्याप्त नहीं हैं
  • log files उपयोगी हैं, लेकिन झूठ बोलना आसान है
    • कुछ error classes के logs file space का बड़ा हिस्सा ले सकते हैं, फिर भी real request ratio कम हो सकता है
    • success logs अधिकतर redundant होते हैं और disk भर सकते हैं, और engineers अक्सर गलत अनुमान लगाते हैं कि कौन से error logs उपयोगी होंगे
    • logs ऐसे छोड़ना बेहतर है मानो उन्हें कोई ऐसा व्यक्ति पढ़ेगा जिसने code कभी नहीं देखा
    • logs में दिखी अजीब बात को metrics से confirm किए बिना overestimate करने पर outage लंबा हो सकता है
  • average के बजाय percentiles इस्तेमाल करने चाहिए
    • 50th, 99th, 99.9th, 99.99th percentiles ज्यादातर distributed systems में average से ज्यादा accurate और useful हैं
    • average यह मानता है कि evaluation metric bell-shaped distribution follow करता है, लेकिन engineers जिन metrics को important मानते हैं उनमें ऐसा बहुत कम होता है
    • अगर distributed system latency bell-shaped distribution follow नहीं करती, तो average latency गलत decision-making और understanding की ओर ले जाती है
  • capacity estimation की skill सीखनी चाहिए
    • किसी काम के लिए कितनी machines चाहिए यह जानना long-lived system और 3 महीने में replace करने वाले system के बीच फर्क करता है
    • 2012 के अंत के हिसाब से एक typical machine में 24GB memory होती है, OS को 4–5GB, request handling को कम से कम कुछ GB चाहिए, और tweet id 8 bytes का होता है—ऐसी rough calculations जरूरी हैं
    • Jeff Dean का Numbers Everyone Should Know expectations set करने में मदद करता है
  • feature flags infrastructure rollout करने का तरीका हैं
    • feature flags सिर्फ frontend A/B testing ही नहीं, infrastructure replacement में भी बहुत powerful होते हैं
    • “big cutover” तरीके में देर से मिले bugs के कारण rollback करना पड़ता है, और ऐसे कई projects fail हुए हैं
    • single database से नए storage को छिपाने वाली service पर जाते समय, नई service की ओर write parallel transmission धीरे-धीरे बढ़ाई जा सकती है, backfill पूरा होने के बाद read को user response में इस्तेमाल किए बिना test किया जा सकता है, old और new system reads की तुलना की जा सकती है, फिर real reads को धीरे-धीरे बढ़ाया जा सकता है
    • समस्या आने पर flag value घटाकर या 0 करके तुरंत वापस लौटा जा सकता है, और traffic volume adjust करते हुए debugging और experiments किए जा सकते हैं
    • feature flags code के अंदर local complexity को global simplicity और resilience से exchange करने वाला trade-off हैं
    • यह स्वीकार करना होगा कि infrastructure और data के कई versions exception नहीं, बल्कि normal हैं

data model और boundary design

  • ID space system का shape तय करता है
    • data के किसी item तक पहुंचने के लिए जितने ज्यादा IDs चाहिए, data partitioning के उतने ज्यादा choices मिलते हैं
    • data के किसी item के लिए जितने कम IDs चाहिए, system output consume करना उतना आसान होता है
    • Twitter API v1 tweet को single 64-bit numeric ID से query, create और delete करता था, और यह ID दूसरे data से linked नहीं था
    • tweets की संख्या बढ़ने पर एक ही user के tweets को एक ही machine में store करके user tweet timeline और subscription timeline efficiently बना सकते हैं, लेकिन public API ने हर tweet को सिर्फ tweet id से addressable बना दिया था, इसलिए यह जानने वाली lookup service चाहिए थी कि कौन सा user किस tweet id का मालिक है
    • alternative के रूप में tweet lookup के लिए user id मांग सकते हैं, या tweet id में ही user id शामिल कर सकते हैं, लेकिन बाद वाले की cost यह है कि tweet id अब k-sortable numeric नहीं रहता
    • ID structure private data de-anonymization, unexpected crawling, auto-increment ID problems, और Insecure Direct Object References जैसे attacks को प्रभावित कर सकता है
  • data locality का लाभ उठाना चाहिए
    • data processing और caching को persistent storage के जितना पास रखा जाए, processing उतनी efficient होती है और cache consistency व speed बनाए रखना आसान होता है
    • network में pointer dereference या fread(3) की तुलना में failures और latency ज्यादा होते हैं
    • locality केवल space पर नहीं, time पर भी लागू होती है
    • अगर कई users लगभग एक ही समय पर वही महंगा request करते हैं, तो उन्हें एक में merge किया जा सकता है, और अगर एक ही तरह के data requests समय में करीब-करीब आते हैं, तो उन्हें एक बड़े request में batch किया जा सकता है
    • यह तरीका communication overhead घटाता है और failure management को आसान बनाता है
  • cached data को persistent storage में वापस लिखना खराब है
    • खासकर distributed systems का कम अनुभव रखने वाले लोगों द्वारा पहली बार design किए गए systems में यह defect दिख सकता है
    • “Russian-doll caching” कहने वाले implementation में noticeable bugs मिलने की संभावना ज्यादा है
    • आम symptom यह है कि user information, जैसे screenname, email, hashed password, पुराने values पर वापस लौट जाते हैं
  • computers अपेक्षा से ज्यादा काम कर सकते हैं
    • 2012 के अंत का हल्का web server भी 6 से अधिक processors, 24GB memory और बहुत बड़ा disk space रखता है
    • modern language runtime की अपेक्षाकृत complex CRUD application भी single machine पर कुछ सौ milliseconds में हजारों requests per second handle कर सकती है
    • ज्यादातर cases में प्रति machine सैकड़ों requests per second operational capability के लिहाज से गर्व करने लायक संख्या नहीं है
    • application को profile करके और measurement-based optimization लागू करके ज्यादा performance पाना बहुत कठिन नहीं है
  • CAP theorem को system बनाने की विधि नहीं, बल्कि design critique tool के रूप में इस्तेमाल करना चाहिए
    • CAP theorem बहुत general है और possible solution space बहुत बड़ा है, इसलिए first principle बनाकर working system निकालने के लिए उपयुक्त नहीं है
    • system design पर CAP sub-systems पर जो constraints लगाता है, उनकी बार-बार समीक्षा करने से बेहतर design तक पहुंचा जा सकता है
    • C, A, P में से CA choose नहीं कर सकते
  • services extract करने से encapsulation और deployment के फायदे मिलते हैं
    • यहां service से मतलब ऐसे distributed system से है जिसमें storage system से higher-level logic हो और आमतौर पर request-response style API हो
    • यह लगातार देखना चाहिए कि कोई specific code system के अंदर न होकर अलग service में हो तो change करना आसान होगा या नहीं
    • extracted service library की तरह encapsulation देती है, साथ ही client system की library upgrade करने की तुलना में changes deploy करना तेज और आसान बना सकती है
    • छोटी services में code और operational dependencies कम होती हैं, और strict boundaries उन shortcuts को घटाती हैं जो library में allow हो जाते हैं
    • कई client systems होने पर shared library में हर client deployment coordinate करना पड़ता है, और अगर data corruption deployment order पर निर्भर होकर हो सकता है तो यह और कठिन हो जाता है
    • client system maintainers अलग हों तो priorities match न होने से upgrade approval पाने की social coordination cost भी बढ़ जाती है
    • typical use case है बदलते storage layer को एक ज्यादा convenient और small-surface-area API वाली service के पीछे छिपाना

1 टिप्पणियां

 
GN⁺ 2024-09-03
Hacker News टिप्पणियाँ
  • लेख में CALM (तार्किक monotonicity के रूप में consistency) को ज़रूर कवर करना चाहिए था। यह CAP से कहीं ज़्यादा समझने में आसान और अधिक बुनियादी परिणाम है, और कम अनुभव वाले लोगों को भी बहुत मज़बूत distributed systems बनाने में मदद करता है
    idempotency, CRDT, WAL, Raft — ये सभी CALM सिद्धांत के विशेष मामले हैं
    https://arxiv.org/pdf/1901.01930

    • वह पेपर इस लेख के 6 साल बाद आया था
    • bloom repository देखकर लगता है कि वह काफ़ी ठहरा हुआ है; उत्सुकता है कि उस पर अब भी काम जारी है या नहीं
  • यहाँ यह बात छूट गई, लेकिन एक सामान्य सिद्धांत के तौर पर मुझे पसंद है: exactly-once delivery असंभव है
    at-most-once या at-least-once संभव हैं, लेकिन आपको चुनना होगा कि किस तरह की failure mode स्वीकार करनी है और उसी के हिसाब से design करना होगा

    • हाँ, इसका मतलब दो distributed systems के बीच है जो एक ही transaction domain share नहीं करते या तार्किक रूप से monotonic नहीं हैं
      किसी clustered database में डेटा की एक row को दूसरी row में ले जाना संभव है, और इसे message delivered होने के रूप में भी समझा जा सकता है
      अगर पूरा system idempotent है, या पूरे distributed system को rollback किए जा सकने वाले single unit की तरह treat किया जा सकता है, तो exactly-once delivery मिल सकती है। यानी domain के बाहर किसी दूसरे system पर side effect नहीं होना चाहिए
      दोनों ही एक तरह की तार्किक monotonicity हैं। idempotency पहचानना आसान है, और transactionality भी WAL और Raft जैसे algorithms के ज़रिए monotonicity पर आधारित है
      लेख में CALM (तार्किक monotonicity के रूप में consistency) को कवर करना चाहिए था। यह CAP से कहीं ज़्यादा समझने में आसान और अधिक बुनियादी परिणाम है
      https://arxiv.org/pdf/1901.01930
    • अपने करियर में मैंने distributed systems design करते समय बहुत से engineers देखे हैं जिन्हें यह concept पता नहीं था, और इस पर जितना ज़ोर दिया जाए कम है
    • arbitrary स्तर की network failures वाले environment में at-least-once delivery भी असंभव है
    • इस सीख का अहम हिस्सा यह है: “और सच तो यह है कि इसकी ज़रूरत भी नहीं होती”
    • Apache Flink उन data sources और data sinks के साथ इस्तेमाल होने पर end-to-end exactly-once guarantees देता है जो checkpoint mechanism में भाग लेते हैं
      An Overview of End-to-End Exactly-Once Processing in Apache Flink (with Apache Kafka, too!) — https://flink.apache.org/2018/02/28/an-overview-of-end-to-en...
      Flink's Fault Tolerance Guarantees — https://nightlies.apache.org/flink/flink-docs-release-1.20/d...
  • “अगर समस्या memory में fit हो सकती है, तो शायद वह trivial है” के corollary के तौर पर, memory में fit हो सकने वाली सीमा आपकी सोच से कहीं ज़्यादा बड़ी है
    मुझे लगता था कि मुझे पता है बड़ी RAM क्या होती है, लेकिन जब बड़े cloud providers ने SAP HANA के लिए 12TB VM देने शुरू किए, तो मेरी सोच बदल गई
    लेख में भी “computers आपकी सोच से ज़्यादा काम कर सकते हैं” के रूप में इसे बहुत संक्षेप में छुआ गया है, लेकिन वहाँ सिर्फ़ 24GB machine की बात है। 2012 का संदर्भ मान भी लें, तब भी उस समय 10 गुना RAM वाली machines काफ़ी रही होंगी

    • अपेक्षाकृत senior engineers भी यह गलती काफ़ी बार करते हैं। अगर किसी SaaS में प्रति customer analytics data अधिकतम 100GB है, तो अंततः sharded Postgres ही पर्याप्त होगा
  • मैं यह document अपने साथ काम करने वाले सबसे promising लोगों के साथ share करता हूँ
    Lookout में काम करते समय Jeff Hodges ने यह essay एक presentation के रूप में share किया था, और अंत में “यह दिखावा मत करो कि engineering political नहीं है” वाला corollary जोड़ा था
    जो लोग सोचते हैं कि code अपने आप बोलता है, वे इस बात का एक अहम पहलू छोड़ देते हैं कि कुछ कैसे बनेगा, उस पर प्रभाव कैसे पड़ेगा और वास्तविक परिणाम कैसे मिलेंगे
    10 साल बाद भी बहुत कम लोग engineering leadership और आम तौर पर SRE/DevOps की basic capabilities मानी जाने वाली चीज़ों के overlap को इतनी संक्षिप्तता से समझते हैं

    • अगर इस विषय पर पढ़ने लायक कोई और अच्छे resources हों, तो जानना चाहूँगा
  • पुरानी चर्चाएँ
    https://news.ycombinator.com/item?id=5055371
    346 points|jcdavis|12 years ago|42 comments
    https://news.ycombinator.com/item?id=12245909
    386 points|kiyanwang|8 years ago|133 comments

  • शानदार list है, और practical व realistic explanation अच्छी है। कोई buzzwords नहीं, “microservices” भी नहीं
    मेरे हिसाब से इस advice का बड़ा हिस्सा single-machine systems पर भी लागू होता है। Programs के बीच IPC या एक process के अंदर threads को coordinate करने जैसी स्थितियों में कुछ हद तक distributed sub-components बहुत हो सकते हैं
    single machine की unified memory का idea भी कुछ हद तक झूठा है, लेकिन फिर भी hardware “वास्तविक” distributed environment से बेहतर guarantees दे सकता है
    लेख में “distributed” और “single machine” की तुलना करने वाली कई सलाहें multi-threaded बनाम single-threaded तुलना पर भी काफ़ी अच्छी तरह fit बैठती हैं
    एक और axis पर, अगर आप कोई program बनाकर कई लोगों के चलाने के लिए distribute करते हैं, तो वह भी एक तरह की “distributed” स्थिति बन जाती है। wild में अलग-अलग versions मौजूद रहते हैं, और compatibility व upgrade issues का ध्यान रखना पड़ता है, इसलिए लेख में बताए feature flags भी relevant हैं
    distributedness एक spectrum जैसी है — single CPU से multi-CPU, tightly connected multiple computers, और दुनिया भर में फैले multiple computers तक; इनके बीच कई points और कई dimensions हैं

    • “distributed system” शब्द में deployment method पर कोई restriction शामिल नहीं है। definition की मुख्य विशेषता बस यह है कि अलग-अलग control flows message passing के ज़रिए network पर communicate करते हैं
      एक ही machine पर कई processes का localhost के ज़रिए communicate करना भी distributed system का बहुत प्रसिद्ध example है, और वास्तव में कई लोग distributed systems सबसे पहले वहीं सीखते हैं
    • मैं अक्सर उस बहुत पास वाले, और इसी वजह से और भी अफ़सोसजनक, neighboring universe के बारे में सोचता हूँ जहाँ AMD ने हर chiplet को अलग memory space दिया होता
      ऐसा होता तो सभी लोग सारे code को सुंदर distributed memory MPI programs के रूप में लिख रहे होते। false sharing भी गायब हो जाती, और communication patterns पर explicitly गहराई से सोचना पड़ता
  • हाल के वर्षों में मुझे इस लेख के लेखक के साथ थोड़े समय तक काम करने का मौका मिला। Jeff उन सबसे insightful और positive लोगों में से एक थे जिनसे मैंने सीखा है
    वे अपनी मुश्किलों के बारे में आश्चर्यजनक रूप से ईमानदार थे, और mentoring व advice के लिए भी बहुत सहज रूप से approachable थे

  • “distributed systems अलग होते हैं क्योंकि वे अक्सर fail होते हैं” में मुख्य बात सिर्फ़ failure rate नहीं, बल्कि कई nodes वाले system में failure rate है
    और “distributed system problems” सिर्फ़ network से जुड़े कई servers में ही नहीं पैदा होतीं। अगर यह आपस में संबंध रखने वाले nodes का समूह है, तो logically connected disk files या अलग-अलग I/O devices के buffers में भी मिलती-जुलती समस्याएँ आती हैं

    • सही है। असल में memory में pinned single-threaded process से आगे लगभग हर software system में इस तरह की समस्याएँ पैदा हो सकती हैं और होती भी हैं
      कुछ old-timers ऐसी समस्याओं को कम करने से आने वाली excessive complexity का मज़ाक उड़ाते हैं, और शिकायत करते हैं कि software को बस single server पर चलाना कहीं सरल होगा
      वास्तविकता में AS/400 या VAXft के दौर में भी यह बात शायद ही सही थी, और अधिक chaotic multi-user, multi-process Unix दुनिया पर तो और भी कम लागू होती थी
  • “अगर समस्या memory में fit हो सकती है, तो शायद वह trivial है” कुछ distributed system engineers के बीच आम गलती है
    वह बिल्कुल trivial नहीं होती; बस जिन समस्याओं से निपटना है, वे complementary domain में चली जाती हैं
    यह गलती आसानी से ऐसी स्थिति तक ले जाती है जहाँ ठीक से optimize करने पर जो काम single machine पर हो सकता है, उसके लिए 100-machine cluster लगा दिया जाता है