Dağıtılmış iş işlemi performansını ayarlama

Azure Kubernetes Service (AKS)
Azure Cache for Redis

Bu makalede, bir geliştirme ekibinin performans sorunlarını bulmak ve dağıtılmış bir sistemin performansını artırmak için ölçümleri nasıl kullandığı açıklanmaktadır. Makale, örnek bir uygulama için yaptığımız gerçek yük testlerini temel alır. Uygulama, mikro hizmetler için Azure Kubernetes Service (AKS) Temeli'nden alınır.

Bu makale, bir serinin bir parçasıdır. buradaki ilk bölümü okuyun.

Senaryo: İstemci uygulaması, birden çok adım içeren bir iş işlemi başlatır.

Bu senaryo AKS üzerinde çalışan bir insansız hava aracı teslim uygulamasını içerir. Müşteriler, teslimatları insansız hava aracıyla zamanlamak için bir web uygulaması kullanır. Her işlem, arka uçta ayrı mikro hizmetler tarafından gerçekleştirilen birden çok adım gerektirir:

  • Teslim hizmeti teslimatları yönetir.
  • İnsansız Hava Aracı Scheduler hizmeti, insansız hava araçlarını teslim alma için zamanlar.
  • Paket hizmeti paketleri yönetir.

İki hizmet daha vardır: İstemci isteklerini kabul eden ve bunları işlenmek üzere kuyruğa alan bir Alma hizmeti ve iş akışındaki adımları koordine eden bir İş Akışı hizmeti.

Dağıtılmış iş akışını gösteren diyagram

Bu senaryo hakkında daha fazla bilgi için bkz. Mikro hizmet mimarisi tasarlama.

Test 1: Temel

İlk yük testi için ekip altı düğümlü bir AKS kümesi oluşturdu ve her mikro hizmetin üç çoğaltmasını dağıttı. Yük testi, iki sanal kullanıcıdan başlayıp 40'a kadar sanal kullanıcıyı hızlandıran bir adım yükleme testiydi.

Ayar Değer
Küme düğümleri 6
Bakla Hizmet başına 3

Aşağıdaki grafikte, Visual Studio'da gösterildiği gibi yük testinin sonuçları gösterilmektedir. Mor çizgi kullanıcı yükünü, turuncu çizgi ise toplam istekleri çizer.

Visual Studio yük testi sonuçlarının grafiği

Bu senaryo hakkında fark edilmesi gereken ilk şey, saniye başına istemci isteklerinin yararlı bir performans ölçümü olmamasıdır. Bunun nedeni, uygulamanın istekleri zaman uyumsuz olarak işlemesi ve istemcinin hemen yanıt almasıdır. Yanıt kodu her zaman HTTP 202 (Kabul Edildi) şeklindedir; bu da isteğin kabul edildiği ancak işlemenin tamamlanmadığı anlamına gelir.

Asıl bilmek istediğimiz arka ucun istek oranına uygun olup olmadığıdır. Service Bus kuyruğu ani artışları sindirebilir, ancak arka uç sürekli bir yükü işleyemezse işlem daha da geride kalır.

İşte daha bilgilendirici bir grafik. Service Bus kuyruğundaki gelen ve giden iletilerin sayısını çizer. Gelen iletiler açık mavi, giden iletiler ise koyu mavi renkle gösterilir:

Gelen ve giden iletilerin grafiği

Bu grafik, gelen iletilerin hızının arttığını, zirveye ulaştığını ve yük testinin sonunda sıfıra geri döndüğünü gösterir. Ancak giden iletilerin sayısı testin erken aşamalarında zirveye çıkıp aslında düşer. Bu, istekleri işleyen İş Akışı hizmetinin yetişmiyor olduğu anlamına gelir. Yük testi sona erdikten sonra bile (grafikte yaklaşık 9:22'de), İş Akışı hizmeti kuyruğu boşaltmaya devam ettikçe iletiler işleniyor.

İşlemi yavaşlatan nedir? Aranacak ilk şey, sistematik bir soruna işaret eden hatalar veya özel durumlardır. Azure İzleyici'deki Uygulama Haritası bileşenler arasındaki çağrıların grafiğini gösterir ve sorunları tespit etmenin hızlı bir yoludur ve ardından daha fazla ayrıntı almak için tıklayın.

Uygulama Eşlemesi, İş Akışı hizmetinin Teslim hizmetinden hata alıyor olduğunu gösterir:

Uygulama Haritası'nın ekran görüntüsü

Diğer ayrıntıları görmek için grafikte bir düğüm seçebilir ve uçtan uca işlem görünümüne tıklayabilirsiniz. Bu durumda, Teslim hizmetinin HTTP 500 hataları döndürdüğünü gösterir. Hata iletileri, Redis için Azure Cache bellek sınırları nedeniyle bir özel durumun oluştuğuna işaret eder.

Uçtan uca işlem görünümünün ekran görüntüsü

Redis'e yapılan bu çağrıların Uygulama Haritası'nda görünmediğini fark edebilirsiniz. Bunun nedeni Application Insights için .NET kitaplığının Redis'i bağımlılık olarak izlemek için yerleşik desteğe sahip olmamasıdır. (Kullanıma hazır olarak desteklenenlerin listesi için bkz . Bağımlılık otomatik toplama.) Geri dönüş olarak, herhangi bir bağımlılığı izlemek için TrackDependency API'sini kullanabilirsiniz. Yük testi genellikle telemetride düzeltilebilen bu tür boşlukları ortaya çıkartır.

Test 2: Önbellek boyutu artırıldı

İkinci yük testi için geliştirme ekibi Redis için Azure Cache önbellek boyutunu artırdı. (Bkz. Redis için Azure Cache Ölçeklendirme.) Bu değişiklik yetersiz bellek özel durumlarını çözdü ve şimdi Uygulama Haritası sıfır hata gösteriyor:

Önbellek boyutunu artırmanın yetersiz bellek özel durumlarını çözdüğünü gösteren Uygulama Haritası'nın ekran görüntüsü.

Ancak iletilerin işlenmesinde hala önemli bir gecikme yaşanıyor. Yük testinin en yoğun olduğu noktada, gelen ileti hızı 5'ten fazladır× giden hız:

Gelen ileti hızını gösteren gelen ve giden iletilerin grafiği, giden oranın 5 katını aşmıştı.

Aşağıdaki grafik, aktarım hızını ileti tamamlama açısından ölçer; diğer bir deyişle, İş Akışı hizmetinin Service Bus iletilerini tamamlandı olarak işaretleme hızı. Grafikteki her nokta, yaklaşık 16/sn maksimum aktarım hızını gösteren 5 saniyelik verileri temsil eder.

İleti aktarım hızı grafiği

Bu grafik, Log Analytics çalışma alanında Kusto sorgu dili kullanılarak bir sorgu çalıştırılarak oluşturulmuştur:

let start=datetime("2020-07-31T22:30:00.000Z");
let end=datetime("2020-07-31T22:45:00.000Z");
dependencies
| where cloud_RoleName == 'fabrikam-workflow'
| where timestamp > start and timestamp < end
| where type == 'Azure Service Bus'
| where target has 'https://dev-i-iuosnlbwkzkau.servicebus.windows.net'
| where client_Type == "PC"
| where name == "Complete"
| summarize succeeded=sumif(itemCount, success == true), failed=sumif(itemCount, success == false) by bin(timestamp, 5s)
| render timechart

Test 3: Arka uç hizmetlerinin ölçeğini genişletme

Arka uç bir performans sorunu gibi görünüyor. Kolay bir sonraki adım, iş hizmetlerinin (Paket, Teslimat ve İnsansız Hava Aracı Zamanlayıcı) ölçeğini genişletmek ve aktarım hızının iyileşip iyileşmediğini görmektir. Bir sonraki yük testi için ekip, bu hizmetleri üç çoğaltmadan altı çoğaltmaya ölçeklendirdi.

Ayar Değer
Küme düğümleri 6
Veri alımı hizmeti 3 çoğaltma
İş akışı hizmeti 3 çoğaltma
Paket, Teslimat, İnsansız Hava Aracı Zamanlayıcı hizmetleri Her birinde 6 çoğaltma

Ne yazık ki bu yük testi yalnızca mütevazı bir iyileştirme gösteriyor. Giden iletiler hala gelen iletilere yetişmiyor:

Giden iletilerin hala gelen iletileri takip etmediğini gösteren gelen ve giden iletilerin grafiği.

Aktarım hızı daha tutarlıdır, ancak elde edilen maksimum değer önceki testle yaklaşık olarak aynıdır:

Elde edilen maksimum değerin önceki testle yaklaşık olarak aynı olduğunu gösteren ileti aktarım hızı grafiği.

Ayrıca Azure İzleyici kapsayıcı içgörülerine baktığımızda sorunun küme içindeki kaynak tükenmesi nedeniyle kaynaklanmadığı görülüyor. İlk olarak düğüm düzeyindeki ölçümler CPU kullanımının 95. yüzdebirlik dilimde bile %40'ın altında kaldığını ve bellek kullanımının yaklaşık %20 olduğunu gösterir.

AKS düğümü kullanımı grafiği

Kubernetes ortamında, düğümler olmasa bile tek tek podların kaynak kısıtlaması olması mümkündür. Ancak pod düzeyindeki görünüm tüm podların iyi durumda olduğunu gösterir.

AKS pod kullanımı grafiği

Bu testten arka uca daha fazla pod eklemek işe yaramaz gibi görünüyor. Sonraki adım, iletileri işlerken neler olduğunu anlamak için İş Akışı hizmetine daha yakından bakmaktır. Application Insights, İş Akışı hizmetinin Process işleminin ortalama süresinin 246 ms olduğunu gösterir.

Application Insights'ın ekran görüntüsü

Ayrıca her işlemdeki tek tek işlemlere ilişkin ölçümleri almak için bir sorgu çalıştırabiliriz:

Hedef percentile_duration_50 percentile_duration_95
https://dev-i-iuosnlbwkzkau.servicebus.windows.net/ | dev-i-iuosnlbwkzkau 86.66950203 283.4255578
etkinleştirme 37 57
package 12 17
dronescheduler 21 41

Bu tablodaki ilk satır Service Bus kuyruğuyu temsil eder. Diğer satırlar, arka uç hizmetlerine yapılan çağrılardır. Başvuru için bu tablonun Log Analytics sorgusu aşağıdadır:

let start=datetime("2020-07-31T22:30:00.000Z");
let end=datetime("2020-07-31T22:45:00.000Z");
let dataset=dependencies
| where timestamp > start and timestamp < end
| where (cloud_RoleName == 'fabrikam-workflow')
| where name == 'Complete' or target in ('package', 'delivery', 'dronescheduler');
dataset
| summarize percentiles(duration, 50, 95) by target

Log Analytics sorgu sonucunun ekran görüntüsü

Bu gecikme süreleri makul görünür. Ancak önemli içgörü şudur: Toplam işlem süresi yaklaşık 250 ms ise, bu durum iletilerin seri olarak işlenme hızına katı bir üst sınır getirir. Bu nedenle aktarım hızını artırmanın anahtarı daha fazla paralelliktir.

Bu senaryoda iki nedenden dolayı bu mümkün olmalıdır:

  • Bunlar ağ çağrılarıdır, bu nedenle çoğu zaman G/Ç tamamlanmasını beklerken harcanıyor
  • İletiler bağımsızdır ve sırayla işlenmesi gerekmez.

Test 4: Paralelliği artırma

Ekip bu test için paralelliği artırmaya odaklandı. Bunu yapmak için İş Akışı hizmeti tarafından kullanılan Service Bus istemcisinde iki ayarı düzelttiler:

Ayar Açıklama Varsayılan Yeni değer
MaxConcurrentCalls Eşzamanlı olarak işlenmek üzere ileti sayısı üst sınırı. 1 20
PrefetchCount İstemcinin yerel önbelleğine önceden getireceği ileti sayısı. 0 3000

Bu ayarlar hakkında daha fazla bilgi için bkz. Service Bus Mesajlaşması'nı kullanarak performans geliştirmeleri için en iyi yöntemler. Testin bu ayarlarla çalıştırılması aşağıdaki grafı üretti:

Gelen ve giden iletilerin toplam sayısını gerçekten aşan giden ileti sayısını gösteren gelen ve giden iletilerin grafiği.

Gelen iletilerin açık mavi, giden iletilerin ise koyu mavi olarak gösterildiğini hatırlayın.

İlk bakışta, bu çok garip bir grafiktir. Bir süre için giden ileti hızı gelen fiyatı tam olarak izler. Ancak daha sonra, yaklaşık 2:03 işaretinde, gelen iletilerin oranı kapanırken, giden iletilerin sayısı artmaya devam eder ve aslında gelen iletilerin toplam sayısını aşar. İmkansız görünüyor.

Bu gizemin ipucunu Application Insights'taki Bağımlılıklar görünümünde bulabilirsiniz. Bu grafik, İş Akışı hizmetinin Service Bus'a yaptığı tüm çağrıları özetler:

Bağımlılık çağrılarının grafiği

için DeadLettergirdiye dikkat edin. Bu çağrılar iletilerin Service Bus teslim edilemeyen ileti kuyruğuna gittiğini gösterir.

Neler olduğunu anlamak için Service Bus'ta Peek-Lock semantiğini anlamanız gerekir. İstemci Peek-Lock kullandığında Service Bus atomik olarak bir iletiyi alır ve kilitler. Kilit tutulurken iletinin diğer alıcılara teslim edilmemesi garanti edilir. Kilidin süresi dolarsa, ileti diğer alıcıların kullanımına sunulur. En fazla sayıda teslim girişiminden sonra (yapılandırılabilir), Service Bus iletileri daha sonra incelenebileceği teslim edilemeyen bir kuyruğa yerleştirir.

İş Akışı hizmetinin büyük ileti toplu işlemlerini (bir kerede 3000 ileti) önceden oluşturduğunu unutmayın. Bu, her iletinin işlenmesi için toplam sürenin daha uzun olduğu anlamına gelir ve bu da iletilerin zaman aşımına uyacağız, kuyruğa geri dönecek ve sonunda teslim edilemeyen ileti kuyruğuna gidecektir.

Bu davranışı, çok sayıda MessageLostLockException özel durumun kaydedildiği özel durumlarda da görebilirsiniz:

Çok sayıda MessageLostLockException özel durumunu gösteren Application Insights özel durumlarının ekran görüntüsü.

Test 5: Kilit süresini artırın

Bu yük testi için, kilit zaman aşımlarını önlemek için ileti kilitleme süresi 5 dakika olarak ayarlandı. Gelen ve giden iletilerin grafiği artık sistemin gelen iletilerin hızına ayak uydurduğunu gösteriyor:

Sistemin gelen iletilerin hızına ayak uydurduğunu gösteren gelen ve giden iletilerin grafiği.

8 dakikalık yük testinin toplam süresi boyunca uygulama 25 K işlemi tamamladı ve en yüksek aktarım hızı 72 işlem/sn'dir ve bu da maksimum aktarım hızındaki %400 artışı gösterir.

Maksimum aktarım hızındaki %400 artışı gösteren ileti aktarım hızı grafiği.

Ancak, aynı testin daha uzun bir süreyle çalıştırılması, uygulamanın bu hızı sürdüremediğini gösterdi:

Uygulamanın bu hızı sürdüremediğini gösteren gelen ve giden iletilerin grafiği.

Kapsayıcı ölçümleri maksimum CPU kullanımının %100'e yakın olduğunu gösteriyor. Bu noktada uygulama CPU'ya bağlı gibi görünür. Önceki ölçeği genişletme denemesinin aksine kümenin ölçeklenmesi şimdi performansı artırabilir.

Maksimum CPU kullanımının %100'e yakın olduğunu gösteren AKS düğümü kullanımı grafiği.

Test 6: Arka uç hizmetlerinin ölçeğini genişletme (yeniden)

Takım, serideki son yük testi için Kubernetes kümesinin ve podlarının ölçeğini aşağıdaki gibi genişletti:

Ayar Değer
Küme düğümleri 12
Veri alımı hizmeti 3 çoğaltma
İş akışı hizmeti 6 çoğaltma
Paket, Teslimat, İnsansız Hava Aracı Zamanlayıcı hizmetleri Her birinde 9 çoğaltma

Bu test, iletilerin işlenmesinde önemli gecikmeler yaşanmadan daha yüksek sürekli aktarım hızına neden oldu. Ayrıca düğüm CPU kullanımı %80'in altında kaldı.

İletilerin işlenmesinde önemli gecikmeler olmadan daha yüksek sürekli aktarım hızı gösteren ileti aktarım hızı grafiği.

Özet

Bu senaryo için aşağıdaki performans sorunları belirlendi:

  • Redis için Azure Cache bellek yetersiz özel durumları.
  • İleti işlemede paralellik eksikliği.
  • Kilit zaman aşımlarına ve iletilerin teslim edilemeyen ileti kuyruğuna yerleştirilmesine neden olan ileti kilitleme süresi yetersiz.
  • CPU tükenmesi.

Geliştirme ekibi bu sorunları tanılamak için aşağıdaki ölçümlere dayanır:

  • Gelen ve giden Service Bus iletilerinin oranı.
  • Application Insights'ta Uygulama Haritası.
  • Hatalar ve özel durumlar.
  • Özel Log Analytics sorguları.
  • Azure İzleyici kapsayıcı içgörülerinde CPU ve bellek kullanımı.

Sonraki adımlar

Bu senaryonun tasarımı hakkında daha fazla bilgi için bkz. Mikro hizmet mimarisi tasarlama.