सामग्री पर जाएँ

नोड के रूप में फ़ॉल्ट ​

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

नोडयह क्या करता है
नेटवर्क बाधाटेस्ट हो रहे सिस्टम और उसके लक्ष्य के बीच एक रिले, जो पूरे रन के दौरान उससे होकर जाने वाले ट्रैफ़िक को बाधित करता है
बाधा बदलेंरन के किसी रिले को इस चरण से आगे दूसरी प्रोफ़ाइल पर बदल देता है
एमुलेटरपूरे रन के लिए Signal Lab द्वारा निभाया गया API, डिवाइस या ब्रोकर
एमुलेटर बंद/चालूरन के किसी एमुलेटर को बंद करता है, या वापस चालू करता है

चारों जोड़ने वाले मेनू में फ़ॉल्ट और एमुलेशन के नीचे हैं। उनके फ़ील्ड नोड के संदर्भ में हैं; रिले का विवरण बाधा पर है, एमुलेटर का एमुलेटर पर।

नेटवर्क बाधा ​

टेस्ट हो रहा सिस्टम अपने असली लक्ष्य के बजाय रिले को भेजता है; रिले लक्ष्य तक आगे भेजता है, जवाब वापस लाता है, और दोनों दिशाओं को बाधित करता है।

फ़ील्डक्या
सुनने का पताIP:port, जिस पर टेस्ट हो रहा सिस्टम भेजता या कनेक्ट करता है, पोर्ट 0 नहीं
आगे भेजेंअसली गंतव्य का IP:port, या host:port; रन शुरू होते समय होस्ट नाम हल किया जाता है
प्रोटोकॉलUDP — हर डेटाग्राम का भविष्य अलग से तय होता है — या TCP — हर कनेक्शन लक्ष्य तक अपने एक अलग कनेक्शन से जुड़ता है
प्रोफ़ाइलकोई प्रीसेट या आपके अपने मान

रिले अपनी प्रोफ़ाइल में से क्या पढ़ता है, यह प्रोटोकॉल पर निर्भर करता है; बाकी मान छोड़ दिए जाते हैं:

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

पहले चरण से पहले खुलता है। प्रयोग का हर रिले रन शुरू होते ही खुलता है, प्रतीक्षाओं के सॉकेट की तरह, इसलिए उसके सुनने का पता और आगे भेजें में केवल टेक्स्ट और पैरामीटर चलते हैं (node.params_only) — पैरामीटर relay के साथ {{relay}}, कभी वैरिएबल नहीं। जो पोर्ट खोला नहीं जा सकता, या जो गंतव्य नाम हल नहीं किया जा सकता, वह किसी भी ट्रैफ़िक से पहले, उसी नोड पर, रन रोक देता है।

फ़्लो में आगे बढ़ना। जब रन नोड तक पहुँचता है, तो वह तुरंत आगे बढ़ जाता है और टाइमलाइन बताती है कि वह क्या और किससे बाधित करता है। रिले रन की शुरुआत से अंत तक काम करता है, ग्राफ़ में नोड चाहे कहीं भी हो।

रन के साथ बंद होता है। रन चाहे जैसे समाप्त हो, रिले बंद हो जाता है; TCP रिले के कनेक्शन उसके साथ बंद होते हैं। जो रिले अपने आप रिले करना बंद कर दे, वह उसकी वजह रखता है: उसका उपयोग करने वाले चरण उसी वजह से विफल होते हैं, और रिपोर्ट यही बताती है।

बाधा से होकर भेजना

OSC संदेश या UDP डेटाग्राम नोड पर बाधा से होकर भेजें उसके आगे एक नेटवर्क बाधा रख देता है: रिले 127.0.0.1 के किसी ख़ाली पोर्ट पर सुनता है, LAN प्रीसेट के साथ नोड के लक्ष्य तक आगे भेजता है, और नोड अब रिले को भेजता है।

बाधा बदलना ​

बाधा बदलें, नेटवर्क बाधा फ़ील्ड में प्रयोग के रिले में से एक का नाम लेता है और वह प्रोफ़ाइल देता है जिससे वह उस चरण से आगे बाधित करेगा। रिले अपना पोर्ट और अपने कनेक्शन बनाए रखता है; नए मान अगले पैकेट या चंक पर लागू होते हैं। टाइमलाइन नई प्रोफ़ाइल दिखाती है।

हर बदलाव एक फ़ेज़ समाप्त करता है। रन रिपोर्ट हर रिले के लिए रखती है:

  • उसके सुनने और लक्ष्य के पते, और TCP होने पर उसका प्रोटोकॉल;
  • उसकी कुल गिनतियाँ: प्राप्त, आगे भेजे गए, ड्रॉप, थ्रॉटल, डुप्लिकेट, दूषित, क्रम बदले गए, बाइट — और TCP के लिए कनेक्शन, रीसेट हुए कनेक्शन और अर्ध-खुले छोड़े गए कनेक्शन;
  • हर फ़ेज़: प्रोफ़ाइल का नाम, रिले खुलने के क्षण से मिलीसेकंड में वह कब शुरू और कब समाप्त हुआ, और केवल उस फ़ेज़ की वही गिनतियाँ।

पैकेट उस फ़ेज़ में गिना जाता है जिसने उसका भविष्य तय किया, भले ही उसकी विलंबित कॉपी बदलाव के बाद निकले। रिले अपने अंतिम 1000 फ़ेज़ रखता है; पुराने गिने जाते हैं, रखे नहीं जाते।

जो बाधा बदलें प्रयोग के किसी रिले का नाम नहीं लेता, वह अस्वीकार किया जाता है (impair.relay_unknown)।

एमुलेटर ​

एमुलेटर पूरे रन के लिए किसी डिपेंडेंसी की भूमिका निभाता है: HTTP API, OSC, UDP या TCP डिवाइस, या MQTT ब्रोकर। यह वही एमुलेटर है जिसे एमुलेटर स्क्रीन अलग से चलाती है: संपादित करें… उसके नियम खोलता है, लाइब्रेरी में उसकी एक कॉपी लाइब्रेरी में रखता है, लाइब्रेरी से वहाँ से एक लेता है।

  • यह पहले चरण से पहले खुलता है और रन समाप्त होने तक जवाब देता है; जो पोर्ट खोला नहीं जा सकता, वह किसी भी ट्रैफ़िक से पहले रन रोक देता है। फ़्लो में यह तुरंत आगे बढ़ जाता है।
  • इसका पता एक शाब्दिक IP:port होता है। इसके मिलान पैटर्न में केवल पैरामीटर चलते हैं; इसके जवाब ऐसे टेम्पलेट हैं जो आए हुए डेटा ({{request.…}}) और रन के पैरामीटर से पढ़े जाते हैं। यह सीक्रेट नहीं पढ़ सकता।
  • इसके रैंडम चुनाव — रिस्पॉन्स का वज़न वाला मिश्रण, विलंब का जिटर, जवाबों में जनरेटर — रन के सीड से निकलते हैं।
  • HTTP एमुलेटर वही है जिसे उसी पते पर HTTP रिक्वेस्ट की प्रतीक्षा सुनता है: यह जाँचता है कि टेस्ट हो रहे सिस्टम ने क्या भेजा। वहाँ एमुलेटर न हो, तो रन का अपना लिसनर हर रिक्वेस्ट का जवाब 204 से देता है।
  • OSC या UDP एमुलेटर अपना पोर्ट उस पर रन की प्रतीक्षाओं के साथ साझा करता है: दोनों हर डेटाग्राम देखते हैं।
  • MQTT एमुलेटर एक ब्रोकर है, जिसे रन के MQTT पब्लिश और MQTT की प्रतीक्षा नोड किसी भी दूसरे ब्रोकर की तरह उपयोग कर सकते हैं।

रन रिपोर्ट हर एमुलेटर नोड के लिए उसका नाम, प्रोटोकॉल और पता रखती है, और उसकी गिनतियाँ: कुल रिक्वेस्ट, जिन्हें किसी नियम ने नहीं लिया, जो विफल हुईं, जिन्हें वह बंद मिला, वे संदेश जिन्हें ब्रोकर किसी धीमे क्लाइंट तक नहीं पहुँचा सका, और हर नियम के मिलान।

एमुलेटर बंद और चालू ​

एमुलेटर बंद/चालू, एमुलेटर फ़ील्ड में रन के एमुलेटर में से एक का नाम लेता है; स्थिति या तो बंद होती है या चालू। बंद रहते समय:

एमुलेटरक्या मिलता है
HTTPजो बंद रहते समय कहता है: 503 Unavailable (503, बॉडी {"error":"unavailable"}), कनेक्शन बंद करें, या कोई जवाब नहीं — रिक्वेस्ट तब तक रोकी जाती है जब तक क्लाइंट हार न मान ले, अधिकतम 120 s
TCP डिवाइस, MQTT ब्रोकरकनेक्शन तोड़ दिए जाते हैं और नए अस्वीकार किए जाते हैं
OSC, UDP डिवाइसकिसी को जवाब नहीं दिया जाता

बंद रहते जो आता है, वह down के रूप में गिना जाता है, कभी ऐसी रिक्वेस्ट के रूप में नहीं जिसे किसी नियम ने नहीं लिया। HTTP रिक्वेस्ट की प्रतीक्षा फिर भी रिक्वेस्ट देखता है। एमुलेटर तब तक बंद रहता है जब तक कोई चरण उसे चालू न करे, उसका अपना आउटेज शेड्यूल चाहे जो कहे, और रन का अंत उसे हर हाल में बंद कर देता है।

जो एमुलेटर बंद/चालू प्रयोग के किसी एमुलेटर का नाम नहीं लेता, वह अस्वीकार किया जाता है (emulator.node_unknown)।

शेड्यूल पर आउटेज ​

एमुलेटर अपने आप भी बंद हो सकता है: उसके नियमों में बीच-बीच में बंद होता है, चालू अवधि, ms और बंद अवधि, ms सेट करता है, हर एक 10–36,00,000 ms, और HTTP के लिए बंद रहते समय। यह पहली अवधि तक जवाब देता है, दूसरी अवधि तक बंद रहता है, और यही क्रम चलता रहता है, खुलने के क्षण से गिनकर — रन में, पहले चरण से पहले। अपने शेड्यूल के अनुसार बंद रहते समय HTTP एमुलेटर के 503 में Retry-After होता है, जिसमें उसके लौटने तक के पूरे सेकंड होते हैं, कम से कम 1; जब कोई एमुलेटर बंद/चालू चरण उसे बंद रखे, तब 503 में यह नहीं होता, क्योंकि कोई नहीं जानता कि वह कब समाप्त होगा।

शेड्यूल को किसी चरण की ज़रूरत नहीं; चरण को किसी शेड्यूल की ज़रूरत नहीं। बार-बार गिरने-उठने वाली डिपेंडेंसी के लिए शेड्यूल का उपयोग करें, फ़्लो के किसी चुने हुए बिंदु पर आउटेज के लिए चरण का।

उदाहरण: धीमे लिंक के पीछे आउटेज ​

एक क्लाइंट रिले के ज़रिए API से एक ऑर्डर माँगता है। जब वह माँग रहा होता है, एक दूसरी शाखा लिंक को 4G तक धीमा करती है, API को दो सेकंड के लिए बंद करती है, उसे वापस चालू करती है और लिंक को फिर से साफ़ कर देती है। क्लाइंट को तब तक माँगते रहना है जब तक उसे जवाब न मिल जाए।

text
start → orders → link → split
split ─ branch1 → settle → until_ok ─ done → answered → joined
                           until_ok ─ body → get → status → pause → until_ok
split ─ branch2 → slow → down → outage → up → clean → joined
joined → end

नाम नीचे की फ़ाइल में नोड की id हैं।

  1. एक पैरामीटर api = http://127.0.0.1:18091 जोड़ें — रिले, API नहीं।
  2. एक एमुलेटर जोड़ें: HTTP, 127.0.0.1:18090, एक रूट GET /orders/:id, जो 200 और {"order":"{{request.params.id}}"} से जवाब देता है।
  3. उसके बाद एक नेटवर्क बाधा: सुनने का पता 127.0.0.1:18091, आगे भेजें 127.0.0.1:18090, प्रोटोकॉल TCP, प्रीसेट LAN।
  4. उसके बाद एक समानांतर शाखा।
  5. शाखा 1 पर क्लाइंट: 300 ms का विलंब, फिर एक लूप — अधिकतम इटरेशन 40, पहले रुकें, जब {{status}} के बराबर है 200। उसकी बॉडी: एक HTTP रिक्वेस्ट GET {{api}}/orders/42, एक मान निकालें, जो स्टेटस कोड को status में रखे, 250 ms का विलंब, जो वापस लूप से जुड़ा हो। पूर्ण पर एक लॉग मार्कर Orders API answers again: HTTP {{status}}।
  6. शाखा 2 पर फ़ॉल्ट: रिले को 4G पर बदलने वाला एक बाधा बदलें; Orders API को 503 Unavailable के साथ बंद करने वाला एक एमुलेटर बंद/चालू; 2000 ms का विलंब; उसे चालू करने वाला एक और एमुलेटर बंद/चालू; वापस LAN पर ले जाने वाला एक और बाधा बदलें।
  7. दोनों शाखाओं को एक शाखाएँ जोड़ें से जोड़ें, और Join को अंत से।
  8. इसे चलाएँ।

टाइमलाइन दिखाती है कि धीमे लिंक पर क्लाइंट की रिक्वेस्ट को 503 जवाब मिलता है, API वापस आता है, फिर 200 मिलता है और लूप पूर्ण से बाहर निकलता है। रिपोर्ट लगभग पाँच ऐसी रिक्वेस्ट गिनती है जिन्हें API बंद मिला और एक जिसका जवाब उसके रूट ने दिया, और रिले के तीन फ़ेज़ — LAN एक पल के लिए, आउटेज के दौरान 4G, फिर से LAN — हर एक अपने ट्रैफ़िक के साथ।

फ़ाइल के रूप में प्रयोग

इसे .json फ़ाइल के रूप में सहेजें और प्रयोग में JSON खोलें… से खोलें।

json
{
  "version": 9,
  "name": "Outage behind a slow link",
  "params": [{ "name": "api", "value": "http://127.0.0.1:18091" }],
  "profiles": [],
  "profile": null,
  "seed": null,
  "nodes": [
    { "id": "start", "type": "start", "x": 40, "y": 270 },
    { "id": "orders", "type": "emulator", "x": 260, "y": 270,
      "emulator": { "name": "Orders API", "bind": "127.0.0.1:18090", "protocol": "http",
        "routes": [{ "method": "GET", "path": "/orders/:id", "when": [], "order": "sequence",
          "responses": [{ "status": 200, "headers": [], "body": "{\"order\":\"{{request.params.id}}\"}", "delay_ms": 0, "jitter_ms": 0, "fault": "none", "weight": 1 }] }],
        "fallback": null } },
    { "id": "link", "type": "impairment", "x": 490, "y": 270, "listen": "127.0.0.1:18091", "target": "127.0.0.1:18090", "protocol": "tcp",
      "profile": { "name": "lan", "latency_ms": 1, "jitter_ms": 1 } },
    { "id": "split", "type": "fork", "x": 720, "y": 270 },
    { "id": "settle", "type": "delay", "x": 950, "y": 140, "ms": 300 },
    { "id": "until_ok", "type": "loop", "x": 1180, "y": 140, "max": 40,
      "until": { "value": "{{status}}", "op": "eq", "expected": "200" } },
    { "id": "get", "type": "http", "x": 1410, "y": 20,
      "request": { "method": "GET", "url": "{{api}}/orders/42", "headers": [], "body": null, "timeout_ms": 3000 } },
    { "id": "status", "type": "extract", "x": 1640, "y": 20, "variable": "status", "from": "status", "expr": "" },
    { "id": "pause", "type": "delay", "x": 1870, "y": 20, "ms": 250 },
    { "id": "answered", "type": "log", "x": 1410, "y": 140, "message": "Orders API answers again: HTTP {{status}}" },
    { "id": "slow", "type": "impairment_change", "x": 950, "y": 400, "relay": "link",
      "profile": { "name": "4g", "latency_ms": 60, "jitter_ms": 25, "rate_kbps": 20000 } },
    { "id": "down", "type": "emulator_state", "x": 1180, "y": 400, "emulator": "orders", "down": true, "fault": "unavailable" },
    { "id": "outage", "type": "delay", "x": 1410, "y": 400, "ms": 2000 },
    { "id": "up", "type": "emulator_state", "x": 1640, "y": 400, "emulator": "orders", "down": false, "fault": "unavailable" },
    { "id": "clean", "type": "impairment_change", "x": 1870, "y": 400, "relay": "link",
      "profile": { "name": "lan", "latency_ms": 1, "jitter_ms": 1 } },
    { "id": "joined", "type": "join", "x": 2100, "y": 270 },
    { "id": "end", "type": "end", "x": 2330, "y": 270 }
  ],
  "edges": [
    { "from": "start", "to": "orders" },
    { "from": "orders", "to": "link" },
    { "from": "link", "to": "split" },
    { "from": "split", "to": "settle", "port": "branch1" },
    { "from": "split", "to": "slow", "port": "branch2" },
    { "from": "settle", "to": "until_ok" },
    { "from": "until_ok", "to": "get", "port": "body" },
    { "from": "get", "to": "status" },
    { "from": "status", "to": "pause" },
    { "from": "pause", "to": "until_ok" },
    { "from": "until_ok", "to": "answered", "port": "done" },
    { "from": "answered", "to": "joined" },
    { "from": "slow", "to": "down" },
    { "from": "down", "to": "outage" },
    { "from": "outage", "to": "up" },
    { "from": "up", "to": "clean" },
    { "from": "clean", "to": "joined" },
    { "from": "joined", "to": "end" }
  ]
}

Signal Lab के साथ आने वाले दो टेम्पलेट (प्रयोग में) यही काम दूसरे तरीकों से करते हैं: फ़ॉल्ट फ़ेज़ एक UDP रिले के ज़रिए एमुलेट किए गए डिवाइस को डेटाग्राम भेजता है, जबकि रिले साफ़, लॉस वाला, ऑफ़लाइन और फिर साफ़ किया जाता है; डिपेंडेंसी आउटेज एमुलेट किए गए API को दो सेकंड के लिए बंद करता है, जबकि एक क्लाइंट लगातार माँगता रहता है।

पोर्ट ​

एक रन के सॉकेट — प्रतीक्षाएँ, जवाब, एमुलेटर, रिले — एक ही प्रोटोकॉल का पोर्ट साझा नहीं कर सकते; UDP और TCP सॉकेट एक ही संख्या उपयोग कर सकते हैं। किसी रिले के सुनने का पता के लिए 0.0.0.0 का पता उसी पोर्ट के हर पते से टकराता है।

सॉकेटकिसके साथ अपना पोर्ट साझा नहीं कर सकता
HTTP, TCP या MQTT एमुलेटरइनमें से किसी दूसरे के साथ (emulator.bind_taken)
OSC या UDP एमुलेटरइनमें से किसी दूसरे के साथ (emulator.bind_taken)
TCP या MQTT एमुलेटरHTTP रिक्वेस्ट की प्रतीक्षा के साथ (emulator.bind_taken)
UDP रिले का सुनने का पताकिसी दूसरे UDP रिले, OSC या UDP एमुलेटर, प्रतीक्षा या जवाब के सॉकेट के साथ (impair.bind_taken)
TCP रिले का सुनने का पताकिसी दूसरे TCP रिले, HTTP, TCP या MQTT एमुलेटर, HTTP रिक्वेस्ट की प्रतीक्षा के साथ (impair.bind_taken)

जान-बूझकर साझा: HTTP एमुलेटर और उसके पते पर HTTP रिक्वेस्ट की प्रतीक्षा चरण; OSC या UDP एमुलेटर और उसके पोर्ट पर प्रतीक्षाएँ; एक पते पर प्रतीक्षाएँ आपस में।

रिले सीधे या दूसरे रिले के ज़रिए ख़ुद को ही आगे नहीं भेज सकता: उसका ट्रैफ़िक लूपबैक पर चक्कर काटता रहेगा (impair.loop)। किसी डिवाइस के आगे एक के बाद एक दो रिले ठीक हैं।

फ़ॉल्ट वाले रन को दोहराना ​

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

सीड रखने के लिए टाइमलाइन में उसके पास पिन करें दबाएँ, या उसके साथ इसके साथ चलाएँ… से चलाएँ; देखें सीड। सीड जिसे स्थिर नहीं रख सकता, वह है टाइमिंग: टेस्ट हो रहा सिस्टम कब भेजता है, और इसलिए कोई पैकेट किस फ़ेज़ में पड़ता है।