nginx reverse proxy - önce A, sonra B, ardından A'yı tekrar deneyin


22

Çok sayıda arka uç sunucusu içeren nginx'i ters proxy olarak kurmaya çalışıyorum. Talep üzerine (gelen ilk talepte) talep üzerine arka uç başlatmak istiyorum, bu yüzden aldığı talebe bağlı olarak arka uçta başlayan bir kontrol sürecim (HTTP istekleriyle kontrol ediliyor) var.

Benim sorunum bunu yapmak için nginx'i yapılandırmak. İşte şimdiye kadar sahip olduğum şey:

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;
    }
}

Bu işe yaramaz - nginx, kontrol sunucusundan döndürülen durum kodlarını görmezden gelir. Lokasyondaki error_pagedirektiflerin hiçbiri @handle_502çalışmıyor ve 451 kodu müşteriye olduğu gibi gönderiliyor.

Bunun için dahili nginx yönlendirmesini kullanmaktan vazgeçtim ve kontrol sunucusunu aynı yere 307 yönlendirmesi verecek şekilde değiştirmeye çalıştım (böylece müşteri aynı isteği tekrar deneyecek, ama şimdi arka uç sunucusu başladı). Ancak, nginx, kontrol sunucusunun bir "Konum" başlığı göndermesine rağmen, arka uç isteği girişimi (502) 'den gelen durum kodunun aptalca üzerine yazmaktadır. Sonunda error_page satırını değiştirerek "çalışıyor" oldumerror_page 502 =307 @handle_502;Böylece tüm kontrol sunucusu cevaplarını istemciye 307 koduyla geri gönderilmeye zorlamak. Bu çok tehlikeli ve istenmeyen bir durumdur, çünkü 1) kontrol sunucusunun cevabına bağlı olarak nginx'in sonra ne yapması gerektiğine dair bir kontrol yoktur (ideal olarak sadece kontrol sunucusu başarı rapor ederse arka ucu yeniden denemek isteriz) ve 2) tüm HTTP değil istemciler HTTP yönlendirmelerini destekler (örneğin, curl kullanıcıları ve libcurl kullanan uygulamalar açıkça yönlendirmeleri takip etmelidir).

Nginx'in yukarı akış sunucusuna A, sonra B, sonra tekrar A'ya proxy kullanmaya çalışmasının doğru yolu nedir (ideal olarak, yalnızca B belirli bir durum kodu döndürdüğünde)?

Yanıtlar:


20

Anahtar noktaları:

  • upstreamBir sunucuya ping atmak başka bir tane getirecekse, yerine çalışma blokları ile uğraşmayın - nginx'e (en azından FOSS sürümü değil) ilk sunucunun tekrar çalıştığını söylemenin bir yolu yoktur. nginx herhangi rağmen takip istekleri ilk talep üzerine sırayla sunucuları çalışıyorum, ama olmaz backup, weightya da fail_timeoutayarlara.
  • Sen gerekir etkinleştirmek recursive_error_pageskullanarak yerine çalışma uygularken error_pageve adlandırılmış yerleri.
  • Giriş proxy_intercept_errorssunucusundan gönderilen hata kodlarını işlemeyi etkinleştirin .
  • =Sözdizimi (örneğin error_page 502 = @handle_502;) düzgün adlı yer hata kodları işlemek için gereklidir. Eğer =kullanılmazsa, nginx önceki bloktan hata kodunu kullanacaktır.

Orijinal cevap / araştırma günlüğü takip:


İşte bulduğum daha iyi bir geçici çözüm. Bu, istemci yönlendirmesi gerektirmediğinden bir gelişmedir:

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;
}

Ardından, kontrol sunucusuna "başarı" ile 502 döndürmesini sağlayın ve kodun asla arka uçlar tarafından döndürülmediğini umun.


Güncelleme: nginx upstreambloktaki ilk girişi aşağı olarak işaretlemeye devam eder , böylece art arda gelen taleplerde sunucuları denemez. weight=1000000000 fail_timeout=1Etkisi olmayan ilk girişe eklemeye çalıştım . Şimdiye kadar bir müşteri yönlendirmesi içermeyen herhangi bir çözüm bulamadım.


Düzenleme: Keşke bilseydim bir şey daha var - hata durumunu error_pageişleyiciden almak için , bu sözdizimini kullanın: error_page 502 = @handle_502;- işareti eşittir, nginx'in işleyiciden hata durumunu almasına neden olur.


Düzenleme: Ve ben onu işe aldım! error_pageYukarıdaki düzeltmeye ek olarak , tüm ihtiyaç duyulan oldu recursive_error_pages!


1
Benim için proxy_next_upstreamhile yaptım (senaryo benimki kadar karmaşık değildi), bir hata oluştuğunda nginx'in bir sonraki sunucuyu denemesini istedim, bu yüzden eklemek zorunda kaldım proxy_next_upstream error timeout invalid_header non_idempotent;( non_idempotentçünkü POSTistekleri iletmek istiyorum ).
Philipp,

1

Aşağıdaki gibi bir şey deneyebilirsiniz

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;
    }

}

nginx a.example.net, aynı istek üzerinde başarısız olduktan sonra yeniden denemez . İstemciye, bağlanmaya çalışırken karşılaşılan hatayı gönderir b.example.net; kontrol sunucusunda da proxy uygulaması yapmadığım sürece bekledikleri gibi olmaz.
Vladimir Panteleev

Ve bir sonraki durumda konfigürasyonunuzda ne olurdu: yukarı akış A isteği geri dönüş başarısız olur, yukarı akış B dönüş başarısız olur, sonra tekrar A akışını deneriz ve başarısız oluruz (502)?
ALex_hha 08:13

Giriş yönü B, kontrol sunucusudur. Amacı, A giriş yönünde bir sonraki isteğin başarılı olacağından emin olmaktır. Amaç, A girişini denemek, eğer B girişini denemede başarısız olursa, eğer "başarılı olduysa" ("başarı" iç sözleşmemizi kullanarak) tekrar A girişini deneyin. Sorum yeterince açık değilse, nasıl geliştirebileceğimi bilmeme izin ver.
Vladimir Panteleev

Hmm, örneğin bazı donanım sorunları için A akışının aşağı olduğunu varsayalım. Giriş yönü B'yi ne yapacak? Müşteriden gelen talebe cevap verebilecek mi?
ALex_hha

Bu sorun, donanım arızaları için yerine çalışma ile ilgili değildir. Bu sorun, talebe bağlı olarak yukarı havza başlaması ile ilgilidir. Kontrol sunucusu (yukarı akış B) arka ucu (yukarı akış A) yeniden etkinleştiremiyorsa, ideal olarak kullanıcı uygun bir hata mesajı almalıdır, ancak çözmeye çalıştığım sorun değil - sorun yeniden denemeye nginx oluyor Aynı istek içinde tekrar B'den sonra.
Vladimir Panteleev
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.