Apache Bench (ab) ile Web Servis Yük Testi Nasıl Yapılır?
Geliştirdiğimiz web uygulamalarının ve API servislerinin en önemli performans metriklerinden biri de anlık olarak ne kadar yük kaldıracağıdır. Bu performansı ölçümlemek için kimi zaman kendi yazdığımız uygulamalarla test yapabileceğimiz gibi piyasada yaygın olarak kullanılan yük testi araçlarını da tercih edebiliriz. Apache Bench de bu araçlardan biri.
Apache Bench ile (kısaca ab) her türlü Http Server için yük testi (load test) yapmak mümkün. Bu yazıda Apache Bench’in kurulumuna ve kullanımına göz atıp, daha sonra örnek bir Asp.Net Core Web Api uygulaması üzerinden bir yük testi yapacağız. Yazımızın amacı Apache Bench’i tanımak ve bir yük testinin nasıl yapılacağını görmek, ama yazının sonunda aynı zamanda basit bir senkron-asenkron API metot performans incelemesi de görmüş olacağız.
Bir uygulama geliştirilmeye başlandığı andan itibaren aslında test süreci de başlamış oluyor. Burada ilk akla gelen ALM (Application Lifecycle Management)’in önemli bir bileşeni olan Test adımında görev alan mühendisler tarafından, belirli prensipler doğrultusunda yapılan testlerdir. Peki ALM’in Test bileşeni insan eliyle yapılan bu testlerden ibaret midir? Aklınıza hemen Unit Test, Integration Test, Functional Test, Load Test gibi kavramlar gelmeli. Bu kavramlardan her biri birbirinden önemli ve asla göz ardı edilmemesi gereken kavramlardır. Biz bu yazıda yük testi yani load test konusuna değineceğiz. Basit bir web api uygulaması üzerinden Apache Bench’in kullanımı ve sonuçların yorumlanmasından bahsedeceğiz.
Wikipedia da yer alan tanıma göre;
ApacheBench (ab) is a single-threaded command line computer program for measuring the performance of HTTP web servers.
Ab, Apache Http Server’ın performans testlerini yapmak için bir tool’a duyulan ihtiyaçtan ortaya çıkmıştır ancak şu an herhangi bir Http Server için aynı amaçla kullanılabilmektedir.
Ab ile yük testlerimizi komut satırından yapıyoruz ve sonuçları yine komut satırından görebiliyoruz. Kurulumlar için öncelikle buradan sistemimize uygun olan Apache versiyonunu indiriyoruz, ve ZIP dosyasını açıyoruz. /bin/ab.exe dizinindeki .exe yi istediğimiz bir dizine kopyalıyoruz ve artık komut satırından Apache Bench’i kullanabiliriz. Hemen bir ‘hello world’ testi yapalım ve sonuçları yorumlamaya çalışalım.
http://www.devnot.com adresine 100 adet isteği, 10 concurrency (aynı anda 10 kullanıcı istek yapıyor olarak düşünebiliriz) ile aşağıdaki gibi yapıyoruz.
Ekran görüntüsünde odaklanılması gereken kısımları belirtmeye çalıştım. Etiketler yeterince açık olsa da örneğimize geçmeden önce bu sonuç ekranını biraz yorumlamakta fayda var.
Burada kullanılan parametreleri açıklamakla başlayalım. Bu arada tüm parametreler için ab‘nin buradaki dokümantasyonuna göz atabilirsiniz.
-n: Belirtilen adrese yapılacak olan toplam istek sayısını belirtir.
-c: Concurrency, yani aynı anda yapılacak işlem sayısını ifade eder. Burada verdiğimiz 10 değeri herhangi bir t anında devnot.com adresine istek yapan kullanıcı sayısını belirtir. Stress testi yapılmak istendiğinde bu değer artırılabilir. Ancak buradaki optimum değerin ne olacağı konusu üzerinden düşünülmesi gereken bir konudur. Zira çok yüksek değerlerde ab‘nin kendisi bile zorlanabilir. Bu gibi durumlarda 2. hatta 3. ab instance’ı birlikte paralel olarak çalıştırılabilir.
-k: KeepAlive Http Header‘ının kullanılmasını sağlar. Böylelikle ilk istekten sonra connection sürdürülür. Browser’lar bu işlemi doğal olarak gerçekleştirdiklerinden, testler esnasında bu flag’in set edilmesi tavsiye edilir. Boolean bir parametre olduğu için herhangi bir değer almaz. Ekran görüntüsünde -k olmaksızın yapılan testlerde toplam test süresi 5.8 sn. iken, -k parametresiyle yapılan testlerde yaklaşık 2.5 sn. olduğu görülmüştür.
-H: Yapılan isteklere ekstradan Http Header eklemek için kullanılır. Bu özelliği token-based çalışan API metotlarının testi için kullanırız. Örneğin, aşağıdaki şekilde bearer token set ederek API’ın yük testlerini gerçekleştirebilirsiniz.
ab -k -n 100 -c 10 -H “Authorization: bearer <…token…>” http://api_url
Örneğimizi daha eğlenceli hale getirmek için, sync ve async çalışan 2 farklı uç noktası oluşturacağız. Aslında bu makalenin konusu olmayan async /await servislerin performansa olan olumlu katkısını da görmüş olacağız.
Öncelikle örnek uygulama kodlarına buradan ulaşabilirsiniz. Aşağıdaki kod bloğunda aynı işi yapan iki action method görüyorsunuz. Bunlardan birisi async diğeri ise sync çalışıyor. async/wait in performansa katkısını daha net görebilmek adına aynı isteği döngü içerisinde 5 defa gerçekleştiriyoruz. Burada test için basit ve yoğun matematiksel işlemler de yapabilirdik, ancak bu işlem cpu-based olacağı, dolayısıyla awaitable olmayacağı için tercih etmedik. Örnek servis parametre olarak aldığı kullanıcı adı için GitHub API’ınden ilgili kullanıcının profil bilgisini dönmektedir.
Bu arada, Http Client için Asp.Net Core 2.1 ile gelen HttpClientFactory kullanılmıştır.
Sırasıyla önce sync, ardından async servisimize 100 adet istek göndereceğiz. Burada aslında “10 kullanıcının eş zamanlı olarak toplam 100 adet istek yapması” senaryosunu test ediyoruz.
İlk olarak sync uç noktamızı aşağıdaki gibi test ediyoruz.
ab -n 100 -c 10 http://localhost:5000/api/apachebench/getsync?userName=suadev
Aynı işlemi async uç noktası için yapıyoruz.
ab -n 100 -c 10 http://localhost:5000/api/apachebench/getasync?userName=suadev
Sync metot için test 16 saniye civarı iken, async metotta 7.7 saniye sürdüğünü görmekteyiz. Toplam transfer edilen datanın byte cinsinden aynı olduğu da görülmekte. Diğer değerlerde de yine yaklaşık olarak 1/2 gibi bir oran söz konusu.
Peki nasıl yorumlamalıyız?
Async servisimiz 10 eş zamanlı kullanıcı için saniye de 12.87 adet request işlemiş. Bu performans bizim için yeterli mi? Eğer cevabımız evet ise, -n ve -c parametreleri üzerinde artırıma giderek servisimizi zorlayabiliriz. Hatta stress testine doğru gidebiliriz. Tabi burada uygulamanın büyüklüğü, canlıya alındıktan sonra öngörülen kullanıcı sayıları vb. gibi kriterler -n ve -c nin değerinin ne olacağı konusunda önemlidir. Bu arada yukarıdaki testler esnasında -k parametresini geçmeyi unuttuğumu farkettim, –k parametresine değinmiştik hatırlarsanız, bir Http Session ile birden fazla istek yapabilmemizi sağlıyordu. Aslında siz bu şekilde bir istek yaparken sunucuya sizin bağlantınızı kapatmamasını, bu bağlandığı yeniden kullanacağınızı bildiriyorsunuz. Siz örnek uygulamayı indirip –k parametresiyle test ederseniz saniyede 12.87 adet isteğin üzerinde bir değer görmelisiniz.
Sonuç olarak Apache Bench ile aşağıdaki sorulara yanıt aramalıyız;
- Uygulamamın veya servisimin gelen çok sayıda eş zamanlı isteğe ortalama yanıt süresi nedir?
- Uygulamam saniyede maksimum kaç adet isteği işleyebilir?
- Uygulamamın kaldırabileceği yük ne kadardır?
Not: Ciddi stress altında çalışacak olan yoğun trafikli uygulamalar için yalnıza ab ile yapılan testlere bağımlı kalmamakta fayda var.
Bu yazıda yük testi hakkında bir farkındalık oluşturmayı ve Apache Bench’i giriş seviyesinde tanıtmayı amaçladım. Yük testi için başka alternatif tool’lar veya yaklaşımlar olabilir, paylaşmak isterseniz yorumlarınızı beklerim.
Uygulama kaynak kodlarına buradan erişebilirsiniz. Yazıda veya örnek uygulamada fark ettiğiniz hatalar için buradan hata kaydı açabilirsiniz.