सिस्टम डिज़ाइन की बुनियाद, जो हर डेवलपर को चाहिए

हर बैकएंड डेवलपर आख़िरकार एक दीवार से टकराता है। ऐप्लिकेशन आपके लैपटॉप पर बढ़िया चलता है। तीन साथ-साथ उपयोगकर्ताओं वाले स्टेजिंग पर भी बढ़िया चलता है। फिर आप प्रोडक्शन में तैनात करते हैं, हज़ार लोग एक साथ आते हैं और डेटाबेस बैठ जाता है। API 5xx लौटाने लगता है, फ़्रंटएंड अटक जाता है, और कहीं किसी चैट में कोई वह स्क्रीनशॉट डालता है जिससे रात दो बजे आपका फ़ोन बजने लगता है।

सिस्टम डिज़ाइन वही है जो उस दीवार के दूसरी ओर है। पैटर्न, अदला-बदलियों और अवसंरचना के फ़ैसलों का वह समूह जो खिलौना ऐप्लिकेशन को ऐसे प्रोडक्शन सिस्टम से अलग करता है जो असली ट्रैफ़िक बिना ढहे संभाल ले। अच्छी ख़बर यह है कि बुनियाद समझने के लिए वरिष्ठ अवसंरचना इंजीनियर होना ज़रूरी नहीं। लगभग आठ अवधारणाएँ जाननी हैं, यह कि वे आपस में कैसे जुड़ती हैं, और हर एक तक कब हाथ बढ़ाना है।

यह लेख उन्हीं पैटर्नों पर है जो काम करते बैकएंड डेवलपर के लिए सबसे ज़्यादा मायने रखते हैं। हर खंड अवधारणा समझाता है, व्यावहारिक उदाहरण देता है और वे अदला-बदलियाँ बताता है जिन्हें अपनाने से पहले तौलना ज़रूरी है। ये अमूर्त अकादमिक विचार नहीं, वे औज़ार हैं जिन तक आप हर बार पहुँचेंगे जब ऐसा कुछ बनाना होगा जिसे बढ़ना है।

लोड संतुलन: हर सर्वर व्यस्त रहे, पर हद से ज़्यादा नहीं

लोड संतुलन सबसे सरल और सबसे असरदार पैटर्न है जिसे आप लागू कर सकते हैं। विचार सीधा है: सारा ट्रैफ़िक एक सर्वर पर भेजने के बजाय आप आने वाले अनुरोध सर्वरों के एक समूह में बाँट देते हैं। इससे एक साथ दो चीज़ें मिलती हैं: अधिक उपलब्धता (एक सर्वर बैठ जाए तो बाक़ी काम करते रहते हैं) और अधिक क्षमता (कई सर्वर काम बाँट लेते हैं)।

सबसे आम एल्गोरिदम हैं राउंड-रॉबिन, सबसे कम कनेक्शन, और IP हैश। राउंड-रॉबिन सर्वरों की सूची पर क्रम से घूमता है — सरल और अनुमेय, पर यह ध्यान नहीं रखता कि हर सर्वर असल में कितना व्यस्त है। «सबसे कम कनेक्शन» हर अनुरोध उस सर्वर को भेजता है जिस पर सबसे कम सक्रिय कनेक्शन हैं, जो असमान भार को बेहतर संभालता है। IP हैश ग्राहक के पते से सर्वर निश्चित रूप से चुनता है, जो तब ज़रूरी है जब आपको «चिपकी» सत्र चाहिए — यानी एक ही ग्राहक हमेशा उसी सर्वर पर जाए।

व्यवहार में अधिकांश प्रोडक्शन व्यवस्थाएँ मिश्रण अपनाती हैं। चौथे स्तर का संतुलक (TCP स्तर पर) कच्चे कनेक्शन रिवर्स प्रॉक्सी या API गेटवे के समूह में बाँटता है, जो फिर सातवें स्तर का संतुलन (HTTP स्तर पर) करके अनुरोध विशिष्ट उदाहरणों तक पहुँचाते हैं। यह बहुस्तरीय तरीक़ा डेटा-तल को तेज़ और मार्ग-तर्क को लचीला रखता है।

# nginx.conf - simple round-robin load balancing across three app servers
upstream app_cluster {
    round-robin;
    server app1.internal:3000 max_fails=3 fail_timeout=30s;
    server app2.internal:3000 max_fails=3 fail_timeout=30s;
    server app3.internal:3000 max_fails=3 fail_timeout=30s;
}

server {
    listen 443 ssl;
    location / {
        proxy_pass http://app_cluster;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

वह निर्णायक बारीकी जो अधिकांश डेवलपर छोड़ देते हैं, स्वास्थ्य-जाँच है। संतुलक तभी उपयोगी है जब उसे पता हो कि कौन-से सर्वर स्वस्थ हैं। अगर app2 गिर गया पर संतुलक उसी पर ट्रैफ़िक भेजता रहा, तो आपकी त्रुटि-दर लगभग एक-तिहाई बढ़ जाएगी। हमेशा सक्रिय स्वास्थ्य-जाँच लगाएँ — संतुलक समय-समय पर हर सर्वर से पूछता है और जवाब न देने वालों को अपने आप समूह से हटा देता है।

कैशिंग: गति, पर किस क़ीमत पर?

कैशिंग किसी भी डेवलपर के लिए उपलब्ध सबसे बड़े लीवर वाला प्रदर्शन-सुधार है। एक कैश-हिट 200 मिलीसेकंड वाली डेटाबेस पूछताछ को 2 मिलीसेकंड की स्मृति-पठन में बदल देता है। परिमाण के दो क्रम। लाखों अनुरोधों के पैमाने पर यह अंतर महीने के दस हज़ार डॉलर के डेटाबेस बिल और पाँच सौ डॉलर के बिल का अंतर है।

प्रामाणिक कैशिंग ढेर में तीन स्तर होते हैं, हर एक के अलग गुण। ऐप्लिकेशन-स्तर का कैश (Redis, Memcached) महँगी गणनाओं या डेटाबेस पूछताछ के परिणाम रखता है। CDN का कैश स्थिर और अर्ध-स्थिर संपत्तियाँ उपयोगकर्ताओं के पास किनारे के नोड पर रखता है। HTTP कैशिंग Cache-Control और ETag शीर्षकों से ब्राउज़र और प्रॉक्सी को प्रतिक्रियाएँ कैश करने देती है, आपके सर्वर को छुए बिना।

कैशिंग का सबसे कठिन हिस्सा उसे लगाना नहीं, बल्कि मूल डेटा बदलने पर कैश को अमान्य करना है। उद्योग कुछ भरोसेमंद पैटर्नों पर आकर टिका है। «कैश-असाइड» (आलसी लोडिंग) का अर्थ है कि ऐप्लिकेशन पहले कैश देखता है, न मिलने पर डेटाबेस से लाता है और कैश भर देता है। «राइट-थ्रू» का अर्थ है कि हर लेखन कैश और डेटाबेस दोनों में एक साथ जाता है। «राइट-बिहाइंड» का अर्थ है कि लेखन पहले कैश में जाता है और असमकालिक रूप से डेटाबेस में उतरता है।

कंप्यूटर विज्ञान में केवल दो कठिन चीज़ें हैं: कैश अमान्य करना और चीज़ों के नाम रखना। कैश अमान्य करना कठिनतर है, क्योंकि आप उसका नाम बदलकर यह उम्मीद नहीं कर सकते कि वह ग़ायब हो जाएगा।

अधिकांश ऐप्लिकेशन के लिए छोटे जीवनकाल वाला कैश-असाइड ही सही डिफ़ॉल्ट है। वह TTL रखें जो बासी डेटा के प्रति आपकी सहनशीलता से मेल खाए — उपयोगकर्ता प्रोफ़ाइल के लिए 60 सेकंड, उत्पाद-सूची के लिए 5 मिनट, संदर्भ डेटा के लिए 24 घंटे। जहाँ मज़बूत संगति चाहिए वहाँ राइट-थ्रू लें, पर लेखन का अधिक विलंब स्वीकारें। जहाँ अधिकतम पठन-क्षमता चाहिए और अंतिम संगति चल जाए, वहाँ उदार TTL के साथ कैश-असाइड लें।

import redis.asyncio as aioredis
import json

cache = aioredis.Redis.from_url("redis://cache:6379")

CACHE_TTL = 300  # 5 minutes

async def get_user_profile(user_id: str) -> dict:
    key = f"profile:{user_id}"
    cached = await cache.get(key)
    if cached:
        return json.loads(cached)
    profile = await db.fetch_user(user_id)
    if profile:
        await cache.setex(key, CACHE_TTL, json.dumps(profile))
    return profile

एक चेतावनी: कैशिंग समस्याओं को हल करने के बजाय ढक सकती है। अगर आपकी पूछताछ इसलिए धीमी है कि इंडेक्स ग़ायब है, तो कैश लक्षण छिपा देता है पर मूल पूछताछ धीमी ही रहती है। कैश ख़ाली होते ही वह धीमी पूछताछ चलती है और उपयोगकर्ता इंतज़ार करता है। पहले अपने धीमे रास्तों की प्रोफ़ाइल लेकर उन्हें सुधारें, फिर सुधरे हुए संस्करण के ऊपर कैश लगाएँ।

डेटाबेस शार्डिंग: काम बाँटें ताकि कोई डेटाबेस न डूबे

शार्डिंग (क्षैतिज विभाजन) वह है जिसकी ओर आप तब जाते हैं जब डेटाबेस का एक उदाहरण आपके लेखन-आयतन या डेटा के आकार को नहीं संभाल पाता। विचार यह है कि डेटा को कई उदाहरणों में बाँट दिया जाए, जहाँ हर उदाहरण (शार्ड) डेटा का एक उपसमुच्चय रखे। ऐप्लिकेशन शार्ड कुंजी के आधार पर तय करता है कि किस शार्ड तक जाना है — आमतौर पर उपयोगकर्ता आईडी का हैश, भौगोलिक क्षेत्र या समय का दायरा।

शार्ड कुंजी किसी भी शार्डेड सिस्टम का सबसे महत्वपूर्ण अकेला फ़ैसला है। अच्छी कुंजी डेटा को शार्डों में समान रूप से बाँटती है और आपकी पूछताछ के ढर्रे से मेल खाती है। ख़राब कुंजी «गर्म» शार्ड बनाती है — कुछ शार्ड अधिकांश ट्रैफ़िक संभालते हैं जबकि बाक़ी ख़ाली बैठे रहते हैं। मिसाल के लिए, निर्माण के समय के हिसाब से शार्डिंग तब तक समझदारी लगती है जब तक यह पता न चले कि आज का शार्ड सारे लेखन ले रहा है और बीते वर्षों के शार्ड कुछ भी नहीं।

संगत हैशिंग उस पुनर्संतुलन की समस्या हल करती है जो भोली शार्डिंग को सताती है। सरल शेषफल-आधारित योजना (shard = hash(key) % N) में नया शार्ड जोड़ने पर लगभग सारा डेटा हिलाना पड़ता है। संगत हैशिंग कुंजियों और शार्डों दोनों को एक हैश-वलय पर रखती है; नया शार्ड जोड़ने पर केवल उसके आसपास की कुंजियाँ हिलती हैं। इससे ऊपर-नीचे स्केल करना कहीं कम कष्टदायक हो जाता है।

  • हैश आधारित शार्डिंग — शार्ड कुंजी के हैश से वितरण; सरल और समान, पर दोबारा शार्ड करना महँगा।
  • दायरा आधारित शार्डिंग — मानों के दायरे से बँटवारा (आईडी 1–10000 शार्ड A पर, 10001–20000 शार्ड B पर); दायरा-पूछताछ के लिए कुशल, पर गर्म बिंदु बनने का ख़तरा।
  • निर्देशिका आधारित शार्डिंग — कुंजियों और शार्डों का मिलान-कोष्ठक रखना; लचीला, पर एक अतिरिक्त खोज-चरण और निर्देशिका गिरने पर एक ही विफलता-बिंदु।
  • भौगोलिक शार्डिंग — उपयोगकर्ताओं के क्षेत्र से बँटवारा; विलंब के लिए बढ़िया, पर असुविधाजनक जब उपयोगकर्ता यात्रा करें या डेटा वैश्विक होना चाहिए।

शार्डिंग की अदला-बदली यह है कि शार्ड-पार पूछताछ महँगी या असंभव हो जाती है। अगर उपयोगकर्ता तालिका user_id से शार्ड है और आदेश तालिका भी, तो पिछले 30 दिनों के सारे आदेश पूछने के लिए हर शार्ड तक जाना पड़ेगा। जिन ऐप्लिकेशनों को वैश्विक विश्लेषण या शार्ड-पार जोड़ चाहिए, वे आमतौर पर पठन के लिए एक द्वितीयक प्रति (या अलग विश्लेषण डेटाबेस) रखते हैं, जहाँ सारे शार्ड का डेटा असमकालिक रूप से इकट्ठा होता है।

CAP प्रमेय: आप केवल दो चुन सकते हैं

CAP प्रमेय कहता है कि वितरित डेटा-भंडार तीन में से दो से अधिक गारंटी एक साथ नहीं दे सकता: संगति (हर पठन को सबसे नया लेखन मिले), उपलब्धता (हर अनुरोध को उत्तर मिले, भले ही सबसे नया डेटा न हो) और विभाजन-सहिष्णुता (नोडों के बीच नेटवर्क विफलता के बावजूद सिस्टम चलता रहे)।

व्यवहार में विभाजन-सहिष्णुता वैकल्पिक नहीं है। नेटवर्क विफल होते हैं। पैकेट खोते हैं, कनेक्शन समय पार कर जाते हैं, डेटा सेंटर की बिजली जाती है। इसलिए असली चुनाव CP (संगति और विभाजन-सहिष्णुता) तथा AP (उपलब्धता और विभाजन-सहिष्णुता) के बीच है। etcd या ZooKeeper जैसा CP सिस्टम पठन देने से मना कर देगा अगर वह नोडों के बीच संगति की गारंटी न दे सके। Cassandra या DynamoDB जैसा AP सिस्टम किसी भी उपलब्ध नोड से पठन दे देगा, भले ही उस नोड का डेटा बासी हो।

यह अकादमिक भेद नहीं है। जब आप कई डेटा सेंटरों में फैला सिस्टम डिज़ाइन करते हैं, तो तय करना पड़ता है कि उनके बीच का संपर्क टूटने पर क्या होगा। क्या आप संभवतः बासी डेटा के साथ अनुरोध देते रहेंगे (AP)? या नेटवर्क लौटने तक सेवा रोक देंगे (CP)? उत्तर आपके ऐप्लिकेशन पर निर्भर है। कंटेंट वितरण नेटवर्क को AP होना चाहिए — बासी कंटेंट न होने से बेहतर है। भुगतान प्रणाली को CP होना चाहिए — आप कभी नहीं चाहेंगे कि विभाजन के दौरान दो नोडों के एक ही भुगतान स्वीकार कर लेने से ग्राहक से दो बार पैसे कटें।

संदेश क़तारें: समकालिक पीड़ा को असमकालिक शालीनता में बदलना

संदेश क़तारें वितरित सिस्टमों में असमकालिक प्रसंस्करण की रीढ़ हैं। वे एक सेवा को क़तार में संदेश डालने देती हैं, बिना यह प्रतीक्षा किए कि उपभोक्ता उसे संसाधित करे। उपभोक्ता तैयार होने पर संदेश उठाता है, संसाधित करता है और पूर्णता की पुष्टि देता है। इससे भेजने वाला और लेने वाला समय और स्थान दोनों में अलग हो जाते हैं — उन्हें एक ही गति से या एक ही समय पर चलने की ज़रूरत नहीं।

हर ग़ैर-मामूली बैकएंड सिस्टम में कहीं न कहीं क़तार होनी चाहिए। प्रामाणिक उदाहरण ई-मेल भेजना है। जब उपयोगकर्ता पंजीकरण करता है, आप नहीं चाहते कि HTTP प्रतिक्रिया तब तक रुकी रहे जब तक वितरण सेवा टेम्प्लेट न बना ले, प्रदाता से न जुड़ जाए और संदेश न पहुँचा दे। इसके बजाय आपका API क़तार में send_email घटना डालता है और तुरंत 201 Created लौटा देता है। अलग कर्मी घटना उठाता है, ई-मेल भेजता है और काम पूरा चिह्नित कर देता है।

दो प्रमुख मॉडल हैं: «प्रकाशन-अभिदान» और कार्य-क़तार। पहले में हर संदेश सभी अभिदाताओं तक जाता है। यह घटना-आधारित वास्तुकला के लिए उपयोगी है, जहाँ एक ही घटना पर कई सेवाओं को प्रतिक्रिया देनी है — नया पंजीकरण स्वागत-पत्र, CRM अद्यतन और विश्लेषण घटना एक साथ छेड़ सकता है। कार्य-क़तार में हर संदेश ठीक एक उपभोक्ता तक जाता है। यह काम को कर्मियों के समूह में बाँटने के लिए उपयोगी है — हर छवि-अपलोड ठीक एक थंबनेल जनरेटर के पास जाता है।

# docker-compose.yml - minimal RabbitMQ setup for local development
version: "3.8"
services:
  rabbitmq:
    image: rabbitmq:3-management-alpine
    ports:
      - "5672:5672"   # AMQP port for producers and consumers
      - "15672:15672" # management UI
    environment:
      RABBITMQ_DEFAULT_USER: app
      RABBITMQ_DEFAULT_PASS: dev-only-password
    volumes:
      - rabbitmq_data:/var/lib/rabbitmq

volumes:
  rabbitmq_data:

क़तारों का पेचीदा हिस्सा विफलताओं को सही तरह संभालना है। अगर उपभोक्ता संदेश संसाधित करते-करते बीच में गिर जाए तो क्या होगा? RabbitMQ और Amazon SQS इसे पावती से संभालते हैं — उपभोक्ता को स्पष्ट रूप से पुष्टि देनी होती है कि संदेश सफलतापूर्वक संसाधित हुआ। बिना पावती के वह हट जाए तो संदेश वापस क़तार में आकर किसी और उपभोक्ता तक जाता है। «कम से कम एक बार» वाली यह गारंटी माँगती है कि आपके उपभोक्ता वर्ग-सम हों: एक ही संदेश दो बार संसाधित करने का परिणाम वही हो जो एक बार करने का।

मृत-पत्र क़तार दूसरा अनिवार्य पैटर्न है। जब कोई संदेश कई प्रयासों के बाद भी संसाधित न हो सके (नीचे की सेवा अनुपलब्ध है, डेटा दूषित है, व्यापार-नियम बदल गया है), तो अनंत पुनःप्रयास के बजाय वह मृत-पत्र क़तार में चला जाता है। कोई संचालक उस क़तार पर नज़र रखता है, मूल कारण जाँचता है और या तो संदेश सुधारकर वापस डालता है या यह पक्का करके छोड़ देता है कि उसे अनदेखा करना सुरक्षित है।

CDN और दर-सीमा: बचाव की अगली पंक्ति

कंटेंट वितरण नेटवर्क और दर-सीमक अलग उद्देश्य साधते हैं, पर उनमें एक बात साझा है: वे आपके उपयोगकर्ताओं और आपके सर्वरों के बीच बचाव की पहली पंक्ति हैं। CDN स्थिर संपत्तियाँ और कैश की गई प्रतिक्रियाएँ उपयोगकर्ताओं के पास रखता है, जिससे विलंब घटता है और मूल सर्वरों का बोझ कम होता है। दर-सीमक किसी एक उपयोगकर्ता या ग्राहक को अनुरोधों से सिस्टम भर देने से रोकता है।

CDN आपके कंटेंट को किनारे के सर्वरों के वैश्विक जाल में फैलाकर काम करते हैं। टोक्यो का उपयोगकर्ता जब कोई संपत्ति माँगता है, CDN उसे निकटतम किनारे से देता है, न कि अनुरोध को वर्जीनिया के मूल सर्वर तक भेजता है। स्थिर संपत्तियों के लिए इससे विलंब 200 मिलीसेकंड से घटकर 10 रह जाता है। आधुनिक CDN इससे आगे भी जाते हैं — वे API प्रतिक्रियाएँ कैश करते हैं, TLS कनेक्शन वहीं समाप्त करते हैं और किनारे पर सर्वरलेस फ़ंक्शन तक चलाते हैं।

दर-सीमा आपके सिस्टम की कई स्तरों पर रक्षा करती है। वैश्विक दर-सीमा पूरे सिस्टम के प्रति सेकंड कुल अनुरोधों की छत तय करती है, जो ट्रैफ़िक के उछाल और DDoS से बचाती है। प्रति-उपयोगकर्ता दर-सीमा सुनिश्चित करती है कि कोई एक दुर्भावनापूर्ण ग्राहक बाक़ियों के संसाधन न हड़प ले। एंडपॉइंट-स्तर की दर-सीमा अलग-अलग मार्गों पर अलग सीमाएँ लगाती है — लॉगिन एंडपॉइंट पर प्रति मिनट 5 अनुरोध, जबकि केवल-पठन खोज एंडपॉइंट पर 100।

सरकती-खिड़की का एल्गोरिदम दर-सीमा का उद्योग मानक बन चुका है, क्योंकि वह सटीक और किफ़ायती है। निश्चित अंतराल पर गणक शून्य करने के बजाय (जिससे सीमा पर उछाल संभव रहता है) सरकती खिड़की एक चलते समय-खंड के अनुरोध गिनती है। Redis इसके लिए स्वाभाविक चुनाव है: समय-चिह्नों को अंक बनाकर क्रमित समुच्चय रखें, खिड़की से बाहर की प्रविष्टियाँ हटाएँ और बची हुई गिन लें। स्मृति का ख़र्च नगण्य है (प्रति अनुरोध कुछ बाइट) और समय-जटिलता लघुगणकीय।

// Redis-backed sliding window rate limiter (TypeScript)
import { createClient } from "redis";

const redis = createClient({ url: "redis://ratelimit:6379" });

async function checkRateLimit(
  key: string,
  limit: number,
  windowMs: number
): Promise<{ allowed: boolean; remaining: number }> {
  const now = Date.now();
  const windowStart = now - windowMs;

  const multi = redis.multi();
  multi.zRemRangeByScore(key, 0, windowStart);
  multi.zAdd(key, { score: now, value: `${now}` });
  multi.zCard(key);
  multi.expire(key, Math.ceil(windowMs / 1000));

  const [, , count] = await multi.exec() as [any, any, number];
  return {
    allowed: count <= limit,
    remaining: Math.max(0, limit - count),
  };
}

CDN और दर-सीमक दोनों एक महत्वपूर्ण परिचालन सिद्धांत साझा करते हैं: विफलता पर खुलना या बंद होना? अगर CDN का किनारा मूल सर्वर तक न पहुँच सके, तो क्या वह बासी कैश दे (खुलना) या त्रुटि लौटाए (बंद होना)? अगर दर-सीमक का Redis क्लस्टर बैठ जाए, तो क्या सारे अनुरोध जाने दिए जाएँ (खुलना — बोझ का ख़तरा) या सारे ठुकरा दिए जाएँ (बंद होना — निश्चित ठहराव)?

कोई सार्वभौमिक उत्तर नहीं, पर अधिकांश सिस्टमों के लिए अच्छा डिफ़ॉल्ट यह है: पठन पर विफलता में खुलें, लेखन पर बंद हों। बासी उत्पाद-पृष्ठ स्वीकार्य है। खोया हुआ आदेश नहीं। यह फ़ैसला अपनी संचालन-पुस्तिका में स्पष्ट लिखें, ताकि ड्यूटी पर बैठे इंजीनियर को पता हो कि अवसंरचना गिरने पर किस व्यवहार की उम्मीद करनी है।

सब मिलाकर: अदला-बदली में सोचना

सिस्टम डिज़ाइन पैटर्न रट लेना नहीं है। यह अदला-बदलियाँ समझना और यह पहचानना है कि कौन-सा पैटर्न आपकी बाध्यताओं पर बैठता है। हर फ़ैसला किसी न किसी अदला-बदली में उलझा है — संगति बनाम उपलब्धता, पठन-क्षमता बनाम लेखन-विलंब, परिचालन जटिलता बनाम शुद्ध प्रदर्शन। सबसे अच्छे इंजीनियर वे नहीं जो सबसे ज़्यादा पैटर्न जानते हैं; वे हैं जो समस्या देखकर पहचान लेते हैं कि कौन-सी बाध्यताएँ तय हैं और कौन-सी बातचीत के लायक़।

नई डिज़ाइन समस्या के लिए एक त्वरित ढाँचा। अपनी ग़ैर-कार्यात्मक अपेक्षाओं की सूची से शुरू करें: अपेक्षित ट्रैफ़िक, लक्षित विलंब, संगति की माँग, अवसंरचना का बजट और तकनीक से टीम की परिचितता। फिर इस लेख के पैटर्नों पर नज़र दौड़ाएँ और ख़ुद से पूछें कि हर एक आपको अपनी अपेक्षाओं के क़रीब ले जाता है या दूर।

अगर मुख्य चिंता विलंब है, कैशिंग और CDN से शुरू करें — वे सबसे कम जटिलता में सबसे बड़ा सुधार देते हैं। अगर उपलब्धता निर्णायक है, स्वास्थ्य-जाँच वाला लोड संतुलन लगाएँ, सेवाएँ बिना-अवस्था डिज़ाइन करें और जहाँ कारोबार इजाज़त दे वहाँ CP के बजाय AP चुनें। अगर भार लेखन-प्रधान है, शार्डिंग और क़तारों पर पहले ही विचार कर लें — लाखों पंक्तियाँ जमा होने से पहले उन्हें लाना कहीं आसान है। अगर आप ऐसा सार्वजनिक API बना रहे हैं जिसे बाहरी डेवलपर उपयोग करेंगे, तो दर-सीमा पहले ही दिन लागू करें; बाद में जोड़ने का अर्थ है API का संस्करण बदलना या मौजूदा ग्राहकों को तोड़ना।

सिस्टम डिज़ाइन का सबसे महत्वपूर्ण कौशल यह जानना है कि आपको क्या नहीं चाहिए। अधिकांश ऐप्लिकेशन को शार्डिंग नहीं चाहिए। अधिकांश को संदेश क़तार नहीं चाहिए। समय से पहले किया गया वितरण सब बुराइयों की जड़ है — हर वितरित सिस्टम ऐसे विफलता-रूप लाता है जो एक-सर्वर वाले सिस्टम में होते ही नहीं। जटिलता तभी जोड़ें जब आपके माप ऐसा कहें, इसलिए नहीं कि कोई पैटर्न साक्षात्कार में प्रभावशाली लगता है।

सरल से शुरू करें। सब कुछ मापें। एक बार में एक पैटर्न जोड़ें। आगे बढ़ने से पहले सुधार की पुष्टि करें। जो सिस्टम टिकते हैं, वे सबसे जटिल वास्तुकला वाले नहीं होते; वे वही होते हैं जिन्हें समझना आसान है, चलाना आसान है और अगली अड़चन आने पर बदलना आसान है।

See what your own repository can account for.

Thirty minutes on a repository you choose, including the part the record cannot attribute.