Nginx ve NodeJS ile Load Balancing
Bugün, "Yük Dengeleme" yani ecnebilerin deyimiyle "Load Balancing" kavramını Nginx
ve NodeJS
özelinde inceleyeceğiz.
Neden yük dengeleme yapmamız gerektiğine, "bir elin nesi var iki elin sesi var" diyerek iyi bir cevap vermiş atalarımız. Aynen öyle. Eğer web uygulamanız tek bir sunucu üzerinde çalışıyorsa ve tüm yükü bu sunucu çekiyorsa haliyle biraz zorlanacatır. Ancak siz bu yükü, aynı işi yapan birden fazla sunucuya paylaştırırsanız, iş çok daha hızlı tamamlanacaktır.
Senaryomuz şöyle olsun;
Üç adet sunucumuz bulunsun. Sunuculardan biri yük paylaşımının yapılacağı, diğer ikisi ise web uygulamasının bulunacağı sunucular olsun.
Server 1
Nginx web sunucusunun kurulu olacağı ve gelen isteklerin diğer web sunucularına nasıl paylaştırılacağına karar veren sunucumuz.
name: loadbalancer
ip: 192.168.1.11
Server 2
Nodejs web uygulamasının bulunacağı sunucu.
name: web1
ip: 192.168.1.12
Server 3
Nodejs web uygulamasının bulunacağı diğer sunucu.
name: web2
ip: 192.168.1.13
Vagrant Yapılandırması
Öncelikle dizin planımızı şöyle hazırlayalım. Resimdeki gibi üç ayrı dizin oluşturalım ve her birinin içerisine Vagrantfile
adında birer dosya oluşturalım.
Vagrantfile
içeriklerimiz aşağıdaki gibi olsun;
"Server1" için Vagrantfile Tanımlaması
NAME = 'loadbalancer'
IP = "192.168.1.11"
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.hostname = NAME
config.vm.network "public_network", ip: IP
config.vm.provider "virtualbox" do |vb|
vb.customize ["modifyvm", :id, "--memory", '2048']
end
end
"Server2" için Vagrantfile Tanımlaması
NAME = 'web1'
IP = "192.168.1.12"
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.hostname = NAME
config.vm.network "public_network", ip: IP
config.vm.provider "virtualbox" do |vb|
vb.customize ["modifyvm", :id, "--memory", '2048']
end
end
"Server3" için Vagrantfile Tanımlaması
NAME = 'web2'
IP = "192.168.1.13"
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.hostname = NAME
config.vm.network "public_network", ip: IP
config.vm.provider "virtualbox" do |vb|
vb.customize ["modifyvm", :id, "--memory", '2048']
end
end
Vagrantfile içeriklerinde değişien tek şey IP adresleri ve sunucu isimleri oldu. Dilerseniz ek konfigürasyonlar ekleyebilirsiniz elbette.
Şimdi Vagrant sunucularımızı ayağa kaldıralım.
"Server1" için
server1
adlı dizine gidelim ve aşağıdaki komutu çalıştıralım.
vagrant up
"Server2" için
server2
adlı dizine gidelim ve aşağıdaki komutu çalıştıralım.
vagrant up
"Server3" için;
server3
adlı dizine gidelim ve aşağıdaki komutu çalıştıralım.
vagrant up
Sunucu Konfigürasyonları
Load balancer sunucumuz ve uygulama sunucularımız için aşağıdaki konfigürasyonları yapmamız gerekiyor.
"Server2" ve "Server3" için
Aşağıdaki işlemleri server2
ve server3
için ayrı ayrı yapmamız gerekiyor. Bu iki sunucumuzda da aynı web uygulaması bulunacak. Aynı kurulumlar yapılacak. Web uygulaması NodeJS ile çalışacak. Hızlı bir kurulum yapıp test edebilmek adına express
ile çalışacağız.
NodeJS Kurulumu
vagrant ssh
sudo apt-get update
sudo apt-get install nodejs npm -y
sudo ln -s /usr/bin/nodejs /usr/bin/node
Express Kurulumu ve Uygulamayı Ayağa Kaldırmak
sudo npm install express-generator -g
sudo mkdir /var/www && cd /var/www
sudo express .
sudo npm install
npm start
Uygulamamızı ayağa kaldırdık. Hemen test edelim. Web tarayıcımızdan, web1 ve web2 sunucularımızda koşturan NodeJS uygulamasına erişelim.
http://192.168.1.12:3000 veya http://192.168.1.13:3000
adreslerine erişmeye çalıştığımızda express'in aşağıdaki karşılama ekranı ile karşılaşacağız. Eğer iki IP adresinde de bu ekran ile karşılaşıyorsak nodejs uygulamasını başarıyla çalıştırmışız demektir.
Server 1
Aşağıdaki komut ile sunucumuzun komut satırı arayüzüne erişelim.
vagrant ssh
Nginx kurulumunu yapalım.
sudo apt-get install nginx -y
Nginx konfigürasyonunu yapalım.
sudo vi /etc/nginx/sites-available/default
Nginx'in varsayılan ayarlarının bulunduğu dosyayı bir komut satırı editörü olan vi
ile açtık. Şimdi bu dosyanın içeriğini tamamen silelim ve aşağıdaki kodları yapıştıralım.
Vi editörünü kullanarak dosya üzerinde değişiklik yapabilmek için insert moduna geçmeniz gerekiyor. Klavyenizden
i
tuşuna basarak bu moda geçebilirsiniz. Insert modundan çıkmak içinescape
tuşuna basmalısınız. Herhangi satırı komple simek için, insert modunda değilkend
tuşuna ardarda iki kere basmalısınız. Dosyayı kaydedip çıkmak için ise yine insert modunda değilken:wq
yazıpenter
tuşuna basmanız gerekiyor. Kaydetmeden çıkmak için ise:q!
. Daha fazlası şurada.
upstream servers {
server 192.168.1.12:3000;
server 192.168.1.13:3000;
}
server {
listen 80;
location / {
proxy_pass http://servers;
}
}
Yukarıdaki kodun upstream
kısmında bulunan IP adresleri web uygulamalarımızın çalıştığı sunucunun ip adresini ve dinlediği portu belirtmekte.
Kaydedip çıkalım ve Nginx'i yeniden başlatalım.
sudo service nginx reload
Şimdi web tarayıcımıza gidelim loadbalancer sunucumuzun IP adresine erişmeye çalışalım.
Eğer bu ekran ile karşılaşıyorsanız, hayırlı olsun nur topu gibi bir load balancer'ınız oldu.
"Yok arkadaş ben inanmadım, kanıtla" dersen de şöyle bir şey yapabiliriz. Web uygulamamızın koştuğu iki ayrı sunucu vardı. Bu sunucuların döndüğü cevabı değiştirelim ve tekrar test edelim. Göreceksiniz ki her refresh yapışınızda farklı sunucuya yönlendirileceksiniz.
Server 2 için (web1)
vagrant ssh
sudo vi routes/index.js
Aşağıdaki satırı,
res.render('index', { title: 'Express' });
Aşağıdaki satır ile değiştirelim.
res.render('index', { title: 'Served from Web1' });
Server 3 için (web2)
vagrant ssh
sudo vi routes/index.js
Aşağıdaki satırı,
res.render('index', { title: 'Express' });
Aşağıdaki satır ile değiştirelim.
res.render('index', { title: 'Served from Web2' });
Şimdi http://192.168.1.11/ adresine gidin ve sayfayı hızlıca yenileyin. Göreceksiniz ki en müsait sunucu hangisi ise ona yönlendirileceksiniz.
Performans testleri
Şimdi load balancerdan önce ve sonraki performans durumuna bakalım.
Apache Benchmark
aracı ile testimizi yapalım.
n: Gerçekleştirilecek istek sayısı
c: Bir seferde gerçekleştirilecek birden çok istek sayısı.
Load balancer olmadan
ab -n 2000 -c 100 http://192.168.1.12:3000/
Sonuç
Server Software:
Server Hostname: 192.168.1.12
Server Port: 3000
Document Path: /
Document Length: 197 bytes
Concurrency Level: 100
Time taken for tests: 16.932 seconds
Complete requests: 2000
Failed requests: 0
Total transferred: 786000 bytes
HTML transferred: 394000 bytes
Requests per second: 118.12 [#/sec] (mean)
Time per request: 846.616 [ms] (mean)
Time per request: 8.466 [ms] (mean, across all concurrent requests)
Transfer rate: 45.33 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 1.4 0 10
Processing: 55 826 138.7 819 1171
Waiting: 55 825 138.7 819 1171
Total: 57 827 138.1 820 1172
Percentage of the requests served within a certain time (ms)
50% 820
66% 857
75% 894
80% 916
90% 954
95% 1017
98% 1086
99% 1154
100% 1172 (longest request)
Load balancer ile
ab -n 2000 -c 100 http://192.168.1.11/
Sonuç
Server Software: nginx/1.4.6
Server Hostname: 192.168.1.11
Server Port: 80
Document Path: /
Document Length: 197 bytes
Concurrency Level: 100
Time taken for tests: 12.773 seconds
Complete requests: 2000
Failed requests: 0
Total transferred: 846000 bytes
HTML transferred: 394000 bytes
Requests per second: 156.59 [#/sec] (mean)
Time per request: 638.629 [ms] (mean)
Time per request: 6.386 [ms] (mean, across all concurrent requests)
Transfer rate: 64.68 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 1.9 0 19
Processing: 39 622 182.3 592 1024
Waiting: 39 622 182.3 592 1024
Total: 41 623 182.1 595 1024
Percentage of the requests served within a certain time (ms)
50% 595
66% 672
75% 743
80% 821
90% 900
95% 938
98% 967
99% 974
100% 1024 (longest request)
Geçen Zaman
Test sonuçlarına baktığımızda 2000 isteğin karşılanması için;
Load balancer olmadan: 16.932sn
Load balancer ile: 12.773sn
Saniyede karşılanan istek sayısı
Load balancer olmadan: 118.12
Load balancer ile: 156.59
Fark ortada. Toplam 2000 istekte 4 saniyenin biraz üzerinde kârımız var ve saniyede 38 tane fazladan istek işlemiş olduk.