Elosztott üzleti tranzakciók teljesítményének finomhangolása

Azure Kubernetes Service (AKS)
Azure Cache for Redis

Ez a cikk azt ismerteti, hogy egy fejlesztői csapat hogyan használt metrikákat a szűk keresztmetszetek kereséséhez és az elosztott rendszerek teljesítményének javításához. A cikk egy mintaalkalmazás esetében végzett tényleges terheléses tesztelésen alapul. Az alkalmazás a mikroszolgáltatások Azure Kubernetes Service (AKS) alapkonfigurációjából származik.

Ez a cikk egy sorozat része. Olvassa el az első részt itt.

Forgatókönyv: Az ügyfélalkalmazás olyan üzleti tranzakciót kezdeményez, amely több lépésből áll.

Ez a forgatókönyv egy AKS-en futó drónkézbesítési alkalmazást foglal magában. Az ügyfelek webalkalmazással ütemezik a szállításokat drónnal. Minden tranzakcióhoz több lépésre van szükség, amelyeket külön mikroszolgáltatások hajtanak végre a háttérrendszeren:

  • A kézbesítési szolgáltatás kezeli a kézbesítéseket.
  • A Drone Scheduler szolgáltatás drónokat ütemez a felvételhez.
  • A Csomag szolgáltatás kezeli a csomagokat.

Két másik szolgáltatás is létezik: egy betöltési szolgáltatás, amely fogadja az ügyfélkéréseket, és várólistára helyezi őket feldolgozásra, valamint egy munkafolyamat-szolgáltatás, amely koordinálja a munkafolyamat lépéseit.

Az elosztott munkafolyamatot bemutató diagram

További információ erről a forgatókönyvről: Mikroszolgáltatás-architektúra tervezése.

1. teszt: Alapkonfiguráció

Az első terhelési teszthez a csapat létrehozott egy hatcsomópontos AKS-fürtöt, és minden mikroszolgáltatás három replikáját telepítette. A terhelési teszt egy lépéses terheléses teszt volt, amely két szimulált felhasználótól kezdve legfeljebb 40 szimulált felhasználóig futott.

Beállítás Érték
Fürtcsomópontok 6
Hüvely Szolgáltatásonként 3

Az alábbi grafikonon a terheléses teszt eredményei láthatók a Visual Studióban látható módon. A lila vonal a felhasználói terhelést ábrázolja, a narancssárga vonal pedig az összes kérést ábrázolja.

A Visual Studio betöltési teszteredményeinek grafikonja

Ebben a forgatókönyvben az első dolog, hogy az ügyfélkérések másodpercenkénti száma nem a teljesítmény hasznos mérőszáma. Ennek az az oka, hogy az alkalmazás aszinkron módon dolgozza fel a kéréseket, így az ügyfél azonnal választ kap. A válaszkód mindig HTTP 202 (Elfogadva), ami azt jelenti, hogy a kérést elfogadták, de a feldolgozás nem fejeződött be.

Azt szeretnénk tudni, hogy a háttérrendszer lépést tart-e a kérések arányával. A Service Bus-üzenetsor képes felszívni a kiugró értékeket, de ha a háttérrendszer nem tudja kezelni a tartós terhelést, a feldolgozás tovább és tovább csökken.

Íme egy informatívabb grafikon. A Service Bus-üzenetsor bejövő és kimenő üzeneteinek számát ábrázolja. A bejövő üzenetek világoskék színnel, a kimenő üzenetek pedig sötétkék színnel jelennek meg:

Bejövő és kimenő üzenetek grafikonja

Ez a diagram azt mutatja, hogy a bejövő üzenetek száma nő, elérte a csúcsot, majd a terhelési teszt végén visszaesett a nullára. A kimenő üzenetek száma azonban a teszt elején csúcsosul, és valójában csökken. Ez azt jelenti, hogy a kéréseket kezelő Munkafolyamat szolgáltatás nem tart lépést. A terhelési teszt befejezése után (a gráfon 9:22 körül) az üzenetek feldolgozása továbbra is folyamatban van, mivel a munkafolyamat-szolgáltatás továbbra is kiüríti az üzenetsort.

Mi lassítja a feldolgozást? Az első dolog, amit meg kell keresni, az olyan hibák vagy kivételek, amelyek szisztematikus problémát jelezhetnek. Az Azure Monitor alkalmazástérképe megjeleníti az összetevők közötti hívások grafikonját, és gyorsan észlelheti a problémákat, majd a további részletekért kattintson ide.

Az alkalmazástérképen az látható, hogy a munkafolyamat-szolgáltatás hibákat kap a kézbesítési szolgáltatástól:

Képernyőkép az alkalmazástérképről

További részletek megtekintéséhez jelöljön ki egy csomópontot a gráfban, és kattintson egy végpontok közötti tranzakciós nézetre. Ebben az esetben azt mutatja, hogy a kézbesítési szolgáltatás HTTP 500-ás hibákat ad vissza. A hibaüzenetek azt jelzik, hogy a rendszer kivételt jelez a Azure Cache for Redis memóriakorlátja miatt.

Képernyőkép a végpontok közötti tranzakció nézetről

Észreveheti, hogy ezek a Redis-hívások nem jelennek meg az alkalmazástérképen. Ennek az az oka, hogy az Application Insights .NET-kódtára nem támogatja a Redis függőségként való követését. (A támogatott szolgáltatások listájáért lásd: Függőségek automatikus gyűjtése.) Tartalékként használhatja a TrackDependency API-t a függőségek nyomon követésére. A terheléstesztelés gyakran feltárja a telemetriai adatok ilyen jellegű hiányosságait, amelyek orvosolhatók.

2. teszt: A gyorsítótár méretének növelése

A második terheléses teszt esetében a fejlesztői csapat növelte a gyorsítótár méretét Azure Cache for Redis. (Lásd: Azure Cache for Redis méretezése.) Ez a módosítás megoldotta a memóriakivételeket, és most az alkalmazástérkép nulla hibát jelenít meg:

Képernyőkép az Alkalmazástérképről, amelyen az látható, hogy a gyorsítótár méretének növelése megoldotta a memóriakivételeket.

Az üzenetek feldolgozása azonban továbbra is jelentős késéssel jár. A terhelési teszt csúcsidőszakában a bejövő üzenetek sebessége meghaladja az 5-öt× a kimenő üzenetek sebességét:

A bejövő és kimenő üzenetek számának grafikonja, amelyen a bejövő üzenetek száma meghaladja a kimenő üzenetek számának 5-szörösét.

Az alábbi gráf az üzenetkiegészítés szempontjából méri az átviteli sebességet – vagyis azt, hogy a munkafolyamat-szolgáltatás milyen sebességgel jelöli meg a Service Bus-üzeneteket befejezettként. A gráf minden pontja 5 másodpercnyi adatot jelöl, amely ~16/s maximális átviteli sebességet mutat.

Az üzenet átviteli sebességének grafikonja

Ez a gráf egy lekérdezés Log Analytics-munkaterületen a Kusto lekérdezési nyelv használatával történő futtatásával jött létre:

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

3. teszt: A háttérszolgáltatások vertikális felskálázása

Úgy tűnik, hogy a háttér a szűk keresztmetszet. A következő egyszerű lépés az üzleti szolgáltatások (Csomag, Kézbesítés és Drónütemező) vertikális felskálázása, és annak megtekintése, hogy javul-e az átviteli sebesség. A következő terhelési teszthez a csapat ezeket a szolgáltatásokat három replikáról hat replikára skálázta.

Beállítás Érték
Fürtcsomópontok 6
Betöltési szolgáltatás 3 replika
Munkafolyamat-szolgáltatás 3 replika
Csomag, kézbesítés, drónütemező szolgáltatások 6 replika egyenként

Sajnos ez a terhelési teszt csak szerény javulást mutat. A kimenő üzenetek továbbra sem tartanak lépést a bejövő üzenetekkel:

A bejövő és kimenő üzenetek grafikonja, amely azt mutatja, hogy a kimenő üzenetek továbbra sem tartanak lépést a bejövő üzenetekkel.

Az átviteli sebesség konzisztensebb, de az elért maximális érték körülbelül megegyezik az előző tesztével:

Az üzenet átviteli sebességének grafikonja, amely azt mutatja, hogy az elért maximális érték körülbelül megegyezik az előző teszt értékével.

Emellett az Azure Monitor tárolóelemzési adatai alapján úgy tűnik, hogy a problémát nem a fürtön belüli erőforrás-kimerültség okozza. Először is a csomópontszintű metrikák azt mutatják, hogy a cpu-kihasználtság még a 95. percentilisnél is 40% alatt marad, a memóriakihasználtság pedig körülbelül 20%.

Az AKS-csomópont kihasználtságának grafikonja

Kubernetes-környezetben az egyes podok erőforrás-korlátozottak akkor is, ha a csomópontok nem. A podszintű nézet azonban azt mutatja, hogy az összes pod kifogástalan állapotban van.

Az AKS-pod kihasználtságának grafikonja

Ebből a tesztből úgy tűnik, hogy ha csak további podokat ad hozzá a háttérhez, az nem segít. A következő lépés az, hogy közelebbről is megvizsgáljuk a Munkafolyamat szolgáltatást, hogy megértsük, mi történik az üzenetek feldolgozásakor. Az Application Insights azt mutatja, hogy a munkafolyamat-szolgáltatás Process műveletének átlagos időtartama 246 ms.

Az Application Insights képernyőképe

Lekérdezést is futtathatunk az egyes tranzakciókon belüli egyes műveletek metrikáinak lekéréséhez:

Cél percentile_duration_50 percentile_duration_95
https://dev-i-iuosnlbwkzkau.servicebus.windows.net/ | dev-i-iuosnlbwkzkau 86.66950203 283.4255578
teljesítéssel 37 57
package 12 17
dronescheduler 21 41

A táblázat első sora a Service Bus-üzenetsort jelöli. A többi sor a háttérszolgáltatások hívása. Referenciaként tekintse meg a táblához tartozó Log Analytics-lekérdezést:

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

A Log Analytics-lekérdezés eredményének képernyőképe

Ezek a késések ésszerűnek tűnnek. De itt van a legfontosabb megállapítás: Ha a teljes műveleti idő ~250 ms, ez szigorú felső határt szab annak, hogy az üzenetek hogyan dolgozhatók fel sorosan. Ezért az átviteli sebesség javításának kulcsa a nagyobb párhuzamosság.

Ennek ebben a forgatókönyvben két okból kell lehetségesnek lennie:

  • Ezek hálózati hívások, így az idő nagy része az I/O-befejezésre való várakozással telik
  • Az üzenetek függetlenek, és nem kell sorrendben feldolgozni.

4. teszt: A párhuzamosság növelése

Ebben a tesztben a csapat a párhuzamosság növelésére összpontosított. Ehhez két beállítást módosítottak a Munkafolyamat szolgáltatás által használt Service Bus-ügyfélen:

Beállítás Leírás Alapértelmezett Új érték
MaxConcurrentCalls Az egyidejűleg feldolgozandó üzenetek maximális száma. 1 20
PrefetchCount Hány üzenetet fog az ügyfél előre beolvasni a helyi gyorsítótárba. 0 3000

További információ ezekről a beállításokról: Ajánlott eljárások teljesítménybeli fejlesztésekhez a Service Bus-üzenetkezelés használatával. A teszt futtatása ezekkel a beállításokkal a következő grafikont eredményezte:

A bejövő és kimenő üzenetek grafikonja, amelyen a kimenő üzenetek száma ténylegesen meghaladja a bejövő üzenetek teljes számát.

Ne feledje, hogy a bejövő üzenetek világoskék színnel, a kimenő üzenetek pedig sötétkék színnel jelennek meg.

Első pillantásra ez egy nagyon furcsa grafikon. Egy ideig a kimenő üzenetek sebessége pontosan nyomon követi a bejövő üzenetek gyakoriságát. Ezután körülbelül 2:03-kor a bejövő üzenetek száma csökken, miközben a kimenő üzenetek száma folyamatosan emelkedik, ami valójában meghaladja a bejövő üzenetek teljes számát. Ez lehetetlennek tűnik.

Ennek a rejtélynek a nyomát az Application Insights Függőségek nézetében találhatja meg. Ez a diagram összefoglalja a Munkafolyamat szolgáltatás által a Service Busba indított összes hívást:

Függőségi hívások grafikonja

Figyelje meg, hogy a bejegyzése a következő: DeadLetter. Ez a hívás azt jelzi, hogy az üzenetek a Service Bus kézbesíthetetlen üzenetsorába kerülnek.

A történtek megértéséhez ismernie kell a Service Bus Peek-Lock szemantikáját. Amikor egy ügyfél Peek-Lockot használ, a Service Bus atomilag lekéri és zárol egy üzenetet. A zárolás alatt az üzenet garantáltan nem lesz kézbesítve más fogadóknak. Ha a zárolás lejár, az üzenet elérhetővé válik más fogadók számára. A maximális számú (konfigurálható) kézbesítési kísérlet után a Service Bus kézbesíthetetlen üzeneteket tartalmazó üzenetsorba helyezi az üzeneteket, ahol később megvizsgálható.

Ne feledje, hogy a Munkafolyamat szolgáltatás nagy mennyiségű üzenetet – egyszerre 3000 üzenetet – fogad előre. Ez azt jelenti, hogy az egyes üzenetek feldolgozásának teljes időtartama hosszabb, ami azt eredményezi, hogy az üzenetek túllépik az időkorlátot, visszakerülnek az üzenetsorba, és végül a kézbesíthetetlen üzenetek várólistájára kerülnek.

Ez a viselkedés a kivételekben is látható, ahol számos MessageLostLockException kivételt rögzít a rendszer:

Képernyőkép az Application Insights számos kivételéről, amelyek számos MessageLostLockException kivételt mutatnak.

5. teszt: A zárolás időtartamának növelése

Ebben a terhelési tesztben az üzenet zárolási időtartama 5 percre volt beállítva, hogy megakadályozza a zárolási időtúllépéseket. A bejövő és kimenő üzenetek grafikonja most azt mutatja, hogy a rendszer lépést tart a bejövő üzenetek számával:

A bejövő és kimenő üzenetek grafikonja, amely azt mutatja, hogy a rendszer lépést tart a bejövő üzenetek számával.

A 8 perces terhelési teszt teljes időtartama alatt az alkalmazás 25 K-műveletet hajtott végre, 72 művelet/s csúcsteljesítmény mellett, ami a maximális átviteli sebesség 400%-os növekedését jelenti.

Az üzenet átviteli sebességének grafikonja, amelyen a maximális átviteli sebesség 400%-os növekedése látható.

Ha azonban ugyanazt a tesztet hosszabb időtartammal futtatja, az azt mutatta, hogy az alkalmazás nem tudta fenntartani ezt az arányt:

A bejövő és kimenő üzenetek grafikonja, amely azt mutatja, hogy az alkalmazás nem tudta fenntartani ezt az arányt.

A tárolómetrikák azt mutatják, hogy a maximális processzorkihasználtság megközelíti a 100%-ot. Ekkor úgy tűnik, hogy az alkalmazás processzorhoz kötött. A fürt skálázása most javíthatja a teljesítményt, ellentétben az előző horizontális felskálázási kísérlettel.

Az AKS-csomópont kihasználtságának grafikonja, amelyen az látható, hogy a maximális processzorkihasználtság megközelíti a 100%-ot.

6. teszt: A háttérszolgáltatások felskálázása (ismét)

A sorozat utolsó terheléses tesztjéhez a csapat az alábbiak szerint skálázta fel a Kubernetes-fürtöt és a podokat:

Beállítás Érték
Fürtcsomópontok 12
Betöltési szolgáltatás 3 replika
Munkafolyamat-szolgáltatás 6 replika
Csomag, kézbesítés, drónütemező szolgáltatások 9 replika egyenként

Ez a teszt nagyobb tartós átviteli sebességet eredményezett, és az üzenetek feldolgozása nem okozott jelentős késést. Emellett a csomópont cpu-kihasználtsága 80% alatt maradt.

Az üzenet átviteli sebességének grafikonja, amely nagyobb tartós átviteli sebességet mutat, és nincs jelentős késés az üzenetek feldolgozásában.

Összefoglalás

Ebben a forgatókönyvben a következő szűk keresztmetszeteket azonosítottuk:

  • Memóriakivételek a Azure Cache for Redis.
  • A párhuzamosság hiánya az üzenetfeldolgozásban.
  • Nincs elegendő üzenetzárolási időtartam, ami zárolási időtúllépéseket eredményez, és az üzenetek a kézbesíthetetlen levelek üzenetsorába kerülnek.
  • CPU-kimerültség.

A problémák diagnosztizálásához a fejlesztői csapat a következő metrikákra támaszkodott:

  • A bejövő és kimenő Service Bus-üzenetek sebessége.
  • Alkalmazástérkép az Application Insightsban.
  • Hibák és kivételek.
  • Egyéni Log Analytics-lekérdezések.
  • Cpu- és memóriakihasználtság az Azure Monitor tárolóelemzéseiben.

Következő lépések

A forgatókönyv kialakításával kapcsolatos további információkért lásd : Mikroszolgáltatási architektúra tervezése.