Benchmark Sonuçları
ÖZET
Eş-Zamanlı 2.000 Thread ile 1Cpu 8 Core sistem üzerinde, 15.000 reqs/sec karşılanmaktadır.


Bu sonuçlar çağrılan servisin yanıt süresine, network gecikmesine, gateway üzerine eklenen politikaların sistem gereksinimlerine göre değişiklik göstereceğinden yaptığımız yük testinin detaylarını aşağıdaki bölümde inceleyebilirsiniz.
DETAY
Apinizer platformunun kolay kullanımı ve hızlı desteği nedeniyle yük testlerinin çalıştırılmasında altyapı olarak DigitalOcean platformu kullanılmıştır.
Yük testi topolojisi aşağıdaki gibidir:

Bu topolojiyi oluşturmak ve yük testlerimizi çalıştırmak için şu adımlar izlendi:
1 "Yük Test Sunucusu" Kurulumu ve JMeter Yapılandırması
Yük Testi Sunucusu özellikleri:
- CPU-Optimized
- Dedicated CPU
- 8 vCPUs (Intel, second generation Xeon Scalable processors, 2.5 GHz)
- 16 GB Ram
- 100 GB Disk
- CentOS 8.3 x64
Aşağıdaki adımlar "root" kullanıcısı ile yapıldı.
- Java kurulumu yapıldı.
- Java kurulumunun başarılı olduğu aşağıdaki komut ile teyit edildi.
- Dosya indirme komutu kuruldu.
- Jmeter kurulumu için gerekli dosya indirildi.
- tar dosyası açıldı ve dosyalar ayıklandı.
- Jmeter için ortam bilgisi ayarlandı.
- .bashrc dosyasına aşağıdaki satırlar eklendi.
- source komutu ile Linux'un
.bashrc
dosyasını tekrar yüklemesi sağlandı.
- Yük testi için script, Jmeter'in arayüzü ile hazırlandı.
- Thread sayısını ve ne kadar süre ile çalışacağı bilgisi parametrik yapıldı.
Örnek içerik:
<Change with Your IP> yazan kısımda yükün gönderileceği IP adresinin olması gerekli.
<Change with Your Path> yazan kısımda yükün gönderileceği Http istek adresinin olması gerekli.
threads ve seconds değerleri parametrik olup çalışma zamanında verilecek.
Bu konfigürasyon'un ekran görüntüsü:
- Thread Group:

- HTTP Request:

- Aşağıdaki komutu thread ve mesaj süresini değiştirerek çalıştırıldı, sonuçlar kayıt altına alındı.
2 "NGINX Sunucusu" Kurulumu ve NGINX Yapılandırması
NGINX backend servisin simülasyonu için kullanıldı.
Kurulu olduğu sunucunun özellikleri:
- CPU-Optimized
- Dedicated CPU
- 4 vCPUs (Intel, second generation Xeon Scalable processors, 2.5 GHz)
- 8 GB Ram
- 50 GB Disk
- CentOS 8.3 x64
Sunucuya şu adımlarla NGINX kuruldu :
Aşağıdaki adımlar "root" kullanıcısı ile yapıldı.
- EPEL repository kurulumunu yapıldı.
- NGINX kurulumunu yapıldı.
- NGINX'i başlatıldı.
- NGINX'in başladığından emin olmak için tarayıcı ile kurulum yapılan makineye erişim denendi.
- Başarılı sonucu görüldükten sonra NGINX'in servis olarak çalışması sağlandı.
- NGINX'in yüksek yük altında çalışabilmesi için konfigürasyon dosyasına aşağıdakiler eklendi/düzenlendi.
- NGINX'in body olarak 'OK', statusCode olarak 200 dönmesi için aşağıdaki ayar yapıldı:
- NGINX'in konfigürasyonu son durumda şu şekilde oldu:
- NGINX'in yukarıda yapılan ayarlarının yeniden yüklemesini sağlandı:
- NGINX'in ayarları yüklediğinden emin olmak için tarayıcı ile sunucu adresine erişim denendi ve 'OK' yazısı görüldü.
3 "Apinizer ve Log Server" kurulumu ve Kubernetes, MongoDb, ElasticSearch kurulum ve konfigürasyonu
Kubernetes master ve mongodb sunucu özellikleri:
- CPU-Optimized
- Dedicated CPU
- 4 vCPUs (Intel, second generation Xeon Scalable processors, 2.5 GHz)
- 8 GB Ram
- 50 GB Disk
- CentOS 8.3 x64
Log veri tabanı (Elasticsearch) sunucu özellikleri:
- CPU-Optimized
- Dedicated CPU
- 8 vCPUs (Intel, second generation Xeon Scalable processors, 2.5 GHz)
- 16 GB Ram
- 100 GB Disk
- CentOS 8.3 x64
Kubernetes worker sunucu özellikleri:
- CPU-Optimized
- Dedicated CPU
- 16 vCPUs (Intel, second generation Xeon Scalable processors, 2.5 GHz)
- 32 GB Ram
- 200 GB Disk
- CentOS 8.3 x64
Bu bölümde kubernetes master, worker, mongodb, elasticsearch ve Apinizer kurulumları https://docs.apinizer.com/ adresinde yer alan kurulum adımları takip edilerek yapılmıştır.
4 Yük Testinin Önemli Noktaları
Test ederken dikkat edilecek noktalar:
- Apinizer, tüm istek & yanıt mesajlarını ve metriklerini Elasticsearch log veritabanında asenkron olarak saklar. Testler sırasında bu loglama işlemleri olması gerektiği gibi devam etti.
- Tüm testlerimizde ağ gecikmesini azaltmak ve Apinizer'ın gerçek etkisini görmek için iç IP'ler kullanıldı.
- Kubernetes'in çalışma zamanı sırasında pod'ları yeniden başlatmadığını özellikle gözlemledik. Yeniden başlatma sayısı, aşırı yük/tıkanma veya hatalı durumları yansıttığı için önemli bir parametredir.
- Aşağıdaki 4 konfigürasyon Apinizer üzerinde yer alan API Gateway Ortam Ayarlama ekranı ve Elasticsearch Cluster Ayarlama ekranlarında ayarlandı ve testlerde kullanıldı:
Worker Settings | Routing Connection Pool | Elastic Search Client | ||||||||
Core | Ram (gb) | IO Threads | Min. Thread Count | Max. Thread Count | Http Max Connections | Max Conn. Per Route | Max Conn. Total | IO Thread Count | Max Conn. Per Route | Max Conn. Total |
1 | 1 | 1 | 512 | 1024 | 1024 | 512 | 1024 | 4 | 32 | 64 |
2 | 2 | 2 | 1024 | 2048 | 4096 | 2048 | 4096 | 16 | 64 | 128 |
4 | 4 | 4 | 1024 | 4096 | 8192 | 4096 | 8192 | 32 | 64 | 128 |
8 | 8 | 16 | 1024 | 8192 | 8192 | 4096 | 8192 | 32 | 128 | 256 |
- Jvm parametrelerine şu değerler verildi: -server -XX:MaxRAMPercentage=90
- Yukarıdaki 4 durumu Get ve Post isteği ile test edildi. Post isteği için 5K ve 50K’lık istek gövdeleri kullandık.
- Testlerin her bir alt adımı 10'ar dakika sürdü.
5 Sunucu kaynaklarının izlenmesi
Apinizer kubernetes ortamında çalıştığından harcanan kaynakların izlenmesi için iki yöntem tercih edildi. Bunlar:
- Kurulumu şu sayfada açıklanan Kubernetes dashboard,
- JConsole
Kubernetes Dashboard üzerinden kaynakların izlenmesi nispeten kolaydı, sunucunun CPU ve Ram durumları anlık olarak veriyordu. Fakat bu yöntemin sakıncası kaynakları uzun vadeli izleyemiyor olmak ve detayı göstermiyor olmasıydı:

Bu sebeple JConsole kullanımı daha kullanışlı oldu.
JConsole uygulamasının kubernetes içindeki Pod'un içinde çalışan Java uygulamasına erişebilmesi için bazı ayarlar yapıldı:
- Java uygulamasına Jmx parametrelerinin geçilmesi için Java başlangıç parametreleri şu şekilde ayarlandı:
- Worker pod'un 30180 portundan açılan JMX servisinin dış dünyaya açılabilmesi için kubernetes'de aşağıdaki servis tanımı yapıldı:
Ayarlar bitince JConsole uygulaması çalıştırıldı ve worker sunucusunun dış erişim adresi ve 30180 portunu verilerek worker üzerinde çalışan JVM'e erişim sağlandı.


6 Yük testi sonuçları
GET | POST 5Kb | POST 50Kb | |||||
No | Thread Count | Throughput | Avg | Throughput | Avg | Throughput | Avg |
A | 50 | 1133 | 43 | 1002 | 49 | 675 | 73 |
100 | 1100 | 90 | 983 | 101 | 653 | 152 | |
250 | 1025 | 242 | 852 | 292 | 554 | 448 | |
500 | 963 | 516 | - | - | - | - | |
B | 50 | 2232 | 22 | 1868 | 26 | 1437 | 34 |
100 | 2169 | 45 | 1768 | 56 | 1409 | 70 | |
250 | 2089 | 119 | 1456 | 170 | 1223 | 203 | |
500 | 1915 | 259 | 1398 | 355 | 1149 | 432 | |
1000 | 1762 | 564 | 1229 | 809 | 877 | 1134 | |
1500 | 1631 | 915 | 1199 | 1245 | - | - | |
2000 | 1379 | 1441 | - | - | - | - | |
C | 50 | 8090 | 6 | 7353 | 6 | 4679 | 10 |
100 | 7816 | 12 | 7257 | 13 | 4675 | 21 | |
250 | 7011 | 35 | 7138 | 34 | 4020 | 61 | |
500 | 6759 | 73 | 7141 | 69 | 3221 | 154 | |
1000 | 6742 | 147 | 7011 | 141 | 2962 | 335 | |
1500 | 6683 | 223 | 6935 | 215 | - | - | |
2000 | 6692 | 297 | - | - | - | - | |
4000 | 6448 | 617 | - | - | - | - | |
D | 50 | 15420 | 3 | 13396 | 3 | 4683 | 10 |
100 | 15812 | 6 | 13482 | 7 | 4671 | 21 | |
250 | 15614 | 15 | 13587 | 18 | 4382 | 56 | |
500 | 15664 | 31 | 13611 | 36 | 3496 | 142 | |
1000 | 15454 | 64 | 13562 | 73 | 3046 | 326 | |
1500 | 15026 | 99 | 13208 | 112 | 2853 | 522 | |
2000 | 14839 | 133 | 13179 | 150 | 2794 | 710 | |
4000 | 14356 | 276 | 12792 | 309 | - | - | |
8000 | 11603 | 655 | 11115 | 701 | - | - |
Throughput & Concurrent Users

Average Response Time & Concurrent Users

Sonuçlar ile ilgili yorumlar:
Sonuçları incelerken çok sık yapılan hata session sayısı ile anlık istek sayısının karıştırılmasıdır. İstek, belirli bir Http metod ile belirli bir hedef için yapılan HTTP isteğidir. Session başına sıfır veya daha fazla istek olabilir. Örneğin bir web uygulamasında 50K session olması anlık isteğin 50K olacağı anlamına gelmez 50K’nın aynı anda istek yapma olasılığı ise çok düşüktür. Gatewaylerde session tutmak çok nadir görülür, genellikle servislere erişim stateless’dir. Bu yüzden eş zamanlı istek sayısını ve gecikmeyi (latency) ölçmek daha anlamlı hale gelir.
Eşzamanlı kullanıcı sayısı arttığında verim belirli bir sınıra kadar arttar. Sonrasında düşüş yaşanmaya başlar. Aslında doğal olan bu seyir dikey büyümenin bir sınırı olduğunu ifade eder. Kabul edilebilir yanıt sürelerine sahip daha fazla eşzamanlı kullanıcıyı desteklemek için, yatay veya dikey ölçeklendirmeyi beraber düşünmek gerekir. Yatay olarak ölçeklendirme yapılırken, diğer gatewaylerde iki veya daha fazla gateway’in önüne bir yük dengeleyici koymak gerekirken Apinizer’da kubernetes altyapısı kullanıldığından bu işlem çok kolay ve hızlı şekilde yapılandırılabilir.
Mesaj boyutları arttığında işlem gücü artacağından verim azalır. Dolayısıyla yanıt süresi de uzar. Genellikle gerçek yaşam senaryolarında istek boyutları 1Kb ortalamasında olsa da testlerimizde 1Kb Post ile Get isteklerimiz arasında çok küçük bir fark olduğundan 5Kb ve 50Kb Post isteklerini incelemeye değer bulduk. Sonuçlar doğal olarak GET isteklerine göre daha düşük bir değerde seyretse de 10 kat artan veriye göre rakamların sadece 4'te birine düşmesi bizim adımıza sevindirici oldu.
Yük testi boyunca harcanan Ram oranları çok tutarlıydı. İsteklerin boyutu on kat artsa da Ram kullanımında ciddi bir artış gözlenmedi. Bu da Openj9'un doğru bir tercih olduğunu ispatladı.
“D” Durumu, 8000 Thread, Get isteği için VM’den bir kesit:

Poliçe Ekleyelim
Gateway’e eklediğimiz her bir poliçe gateway'de karmaşıklığına ve bağımlılıklarına göre performansı etkiler.
Şimdi Apinizer’a “basic authentication” poliçesi ekleyelim. Bu konfigürasyonu tüm durumlar için değil sadece “D” durumu için test edelim, sonuçta bir fikir vermesi yeterli:
GET | GET with Policy | ||||
No | Thread Count | Throughput | Avg | Throughput | Avg |
D | 50 | 15420 | 3 | 14760 | 3 |
100 | 15812 | 6 | 14843 | 6 | |
250 | 15614 | 15 | 14891 | 16 | |
500 | 15664 | 31 | 14748 | 33 | |
1000 | 15454 | 64 | 14285 | 68 | |
1500 | 15026 | 99 | 14373 | 102 | |
2000 | 14839 | 133 | 14280 | 136 | |
4000 | 14356 | 276 | 13795 | 279 | |
8000 | 11603 | 655 | 11437 | 672 |
Throughput & Concurrent Users

Average Response Time & Concurrent Users

Gördüğümüz gibi performansa etkisi hissedilmeyecek derecede de olsa olmuş. Fakat örneğin “content filtering” gibi işlem gücü yüksek maliyetli bir poliçe eklenseydi ya da “Ldap Authentication” gibi dış bağlantı gerektiren ve araya bir de network latency ekleyen poliçe eklenseydi performans daha da hızlı bir şekilde düşecekti. Burada önemli olan her bir poliçenin ne kadar yük getireceğini bilmek ve tasarımı ona göre seçmek.