Storm kötü amaçlı yazılımdan korumayı yeniden deneme

Bir hizmet kullanılamaz duruma geldiğinde veya meşgul olduğunda, sık sık yapılan istemci yeniden denemeleri hizmetin kurtarılmasını engelleyebilir ve sorunu kötüleştirebilir. İstekler genellikle yalnızca sınırlı bir süre için geçerli kaldığından, süresiz olarak yeniden deneme işlemi etkisizdir.

Bağlam ve sorun

Bulutta, hizmetler bazen sorunlarla karşılaşır ve istemciler tarafından kullanılamaz duruma gelir ya da azaltma veya hız sınırları uygular. İstemcilerin hizmetlerle başarısız bağlantıları yeniden denemesi iyi bir uygulama olsa da, çok sık veya çok uzun süre yeniden denememelidir. Hizmetin henüz normale dönmemiş olmasından dolayı, kısa bir süre içinde yeniden denemelerin başarılı olma ihtimali düşüktür. Kurtarma sırasında aşırı bağlantı girişimleri hizmeti bunaltabilir ve özgün sorunu yoğunlaştırabilir. Bu duruma bazen gümbürdenen sürü denir.

Aşağıdaki örnekte, istemcinin sunucu tabanlı API'ye bağlandığı bir senaryo gösterilmektedir. İstek başarılı olmazsa, istemci hemen isteği yeniden dener ve sonsuza kadar yeniden denemeye devam eder. Bu tür davranışlar genellikle bu örnekten 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.
}

Çözüm

İstemci uygulamaları, yeniden deneme saldırılarını önlemek için en iyi yöntemleri izlemelidir.

  • Yeniden deneme denemesi sayısını ve süresini sınırlayın. while(true) Döngü yazmak basit görünebilir, ancak genellikle uzun bir süre yeniden denemek istemezsiniz. İsteğin başlatılmasına neden olan koşullar büyük olasılıkla değişmiştir. Çoğu uygulamanın yalnızca birkaç saniye veya dakika boyunca yeniden denemesi gerekir.

  • Yeniden deneme girişimleri arasında duraklatın ve bekleme süresini artırın. Bir hizmet kullanılamıyorsa, hemen yeniden denemenin başarılı olma olasılığı düşüktür. Örneğin üstel geri alma stratejisini kullanarak girişimler arasındaki süreyi kademeli olarak artırın.

  • Hizmet hatalarını zarifçe işleyin. Hizmet yanıt vermezse, girişimi iptal edip etmeyeceğinizi belirleyin ve bileşeninizin kullanıcısına veya çağırana bir hata döndürin. Uygulamanızı tasarlarken bu hata senaryolarını göz önünde bulundurun.

  • Devre Kesici desenini kullanın. Bu düzen, yeniden deneme fırtınalarını önlemeye yardımcı olmak için özel olarak tasarlanmıştır.

  • Yanıt üst bilgilerini dikkate alın. Sunucu bir retry-after yanıt üst bilgisi sağlıyorsa, belirtilen süre geçene kadar yeniden denemeyin.

  • Azure hizmetleriyle iletişim kurmak için resmi SDK'ları kullanın. Bu SDK'lar genellikle yerleşik yeniden deneme ilkelerine ve yeniden deneme fırtınalarına neden olma veya bunlara katkıda bulunmaya karşı koruma sağlar. SDK'sı olmayan bir hizmetle iletişim kurarsanız veya SDK yeniden deneme mantığını yanlış işlerse, JavaScript'in yeniden deneme mantığınızı doğru şekilde işlemesi ve kodu kendiniz yazmaktan kaçınması için .NET veya retry için Polly gibi bir kitaplık kullanmayı göz önünde bulundurun.

  • Kullanılabilir olduğunda bir soyutlama katmanı kullanın. Bunu destekleyen bir ortam kullanıyorsanız, giden çağrılar göndermek için bir hizmet ağı veya başka bir soyutlama katmanı kullanın. Genellikle Daprgibi bu araçlar yeniden deneme ilkelerini destekler ve yinelenen denemelerden sonra geri dönme gibi en iyi yöntemleri otomatik olarak izler. Bu yaklaşım, yeniden deneme kodunu kendiniz yazma gereğini ortadan kaldırır.

  • İstekleri toplu işleme ve kullanılabilir olduğunda istek havuzlamayı 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ı girişimi sayısını azaltır. Ancak bu bağlantıları çok sık yeniden denemekten kaçının.

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

  • Olaylar sırasında bağlantıları engellemek için bir ağ geçidi katmanı ekleyin. Bu yaklaşım Bulkhead desenini izler. Azure Azure Front Door, Azure Application Gateway ve Azure API Management gibi farklı çözüm türleri için birçok ağ geçidi hizmeti sağlar.

  • Ağ geçidinizdeki istekleri kısıtlama. Bu yaklaşım, arka uç bileşenlerinin aşırı isteklerden etkilenmesini önler.

  • İstemcilere sinyal gönderin. Hız kesme sırasında, istemcilerin bağlantılarını yenileyecekleri zamanı anlamalarına yardımcı olmak için bir retry-after üst bilgisi geri gönderin. İstemcilerin bu üst bilgileri yerine getirmesi gerekmez, ancak birçoğu bunu yapar.

Hususlar

  • Hata türlerini anlama. Bazı hata türleri hizmet hatasını göstermez, bunun yerine istemciden geçersiz bir istek olduğunu gösterir. Örneğin, bir istemci uygulaması bir 400 Bad Request hata yanıtı alırsa, sunucu isteğinizin geçerli olmadığını size zaten bildirdiğinden aynı isteği yeniden denemek büyük olasılıkla yardımcı olmaz.

  • Uygun yeniden deneme süresini tanımlayın. İstemciler, bağlantıları yeniden kullanmak için en uygun süreyi dikkate almalıdır. Zaman penceresi, iş gereksinimleriyle ve bir kullanıcıya veya arayana makul bir şekilde hata döndürebilme özelliğiyle uyumlu olmalıdır. Çoğu uygulamanın yalnızca birkaç saniye veya dakika boyunca yeniden denemesi gerekir.

Sorunu algılama

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

Hizmet açısından bakıldığında, bu sorunun belirtileri kısa bir süre içinde bir istemciden gelen birkaç isteği veya kesintilerden kurtarılırken tek bir istemciden gelen birkaç isteği içerebilir. Bir hizmet, bir arızadan sonra da kendini toparlamakta zorlanabilir. Veya bir hizmette hata onarımı sonrasında devam eden art arda hatalar olabilir.

Örnek tanılama

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

İstemci telemetrisi kullanarak desenleri tanımlama

Application Insights uygulamalardan telemetri kaydeder ve bu verileri sorgulama ve görselleştirme için kullanılabilir hale getirir. Giden bağlantıları bağımlılık olarak izler ve bir istemcinin aynı hizmete birkaç giden istekte bulunduğu zamanları belirlemek için kullanıcıların bu bilgilere erişmesine ve bu bilgilere grafik oluşturmasına olanak tanır.

Aşağıdaki ekran görüntüsünde, Application Insights portalındaki Ölçümler sekmesindeki bir grafik gösterilmektedir. Uzak bağımlılık adına göre bölünmüş Bağımlılık hataları ölçümünü gösterir. Bu senaryoda, kısa bir süre içinde bir bağımlılıkla 21.000'den fazla başarısız bağlantı girişimi vardır.

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

Sunucu telemetrisi kullanarak desenleri 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 görevi görür ve tüm istekleri bir Log Analytics çalışma alanında kaydetmek üzere yapılandırılmıştır.

Son gün içinde uygulamaya çok sayıda istek gönderen istemci IP adreslerini tanımlamak için Log Analytics'de aşağıdaki Kusto sorgusunu çalıştırın.

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

Bu sorguyu yeniden deneme fırtınası sırasında çalıştırırsanız, tek bir IP adresinden çok sayıda bağlantı girişimi gösterilir.

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