nginx रिवर्स प्रॉक्सी - अपस्ट्रीम A, फिर B, फिर A फिर से प्रयास करें


22

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

मेरी समस्या इसे करने के लिए nginx को कॉन्फ़िगर कर रही है। यहाँ मेरे पास अभी तक क्या है:

server {
    listen 80;
    server_name $DOMAINS;

    location / {
        # redirect to named location
        #error_page 418 = @backend;
        #return 418; # doesn't work - error_page doesn't work after redirect

        try_files /nonexisting-file @backend;
    }

    location @backend {
        proxy_pass http://$BACKEND-IP;
        error_page 502 @handle_502; # Backend server down? Try to start it
    }

    location @handle_502 { # What to do when the backend server is not up
        # Ping our control server to start the backend
        proxy_pass http://127.0.0.1:82;
        # Look at the status codes returned from control server
        proxy_intercept_errors on;
        # Fallback to error page if control server is down
        error_page 502 /fatal_error.html;
        # Fallback to error page if control server ran into an error
        error_page 503 /fatal_error.html;
        # Control server started backend successfully, retry the backend
        # Let's use HTTP 451 to communicate a successful backend startup
        error_page 451 @backend;
    }

    location = /fatal_error.html {
        # Error page shown when control server is down too
        root /home/nginx/www;
        internal;
    }
}

यह काम नहीं करता है - nginx नियंत्रण सर्वर से लौटे किसी भी स्थिति कोड को अनदेखा करता है। स्थान कार्य error_pageमें कोई भी निर्देश नहीं है @handle_502, और 451 कोड ग्राहक को-के रूप में भेजा जाता है।

मैंने इसके लिए आंतरिक nginx पुनर्निर्देशन का उपयोग करने की कोशिश करना छोड़ दिया, और उसी स्थान पर 307 पुनर्निर्देशित करने के लिए नियंत्रण सर्वर को संशोधित करने का प्रयास किया (ताकि ग्राहक उसी अनुरोध को पुनः प्रयास कर सके, लेकिन अब बैकेंड सर्वर के साथ शुरू हुआ)। हालाँकि, अब nginx स्टेटस कोड को बेवकूफ़ तरीके से ओवरराइट कर रहा है, क्योंकि इसे बैकएंड अनुरोध प्रयास (502) से मिला है, इसके बावजूद कंट्रोल सर्वर "लोकेशन" हेडर भेज रहा है। आखिरकार मैंने error_page लाइन को बदलकर इसे "काम" कर लियाerror_page 502 =307 @handle_502;, इस प्रकार 307 कोड के साथ ग्राहक को वापस भेजे जाने के लिए सभी नियंत्रण सर्वर उत्तरों को मजबूर करने के लिए। यह बहुत ही घटिया और अवांछनीय है, क्योंकि 1) नियंत्रण सर्वर की प्रतिक्रिया के आधार पर nginx को आगे क्या करना चाहिए, इस पर कोई नियंत्रण नहीं है (आदर्श रूप से हम केवल बैकएंड को फिर से प्राप्त करना चाहते हैं यदि नियंत्रण सर्वर सफलता की रिपोर्ट करता है), और 2) सभी HTTP क्लाइंट HTTP पुनर्निर्देशन का समर्थन करते हैं (उदाहरण के लिए कर्ल उपयोगकर्ता और libcurl का उपयोग करने वाले अनुप्रयोगों को स्पष्ट रूप से पुनर्निर्देशित करने में सक्षम करने की आवश्यकता होती है)।

सर्वर ए, फिर बी, फिर ए (फिर आदर्श रूप में, केवल जब बी एक विशिष्ट स्थिति कोड लौटाता है) को प्रॉक्सी करने की कोशिश करने के लिए nginx प्राप्त करने का उचित तरीका क्या है?

जवाबों:


20

प्रमुख बिंदु:

  • upstreamफ़ेलओवर के लिए ब्लॉक के साथ परेशान न करें , अगर एक सर्वर को पिंग करने से एक और एक उठेगा - nginx (कम से कम, नहीं FOSS संस्करण) को बताने का कोई तरीका नहीं है कि पहला सर्वर फिर से है। nginx किसी भी के बावजूद पहले अनुरोध पर आदेश में सर्वर की कोशिश करेंगे, लेकिन नहीं अनुवर्ती अनुरोधों, backup, weightया fail_timeoutसेटिंग्स।
  • स्थानों और नाम वाले स्थानों का उपयोग करते समय आपको सक्षम होना चाहिएrecursive_error_pageserror_page
  • सक्षम proxy_intercept_errorsअपस्ट्रीम सर्वर से भेजा त्रुटि कोड को संभालने के लिए।
  • =वाक्य रचना (जैसे error_page 502 = @handle_502;) सही ढंग से नामित स्थान में त्रुटि कोड को संभालने के लिए आवश्यक है। यदि =उपयोग नहीं किया जाता है, तो nginx पिछले ब्लॉक से त्रुटि कोड का उपयोग करेगा।

मूल उत्तर / शोध लॉग का पालन करें:


यहां मैंने एक बेहतर समाधान पाया है, जो एक सुधार है क्योंकि इसके लिए ग्राहक को पुनर्निर्देशित करने की आवश्यकता नहीं है:

upstream aba {
    server $BACKEND-IP;
    server 127.0.0.1:82 backup;
    server $BACKEND-IP  backup;
}

...

location / {
    proxy_pass http://aba;
    proxy_next_upstream error http_502;
}

फिर, "सफलता" पर 502 वापस करने के लिए बस नियंत्रण सर्वर प्राप्त करें और आशा करें कि कोड कभी भी बैकएंड द्वारा वापस नहीं किया गया है।


अद्यतन: nginx upstreamनीचे के रूप में ब्लॉक में पहली प्रविष्टि को चिह्नित करता रहता है , इसलिए यह क्रमिक अनुरोधों पर सर्वर का प्रयास नहीं करता है। मैंने weight=1000000000 fail_timeout=1पहली प्रविष्टि को बिना किसी प्रभाव के जोड़ने की कोशिश की है। अभी तक मुझे ऐसा कोई समाधान नहीं मिला है जिसमें क्लाइंट रिडायरेक्ट न हो।


संपादित करें: एक और बात जो मैं चाहता हूं कि मुझे पता था - error_pageहैंडलर से त्रुटि की स्थिति प्राप्त करने के लिए , इस सिंटैक्स का उपयोग करें: error_page 502 = @handle_502;- जो बराबर होता है संकेत हैंडलर से त्रुटि स्थिति प्राप्त करने के लिए nginx का कारण होगा।


संपादित करें: और मुझे यह काम कर रहा है! error_pageऊपर दिए गए फिक्स के अलावा , जो भी आवश्यक था वह सक्षम था recursive_error_pages!


1
मेरे लिए proxy_next_upstreamट्रिक (अच्छी तरह से मेरा परिदृश्य आपके जैसे जटिल नहीं था), मुझे बस अगले सर्वर की कोशिश करने के लिए nginx चाहिए था यदि कोई त्रुटि हुई, इस प्रकार मुझे जोड़ना था proxy_next_upstream error timeout invalid_header non_idempotent;( non_idempotentक्योंकि, मैं मुख्य रूप से POSTअनुरोधों को आगे करना चाहता हूं )।
फिलिप

1

आप निम्नलिखित की तरह कुछ कोशिश कर सकते हैं

upstream backend {
    server a.example.net;
    server b.example.net backup;
}

server {
    listen   80;
    server_name www.example.net;

    proxy_next_upstream error timeout http_502;

    location / {
        proxy_pass http://backend;
        proxy_redirect      off;
        proxy_set_header    Host              $host;
        proxy_set_header    X-Real-IP         $remote_addr;
        proxy_set_header    X-Forwarded-for   $remote_addr;
    }

}

a.example.netएक ही अनुरोध पर एक बार विफल होने के बाद nginx पीछे नहीं हटेगा । यह ग्राहक को उस त्रुटि के लिए भेजेगा b.example.net, जिसे कनेक्ट करने की कोशिश करते समय त्रुटि हुई थी , जो कि तब तक होने वाली नहीं है जब तक कि मैं नियंत्रण सर्वर में समीपता को लागू नहीं करता।
व्लादिमीर पेंटेलेव

और अगली स्थिति में आपके कॉन्फिगरेशन के साथ क्या होगा: अपस्ट्रीम के लिए अनुरोध करें एक वापसी विफल, अपस्ट्रीम बी रिटर्न विफल, तो हम फिर से अपस्ट्रीम ए की कोशिश कर रहे हैं और असफल भी हो (502)?
ALex_hha

अपस्ट्रीम B कंट्रोल सर्वर है। इसका उद्देश्य यह सुनिश्चित करना है कि अपस्ट्रीम ए का अगला अनुरोध सफल होगा। लक्ष्य अपस्ट्रीम ए का प्रयास करना है, अगर यह अपस्ट्रीम बी को विफल करने की कोशिश करता है, अगर यह "सफल" ("सफलता" के हमारे आंतरिक सम्मेलन का उपयोग करके), फिर से ऊपर की तरफ एक प्रयास करें। यदि मेरा प्रश्न पर्याप्त स्पष्ट नहीं था, तो मुझे बताएं कि मैं इसे कैसे सुधार सकता हूं।
व्लादिमीर पेंटेलेव

हम्म, चलो ऊपर की ओर A मान लें, जैसे कुछ हार्डवेयर समस्या। क्या करेंगे बी अपस्ट्रीम? क्या यह क्लाइंट से अनुरोध पर प्रतिक्रिया देने में सक्षम है?
ALex_hha

यह समस्या हार्डवेयर विफलताओं के लिए विफलता के बारे में नहीं है। यह समस्या ऑन-डिमांड बैकस्टेज शुरू करने के बारे में है। यदि नियंत्रण सर्वर (अपस्ट्रीम B) बैकएंड (अपस्ट्रीम A) को पुन: सक्रिय नहीं कर सकता है, तो आदर्श रूप से उपयोगकर्ता को एक उपयुक्त त्रुटि संदेश मिलना चाहिए, लेकिन यह वह समस्या नहीं है जिसे मैं हल करने की कोशिश कर रहा हूं - समस्या फिर से होने के लिए nginx हो रही है ए के बाद बी फिर से, उसी अनुरोध के भीतर।
व्लादिमीर पेंटेलेव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.