Aracılığıyla paylaş


Storm kötü modeli yeniden deneme

Bir hizmet kullanılamadığında veya meşgul olduğunda, istemcilerin bağlantılarını çok sık yeniden denemesi hizmetin kurtarılmasında zorlanabilir ve sorunu daha da kötüleştirebilir. İstekler genellikle yalnızca tanımlı bir süre için geçerli olduğundan, sonsuza kadar yeniden denemeniz de mantıklı değildir.

Sorun açıklaması

Bulutta hizmetler bazen sorun yaşar ve istemciler tarafından kullanılamaz duruma gelir ya da istemcilerini kısıtlamak veya hız sınırlaması yapmak zorunda kalır. İstemcilerin hizmetlere başarısız bağlantıları yeniden denemesi iyi bir uygulama olsa da, çok sık veya çok uzun süre yeniden denememeleri önemlidir. Hizmetler büyük olasılıkla kurtarılmayacağı için kısa bir süre içinde yeniden denemelerin başarılı olma olasılığı düşüktür. Ayrıca, kurtarmaya çalışırken çok sayıda bağlantı girişimi yapıldığında hizmetler daha da baskı altına alınabilir ve yinelenen bağlantı girişimleri hizmeti bile bunaltabilir ve temel sorunu daha da kötü hale getirebilir.

Aşağıdaki örnekte, istemcinin sunucu tabanlı API'ye bağlandığı bir senaryo gösterilmektedir. İstek başarılı olmazsa, istemci hemen yeniden denenir ve sonsuza kadar yeniden denemeye devam eder. Genellikle bu tür davranışlar bu örnektekinden daha hafiftir, ancak aynı ilke geçerlidir.

public async Task<string> GetDataFromServer()
{
    while(true)
    {
        var result = await httpClient.GetAsync(string.Format("http://{0}:8080/api/...", hostName));
        if (result.IsSuccessStatusCode) break;
    }

    // ... Process result.
}

Sorunun çözümü

İstemci uygulamaları, yeniden deneme fırtınasına neden olmaktan kaçınmak için bazı en iyi yöntemleri izlemelidir.

  • Yeniden deneme denemesi sayısını sınırlayıp uzun süre yeniden denemeye devam etmeyin. Döngü yazmak while(true) kolay gibi görünse de, isteğin başlatılmasına neden olan durum büyük olasılıkla değiştiğinden, uzun bir süre gerçekten yeniden denemek istemezsiniz. Çoğu uygulamada, birkaç saniye veya dakika boyunca yeniden denemek yeterlidir.
  • Yeniden deneme girişimleri arasında duraklatma. Bir hizmet kullanılamıyorsa, hemen yeniden denemenin başarılı olma olasılığı düşüktür. Örneğin üstel geri alma stratejisini kullanarak denemeler arasında bekleme süresini aşamalı olarak artırın.
  • Hataları düzgün bir şekilde işleyin. Hizmet yanıt vermiyorsa, denemeyi durdurmanın ve bileşeninizin kullanıcısına veya çağırana bir hata döndürmenin mantıklı olup olmadığını düşünün. Uygulamanızı tasarlarken bu hata senaryolarını göz önünde bulundurun.
  • Yeniden deneme fırtınalarını önlemeye yardımcı olmak için özel olarak tasarlanan Devre Kesici desenini kullanmayı göz önünde bulundurun.
  • Sunucu bir retry-after yanıt üst bilgisi sağlıyorsa, belirtilen süre geçene kadar yeniden denemeyi denemediğinizden emin olun.
  • Azure hizmetleriyle iletişim kurarken resmi SDK'ları kullanın. Bu SDK'lar genellikle yerleşik yeniden deneme ilkelerine ve yeniden deneme fırtınalarına neden veya bunlara katkıda bulunmaya karşı korumalara sahiptir. SDK'sı olmayan veya SDK'nın yeniden deneme mantığını doğru işlemediği bir hizmetle iletişim kuruyorsanız, yeniden deneme mantığınızı doğru şekilde işlemek ve kodu kendiniz yazmaktan kaçınmak için Polly (.NET için) veya yeniden deneme (JavaScript için) gibi bir kitaplık kullanmayı göz önünde bulundurun.
  • Bunu destekleyen bir ortamda çalıştırıyorsanız, giden çağrılar göndermek için bir hizmet ağı (veya başka bir soyutlama katmanı) kullanın. Genellikle Dapr gibi bu araçlar yeniden deneme ilkelerini destekler ve yinelenen denemelerden sonra geri adım atma gibi en iyi yöntemleri otomatik olarak izler. Bu yaklaşım, yeniden deneme kodunu kendiniz yazmanız gerekmeyecek anlamına gelir.
  • İstekleri toplu olarak oluşturmayı ve varsa istek havuzunu kullanmayı göz önünde bulundurun. Birçok SDK, istek toplu işlemini ve bağlantı havuzunu sizin yerinize işler ve bu da uygulamanızın yaptığı toplam giden bağlantı denemesi sayısını azaltır, ancak yine de bu bağlantıları çok sık yeniden denememeye dikkat etmeniz gerekir.

Hizmetler de kendilerini yeniden deneme fırtınalarına karşı korumalıdır.

  • Olay sırasında bağlantıları kapatabilmeniz için bir ağ geçidi katmanı ekleyin. Bu, Bulkhead deseninin bir örneğidir. Azure, Front Door, Application Gateway ve API Management gibi farklı çözüm türleri için birçok farklı ağ geçidi hizmeti sunar.
  • Ağ geçidinizdeki istekleri kısıtlayabilir ve bu sayede arka uç bileşenlerinizin çalışmaya devam etmeyeceği kadar çok isteği kabul etmezsiniz.
  • Azaltma işlemi kullanıyorsanız, istemcilerin bağlantılarını ne zaman yeniden değerlendirmeleri gerekenleri anlamalarına yardımcı olmak için bir retry-after üst bilgi gönderin.

Dikkat edilmesi gerekenler

  • İstemciler döndürülen hata türünü dikkate almalıdır. Bazı hata türleri hizmetin başarısız olduğunu göstermez, bunun yerine istemcinin geçersiz bir istek gönderdiğini gösterir. Örneğin, bir istemci uygulama bir 400 Bad Request hata yanıtı alırsa, sunucu isteğinizin geçerli olmadığını söylediği için aynı isteği yeniden denemek büyük olasılıkla yararlı olmayacaktır.
  • İstemciler, bağlantıları yeniden kullanmak için anlamlı olan süreyi dikkate almalıdır. Yeniden denemeniz gereken süre, iş gereksinimlerinize ve bir hatayı makul bir şekilde bir kullanıcıya veya arayana geri yayıp yayamayacağınıza göre yönlendirilir. Çoğu uygulamada, birkaç saniye veya dakika boyunca yeniden denemek yeterlidir.

Sorunu algılama

İstemci açısından bakıldığında, bu sorunun belirtileri çok uzun yanıt veya işlem süreleri ve bağlantıyı yeniden deneme girişimlerinin tekrarlandığını gösteren telemetri içerebilir.

Hizmet açısından bakıldığında, bu sorunun belirtileri kısa bir süre içinde bir istemciden çok sayıda istek veya kesintilerden kurtarılırken tek bir istemciden çok sayıda istek içerebilir. Belirtiler, hizmetin kurtarılmasında zorluk veya bir hata onarıldıktan hemen sonra hizmetin sürekli art arda hataları da içerebilir.

Örnek tanılama

Aşağıdaki bölümlerde, hem istemci tarafında hem de hizmet tarafında olası yeniden deneme fırtınasını algılamaya yönelik bir yaklaşım gösterilmektedir.

İstemci telemetrisinden tanımlama

Azure Uygulaması Insights, uygulamalardan gelen telemetri verilerini kaydeder ve verileri sorgulama ve görselleştirme için kullanılabilir hale getirir. Giden bağlantılar bağımlılık olarak izlenir ve bir istemcinin aynı hizmete çok sayıda giden istekte bulunduğu zamanları belirlemek için bunlara ilişkin bilgilere erişilip grafik oluşturulabilir.

Aşağıdaki grafik Application Insights portalındaki Ölçümler sekmesinden alınmıştır ve Bağımlılık hataları ölçümü Uzak bağımlılık adına göre bölünmüş olarak görüntülenmektedir. Bu, kısa bir süre içinde bir bağımlılıkla başarısız olan bağlantı girişimlerinin çok sayıda (21.000'den fazla) olduğu bir senaryoyu gösterir.

30 dakikalık bir süre içinde tek bir bağımlılıkta 21k bağımlılık hatalarını gösteren Application Insights'ın ekran görüntüsü

Sunucu telemetrisinden tanımlama

Sunucu uygulamaları tek bir istemciden çok sayıda bağlantı algılayabilir. Aşağıdaki örnekte, Azure Front Door bir uygulama için ağ geçidi işlevi görür ve tüm istekleri Log Analytics çalışma alanına günlüğe kaydedecek şekilde yapılandırılmıştır .

Aşağıdaki Kusto sorgusu Log Analytics'e karşı yürütülebilir. Son gün içinde uygulamaya çok sayıda istek gönderen istemci IP adreslerini belirler.

AzureDiagnostics
| where ResourceType == "FRONTDOORS" and Category == "FrontdoorAccessLog"
| where TimeGenerated > ago(1d)
| summarize count() by bin(TimeGenerated, 1h), clientIp_s
| order by count_ desc

Yeniden deneme fırtınası sırasında bu sorgunun yürütülmesi, tek bir IP adresinden çok sayıda bağlantı girişimi olduğunu gösterir.

Bir saatlik süre içinde tek bir IP adresinden Front Door'a 81.608 gelen bağlantıyı gösteren Log Analytics'in ekran görüntüsü