फ़ॉलबैक पैटर्न: माइक्रोसर्विसेज़ में ग्रेसफुल डिग्रेडेशन डिज़ाइन करना

फ़ॉलबैक पैटर्न: माइक्रोसर्विसेज़ में ग्रेसफुल डिग्रेडेशन डिज़ाइन करना

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

किसी एकल निर्भरता के विफल होने पर उपयोगकर्ताओं को एक सामान्य “500 आंतरिक सर्वर त्रुटि” या एक खाली पृष्ठ लौटाना एक खराब उपयोगकर्ता अनुभव है। इसके बजाय, जब चीजें गलत हो जाती हैं तो लचीली प्रणालियाँ शालीनता से ख़राब होने के लिए बनाई जाती हैं।

यहीं पर फ़ॉलबैक पैटर्न आता है। प्राथमिक सेवा कॉल विफल होने पर निष्पादन के एक सुरक्षित, वैकल्पिक पथ को परिभाषित करके, आप अपने एप्लिकेशन को कार्यात्मक रख सकते हैं - यहां तक ​​कि ख़राब स्थिति में भी।

इस गाइड में, हम फ़ॉलबैक पैटर्न, इसे लागू करने के लिए सामान्य रणनीतियों, यह अन्य लचीलेपन पैटर्न के साथ कैसे इंटरैक्ट करता है, और जावा (रेसिलिएंस4जे) और गो में फ़ॉलबैक लॉजिक कैसे लिखें, इसका पता लगाएंगे।


वास्तविक दुनिया सादृश्य: कॉफ़ी शॉप बैकअप योजना

कल्पना कीजिए कि आप लट्टे खरीदने के लिए एक स्थानीय कॉफी शॉप में जाते हैं। बरिस्ता आपके ऑर्डर को इनपुट करता है, लेकिन जब आप अपने कार्ड पर टैप करने जाते हैं, तो भुगतान टर्मिनल एक कनेक्शन त्रुटि दिखाता है - दुकान का इंटरनेट प्रदाता आउटेज का अनुभव कर रहा है।

क्या कॉफ़ी शॉप तुरंत लाइटें बंद कर देती है, दरवाज़े बंद कर देती है और सभी ग्राहकों को घर भेज देती है?

बिल्कुल नहीं। वे एक फ़ॉलबैक रणनीति लागू करते हैं:

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

सॉफ़्टवेयर डिज़ाइन में:

  • कॉफ़ी ऑर्डर ग्राहक का अनुरोध है।
  • कार्ड टर्मिनल प्राथमिक डाउनस्ट्रीम सेवा है (उदाहरण के लिए, भुगतान गेटवे एपीआई)।
  • इंटरनेट आउटेज एक नेटवर्क टाइमआउट या सेवा क्रैश है।
  • लेजर/ऑफ़लाइन रीडर फ़ॉलबैक निष्पादन पथ है।

सामान्य फ़ॉलबैक रणनीतियाँ

व्यावसायिक तर्क और विफल सेवा की गंभीरता के आधार पर, आप कई फ़ॉलबैक रणनीतियों में से चुन सकते हैं:

1. स्थैतिक डिफ़ॉल्ट मान

सबसे सरल रणनीति एक सुरक्षित, पूर्व-कॉन्फ़िगर स्थिर मान वापस करना है। यह गैर-महत्वपूर्ण सुविधाओं के लिए अत्यधिक प्रभावी है जहां रिक्त या डिफ़ॉल्ट डेटा प्रदर्शित करना स्वीकार्य है।

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

2. कैश्ड प्रतिक्रियाएँ (बासी-जबकि-पुनर्वैधीकरण)

यदि लाइव डेटा अनुपलब्ध है, तो आप स्थानीय कैश या रेडिस जैसे तेजी से वितरित मेमोरी स्टोर से केवल-पढ़ने के लिए पुराने डेटा पर वापस आ सकते हैं।

  • उदाहरण: यदि कोई उत्पाद इन्वेंट्री सेवा बंद हो जाती है, तो 5 मिनट पहले कैश किए गए स्टॉक में मात्रा प्रदर्शित करें, साथ ही एक सूक्ष्म यूआई संदेश यह दर्शाता है कि डेटा पूरी तरह से अद्यतित नहीं हो सकता है।
  • उदाहरण: यदि कोई उपयोगकर्ता सेटिंग सेवा विफल हो जाती है, तो उनके लॉगिन प्रवाह को अवरुद्ध करने के बजाय कैश्ड उपयोगकर्ता प्रोफ़ाइल लोड करें।

3. वैकल्पिक सेवा (बहु-प्रदाता)

किसी महत्वपूर्ण ऑपरेशन को निष्पादित करते समय जो सफल होना चाहिए, आप एक द्वितीयक सेवा प्रदाता को बैकअप के रूप में कॉन्फ़िगर कर सकते हैं।

  • उदाहरण: यदि आपका प्राथमिक भुगतान गेटवे (उदाहरण के लिए, स्ट्राइप) 5xx त्रुटि या टाइम आउट देता है, तो फ़ॉलबैक तंत्र तुरंत लेनदेन अनुरोध को द्वितीयक गेटवे (उदाहरण के लिए, पेपैल या एडेन) पर रीडायरेक्ट करता है।
  • उदाहरण: यदि जियोकोडिंग एपीआई विफल हो जाता है, तो द्वितीयक मैपिंग प्रदाता पर वापस जाएं।

4. बाद के लिए कतार (एसिंक्रोनस बफर)

ऐसे लिखने के संचालन के लिए जिन्हें तत्काल सिंक्रोनस प्रोसेसिंग की आवश्यकता नहीं होती है, फ़ॉलबैक बाद में पुनः प्रयास करने के लिए स्थानीय कतार या डेटाबेस में अनुरोध को बफर कर सकता है।

  • उदाहरण: यदि कोई ईमेल अधिसूचना सेवा बंद है, तो अधिसूचना पेलोड को डेड-लेटर कतार या स्थानीय डेटाबेस तालिका में लिखें। एक पृष्ठभूमि कार्यकर्ता इस कतार से पढ़ेगा और अधिसूचना सेवा फिर से स्वस्थ होने पर ईमेल वितरित करेगा।

लचीलापन तिकड़ी: पुनः प्रयास बनाम सर्किट ब्रेकर बनाम फ़ॉलबैक

अत्यधिक लचीला आर्किटेक्चर बनाने के लिए, आपको फ़ॉलबैक पैटर्न को पुनः प्रयास और सर्किट ब्रेकर पैटर्न के साथ संयोजित करने की आवश्यकता है। वे रक्षा की तीन स्तरीय रेखा बनाते हैं:

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

वे एक साथ कैसे काम करते हैं

  1. एक आने वाला अनुरोध सेवा गेटवे पर आता है।
  2. अनुरोध सर्किट ब्रेकर से होकर गुजरता है।
  3. यदि सर्किट ब्रेकर बंद है, तो अनुरोध पुनः प्रयास करें रैपर पर जाता है, जो वास्तविक कॉल करता है।
  4. यदि कोई क्षणिक त्रुटि होती है, तो पुनः प्रयास तंत्र फिर से कॉल का प्रयास करता है।
  5. यदि सभी पुनः प्रयास विफल हो जाते हैं, या यदि सर्किट ब्रेकर पहले से ही खुला था (संसाधनों को बचाने के लिए तेजी से विफल हो रहा है), तो फ़ॉलबैक हैंडलर विफलता को रोकता है और डिग्रेडेड/कैश्ड प्रतिक्रिया लौटाता है।

कोड कार्यान्वयन

आइए देखें कि हम जावा और गो दोनों में फ़ॉलबैक लॉजिक को कैसे लागू कर सकते हैं।

1. जावा (Resilience4j)

जावा में, Resilience4j दोष सहनशीलता के लिए उद्योग मानक है। हम एनोटेशन या प्रोग्रामेटिक रूप से घोषणात्मक रूप से फ़ॉलबैक विधि को परिभाषित कर सकते हैं।

import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;

@Service
public class ProductService {

    private final InventoryClient inventoryClient;
    private final CacheManager cacheManager;

    public ProductService(InventoryClient inventoryClient, CacheManager cacheManager) {
        this.inventoryClient = inventoryClient;
        this.cacheManager = cacheManager;
    }

    // Bind this method to a circuit breaker. If it fails or is open, route to fallback
    @CircuitBreaker(name = "inventoryService", fallbackMethod = "getInventoryFallback")
    public List<String> getProductInventory(String category) {
        return inventoryClient.fetchStockByCategory(category);
    }

    // Fallback method must have the same return type and accept the same parameters,
    // plus a Throwable parameter containing the error that triggered it
    public List<String> getInventoryFallback(String category, Throwable throwable) {
        System.err.println("Primary inventory service failed: " + throwable.getMessage());
        
        // Attempt to fetch from local cache (Strategy 2)
        List<String> cachedStock = cacheManager.get("inventory:" + category, List.class);
        if (cachedStock != null) {
            return cachedStock;
        }

        // Return static empty list if cache is empty (Strategy 1)
        return Collections.emptyList();
    }
}

2. जाओ (गोलंग)

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

package main

import (
	"context"
	"errors"
	"fmt"
	"time"
)

// Request represents a simple payload
type Request struct {
	UserID string
}

// Response represents the returned data
type Response struct {
	Data   string
	Status string
}

// ServiceFunc represents our primary function signature
type ServiceFunc func(ctx context.Context, req Request) (Response, error)

// WithFallback wraps a service function with fallback logic
func WithFallback(primary ServiceFunc, fallback ServiceFunc) ServiceFunc {
	return func(ctx context.Context, req Request) (Response, error) {
		res, err := primary(ctx, req)
		if err != nil {
			fmt.Printf("[Warning] Primary call failed: %v. Running fallback...\n", err)
			return fallback(ctx, req)
		}
		return res, nil
	}
}

func main() {
	// 1. Define primary service that occasionally fails
	primaryService := func(ctx context.Context, req Request) (Response, error) {
		return Response{}, errors.New("database connection timeout (504)")
	}

	// 2. Define fallback service that retrieves cached data
	fallbackService := func(ctx context.Context, req Request) (Response, error) {
		// Simulating cached read
		return Response{
			Data:   fmt.Sprintf("Stale cached profile data for user %s", req.UserID),
			Status: "DEGRADED (CACHED)",
		}, nil
	}

	// 3. Wrap them together
	resilientService := WithFallback(primaryService, fallbackService)

	// 4. Execute
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	req := Request{UserID: "user_992"}
	response, err := resilientService(ctx, req)
	if err != nil {
		fmt.Printf("Operation completely failed: %v\n", err)
	} else {
		fmt.Printf("Response Received:\n - Status: %s\n - Data: %s\n", response.Status, response.Data)
	}
}

फ़ॉलबैक पैटर्न के लिए सर्वोत्तम अभ्यास

  1. फ़ॉलबैक पथ को निर्भरता-मुक्त रखें: फ़ॉलबैक तर्क को उसी डाउनस्ट्रीम सिस्टम या बुनियादी ढांचे पर निर्भर नहीं होना चाहिए जो अभी विफल हुआ है। यदि आपका डेटाबेस डाउन है, तो उसी सर्वर पर किसी अन्य डेटाबेस क्वेरी पर वापस जाना भी संभवतः विफल हो जाएगा।
  2. तेजी से निष्पादित करें: फ़ॉलबैक तर्क को तेज़ी से निष्पादित करना चाहिए। अपने फ़ॉलबैक पथों में जटिल गणनाओं या धीमी नेस्टेड कॉलों से बचें। लक्ष्य उपयोगकर्ता को यथाशीघ्र प्रतिक्रिया देना है।
  3. अलर्ट और मॉनिटर: हमेशा फ़ॉलबैक निष्पादन और वेतन वृद्धि टेलीमेट्री काउंटरों को लॉग करें। यदि आपका सिस्टम फ़ॉलबैक पथ निष्पादित कर रहा है, तो इसका मतलब है कि सिस्टम खराब स्थिति में काम कर रहा है। आपको यह जानने के लिए अलर्ट की आवश्यकता है कि फ़ॉलबैक दरें कब सामान्य सीमा से अधिक हो जाती हैं।
  4. यूआई को लचीला बनाएं: यह सुनिश्चित करने के लिए फ्रंटएंड इंजीनियरों के साथ मिलकर काम करें कि यूआई को क्लाइंट-साइड लेआउट को तोड़े बिना फ़ॉलबैक पेलोड (जैसे खाली संग्रह या आंशिक स्थिति) स्वीकार करने के लिए डिज़ाइन किया गया है।

निष्कर्ष

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