歡迎您光臨本站 註冊首頁

用heartbeat實現浮動地址的雙機互備的反向web緩存

←手機掃碼閱讀     火星人 @ 2014-03-04 , reply:0

用heartbeat實現浮動地址的雙機互備的反向web緩存

  用heartbeat實現浮動地址的雙機互備
 領導提出來要對一地方門戶網站做熱備,雖然未必真的會實施,但還是有點意思的。
 其實做熱備或者說好聽些叫高可用,也就是堆機器,加一台資料庫,做主從方式,網站程序里稍微做些手腳,資料庫的熱備基本也沒什麼問題了,當然要是做網站的能考慮CMS類的,就更好了,不過這些都有專人負責,我就不去管了。怎麼做WEB伺服器的熱備,並且提高訪問速度才是我的臨時工作。
 
 把現在的百兆交換機換成千兆的,這樣的話,單純做WEB服務,一台伺服器應該能夠輕鬆達到200M的流量,而現在的情況是4台WEB加起來也不過只有70M左右的流量,所以用一台伺服器對4台WEB進行緩存加速從帶寬上看是可行的。後面的4台機器每兩台一組做主備,比如域名1主用在WEB1上,備用在WEB2上,域名2主用在WEB2上備用在WEB1上,以此類推,CACHE上做後面的健康監測並進行請求分發。
  Cache伺服器內存應該儘可能大,提高性能。
 出於Cache伺服器的可用性考慮,準備上兩台伺服器,之間用heartbeat做主備,一個浮動地址,平時在主用伺服器上,主用掛了以後浮動到備用上。如果覺得備用機平時閑著太可惜,也可以在主用上進行一下負載分擔,把緩存功能分擔到主備兩台機器上,這樣帶來的另一個好處就是主備切換的時候,緩存不需要從零開始建立。
 大致的結構如下:
 
 找了兩台低端伺服器做實驗,centos4.6,雙網卡,一個接外網,一個用來心跳監測。
 兩台機器,機器名分別為cache1和cache2,也就是uname -n看到的,在hosts里加上另外一台機器,以便通過ping cache1和ping cache2能通
 安裝heartbeat
 為了省事,直接用yum安裝,很方便
 yum install heartbeat
 裝完heartbeat-2.1.3以後,在/etc/ha.d目錄下編輯一個ha.cf,內容是
 use_logd yes
 auto_failback on
 bcast   eth1
 node cache1 cache2
 crm on
 心跳監測通過eth1進行。
 編輯一個logd.cf,內容是
 logfacility     daemon
 編輯一個authkeys,內容是
 auth 1
 1 sha1 mykeystring
 把authkeys屬性改成600。
 配置文件的其他項目這裡都用默認值了。
 也可以從/usr/share/doc/heartbeat-2.1.3下複製這兩個配置文件的樣板來根據需要修改。
 為了實現地址浮動,需要在/var/lib/heartbeat/crm目錄下做一個cib.xml,用來描述資源管理。
 我是在原來預設的文件上修改的
 增加部分為:
    
 上面的主要意思應該也就是加一個IP地址資源,這個IP地址是192.168.11.10,也就是兩個CACHE上的浮動地址,這個浮動地址是在eth0上的。主用是在cache1上。
 這個配置是在cache1上的,主用(resource location)在cache1上。
 如果做雙地址浮動,可以實現雙機互備(而不是主備),再加一個IP地址資源在cache2上就可以。
 cache2上的配置和cache1上差不多,ha.cf,logd.cf,authkeys內容都是一樣的。
 配置完成後,在rc.local里寫上/etc/init.d/heartbeat start,然後兩台機器都重啟一下。
 這時候可以用crm_mon看一下,我的輸出是這樣的,cache1上:
 Last updated: Sat Apr 12 20:12:07 2008
 Current DC: cache2 (b3b95984-acb7-4ca6-ab40-c9a6c18e192a)
 2 Nodes configured.
 1 Resources configured.
 ============
 Node: cache2 (b3b95984-acb7-4ca6-ab40-c9a6c18e192a): online
 Node: cache1 (15347a3b-44a4-4eb3-5ab1-e6cf15fab0b4): online
 ip_resource     (heartbeat::ocf:IPaddr):        Started cache1
 
 cache2上的輸出:
 Last updated: Sat Apr 12 20:08:13 2008
 Current DC: cache2 (b3b95984-acb7-4ca6-ab40-c9a6c18e192a)
 2 Nodes configured.
 1 Resources configured.
 ============
 Node: cache2 (b3b95984-acb7-4ca6-ab40-c9a6c18e192a): online
 Node: cache1 (15347a3b-44a4-4eb3-5ab1-e6cf15fab0b4): online
 ip_resource     (heartbeat::ocf:IPaddr):        Started cache1
 這時候主用在cache1上,在cache1上用ifconfig能看到浮動地址。
 如果這時候我重啟cache1,來模擬宕機,在cache2上crm_mon輸出
 Last updated: Sat Apr 12 20:14:35 2008
 Current DC: cache2 (b3b95984-acb7-4ca6-ab40-c9a6c18e192a)
 2 Nodes configured.
 1 Resources configured.
 ============
 Node: cache2 (b3b95984-acb7-4ca6-ab40-c9a6c18e192a): online
 Node: cache1 (15347a3b-44a4-4eb3-5ab1-e6cf15fab0b4): OFFLINE
 ip_resource     (heartbeat::ocf:IPaddr):        Started cache2
 這時候在cache2上ifconfig能看到浮動IP已經到了cache2上。
 當cache1啟動起來回復正常以後,浮動IP又回到了cache1上。
 我的E文很爛,看heartbeat文檔半懂不懂的,特別是cib.xml部分,看了兩個小時一點頭緒都沒有,看著一堆example糊裡糊塗亂寫亂一通,竟然成了,自己都覺得神奇。
 接下來的事情就比較簡單了:
 在兩台Cache上分別配置相同的varnish和nginx,nginx做前端,承擔日誌記錄和負載分擔功能,把web請求均勻分擔到主備兩台緩存的varnish上,也就是在nginx配置里設置upstream分別為浮動地址和備機真實地址,主備兩台緩存一起為主用伺服器上的nginx提供請求響應。我把主機頭判斷和後台伺服器的主備監測放到varnish上實現。
 如果主用伺服器宕機,對外web地址浮動到備用伺服器上,這時候雖然nginx仍然以為自己是在向兩個後端進行請求的負載分擔,但實際是分別發送到備機的真實IP和浮動IP上,其實也就是備機上緩存服務。當主機恢復以後,浮動地址回到主用伺服器上,緩存服務的負載分擔也恢復。
 而後端web服務的宕機,由varnish里的restart來實現。這個部分還沒有仔細檢驗過,只是以前玩varnish的時候稍稍試了下。準備下周有空進行試驗。
 
 在保證同等理想的帶寬條件下,進行了一個小測試:從同一個客戶端發起單線程的HTTP請求,大約每次測試取100個以上的頁面,頁面大小大約為3K左右,沒有圖片,都是文本HTML,伺服器端不壓縮,取耗時的平均值。實際上通過HTTP取頁面的過程在單位的網路條件下,網路上的延時可以忽略。
 直接訪問原伺服器(IIS6+ASP+SQLServer),平均耗時是902ms/page,這個時間是包括HTTP取頁面以及分析提取頁面中鏈接的過程。基本上每個頁面都要查庫(新聞發布頁面)。
 通過cache訪問,在cache建立過程中,也就是cache中沒有被緩存對象時,測得平均耗時是907ms/page。
 如果cache里已經有被請求的對象,則平均耗時是135ms/page。
 可見緩存對提高WEB響應速度還是非常有幫助的。
 

《解決方案》

 

nginx和varnish的詳細配置:

  nginx和varnish的詳細配置:
 
 nginx的配置文件如下:
 
 user  www www;
 
 worker_processes 2;
 
 error_log  /usr/local/nginx/logs/error.log;
 
 pid        /usr/local/nginx/var/nginx.pid;
 
 worker_rlimit_nofile 51200;
 
 events
 
 {
 
        use epoll;
 
        worker_connections 51200;
 
 }
 
 http
 
 {
 
        include       mime.types;
 
        default_type  application/octet-stream;
 
        log_format  main  '$remote_addr $remote_user - [$time_local] "$request" '
 
                          '$status $body_bytes_sent "$http_referer" '
 
                          '"$http_user_agent" ';
 
 
 
        log_format timing '$remote_addr $remote_user - [$time_local] $request '
 
                   'upstream_response_time $upstream_response_time '
 
                   'msec $msec request_time $request_time';
 
 
 
        log_format up_head '$remote_addr $remote_user - [$time_local] $request '
 
                    'upstream_http_content_type $upstream_http_content_type';
 
 
 
        access_log  /usr/local/nginx/logs/access.log  main;
 
 
 
        keepalive_timeout 30;
 
        server_tokens off;
 
        sendfile        on;
 
        #tcp_nopush        on;
 
        tcp_nodelay       on;
 
 
 
 upstream bk1 {
 
     server 192.168.111.10:8080;
 
     server 192.168.111.20:8080;
 
 }
 
        server
 
        {
 
            listen       80;
 
            client_max_body_size 50M;
 
            server_name  .mysite.cn .mysite.com
 
            index index.htm index.html index.asp index.aspx;
 
            root  /www/default;
 
            #error_page  403 500 502 503 504  /404.html;
 
            #limit_conn httplimit 10;
 
            location /status {
 
                     stub_status             on;
 
                     access_log              off;
 
                     #auth_basic              "NginxStatus";
 
                     #auth_basic_user_file  conf/htpasswd;
 
            }
 
            location /varnish {
 
                alias /www/default/varnish.txt;
 
                default_type text/plain;
 
            }
 
            location /crm {
 
                alias /www/default/crm.txt;
 
                default_type text/plain;
 
            }
 
            location / {
 
 
 
                proxy_redirect off;
 
                proxy_set_header Host $host;
 
                proxy_set_header X-Real-IP $remote_addr;
 
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 
                client_max_body_size 50m;
 
                client_body_buffer_size 256k;
 
                proxy_connect_timeout 30;
 
                proxy_send_timeout 30;
 
                proxy_read_timeout 60;
 
                proxy_buffer_size 4k;
 
                proxy_buffers 4 32k;
 
                proxy_busy_buffers_size 64k;
 
                proxy_temp_file_write_size 64k;
 
                #proxy_next_upstream error timeout invalid_header http_500 http_503 http_404;
 
                proxy_max_temp_file_size 128m;
 
                if (!-f $request_filename) {
 
                    proxy_pass http://bk1;
 
                }
 
            }
 
        }
 
 }
 
 
 
 Varnish的配置文件如下:
 
 acl purge {  
 
  "localhost";
 
          }   
 
 backend bk1 {
 
     set backend.host = "192.168.111.110";
 
     set backend.port = "80";
 
 }
 
 backend bk2 {
 
     set backend.host = "192.168.111.111";
 
     set backend.port = "80";
 
 }
 
 
 
 sub vcl_recv {           
 
     if (req.http.host ~ "mysite.cn") {
 
         if (req.restarts == 0) {
 
             set req.backend=bk1;
 
         }
 
         else {
 
             set req.backend=bk2;
 
         }
 
     }
 
     else {
 
         if (req.http.host ~ "mysite.com"") {
 
             if (req.restarts == 0) {
 
                 set req.backend=bk2;
 
             }
 
             else {
 
                 set req.backend=bk1;
 
             }
 
         }
 
         else {
 
             error 200 "No cahce for this domain";
 
         }
 
     }
 
     if (req.request == "PURGE") {        
 
         if (!client.ip ~ purge) {        
 
             error 405 "Not allowed.";   
 
         }   
 
         else {
 
             lookup;      
 
         }   
 
     }        
 
     if (req.request != "GET" && req.request != "HEAD") {
 
         pipe;
 
     }        
 
     if (req.http.Expect) {  
 
         pipe;
 
     }        
 
     if (req.http.Authenticate ){         
 
         pass;
 
     }        
 
    
 
     if (req.http.Cache-Control ~ "no-cache") {      
 
         pass;
 
     }        
 
     if(req.url ~ "purge.php"){           
 
         pass;
 
     }        
 
 
 
     if (req.url ~ "\.(htm|html|jpg|jpeg|gif|png|tiff|tif|svg|swf|ico|css|js|vsd|doc|ppt|pps|xls|pdf|mp3|mp4|m4a|ogg|mov|avi|wma|flv|wmv|sxw|zip|gz|bz2|tgz|tar|rar|odc|odb|odf|odg|odi|odp|ods|odt|sxc|sxd|sxi|sxw|dmg|torrent|deb|msi|iso|rpm)$") {
 
         lookup;         
 
     }
 
     lookup;  
 
 }            
 
 sub vcl_pipe {           
 
         if (bereq.http.x-forwarded-for) {
 
 set bereq.http.X-forwarded-for =     
 
     bereq.http.X-forwarded-for ", "  
 
     regsub(client.ip, ":.*", "");   
 
         } else {         
 
 set bereq.http.X-forwarded-for =     
 
     regsub(client.ip, ":.*", "") ;   
 
         }   
 
     pipe;   
 
 }            
 
 
 
 sub vcl_pass {           
 
         if (bereq.http.x-forwarded-for) {
 
 set bereq.http.X-forwarded-for =     
 
     bereq.http.X-forwarded-for ", "  
 
     regsub(client.ip, ":.*", "");   
 
         } else {         
 
 set bereq.http.X-forwarded-for =     
 
     regsub(client.ip, ":.*", "");   
 
         }   
 
     pass;   
 
 }            
 
 
 
 sub vcl_hash {           
 
     set req.hash += req.url;
 
     if (req.http.host) {
 
         set req.hash += req.http.host;   
 
     } else {
 
         set req.hash += server.ip;      
 
     }        
 
     hash;   
 
 }            
 
 
 
 sub vcl_hit {
 
     if (req.request == "PURGE") {        
 
          set obj.ttl = 0s;  
 
          error 200 "Purged.";            
 
     }        
 
     if (!obj.cacheable) {
 
         pass;
 
     }        
 
     #set obj.http.X-TTL = obj.ttl;      
 
     deliver;
 
 }            
 
 
 
 sub vcl_miss {           
 
     if (req.request == "PURGE") {        
 
         error 404 "Not in cache.";      
 
     }        
 
     fetch;   
 
 }            
 
 
 
 sub vcl_fetch {         
 
 
 
     if (obj.status >400 && req.restarts == 0 )     
 
     {        
 
         restart;         
 
     }        
 
 
 
     if (!obj.valid) {   
 
         error;           
 
     }        
 
     if (!obj.cacheable) {
 
         pass;
 
     }        
 
    
 
     if (obj.status == 404) {
 
         pass;
 
     }        
 
     if (obj.ttl < 120000s) {
 
         set obj.ttl = 120000s;
 
     }        
 
 
 
     if (req.url ~ "\.(html|htm|jpg|jpeg|gif|png|tiff|tif|svg|swf|ico|css|js|vsd|doc|ppt|pps|xls|pdf|mp3|mp4|m4a|ogg|mov|avi|wma|flv|wmv|sxw|zip|gz|bz2|tgz|tar|rar|odc|odb|odf|odg|odi|odp|ods|odt|sxc|sxd|sxi|sxw|dmg|torrent|deb|msi|iso|rpm)$") {  
 
         insert;         
 
     }        
 
 
 
     if (obj.http.Pragma ~ "no-cache" || obj.http.Cache-Control ~ "no-cache" || obj.http.Cache-Control ~ "private") {         
 
         set obj.http.MYCACHE ="force-cache";
 
         insert;
 
         #pass;
 
     }        
 
 
 
     insert;  
 
 }            
 
 
 
 sub vcl_deliver {        
 
     deliver;
 
 }            
 
 
 
 sub vcl_timeout {        
 
     discard;
 
 }            
 
 
 
 sub vcl_discard {        
 
     discard;
 
 }



[火星人 ] 用heartbeat實現浮動地址的雙機互備的反向web緩存已經有346次圍觀

http://coctec.com/docs/service/show-post-29252.html