Yeniden deneme düzeni

Azure

Bir uygulamanın bir hizmete veya ağa bağlanmayı denerken karşılaştığı geçici hataları, başarısız olmuş bir işlemi saydam bir şekilde yeniden deneyerek işlemesine olanak tanıyın. Bu, uygulamanın kararlılığını iyileştirebilir.

Bağlam ve sorun

Bulutta çalışan öğelerle iletişim kuran bir uygulama, bu ortamda oluşabilecek geçici hataları duyarlı olmalıdır. Bileşen ve hizmetlerle ağ bağlantısının anlık olarak kaybedilmesi, bir hizmetin geçici olarak kullanım dışı kalması veya bir hizmet meşgul olduğunda gerçekleşen zaman aşımları bu hatalar arasında yer alır.

Bu hatalar genellikle kendi kendine düzelir ve hataya yol açan eylem uygun gecikme süresi dolunca yinelenirse başarılı olma olasılığı yüksektir. Örneğin, çok sayıda eşzamanlı isteği işleyen bir veritabanı hizmeti, iş yükü hafifleyene kadar diğer istekleri geçici olarak reddeden bir azaltma stratejisi uygulayabilir. Veritabanına erişmeye çalışan bir uygulama bağlanamayabilir, ancak gecikme süresi dolunca yeniden denerse başarılı olabilir.

Çözüm

Bulutta, geçici hatalar nadir değildir ve uygulamalar bunları zarif ve saydam bir biçimde işleyecek şekilde tasarlanmalıdır. Bu, hataların uygulama tarafından gerçekleştirilen iş görevleri üzerindeki etkilerini en aza indirir.

Bir uygulama uzak bir hizmete istek göndermeye çalışırken bir hata algılarsa, hatayı aşağıdaki stratejileri kullanarak işleyebilir:

  • İptal etme. Hatanın geçici olmadığı veya yinelenirse başarılı sonuç alma olasılığının düşük olduğu belirtiliyorsa uygulama işlemi iptal etmeli ve bir özel durum bildirmelidir. Örneğin, geçersiz kimlik bilgileri sağlanmasından kaynaklanan bir kimlik doğrulama hatası alındığında, girişim sayısından bağımsız olarak başarılı sonuç alma olasılığı yoktur.

  • Yeniden Deneme. Bildirilen hata sıra dışı veya nadirse, bir ağ paketinin aktarılırken bozulması gibi sıra dışı durumlardan kaynaklanıyor olabilir. Böyle durumlarda aynı hatanın yinelenme olasılığı düşük olduğundan ve istek muhtemelen başarılı olacağından uygulama başarısız olan isteği hemen yeniden deneyebilir.

  • Gecikme süresi dolunca yeniden deneme. Hata bir veya daha fazla yaygın bağlantı veya yoğunluk hatasından kaynaklanıyorsa, ağ veya hizmetteki bağlantı sorunlarının düzeltilmesi veya iş kapsamının temizlenmesi için kısa bir süre geçmesi gerekebilir. Uygulamanın isteği yeniden denemeden önce uygun bir süre beklemesi gerekir.

Daha yaygın geçici hatalar söz konusu olduğunda, yeniden deneme işlemleri arasındaki süre, uygulamanın birden çok örneğinden gelen istekleri mümkün olduğunca eşit olarak yayacak şekilde seçilmelidir. Bu, meşgul bir hizmete aşırı yüklenmeye devam etme olasılığını azaltır. Bir uygulamanın birçok örneği sürekli yeniden deneme istekleriyle bir hizmete aşırı yüklenirse, hizmetin kurtarılması daha uzun sürer.

İstek yine başarısız olursa, uygulama bir süre bekleyip başka bir girişimde bulunabilir. Gerekirse, en fazla istek girişimi sayısına ulaşılana kadar, yeniden deneme girişleri arasındaki gecikme süresi artırılarak bu işlem yinelenebilir. Gecikme süresi, hatanın türüne ve ilgili süre içinde düzelme olasılığına bağlı olarak kademeli bir şekilde veya katlanarak artırılabilir.

Aşağıdaki diyagramda, bu düzen kullanılarak barındırılan bir hizmetteki bir işlemin çağrılması gösterilmiştir. Önceden tanımlanmış bir girişim sayısına ulaşılmasına rağmen istek başarısız olursa uygulama hatayı özel bir durum olarak ele almalı ve uygun şekilde işlemelidir.

Şekil 1: Yeniden deneme düzenini kullanarak barındırılan bir hizmetteki bir işlemi çağırma

Uygulama, uzak bir hizmete erişmeye yönelik tüm girişimleri, yukarıda listelenen stratejilerden biriyle eşleşen bir yeniden deneme ilkesi uygulayan kodda sarmalamalıdır. Farklı hizmetlere gönderilen istekler farklı ilkelere tabi olabilir. Bazı satıcılar, uygulamanın en fazla yeniden deneme sayısını, yeniden deneme girişimleri arasındaki süreyi ve diğer parametreleri belirtebileceği yeniden deneme ilkelerini uygulayan kitaplıklar sağlar.

Uygulamalar hataların ve başarısız işlemlerin ayrıntılarını günlüğe kaydetmelidir. Bu bilgiler işleçler için yararlıdır. Bununla birlikte, işleçlerin daha sonra yeniden denenen girişimlerin başarılı olduğu operasyonlarla ilgili uyarılarla dolup taşmasını önlemek için, erken hataları bilgilendirme girdileri olarak günlüğe kaydetmek ve yalnızca yeniden deneme girişimlerinin sonuncusunun başarısızlığını gerçek bir hata olarak kaydetmek en iyisidir. Bu günlük modelinin nasıl görüneceğine bir örnek aşağıda verilmiştir.

Bir hizmet sık sık kullanılamaz hale geliyor veya meşgul oluyorsa çoğu zaman bunun nedeni hizmetin kaynaklarını tüketmiş olmasıdır. Hizmetin ölçeğini genişleterek bu hataların sıklığını azaltabilirsiniz. Örneğin, bir veritabanı hizmeti sürekli olarak aşırı yükleniyorsa veritabanını bölümlemek ve yükü birden çok sunucuya dağıtmak yararlı olabilir.

Microsoft Entity Framework, veritabanı işlemlerinin yeniden denenmesine yönelik olanaklar sağlar. Ayrıca, çoğu Azure hizmeti ve istemci SDK'sı bir yeniden deneme mekanizması içerir. Daha fazla bilgi için bkz. Belirli hizmetlere yönelik yeniden deneme kılavuzu.

Sorunlar ve dikkat edilmesi gerekenler

Bu düzeni nasıl uygulayacağınıza karar verirken aşağıdaki noktaları dikkate almalısınız.

Yeniden deneme ilkesi, uygulamanın iş gereksinimleri ve hatanın yapısı ile eşleşecek şekilde ayarlanmalıdır. Kritik olmayan bazı işlemler için birkaç kez yeniden deneyerek uygulamanın aktarım hızını etkilemek yerine hızlı başarısız kılma daha iyidir. Örneğin, uzak bir hizmete erişen etkileşimli bir web uygulamasında, yeniden deneme girişimleri arasında yalnızca kısa bir gecikmeyle daha az sayıda yeniden denemeden sonra başarısız olmak ve kullanıcıya uygun bir ileti görüntülemek daha iyidir (örneğin, "lütfen daha sonra yeniden deneyin"). Bir toplu iş uygulaması için girişimler arasındaki gecikme süresini katlamalı bir şekilde artırarak yeniden deneme girişimi sayısını artırmak daha uygun olabilir.

Girişimler arasındaki gecikme süresinin çok az, yeniden deneme sayısının yüksek olduğu agresif bir yeniden deneme ilkesi, kapasite üst sınırında veya buna yakın bir seviyede çalıştığı için meşgul olan bir hizmetin performansını daha da düşürebilir. Uygulama sürekli başarısız olan bir işlemi gerçekleştirmeye çalışıyorsa, bu yeniden deneme ilkesi uygulamanın yanıt verme hızını da etkileyebilir.

Bir istek önemli sayıda yeniden deneme girişimine rağmen başarısız olursa, uygulamanın aynı kaynağa gönderilerek anında hata bildirimine yol açacak diğer istekleri önlemesi daha iyidir. Süre dolduğunda, uygulama bir veya daha fazla isteğe kontrollü bir şekilde izin vererek bunların başarılı olup olmadığını denetleyebilir. Bu stratejiyle ilgili daha fazla ayrıntı için bkz. Devre Kesici düzeni.

Uygulamanın bir kere etkili olup olmadığını göz önünde bulundurun. Bir kere etkili oluyorsa yeniden denemek güvenlidir. Aksi takdirde, yeniden deneme girişimleri işlemin birden fazla kez yürütülmesine ve istenmeyen yan etkilere neden olabilir. Örneğin, bir hizmet isteği alıp başarıyla işlemesine rağmen yanıt gönderemiyor olabilir. Bu noktada, yeniden deneme mantığı ilk isteğin alınmadığını varsayarak isteği yeniden gönderebilir.

Bir hizmete yönelik istekler, hatanın türüne bağlı olarak farklı özel durumlara yol açan çeşitli nedenlerden dolayı başarısız olabilir. Bazı özel durumlar hızlı bir şekilde çözülebilecek bir hata olduğunu gösterirken, bazıları hatanın daha kalıcı olduğunu gösterebilir. Yeniden deneme ilkesinin özel durum türüne göre yeniden deneme girişimleri arasındaki süreyi ayarlaması yararlıdır.

Bir işlemin parçası olan bir alt işlemin yeniden denenmesinin genel işlem tutarlılığını nasıl etkileyeceğini göz önünde bulundurun. İşlem alt işlemlerinin başarı olasılığını en üst düzeye çıkarmak ve tüm işlem adımlarını geri alma gereksinimini azaltmak için yeniden deneme ilkesinde ince ayar yapın.

Yeniden deneme kodunun çeşitli hata koşullarında tam olarak test edildiğinden emin olun. Uygulamanın performansını veya güvenilirliğini etkilemediğinden, hizmetlerde aşırı yüklenmeye yol açmadığından veya yarış durumlarına ya da performans sorunlarına neden olmadığından emin olun.

Yalnızca başarısız olan bir işlemin tam bağlamının anlaşıldığı durumlarda yeniden deneme mantığı uygulayın. Örneğin, yeniden deneme ilkesi içeren bir görev yeniden deneme ilkesi içeren başka bir görevi çağırdığında, bu ek yeniden deneme katmanı işlemlerde daha uzun gecikme yaşanmasına neden olabilir. Düşük düzeyli görevi hızla başarısız kılınacak ve kendisini çağıran göreve hatanın nedenini bildirecek şekilde yapılandırmak daha iyi olabilir. Daha sonra, bu üst düzey görev hatayı kendi ilkesine göre işleyebilir.

Uygulama, hizmetler veya kaynaklardaki temel sorunların tanımlanabilmesi için yeniden denemeye neden olan tüm bağlantı hataların günlüğe kaydedilmesi önemlidir.

Bir hizmet veya kaynak için gerçekleşme olasılığı en yüksek hataları araştırarak bunların uzun süreli veya kalıcı olup olmadığını keşfedin. Böyle durumlarda hatanın biz özel durum olarak işlenmesi daha iyidir. Uygulama özel durumu bildirebilir veya günlüğe kaydedebilir ve sonra alternatif bir hizmeti (varsa) çağırarak ya da daha düşük işlevsellik sunarak devam etmeye çalışabilir. Uzun süreli hataları algılama ve işleme hakkında daha fazla bilgi için bkz. Devre Kesici düzeni.

Bu düzenin kullanılacağı durumlar

Bir uygulamanın uzak bir hizmetle etkileşim kurarken veya uzak bir kaynağa erişirken geçici hatalar yaşama olasılığı varsa bu düzeni kullanın. Bu hataların kısa süreli olması beklenir ve daha önce başarısız olmuş bir istek, sonraki bir denemede başarılı olabilir.

Bu düzen aşağıdaki durumlarda kullanışlı olmayabilir:

  • Bir hatanın uzun süreli olma olasılığı yüksekse, bu yapılandırma uygulamanın yanıt verme hızını etkileyebilir. Uygulama, başarısız olma olasılığı yüksek olan bir isteği tekrarlamaya çalışarak zaman ve kaynak israfı yapıyor olabilir.
  • Bir uygulamanın iş mantığındaki hatalardan kaynaklanan iç özel durumlar gibi geçici hatalardan kaynaklanmayan hataların işlenmesi için.
  • Bir sistemdeki ölçeklenebilirlik sorunlarını gidermek için alternatif bir yöntem olarak. Bir uygulamada sık sık meşgul hataları oluşuyorsa, bu genellikle erişilen hizmetin veya kaynağın ölçeğinin büyütülmesi gerektiğini gösteren bir işarettir.

İş yükü tasarımı

Bir mimar, Azure İyi Tasarlanmış Çerçeve yapılarında ele alınan hedefleri ve ilkeleri ele almak için yeniden deneme düzeninin iş yükünün tasarımında nasıl kullanılabileceğini değerlendirmelidir. Örneğin:

Yapı Taşı Bu desen sütun hedeflerini nasıl destekler?
Güvenilirlik tasarımı kararları, iş yükünüzün arızaya karşı dayanıklı olmasına ve bir hata oluştuktan sonra tamamen çalışır duruma gelmesini sağlamaya yardımcı olur. Dağıtılmış bir sistemde geçici hataları azaltmak, bir iş yükünün dayanıklılığını geliştirmeye yönelik temel bir tekniktir.

- RE:07 Kendini koruma
- RE:07 Geçici hatalar

Herhangi bir tasarım kararında olduğu gibi, bu desenle ortaya konulabilecek diğer sütunların hedeflerine karşı herhangi bir dengeyi göz önünde bulundurun.

Örnek

C# dilindeki bu örnekte Yeniden Deneme düzeninin uygulaması gösterilmektedir. Aşağıda gösterilen OperationWithBasicRetryAsync metodu, TransientOperationAsync metodu aracılığıyla zaman uyumsuz olarak bir dış hizmeti çağırır. TransientOperationAsync metodunun ayrıntıları hizmete özgüdür ve örnek koddan çıkarılmıştır.

private int retryCount = 3;
private readonly TimeSpan delay = TimeSpan.FromSeconds(5);

public async Task OperationWithBasicRetryAsync()
{
  int currentRetry = 0;

  for (;;)
  {
    try
    {
      // Call external service.
      await TransientOperationAsync();

      // Return or break.
      break;
    }
    catch (Exception ex)
    {
      Trace.TraceError("Operation Exception");

      currentRetry++;

      // Check if the exception thrown was a transient exception
      // based on the logic in the error detection strategy.
      // Determine whether to retry the operation, as well as how
      // long to wait, based on the retry strategy.
      if (currentRetry > this.retryCount || !IsTransient(ex))
      {
        // If this isn't a transient error or we shouldn't retry,
        // rethrow the exception.
        throw;
      }
    }

    // Wait to retry the operation.
    // Consider calculating an exponential delay here and
    // using a strategy best suited for the operation and fault.
    await Task.Delay(delay);
  }
}

// Async method that wraps a call to a remote service (details not shown).
private async Task TransientOperationAsync()
{
  ...
}

Bu metodu çağıran deyim, bir for döngüsü içinde sarmalanmış bir try/catch bloğu içinde yer alır. TransientOperationAsync metoduna yönelik çağrı özel durum oluşturmadan başarılı olursa for döngüsünden çıkılır. TransientOperationAsync metodu başarısız olursa catch bloğu hatanın nedenini inceler. Hatanın geçici olduğu düşünülüyorsa kod kısa bir gecikme süresinin ardından işlemi yeniden dener.

Ayrıca, for döngüsü işlemin kaç kez gerçekleştirilmeye çalışıldığını izler ve kod üç kez başarısız olursa özel durumun daha uzun süreli olduğu varsayılır. Özel durum geçici değilse veya uzun süreliyse catch işleyicisi bir özel durum oluşturur. Bu özel durum for döngüsünden çıkar ve OperationWithBasicRetryAsync metodunu çağıran kod tarafından yakalanmalıdır.

Aşağıda gösterilen IsTransient metodu, kodun çalıştırıldığı ortamla ilgili olan belirli özel durumları denetler. Geçici özel durum tanımı, erişilen kaynaklara ve işlemin çalıştırıldığı ortama göre değişkenlik gösterir.

private bool IsTransient(Exception ex)
{
  // Determine if the exception is transient.
  // In some cases this is as simple as checking the exception type, in other
  // cases it might be necessary to inspect other properties of the exception.
  if (ex is OperationTransientException)
    return true;

  var webException = ex as WebException;
  if (webException != null)
  {
    // If the web exception contains one of the following status values
    // it might be transient.
    return new[] {WebExceptionStatus.ConnectionClosed,
                  WebExceptionStatus.Timeout,
                  WebExceptionStatus.RequestCanceled }.
            Contains(webException.Status);
  }

  // Additional exception checking logic goes here.
  return false;
}

Sonraki adımlar

  • Özel yeniden deneme mantığı yazmadan önce.NET için Polly veya Java için Resilience4j gibi genel bir çerçeve kullanmayı göz önünde bulundurun.

  • İş verilerini değiştiren komutları işlerken, yeniden denemelerin eylemin iki kez gerçekleştirilmesiyle sonuçlanabileceğini ve bu eylemin müşterinin kredi kartını ücretlendirmeye benzer bir işlem olması durumunda sorunlu olabileceğini unutmayın. Bu blog gönderisinde açıklanan Idempotence desenini kullanmak bu durumlarla ilgilenmeye yardımcı olabilir.

  • Güvenilir web uygulaması düzeni , bulutta yakınsanan web uygulamalarına yeniden deneme deseninin nasıl uygulanacağını gösterir.

  • Çoğu Azure hizmeti için istemci SDK'ları yerleşik yeniden deneme mantığını içerir. Daha fazla bilgi için bkz . Azure hizmetleri için yeniden deneme kılavuzu.

  • Devre Kesici düzeni. Bir hatanın daha uzun süreli olması bekleniyorsa, Devre Kesici düzeninin uygulanması daha uygun olabilir. Yeniden Deneme ve Devre Kesici desenlerinin birleştirilmesi, hataları işlemeye yönelik kapsamlı bir yaklaşım sağlar.