2016年5月30日

設定 Haproxy 以防止 DDOS 攻擊

Load Balancer 可說是整個雲端系統的存取入口,因此針對網路攻擊,在服務處理的第一線就要嘗試識別這樣的攻擊方式,並加以阻絕。但實際上要辨識惡意攻擊,並沒有那麼容易,光以連線產生速度,或是一段時間內的連線數來看,很容易會因為 NAT 的使用環境而誤判,造成原本應該可以使用的環境,卻因為這些設定值而變得沒有辦法使用。

TCP syn flood attacks

向伺服器發送大量的 TCP syn packets,讓 Server 忙於處理這些封包,並耗盡 Server 的 Uplink 頻寬。

修改 OS 的網路參數就可以解決這個問題

vi /etc/sysctl.conf

# Protection from SYN flood
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.tcp_max_syn_backlog = 1024
# 用這個指令可以列印 kernel 的參數
sysctl -p

net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.tcp_max_syn_backlog = 1024

Slowloris like attacks

Clients 緩慢地發送資料給 Server,有些會一次送一個 Header,更糟糕的是一次送一個 Character,讓 Server 花很多時間在等待資料。

在 Haproxy 設定 timeout http-request 5s,限制 Haproxy 等待 client 發送整個 HTTP request,只等 5 秒鐘的時間,超過 5 秒就會關閉連線,產生 Error。

這個設定值是放在 defaults 區塊中:

defaults
     option      http-server-close
     timeout     http-request 5s
     timeout     connect 5s
     timeout     client 30s
     timeout     server 10s
     timeout     tunnel 1h

修改設定後,可以直接用 telnet 來驗證是不是有作用。

telnet localhost 80
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
HTTP/1.0 408 Request Time-out
Cache-Control: no-cache
Connection: close
Content-Type: text/html

<html><body><h1>408 Request Time-out</h1>
Your browser didn't send a complete request in time.
</body></html>
Connection closed by foreign host.

惡意的 client 行為

對於一個 Web Server 來說,惡意的 client 會有以下這些行為

  1. 開啟太多連線 too many connections opened
  2. 新連線的產生速度太快 new connection rate too high
  3. http request 的產生速度太快 http request rate too high
  4. 頻寬使用太高 bandwith usage too high

限制每一個 user 的連線數量

普通用戶瀏覽網站的網頁,或是從網站下載東西時,瀏覽器一般會建立 5-7 個 TCP 鏈接。當一個惡意 client 打開了大量 TCP 連線時,耗費大量資源,因此我們必須要限制同一個用戶的連線數量。

但如果有很多使用者,是從某一個私有網段,透過 NAT 的方式連線到 Server 時,且實際上我們也不知道,到底哪一個會是 NAT 的轉址後的 IP,不知道該將哪個 IP 設定為白名單,這樣的限制就會造成問題,因此我們認為實際的環境,這樣的設定應該要保留不處理。

以下是一個設定的範例,最重要的地方是在 frontend ft_web 區塊的設定。

global
  stats socket ./haproxy.stats level admin
 
defaults
  option http-server-close
  mode http
  timeout http-request 5s
  timeout connect 5s
  timeout server 10s
  timeout client 30s
 
listen stats
  bind 0.0.0.0:8880
  stats enable
  stats hide-version
  stats uri     /
  stats realm   HAProxy Statistics
  stats auth    admin:admin

frontend ft_web
  bind 0.0.0.0:8080
 
  # Table definition  
  stick-table type ip size 100k expire 30s store conn_cur
 
  # Allow clean known IPs to bypass the filter
  tcp-request connection accept if { src -f /etc/haproxy/whitelist.lst }
  # Shut the new connection as long as the client has already 10 opened 
  tcp-request connection reject if { src_conn_cur ge 10 }
  tcp-request connection track-sc1 src
 
  # Split static and dynamic traffic since these requests have different impacts on the servers
  use_backend bk_web_static if { path_end .jpg .png .gif .css .js }

  default_backend bk_web

# Dynamic part of the application
backend bk_web
  balance roundrobin
  cookie MYSRV insert indirect nocache
  server srv1 192.168.1.2:80 check cookie srv1 maxconn 100
  server srv2 192.168.1.3:80 check cookie srv2 maxconn 100
 
# Static objects
backend bk_web_static
  balance roundrobin
  server srv1 192.168.1.2:80 check maxconn 1000
  server srv2 192.168.1.3:80 check maxconn 1000

可以用 apache bench 先產生 10 長時間的連線。

ab -n 50000000 -c 10 http://127.0.0.1:8080/

然後再用 telnet 判斷是否能產生新的連線

telnet 127.0.0.1 8080

限制每個 user 產生新連線的速率 Limiting the connection rate per user

惡意的使用者會在短時間內建立很多連線,但如果產生新連線的速度太高,就會消耗掉過多的資源服務一個使用者。

因為 browser 有可能在幾秒鐘內,建立 7 個 TCP Connection,所以基本上認定如果在 3 秒鐘內,建立了超過 20 個 TCP Connection,就有可能是惡意的 client。

但如果有很多使用者,是從某一個私有網段,透過 NAT 的方式連線到 Server 時,且實際上我們也不知道,到底哪一個會是 NAT 的轉址後的 IP,不知道該將哪個 IP 設定為白名單,這樣的限制就會造成問題,因此我們認為實際的環境,這樣的設定應該要保留不處理。

frontend ft_web
  bind 0.0.0.0:8080
 
  # Table definition  
  stick-table type ip size 100k expire 30s store conn_rate(3s)
 
  # Allow clean known IPs to bypass the filter
  tcp-request connection accept if { src -f /etc/haproxy/whitelist.lst }
  # Shut the new connection as long as the client has already 10 opened 
  # tcp-request connection reject if { src_conn_cur ge 10 }
  tcp-request connection track-sc1 src
 
  # Split static and dynamic traffic since these requests have different impacts on the servers
  use_backend bk_web_static if { path_end .jpg .png .gif .css .js }

  default_backend bk_web

測試設定的方法:先用 apache bench 產生 10 個 requests。

ab -n 10 -c 1 -r http://127.0.0.1:8080/

再利用 telnet 檢查是否可以在產生新的連線。

telnet 127.0.0.1 8080
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.

限制產生 HTTP request 的速度 Limiting the HTTP request rate

global
  stats socket ./haproxy.stats level admin
 
defaults
  option http-server-close
  mode http
  timeout http-request 5s
  timeout connect 5s
  timeout server 10s
  timeout client 30s
 
listen stats
  bind 0.0.0.0:8880
  stats enable
  stats hide-version
  stats uri     /
  stats realm   HAProxy Statistics
  stats auth    admin:admin
 
frontend ft_web
  bind 0.0.0.0:8080
 
  # Use General Purpose Couter (gpc) 0 in SC1 as a global abuse counter
  # Monitors the number of request sent by an IP over a period of 10 seconds
  stick-table type ip size 1m expire 10s store gpc0,http_req_rate(10s)
  tcp-request connection track-sc1 src
  tcp-request connection reject if { src_get_gpc0 gt 0 }
 
  # Split static and dynamic traffic since these requests have different impacts on the servers
  use_backend bk_web_static if { path_end .jpg .png .gif .css .js }
 
  default_backend bk_web
 
# Dynamic part of the application
backend bk_web
  balance roundrobin
  cookie MYSRV insert indirect nocache
 
  # If the source IP sent 10 or more http request over the defined period, 
  # flag the IP as abuser on the frontend
  acl abuse src_http_req_rate(ft_web) ge 10
  acl flag_abuser src_inc_gpc0(ft_web)
  tcp-request content reject if abuse flag_abuser
 
  server srv1 192.168.1.2:80 check cookie srv1 maxconn 100
  server srv2 192.168.1.3:80 check cookie srv2 maxconn 100
 
# Static objects
backend bk_web_static
  balance roundrobin
  server srv1 192.168.1.2:80 check maxconn 1000
  server srv2 192.168.1.3:80 check maxconn 1000

測試設定的方法:先用 apache bench 產生 10 個 requests。

ab -n 10 -c 1 -r http://127.0.0.1:8080/

再利用 telnet 檢查是否可以在產生新的連線。

telnet 127.0.0.1 8080
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.

偵測弱點掃描 Detecting vulnerability scans

如果有人進行弱點掃描,在 Server 通常會遇到以下這些錯誤訊息:

  1. invalid and truncated requests
  2. denied or tarpitted requests
  3. failed authentications
  4. 4xx error pages

設定範例

global
  stats socket ./haproxy.stats level admin
 
defaults
  option http-server-close
  mode http
  timeout http-request 5s
  timeout connect 5s
  timeout server 10s
  timeout client 30s
 
listen stats
  bind 0.0.0.0:8880
  stats enable
  stats hide-version
  stats uri     /
  stats realm   HAProxy Statistics
  stats auth    admin:admin
 
frontend ft_web
  bind 0.0.0.0:8080
 
  # Use General Purpose Couter 0 in SC1 as a global abuse counter
  # Monitors the number of errors generated by an IP over a period of 10 seconds
  stick-table type ip size 1m expire 10s store gpc0,http_err_rate(10s)
  tcp-request connection track-sc1 src
  tcp-request connection reject if { src_get_gpc0 gt 0 }
 
  # Split static and dynamic traffic since these requests have different impacts on the servers
  use_backend bk_web_static if { path_end .jpg .png .gif .css .js }
 
  default_backend bk_web
 
# Dynamic part of the application
backend bk_web
  balance roundrobin
  cookie MYSRV insert indirect nocache
 
  # If the source IP generated 10 or more http request over the defined period, 
  # flag the IP as abuser on the frontend
  acl abuse src_http_err_rate(ft_web) ge 10
  acl flag_abuser src_inc_gpc0(ft_web)
  tcp-request content reject if abuse flag_abuser
 
  server srv1 192.168.1.2:80 check cookie srv1 maxconn 100
  server srv2 192.168.1.3:80 check cookie srv2 maxconn 100
 
# Static objects
backend bk_web_static
  balance roundrobin
  server srv1 192.168.1.2:80 check maxconn 1000
  server srv2 192.168.1.3:80 check maxconn 1000

測試:先用 apache bench 產生錯誤 url 的 request

ab -n 10 http://127.0.0.1:8080/dlskfjlkdsjlkfdsj

再執行一次 ab,就會收到錯誤的結果。

Reference

USE A LOAD-BALANCER AS A FIRST ROW OF DEFENSE AGAINST DDOS

配置 Haproxy 防止 DDOS 攻擊

2016年5月23日

Nginx Reverse Proxy

Web Cache Server 介於 Client 跟 Web Server 之間,當使用者存取一個網址,Web Cache Server 會先向後端的 Web Server 取得資料,如果下一個 request 又存取了相同的網址,這時候就可直接由 Web Cache Server 回傳給 Client,用以減少 Web Server 的 Loading。

其他常見的開源代理伺服器有 Squid,Varnish,Nginx,HAProxy,Apache Traffic Server(ATS),其中 HAProxy 沒有 Cache 的功能,Squid 是比較老牌的 proxy server,但遇到 session 數量太高時,容易失效,已經比較少用了,然後 Varnish 取代了 Squid 的地位。

Varnish 主要功能就是 reverse proxy cache server,由於是使用記憶體作為cache,適合用來處理小文件如 css,js 及小圖片的cache。

nginx 主要功能是靜態網頁服務,若是為了提供訪問最頻繁資源的cache,可以使用 nginx-cache 模組,適合cache少量頁面資源,如果 Cache 內容過多容易造成性能瓶頸與負載過大。

所以目前看起來,有兩個伺服器可以嘗試,一個是 ngnix + cache,這個可以用在少量 cache 資源,加上可以處理靜態網頁檔案,另一個是 Apache Traffic Server (ATS),這是比較專用的 cache server,如果要建置專業的 CDN,應該要選擇使用 ATS。

Apache Traffic Server(ATS或TS)是一個高性能的、模塊化的 HTTP 代理和cache服務器。Traffic Server 最初是 Inktomi 公司的商業產品,該公司在 2003 年被 Yahoo 收購,之後 Traffic Server 一直在 Yahoo 內部使用長達 4 年,直到 2009 年 8 月 Yahoo 向 Apache 軟件基金會(ASF)貢獻了源代碼,並於 2010 年 4 月成為了 ASF 的頂級項目(Top-Level Project)。Apache Traffic Server 現在是一個開源項目,開發語言為C++。

軟件名稱 性能 功能 過濾規則配置
Squid 不能多核,disk cache有容量優勢,性能中等 多,支援ACL角色控制,也支援ICP cache 協定 支援外部規則文件讀取及熱加載,支援熱啟動
Varnish 多核支援,memory cache,性能強 夠用,不支援集群,支援後端存活檢查 不支援外部文件讀取,需要轉譯,支援熱啟動
Nginx 多核,支援代理插件,性能較強 多,通過plugin可以充當多種服務器 不支援外部文件讀取,需要轉譯,支援熱啟動
ATS 多核,disk/memory cache,性能強 夠用,支援plugin開發,也支援ICP協議 支援外部規則文件讀取及熱加載,支援熱啟動,但缺乏文檔
HAProxy 多核,無 cache,支援HTTP header語法操作,性能強 少,只專注HTTP頭部解析和轉發功能,支援ACL角色控制,支援後端存活檢查 支援外部規則文件讀取及熱加載,支援熱啟動,支援 sticky session 和長連接

nginx for CentOS 7

安裝 nginx

yum -y install nginx

# 立即啟動
systemctl start nginx

# 查看目前運作狀態
systemctl status nginx

# 查看 nginx 服務目前的啟動設定
systemctl list-unit-files | grep nginx

# 若是 disabled,可以改成開機自動啟動
systemctl enable nginx

調整 nginx 設定,先把 nginx service port 改為 6000

vi /etc/nginx/nginx.conf
listen       6000 default_server;
listen       [::]:6000 default_server;

systemctl restart nginx

安裝及設定 PHP-FPM

yum -y install php php-fpm php-mysql

# 查詢 PHP-FPM 的狀態
systemctl list-unit-files | grep php-fpm

# 改成開機自動啟動
systemctl enable php-fpm

# 立即啟動
systemctl start php-fpm

# 查看目前運作狀態
systemctl status php-fpm

修改 PHP-FPM 設定

chown -R nginx.nginx /var/lib/php/session

vi /etc/php-fpm.d/www.conf

user = nginx
group = nginx

listen.owner = nginx
listen.group = nginx
listen.mode = 0660

; listen = 127.0.0.1:9000  改成
listen = /var/run/php-fpm/php-fpm.sock


systemctl restart php-fpm

修改 ulimit open file的限制

# 查閱file open 限制
ulimit -a

vi /etc/security/limits.conf
# 增加 4行
* soft nofile 65535
* hard nofile 65535
root hard nofile 65535
root soft nofile 65535

# 設定 file open數量
ulimit -n 65535

nginx proxy_cache

nginx 自 v0.7.48 開始支援了類似 Squid 的功能,他會把 url 當作 key,以 MD5 對 key 進行 hash,然後得到硬碟上對應的 hash 檔案目錄,然後將快取的內容存放到這個目錄中。目前沒有清除 cache 的功能,但可透過 ngxcachepurge 模組,清除指定 URL 的 cache。

建立 cache 目錄

mkdir -p /usr/share/nginx/cache
chown -R nginx.nginx /usr/share/nginx/cache

proxy_cache 相關的設定值

# 設定快取檔案的存放路徑 proxy_cache_path
proxy_cache_path path [levels=number] keys_zone=zone_name:zone_size [inactive=time] [max_size=size];

# path  快取檔案的存放路徑
# levels=number  快取空間有兩層 hash 目錄
# keys_zone=zone_name:zone_size  zone_name是為這個快取空間命名,zone_size是記憶體快取的空間大小
# inactive=time  快取存活的時間
# max_size=size  硬碟快取空間

# example
proxy_cache_path /usr/share/nginx/cache levels=1:2 keys_zone=STATIC:50m inactive=1d max_size=20g;

# ---------------
# 設定要使用哪一個快取空間名稱 proxy_cache
proxy_cache zone_name;
# zone_name 就是剛剛在 proxy_cache_path 設定的 zone_name

# example
proxy_cache STATIC;

# ---------------
# proxy_cache_methods 設定快取哪些 HTTP method,預設為 GET/HEAD
proxy_cache_methods [GET HEAD POST]

# ---------------
# proxy_cache_min_uses 設定快取的最小使用次數,預設為 1
proxy_cache_min_uses 1;

# ---------------
# proxy_cache_valid 對不同的 reponse status code 的 URL 設定不同的快取時間
proxy_cache_valid reply_code time;

# example
proxy_cache_valid 200 302 10m;
proxy_cache_valid 301 1h;
proxy_cache_valid 404 1m;
proxy_cache_valid any 1m;

# ---------------
# proxy_cache_key 設定快取的 key 值
proxy_cache_key "$host:$server_port$uri$is_args$args"

# ---------------
# 如果後端服務器經常發生503錯誤,服務不能保證可正確取得資料,為了避免訪問錯誤,可以在cache server上做調整。如果cache過期,但訪問後端服務器又不能返回正常的內容,則使用cache的內容。
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;

如果要驗證是不是從 Cache 取得的內容,可以加上這個 header

add_header      Nginx-Cache     "$upstream_cache_status from cache";

當我們用瀏覽器觀看 Header 時,如果沒有 hit,會看到這樣的 header

Nginx-Cache:MISS from cache

如果有 hit,會看到這樣的 header

Nginx-Cache:HIT from cache

範例

完整的範例

http {
    proxy_cache_path /usr/share/nginx/cache levels=1:2 keys_zone=STATIC:50m inactive=1d max_size=20g;
    server {
        location / {
            proxy_pass             http://127.0.0.1:8080;
            proxy_set_header       Host $host;
            proxy_cache            STATIC;
            proxy_cache_valid      200 302 10m;
            proxy_cache_valid      301 1h;
            proxy_cache_valid      404 1m;
            proxy_cache_valid      any 1m;
            proxy_cache_use_stale  error timeout invalid_header updating
                                   http_500 http_502 http_503 http_504;
        }
    }
}

紀錄最後修改好的設定檔

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    include /etc/nginx/conf.d/*.conf;

    proxy_cache_path /usr/share/nginx/cache levels=1:2 keys_zone=STATIC:50m inactive=1d max_size=20g;

    server {
        listen       6000 default_server;
        listen       [::]:6000 default_server;
        server_name  _;
    server_tokens off;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
            proxy_pass             http://127.0.0.1:8080;
            proxy_set_header       Host $host;
            proxy_set_header       X-Real-IP $remote_addr;
            proxy_set_header       X-Forwarded-For $proxy_add_x_forwarded_for;
        }

    location ~ .*\.(gif|jpg|png|bmp|swf|js|css|lzv|pdf|html|jsp)$ {
        proxy_cache            STATIC;
        proxy_cache_valid      200 302 10m;
        proxy_cache_valid      301 1h;
        proxy_cache_valid      404 1m;
        proxy_cache_valid      any 1m;
        #proxy_cache_use_stale  error timeout invalid_header updating
        #                       http_500 http_502 http_503 http_504;
        proxy_cache_key     $host$uri$is_args$args;
        proxy_set_header       Host $host;
        proxy_set_header       X-Real-IP $remote_addr;
        #proxy_set_header       X-Real-IP $Forwarded-For;
        proxy_set_header       X-Forwarded-For $proxy_add_x_forwarded_for;
        add_header      Nginx-Cache     "$upstream_cache_status from cache";
        proxy_pass             http://127.0.0.1:8080;
    }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
}

清除 cache

如果要清除 cache,可直接刪除 proxycachepath 目錄下所有檔案

vi clear_nginx_cache.sh

#!/bin/bash
find /usr/share/nginx/cache -type f -exec rm -f {} \;

chmod 755 clear_nginx_cache.sh

每天定時刪除超過兩天的 cache file

vi /etc/cron.daily/delete_nginx_cache.sh

#!/bin/bash
find /usr/share/nginx/cache -type f -mtime +2 -print0 | xargs -0 -r rm >/dev/null 2>&1

chmod 755 /etc/cron.daily/delete_nginx_cache.sh

處理 Nginx 產生的大量 TCP_WAIT

由於 Nginx Proxy 會產生大量 TCP_WAIT,我們需要調整 linux TCP 的參數,並調整 nginx 的設定。

# 用 netstat 查看 TCP_WAIT 數量
netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'

# 用 ss 查看 TCP_WAIT 數量
ss -ant | awk 'NR>1 {++s[$1]} END {for(k in s) print k,s[k]}'

查看 /proc/sys/net/ipv4/iplocalport_range 設定檔,可得知 Linux 動態分配 Local Port 的 Range。

cat /proc/sys/net/ipv4/ip_local_port_range
32768   61000

透過修改 /etc/sysctl.conf 可調整 local service ports

vim /etc/sysctl.conf
net.ipv4.ip_local_reserved_ports = 32768-61000

sysctl -p

修改 /etc/sysctl.conf TCP 參數

vim /etc/sysctl.conf
net.ipv4.ip_local_port_range = 1024 65535
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_window_scaling = 0
net.ipv4.tcp_sack = 0
net.core.netdev_max_backlog = 30000
net.ipv4.tcp_no_metrics_save = 1
net.core.somaxconn = 65535
net.ipv4.tcp_syncookies = 0
net.ipv4.tcp_max_orphans = 262144
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2

# sysctl.conf 重新載入設定
sysctl -p

修改 /etc/security/limits.conf

vim /etc/security/limits.conf
* soft nofile 655360
* hard nofile 655360

ulimit -n 655360

修改 /etc/nginx/nginx.conf 參數

vim /etc/nginx/nginx.conf

worker_rlimit_nofile 102400;
events {
    worker_connections 1024; # 可以加到 4096
    #worker_connections 768;
    use epoll;
    # multi_accept on;
}

upstream webserver {
   server 127.0.0.1:8000 weight=10;
   keepalive       16;
}

http {
    #keepalive_timeout 65;
    keepalive_timeout 1;
}

# 後面 proxy_pass 的地方要改成這樣
proxy_pass             http://webserver;

記一次TIME_WAIT網絡故障

Nginx做前端Proxy時TIME_WAIT過多的問題

Nginx Connection 不夠用 的參數調整

TCP 狀態 TIME_WAIT 分析

References

varnish / squid / nginx cache 有什麼不同?

自建CDN防禦DDoS(2):架構設計、成本與部署細節

RHEL / CentOS 7 安裝 Nginx, MySQL, PHP (LEMP)

在 CentOS 7 安裝 Nginx、PHP-FPM、MariaDB

Nginx proxy 反向代理 轉發Tomcat

Reverse Proxy with Caching example

2016年5月16日

安裝 Nagios in CentOS

網管人員不可能 24 小時隨時監控系統服務的運作,當遇到系統服務發生異常時,需要一個監控網路服務的有效狀態的系統能即時通知管理者,Nagios是這個方面的功能的王者。

安裝 nagios

nagios 目前是 4.1.1 版,目前如果是用 yum install nagios 安裝,則是 3.5.1版,以 yum 安裝參考這個網頁。

How To Install Nagios On CentOS 6

編譯與安裝的過程參考這兩個網頁:

Fedora Quickstart

How to Install Nagios 4.1 (Monitoring Server) on CentOS / RedHat / Fedora

編譯及安裝的過程

yum install httpd php
yum install gcc glibc glibc-common
yum install gd gd-devel

useradd nagios
passwd nagios

# 把 nagios, apache 兩個 user 放入 nagcmd group
groupadd nagcmd
usermod -a -G nagcmd nagios
usermod -a -G nagcmd apache

wget https://assets.nagios.com/downloads/nagioscore/releases/nagios-4.1.1.tar.gz



tar xzvf nagios-4.1.1.tar.gz
cd nagios-4.1.1

./configure –with-command-group=nagcmd

make all
make install
make install-init
make install-config
make install-commandmode

make install-webconf

# 設定管理網頁的帳號及密碼
htpasswd -c /usr/local/nagios/etc/htpasswd.users nagiosadmin

service httpd restart

cd ..

安裝 nagios-plugins 的過程

# 安裝 nagios-plugins

# 如果已經有這個 user 就不用設定
useradd nagios
passwd nagios
# 也可以直接把 nagios 改為不能登入
vi /etc/passwd
nagios:x:501:501::/home/nagios:/sbin/nologin


wget http://www.nagios-plugins.org/download/nagios-plugins-2.1.1.tar.gz

tar xzf nagios-plugins-2.1.1.tar.gz
cd  nagios-plugins-2.1.1

./configure
make
make install

cd ..

chkconfig –add nagios
chkconfig nagios on

# 驗證 nagios 設定檔是否正確
/usr/local/nagios/bin/nagios -v /usr/local/nagios/etc/nagios.cfg

# 啟動 nagios
service nagios start
# 修改 email
vi /usr/local/nagios/etc/objects/contacts.cfg

安裝 NRPE

# NRPE
# 如果已經有這個 user 就不用設定
useradd nagios
passwd nagios
# 也可以直接把 nagios 改為不能登入
vi /etc/passwd
nagios:x:501:501::/home/nagios:/sbin/nologin


wget --no-check-certificate http://sourceforge.net/projects/nagios/files/nrpe-2.x/nrpe-2.15/nrpe-2.15.tar.gz

tar zxvf nrpe-2.15.tar.gz

cd nrpe-2.15

./configure
make all

make install-plugin
make install-daemon
make install-daemon-config

# 將 NRPE 裝在 xinetd 下面
make install-xinetd

# 把要使用這個服務的 IP 放在 only_from 設定中
vi /etc/xinetd.d/nrpe

only_from = 127.0.0.1 <nagios_ip_address>


# 修改 /etc/services ,增加下面這行
vi /etc/services

nrpe            5666/tcp                        # NRPE


service xinetd restart


# 檢查是否有啟動 NRPE,要看到 LISTEN 這一行
netstat -at | grep nrpe

tcp        0      0 *:nrpe                      *:*                         LISTEN


# 用 check_nrpe 檢查是否正常
/usr/local/nagios/libexec/check_nrpe -H localhost
# 會得到 NRPE 的版本資訊
NRPE v2.15

可以用以下指令測試 NRPE 的結果

/usr/local/nagios/libexec/check_nrpe -H localhost -c check_users
/usr/local/nagios/libexec/check_nrpe -H localhost -c check_load
/usr/local/nagios/libexec/check_nrpe -H localhost -c check_total_procs
/usr/local/nagios/libexec/check_nrpe -H localhost -c check_zombie_procs

整合 NRPE 及 nagios

修改設定檔,增加 NRPE 及 host 設定

vim /usr/local/nagios/etc/objects/commands.cfg


define command {
        command_name    check_nrpe
        command_line    $USER1$/check_nrpe -H $HOSTADDRESS$ -c $ARG1$
        }

修改 nagios.cfg 將 /usr/local/nagios/etc/servers 設定目錄打開

vi /usr/local/nagios/etc/nagios.cfg
cfg_dir=/usr/local/nagios/etc/servers

mkdir /usr/local/nagios/etc/servers

新增 host, service

cp /usr/local/nagios/etc/objects/localhost.cfg /usr/local/nagios/etc/servers/monitorserver.cfg

# 把所有 hostname 都改成 monitorserver 的 hostname
define host{
    use linux-server
    host_name monitorserver
    alias monitorserver
    address 192.168.1.7
    }

define service{
    use generic-service
    host_name monitorserver
    service_description CPU Load
    check_command check_nrpe!check_load
    }

增加 NRPE command

vi /usr/local/nagios/etc/nrpe.cfg
# 增加一行
command[check_swap]=/usr/local/nagios/libexec/check_swap -w 20% -c 10%
# 驗證 nagios 設定檔是否正確
/usr/local/nagios/bin/nagios -v /usr/local/nagios/etc/nagios.cfg

service nagios restart

設定 nagios 的發信通知功能

要讓 nagios 發送警告的通知信件,首先必須先在這台機器上,設定 postfix,因為我們是使用 Google Apps 代管 mail server,因此要設定讓 postfix 能夠 relay 到 Google SMTP server。

postfix 安裝就是把需要的套件裝一裝就好了。

yum -y install cyrus-sasl cyrus-sasl-lib cyrus-sasl-plain
yum -y install postfix

首先處理 postfix 設定檔,修改 sasl_passwd

vi /etc/postfix/sasl_passwd

[smtp.gmail.com]:587 <USERNAME@gmail.com>:PASSWORD
或是
[smtp.gmail.com]:587 <USERNAME@yourdomain.com>:PASSWORD


postmap /etc/postfix/sasl_passwd

修改 main.cf

vi /etc/postfix/main.cf

relayhost=[smtp.gmail.com]:587
smtp_sasl_auth_enable=yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_use_tls=yes

重新啟動 postfix

service postfix restart

用 mail 指令測試看看能不能發送信件出去,自己要把 test@a.b.c 改成要收信的 email address。

mail -s "Test Subject" test@a.b.c < /dev/null

echo "Test mail from postfix" | mail -s "Test Postfix" test@a.b.c

postfix 的 log 檔放在 /var/log/maillog 裡面,如果有問題,可以查看這個檔案的 log。

修改 nagios 設定檔: contacts.cfg,新增一個管理者以及 email,並把這個管理者放在 admins 這個群組裡面。

vi /usr/local/nagios/etc/objects/contacts.cfg

define contactgroup{
        contactgroup_name       admins
        alias                   Nagios Administratos
        members                 nagiosadmin,admin
        }

define contact {
        contact_name                            admin
        alias                                   admin
        email                                   admin@a.b.c
        service_notification_period             24x7
        service_notification_options            w,u,c,r,f,s
        service_notification_commands           notify-service-by-email
        host_notification_period                24x7
        host_notification_options               d,u,r,f,s
        host_notification_commands              notify-host-by-email
}

References

RHEL / CentOS 7 安裝 Nagios

結合SNMP服務 Nagios監控能力更全面

以 NAGIOS 實作服務監控系統

Nagios系統監看工具安裝教學

Nagios - 網路監控及告警系統

Nagios - SIP Monitoring using SIPP

Configure Postfix to Send Mail Using an External SMTP Server

Nagios 設定E-mail 警示

2016年5月9日

三種 LVS 的模式:LVS-NAT、LVS-TUN、LVS-DR

LVS(Linux Virtual Server) 是基於 Layer 4 的負載均衡,不支持複雜特性的負載均衡,效率比 Layer 7 高,nginx、haproxy都是 Layer 7 的負載均衡,可以根據特性進行負載均衡,比較靈活。

LVS 是利用iptables的 INPUT chain,攔截訪問集群服務的資料封包,修改進入 server 的資料 header,不同類型更改 header 的方式也不一樣,轉發給後端的RS,最後RS處理請求後再將結果回傳給 client。

LVS 有三種模式:LVS-NAT、LVS-TUN、LVS-DR

  • LVS-NAT

Virtual Server via NAT

LVS-NAT 的實體 Server 架構圖:

這個是通過網路地址轉換的方法來實現的。首先 Load Balancer 接收到客戶的request 時(目的IP為VIP),根據調度演算法決定將 request 發送給哪個後端的 Real Server。然後把客戶端發送的請求數據包的目標IP地址及端口改成後端真實服務器的IP地址(Real IP),這樣 Real Server 就能夠收到客戶的 request 了。Real Server 處理完成後,查看 default gateway(NAT模式下我們需要把 Real Server 的 default gateway 設置為 Load Balancer。)把 reqsponse 發送給 Load Balancer,Load Balancer 把 source address 改成虛擬地址(VIP)然後發送回給客戶端。

VS-NAT基本性質:

  1. cluster nodes (Real Server) 和 Load Balancer 在同一網段
  2. Real Server 的 RIP 地址一般為 Private IP
  3. Load Balancer 負責處理 client 和 Real Server 之間的所有進出的封包
  4. Real Server 將 Load Balancer 的內網 IP 作為 default gateway
  5. 只需要在 Load Balancer 上配置一個 Public IP 就可以了
  6. Load Balancer 支援 Port Mapping
  7. Real Server 可以使用任何一種 OS
  8. 因為 Load Balancer 負責所有資料的進出,所以在大型應用場景中,Load Balancer 容易成為系統瓶頸。因為 NAT 的關係,Load Balancer 必須將 reqeust 和 response 進行 IP 改寫,因此網站訪問量比較大的時候 Load Balancer 會有比較大的瓶頸,一般要求最多只能10-20台節點

  • LVS-TUN

Virtual Server via IP Tunneling

和 NAT 模式不同的是,Load Balacner 和 Real Server 之間的傳輸不用改寫IP地址。而是把 client request 封裝在一個 IP Tunnel 裡面,然後發送給 Real Server,Real Server 接收到之後解開 IP Tunnel 後,處理結果會直接把通過自己的 Pulbic IP 發送給 client,不用經過 Load Balancer。

VS-TUN 的基本性質:

  1. cluster nodes 可跨越 Internet (處於不同的物理網路中)
  2. Real Server 的 Real IP 必須是 Public IP
  3. Load Balancer 只需要處理 reqeust,response 由 Real Server 直接發送給 client
  4. 只有支援 Tunnel 功能的 OS 才能用於 Real Server
  5. Load Balancer 不支援 Port Mapping
  6. Real Server 的 default gateway 不能指向 Load Balancer
  7. Real Server 主機需要綁定VIP地址在LO接口上(各個服務器有相同的VIP和單獨的RIP)

  • LVS-DR

Virtual Server via Direct Routing

DR模式會改寫request的目標 MAC 地址,將 request 轉發給 Real Server,而 Real Server 的處理結果會直接回傳給 Client。當客戶端發送 request 給 cluster 提供的服務時,request 會直接發往 Load Balancer,Load Balancer 會檢查 request 中的 destination address 和 port number,如果和服務匹配,那麼就會根據調度算法來選擇一個 Real Server 處理 request 並且將此次連記入 hash table 中。然後 Load Balancer 轉發 request 給選擇的 Real Server。當連接結束或超時後,這個連接記錄將從 hash table 中刪除。

VS-DR的基本性質:

  1. Load Balancer 與 Real Server 必須在同一個物理網路中;
  2. Real Server 的 RIP 地址不必是私有地址,如可為 Public IP 可以實現遠端管理
  3. Load Balancer 只負責處理 request,response 由 Real Server直接發往 client
  4. Real Server 不能將 Gateway 指向 Load Balancer,而是直接配置為上層路由的 gateway
  5. Load Balancer 不支援 port mapping
  6. 大多數 OS 都可以用在 Real Server
  7. Real Server 主機需要綁定 VIP 地址在 LO 接口上 (有相同的VIP和單獨的RIP),並且需要設定 ARP 抑制(由於網絡接口都會進行ARP廣播回應,但 cluster 的其他機器都有這個 VIP 的 lo port,都回應就會衝突。所以我們需要把 Real Server 的 lo 接口的 ARP 回應關閉掉)

LVS 的調度演算法

LVS集群的負載調度

LVS Scheduling Method LVS的調度方法可以分為兩大類:

1.Fixed Scheduling Method 靜態調度方法

  • RR 輪詢,假設所有服務器處理性能均相同時使用,當所有 Server 的性能不一,request 服務時間變化比較大時,輪叫調度算法容易導致服務器間的負載不平衡。
  • WRR 加權輪詢,假設服務器 A 的權值為 1,B 的權值為 2,則表示服務器B的處理性能是A的兩倍。加權輪詢調度算法是按權值的高低和輪詢方式分配請求到各服務器。
  • DH destination address hash
  • SH source address hash,SH 與 DH 可用在 firewall clustering 裡面。

2.Dynamic Scheduling Method 動態調度方法

  • LC (最少連接) 把新的連接請求分配到當前連接數最小的服務器,當各個服務器的處理能力不同時,該算法並不理想,因為TCP連接處理請求後會進入TIMEWAIT狀態,TCP的TIMEWAIT一般 為2分鐘,此時連接還佔用服務器的資源,所以會出現這樣情形:性能高的服務器已處理所收到的連接,連接處於TIME_WAIT狀態,而性能低的服務器忙於處理所收到的連接,還不斷地收到新的連接請求。
  • WLC 加權最少連接
  • SED Shortest Expected Delay Scheduling 最少期望延遲 指定期望中最短 delay 時間的 Real Server,expected delay 是以 (Ci + 1) / Ui 計算,i 是第 i 個 server,Ci 是第 i 個 server 的連線數,Ui 是固定的服務速度,也可以視為加權值,服務速度越短,計算出來的結果越大。

  • NQ Never Queue Scheduling 從不排隊調度方法 如果有 idle server,就會馬上選擇這個 server,如果沒有 idle server,就採用上面的 SED (Shortest Expected Delay Scheduling) 演算法,找到適合的 server。

  • LBLC Locality-Based Least Connections Scheduling 基於局部性的最少鏈接調度 針對 request 的 destination IP address 的負載均衡調度,目前主要用於Cache cluster,因為在 Cache 集群中,client request 的目標IP地址是變化的。這裡假設任何後端服務器都可以處理任一請求,算法的設計目標是在服務器的負載基本平衡情況下,將相同目標IP地址的request 轉發到同一台服務器,來提高各台服務器的訪問局部性和主存Cache命中率,從而整個集群系統的處理能力。

  • LBLCR Locality-Based Least Connections with Replication Scheduling 帶複製的基於局部性最少鏈接調度 也是針對目標IP地址的負載均衡,目前主要用於Cache集群系統。它與LBLC算法的不同之處是它要維護從一個目標IP地址到一組服務器的映射,而LBLC算法維護從一個目標IP地址到一台服務器的映射。對於一個“熱門”站點的服務請求,一台Cache 服務器可能會忙不過來處理這些請求。這時,LBLC調度算法會從所有的Cache服務器中按“最小連接”原則選出一台Cache服務器,映射該“熱門”站 點到這台Cache服務器,很快這台Cache服務器也會超載,就會重複上述過程選出新的Cache服務器。這樣,可能會導致該“熱門”站點的映像會出現 在所有的Cache服務器上,降低了Cache服務器的使用效率。LBLCR調度算法將“熱門”站點映射到一組Cache服務器(服務器集合),當該“熱 門”站點的請求負載增加時,會增加集合裡的Cache服務器,來處理不斷增長的負載;當該“熱門”站點的請求負載降低時,會減少集合裡的Cache服務器 數目。這樣,該“熱門”站點的映像不太可能出現在所有的Cache服務器上,從而提供Cache集群系統的使用效率。

三種模式的比較

三種 IP 負載均衡技術的優缺點比較

選項 VS/NAT VS/TUN VS/DR
Server OS 任意 OS 要支援 IP Tunnel (目前只有 linux 有支援) 多數(支援 Non-ARP )
服務器網路 LAN LAN/WAN LAN
Real Server 數目(100M網絡) 10-20 100 100
Server 的網路 Gateway Load Balancer 自己的路由 自己的路由
效率 一般 最高
擴展性 差,所有 traffic 都要經過 Load Balancer 好,但需要建立 IP Tunnel,適合用在跨越 Data Center 的環境 好,但要求 Load Balancer 跟 Real Server 在同一個 LAN 裡面
Server 安全性 好,Real Server 使用內部 IP,隱密 差,Real Server 使用 Public IP 差,Real Server 使用 Public IP
Public IP 需求 需要一個 IP 作為 Server VIP(Virtual IP) 除了 VIP 之外,每個 Server 都需要有合法的 IP 可直接連結到客戶端 除了 VIP 之外,每個 Server 都需要有合法的 IP 可直接連結到客戶端

References

初識LVS,lvs/dr 和 lvs/nat lvs/tun

Lvs之NAT、DR、TUN三種模式的應用配置案例

LVS三種模式配置及優點缺點比較

LVS-DR和LVS-NAT以及LVS-TUN

從一個開發的角度看負載均衡和LVS