JMeter ile Performans Testi #101
Performans testinin genel anlamda amacı; hedeflenen bir sistemin çeşitli yük dağılımları altında nasıl performans gösterdiğini keşfetmek ve bu keşifler sonucunda yazılım kalitesini artıracak faaliyetleri tetiklemektir. Performans testleri sayesinde potansiyel geliştirme maliyetleri önlenebildiği gibi zamandan tasarruf sağlanır, maliyeti büyük arızaların önüne geçilebilir ve kullanıcılara daha istikrarlı bir hizmet sunulabilir.
JMeter Nedir?
JMeter; Apache Software Foundation tarafından geliştirilen ve 20 yıldan uzun süredir piyasada olan open-source bir performans/yük testi aracıdır. Temelde bir HTTP istemcisi olsa da FTP, SMTP ve daha birçok protokol ile de yük testi hazırlanması ve koşumu için kullanılabilir. Piyasadaki en popüler yük testi araçlarından biridir. Bu durumun başlıca sebepleri şunlardır:
· Açık kaynak kodlu olması
· Kullanmak için kapsamlı bir kodlama ve programlama bilgisine ihtiyaç duyulmaması
· İndirme, kurma (install) ve kullanma işlemlerinin basitliği
· Çalıştırmak için sadece Java’ya ihtiyaç duyması
· Büyük yükleri simüle edebilme yeteneği
· Recording özelliği sayesinde hedef sistem trafiğini izleyebilme
Buradaki link üzerinden JMeter’ın indirebileceğiniz sürümlerini ve gereksinimlerini kontrol edebilirsiniz.
Biz yazımız boyunca JMeter’ın 5.1.1 sürümünü kullanacağız.
Yukarıdaki görselde örnek bir JMeter GUI ekranını görüyorsunuz. Windows kullanıyorsanız JMeter’ı indirdikten sonra jmeter.bat dosyasını çalıştırarak, Mac bilgisayarlar içinse Terminal üzerinden JMeter bin klasöründe “sh jmeter.sh” komutunu çalıştırarak GUI ekranına ulaşabilirsiniz. Ayrıca hazır adını anmışken belirtelim: JMeter’ın GUI ve CLI olarak iki farklı modu mevcut. GUI üzerinden test oluşturma, debugging ve kontrol işlemlerini yapabilirken yük testi koşumu için CLI modunu kullanabilirsiniz.
Siz JMeter’a ilk kez giriş yapıyorsanız veya proje açmadıysanız, yukarıdaki gibi sadece Test Plan yer alan boş bir ekran göreceksiniz. Simgelerin olduğu menüde, çevresi mavi ile highlight edilmiş ikinci simgeye tıklayarak Template menüsünü açalım. Buradan bir template seçerek testimizi yazmaya başlayacağız.
Farklı test tipleri için pek çok seçenek olduğunu görebilirsiniz. Ancak biz bu makalemizde bir web sitesi için yük testi senaryosu yazacağımızdan Recording template’ini seçebiliriz.
Açılan ekranda, bir web sitesine yük testi yapacağımızı düşünerek hostToRecord alanını hedef internet sitemizin adresi olarak ayarlıyoruz ve Create butonuna basarak Template’imizi dolduruyoruz. Ardından gelen ekranda, Test Plan içerisinde pek çok değişik “element” olduğunu göreceksiniz.
Temel Elementler
Test Plan: Test Plan içerisinde koşmayı planladığınız teste dair tüm elementler, ayarlamalar ve yapılar bulunur. Adını değiştirip Comments bölümünden çeşitli açıklamalar ekleyerek daha spesifik bir hale getirebilirsiniz. Ayrıca çoklu Thread Group içeren test senaryoları için groupların çalışma sırasını belirleme, fonksiyonel test modu açma gibi ileri ayarlamaları da yapabilirsiniz. Ancak bu yazı özelinde ilgileneceğimiz şeyler değil.
User Defined Variables: Adından da anlaşılacağı gibi, kullanıcı tarafından sağlanacak çeşitli girdileri JMeter üzerinden birer değişkene atayabilirsiniz. Örneğin aynı testi farklı ortamlarda koşmanız gerektiği zamanlarda (debug, test, preprod, prod vs.), her bir servisin URL’ini tek tek değiştirmek yerine ortam değişkeninin değerini değiştirerek geçişi kolay hale getirebilirsiniz.
HTTP Request Defaults: Tek URL içeren -tüm servislerin aynı sunucuya gittiği- bir yük testi planlıyorsanız URL için web protocol bilgisini ve URL/IP adresini buradan set ederek test dâhilindeki tüm servislerde geçerli olmasını sağlayabilirsiniz.
HTTP Cookie Manager: Testi gerçekleştireceğiniz URL’lerdeki cookie yönetimini HTTP Cookie Manager elementi sayesinde yapabilirsiniz. Örneğin buradaki “Clear cookies each iteration” checkbox’ını işaretlerseniz, her bir thread (sanal kullanıcı) için test döngüsü tekrar başladığında kaydedilen tüm cookieler temizlenecektir.
Thread Group: Thread Group içerisinde test planımızın akışını oluşturuyor olacağız. Thread Group; uygulamayı kullanacak bir kullanıcının izleyeceği akışı içerir. Ve bu akışı gerçekleştiren her bir sanal kullanıcıya da “Thread” denir. Testimizi oluşturduktan sonra belirli bir yükle testi koşmak istediğimizde bu thread sayısı bizim için fazlasıyla önem arz edecek.
Recording Controller: JMeter’ın recording özelliğinden söz etmiştik. Bu özellik sayesinde; bir web sitesinde gezinirken yaptığımız tüm işlemler -servis çağırımları- JMeter içerisine kaydediliyor. Biz de bu kaydedilen isteklerden bize lazım olanları seçerek test senaryomuzu oluşturuyoruz. Bu senaryomuzu da bir üstteki Thread Group içerisine atacağız. Ayrıca, Recording Controller’ı “HTTP(S) Test Script Recorder” içerisine alarak threadlerin Recording Controller içerisinde kalan servislere istek atmasını engelleyebiliriz.
View Results Tree: JMeter bir test koşumunu analiz etmek için pek çok farklı imkan sunuyor. Bunlardan biri de View Results Tree adlı listener. Bu listener sayesinde, senaryo sırasında çağırılan tüm servisleri sıralı bir şekilde görebiliriz. Request ve response detaylarını görebilir, isteğin başarılı sonuçlanıp sonuçlanmadığını takip edebiliriz. Ayrıca bu listener’a ait Sampler Result sekmesinden zamana bağlı bazı değerleri ve dosya boyutlarını görebiliriz.
HTTP(S) Test Script Recorder: JMeter’ın recording özelliğini kullanmak istediğimiz zaman bu elemente gelip Start butonuna basmamız gerekecek. Bunun ardından seçtiğimiz tarayıcı üzerinden tüm istekler JMeter’a kaydediliyor olacak. Ancak bu kaydı gerçekleştirmek için çeşitli ayarlamalar yapmamız gerekiyor. Şimdi bunu ele alalım.
Sertifika ile Recording’in Aktif Edilmesi
JMeter’ın requestleri record edebilmesi için bir tarayıcıya ihtiyacımız var. Bu tarayıcı üzerinden çeşitli ayarlamalar yaparak record işlemini gerçekleştireceğiz. Hem popüler bir tarayıcı olması, hem de JMeter entegrasyonunun oldukça kolay olmasından dolayı tercihimiz Mozilla Firefox olacak.
İlk olarak Mozilla Firefox üzerine bir JMeter sertifikası yüklememiz lazım. Bu sertifikayı oluşturmak için JMeter içerisinden, HTTP(S) Test Script Recorder’ı start edip sonrasında stop etmeniz gerek. Zaten start ettiğinizde “Sertifika oluşturuldu.” şeklinde bir mesaj da size pop-up olarak gösteriliyor. JMeter’ın kurulu olduğu dizinde bin klasörü içerisinde, .crt uzantısıyla bu sertifikayı bulabilirsiniz.
Sertifikayı bulduktan sonra Firefox’u açalım. Sağ üstteki hamburger menüden ayarları açalım. Arama kısmına sertifika/certificate yazıp Sertifikaları Göster/Show Certificates diyelim. İçe Aktar/Import seçeneğine tıkladıktan sonra sertifikamızın bulunduğu dizine gidip seçim yapalım. Ardından yukarıdan açılan pop-up içerisindeki güven ayarlarına ait checkboxlar’ı seçip “Tamam” tıklayalım. Böylece sertifikamızı yükledik.
Bir ayarlama daha yapmamız gerek. Firefox ayarlarında, arama kısmına vekil sunucu/proxy yazıp çıkan Ayarlar/Settings butonuna tıklayalım. Ayarları aşağıdaki görsel doğrultusunda değiştirelim.
Bu sayede artık Mozilla Firefox tarayıcımız, recorder’ı start etmemizden itibaren yaptığımız tüm işlemleri kaydedecek. Ancak unutmayın; yüklediğiniz sertifikanın süresi dolduğunda sertifikayı yenilemeniz gerekecek. Fakat vekil sunucu/proxy ayarı, bir değişiklik yapmadığınız sürece sabit kalabilir.
Şimdi ise HTTP(S) Test Script Recorder’ı başlatalım. Sertifika uyarısını geçtikten sonra HTTP Sampler Settings yazısının hemen altındaki seçeneği “Transaction name” olarak değiştirelim. Bu sayede atılan isteklerin adını numara olarak değil, servisin ismiyle göreceğiz. Bunu yaptı isek, hedef web sitesine gidelim. Sayfa başarılı bir şekilde yüklendikten sonra recorder’ı durdurup JMeter’a geri dönelim ve Recording Controller altındaki servislere bakalım.
Muhtemelen Recording Controller altında bu şekilde servisler göreceksiniz. Servisler gruplar halinde klasörlenmiş (farklı simple controller’lar içerisine yazılmış) olabilir. Ancak bu bir sorun değil, hepsi eskiden yeniye olacak şekilde sıralanmış durumda. İlk isteğimiz doğrudan hostToRecord alanında verdiğimiz web sitesinde anasayfayı çağıran operasyonuna atılmış. Örneğin bu servise tıklayalım. Tıkladığımız zaman sunucu adı, operasyonun path’i, metodu gibi bilgileri görebiliriz. Ayriyeten POST, PUT, DELETE vb. metotlarla attığımız isteklerde request body detaylarını görebiliriz.
İsteklerin solunda bulunan ok işaretine tıklarsanız, HTTP Header Manager elementini görmeniz mümkün. Bilindiği üzere istekler atılırken Header içerisinde çeşitli bilgilerle hedef sunucuya gidiyorlar. Bu header bilgilerini görüntüleme ve değiştirme işlemlerini HTTP Header Manager içerisinden yapabilirsiniz.
Performans Testi Senaryosunun Oluşturulması
Şimdi de ufak bir yük testi senaryosu planlayalım. Senaryomuz sırasıyla şu adımları içersin:
1. Hedef web adresine gidilir.
2. Bireysel sicil numarası ile giriş yapılır.
3. Giriş yapıldığı assertion ile doğrulanır.
Adımlarımızı recorder açık bir şekilde manuel olarak uyguladığımızda tüm çağırımları recording controller içerisinde görmeyi bekliyoruz. Anasayfaya giden isteği zaten record etmiştik. Ancak başka servisler de olduğunu görebiliriz. Örneğin Mozilla ve Google adreslerine gidenler. Genellikle yük testi yaparken, sadece testi yapacağınız URL veya sunucuya ait servisleri senaryoya eklersiniz. Dolayısıyla işimize yarayan harici diğer servisleri senaryoya dahil etmiyoruz.
Thread Group üzerine sağ tıklayıp Add -> Logic Controller -> Simple Controller diyelim. Bu sayede yukarıdaki senaryo adımlarımıza ait çağırımları gruplayıp daha düzenli ve anlaşılır bir yük testi akışı oluşturabiliriz. Örneğin Anasayfayı açtığımızda gelen çağırımları “Ana Sayfa” isimli bir simple controller içerisine koyalım.
Recording Controller elementi açık iken “Clear all the recorded samples” tıklayarak recording’i temizleyebilirsiniz. Böylece önceki recordların kafanızı karıştırmasını engelleyebilirsiniz.
Şimdi ilk request’imizi ekledikten sonra, yeni bir request daha ekleyelim. Bu sefer de sicil numarası ile giriş yapalım ve ardından bu aşamaya ait servisleri Thread Group altında “Kullanıcı Girişi” isimli bir simple controller içerisine ekleyelim. Bunu yapmadan önce recording’i başlatmayı da unutmayın.
Record işlemini tamamladıysanız, pek çok servisin kayda dâhil edildiğini göreceksiniz. Bu aşamada farklı URL’lere giden ancak aynı sunucudan geçen çağırımlar olduğunu da görmeniz mümkün. Hangi isteklerin senaryo akışına dâhil edileceğini, proje paydaşları ile ortaklaşa karar verebilirsiniz. Biz şimdilik medya çağırımları haricindeki her şeyi dâhil ederek yola devam edeceğiz.
Akışı bu adıma kadar tamamladıysanız, Thread Group içerisindeki çağırımların bu şekilde görünmesini bekleyebiliriz. (Tabi sizin hedef siteniz doğrultusunda operasyon isimleri ve sayıları değişiklik gösterecektir.) Şimdi akışı çalıştırmayı deneyelim. Bunun için yukarıdaki Toolbar’daki yeşil renkli ok butonuna tıklayalım. Thread Group içerisinde herhangi bir değişiklik yapmadı iseniz, akışımız bir thread tarafından bir kez execute edilecektir.
Akışı çalıştırdığımızda yukarıdaki gibi bazı isteklerin kırmızı şekilde göründüğünü gözlemleyebilirsiniz. Bunun pek çok sebebi olabilse de; örnek senaryomuzda esas sebep bir önceki operasyondan dönen token bilgisini, diğer operasyonlara aktarmamış olmamız. …/token servisinden dönen access token bilgisini sonraki servislerin header’larına eklememiz gerekiyor. …/token operasyonu her çağrıldığında bize unique bir token bilgisi üretiyor ve bu token bilgisini dinamik olarak sonraki servislerin header’ına geçmemiz lazım. Bunu da yapmak için ilgili token servisine sağ tıklayıp Add -> Post Processors -> JSON Extractor elementini seçelim. Bu Json extractor elementi; istek atıldıktan sonra bize response kısmında dönen bilgileri yakalama imkânı sunuyor.
Yukarıdaki gibi bir access_token extractor’u oluşturmak işimizi görecektir. Names of created variables alanına, yakalanan değerin hangi isimle tutulacağını seçebiliriz.
İsteklerin HTTP Header Manager elementlerine, yukarıdaki gibi token bilgisini ekleyebilirsiniz. Hata alan servislere bu şekilde yapacağımız ekleme sayesinde hataların giderilmesini ve isteklerin başarılı sonuç dönmesini bekliyoruz.
Giriş işleminin başarılı sonuçlanıp sonuçlanmadığını ise yine response içerisinde Assertion ile kontrol edebiliriz. Senaryomuz özelinde; giriş işlemimiz başarılı sonuçlandı ise; isteklerin response kısmında, yönlendiğimiz sayfaya ait bilgileri json response olarak görmeyi bekliyoruz. Bu kontrolü yapmak için ilgili isteğe sağ tıklayıp Add -> Assertions -> JSON Assertion yolunu izleyelim.
Yukarıdaki şekilde bir assertion hazırladığınız takdirde, yukarıdaki json path’in, expected value kısmındaki text değerini döndürmesini bekleyeceğiz. Bu koşul sağlandığı takdirde operasyonun başarılı çalıştığı kabul edilecek, aksi halde de operasyon çağırımı başarısız olmuş görünecek.
Temel Yük Testi Koşumu
Bu adımları da uygulayıp senaryoyu çalıştırırsanız, akışın başarılı tamamlandığını göreceksiniz. Böylelikle basit bir performans testi senaryosunu JMeter üzerinde oluşturmuş olduk. Şimdi ise temel konfigürasyonlar ile bir yük testi nasıl koşulur bunu görmek için Thread Group elementinin üzerine tıklayalım.
Action to be taken after a Sampler error: Akış sırasında requestlerden (sampler) biri hata aldığında, kalan akışa ne olacağını belirtir. Örneğin hata alan servisten dinamik olarak data çekip bunu akışın devamında kullanmamız gerekiyorsa, bu serviste hata yaşamamız akışı sekteye uğratabilir.
Bu hatayı yönetmediğimiz sürece, akışın sekteye uğraması ihtimalinden kaçınmak için “Start Next Thread Loop” seçeneğini işaretleyelim. Böylelikle eğer ki bir thread senaryoyu birden fazla kez koşacaksa, hata aldığında o akışı sonlandırıp bir sonraki koşum döngüsüne geçecektir.
Number of Threads: Oluşturduğunuz senaryoyu koşacak olan sanal kullanıcı sayısını belirtir. Örneğin bu değeri 10 olarak ayarlarsanız, testi başlattığınız andan itibaren 10 sanal kullanıcı senaryoyu koşuyor olacak.
Ramp-Up Period: Seçtiğiniz thread sayısına kaç saniyede ulaşılacağını belirtir. Örneğin 10 thread için bu süreyi 5 saniye olarak ayarlarsanız, JMeter her saniye 2 yeni thread’i ayağa kaldıracak ve 5 saniye sonunda 10 thread’e ulaşacaksınız.
Loop Count: Bir thread’in senaryoyu kaç kez baştan sona koşacağını belirtir. 1 yaparsanız, senaryoyu koşmayı tamamlayan bir thread testi bırakır.
Bu bilgilerin ardından, 5 thread için 5 saniyelik bir Ramp-Up zamanıyla 1 kez dönecek bir yük testi oluşturalım.
Gördüğünüz gibi her bir request’in sol tarafında yeşil tik bulunuyor. Bu durum başarılı bir şekilde sunucudan yanıt aldıkları anlamına geliyor. Ancak bazı sistemlerde, requestler kendilerinden bekleneni yapmasa ya da hata döndürse bile başarılı olarak görünebilirler. Bu yüzden response data bölümünden requestleri kontrol edip başarılı olup olmadıklarına bizim proje paydaşlarından alacağımız dönüşlerle karar vermemiz lazım. Bu kontrolleri otomatik hale getirmek için de yukarıda gördüğümüz Assertion yapısını kullanabilirsiniz.
Sıfırdan Request Oluşturma
Kurum içerisinde yük testleri yaparken genellikle recording ile operasyonları kaydetmek yerine operasyon bilgilerinin iletildiği bir doküman veya Postman Collection ile ilerliyoruz. Bu noktada ilgili çağırımları JMeter’a aktarabilmek için Add → Sampler -> HTTP Sampler elementini kullanabiliriz. Aslında bu element, record ettiğimiz çağırımlarla aynı element. Sadece metot, gidilecek URL, HTTP Header Manager ve gerekliyse request body alanlarını bizim doldurmamız gerekmekte.
Bu request örneğine Header Manager ekleyebilmek için üzerine sağ tıklayıp Add -> Config Element -> HTTP Header Manager yolunu izleyebiliriz. Request’e parametre eklemek veya body data doldurmak için de sırasıyla Parameters — Body Data pencerelerini kullanabiliriz. Bu request tasarımları için size iletilen doküman, Postman Collection vb. kaynakları göz önünde bulundurabilirsiniz.