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.
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.
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:
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:
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.
É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:
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:
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.
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:
Az átviteli sebesség konzisztensebb, de az elért maximális érték körülbelül megegyezik az előző teszté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%.
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.
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.
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
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:
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:
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:
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 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.
Ha azonban ugyanazt a tesztet hosszabb időtartammal futtatja, az azt mutatta, 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.
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.
Ö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.