詳細分析apache httpd反向代理的用法

apache httpd系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.htmlphp


代理方式有三種:正向代理、透明代理和反向代理。它們的區別,見:透明代理、正向代理、反向代理的區別說明html

1.正向代理

httpd經過ProxyRequests指令配置正向代理的功能。例如:node

ProxyRequests On
ProxyVia On

<Proxy "*">
  Require host internal.example.com
</Proxy>

其中< Proxy >容器表示的是隻有internal.example.com下的主機能夠經過該正向代理去訪問任意URL的請求內容。ProxyVia指令表示在響應首部中添加一個Via字段。web

2.反向代理

爲了成爲一個"基本的"web server,提供靜態和動態內容給最終用戶,httpd(以及其餘大多數web server)能夠扮演反向代理服務器的角色,也就是衆所周知的"網關"服務器。正則表達式

在這種場景下,Httpd自身不生成產出數據,而是從後端服務器中獲取數據,這些後端服務器器通常不會和外界網絡通訊。當httpd從客戶端接收到請求,請求被代理到後端服務器組中的其中一個服務器上,該後端服務器處理請求,生成內容並返回內容給httpd server,最後由httpd server生成實際的HTTP響應給客戶端。算法

有無數應該使用反向代理的理由,最多見的是安全、高可用、負載均衡、集中受權/認證。反向代理的佈置和架構中,後端服務器(真正處理請求的服務器)和外界徹底絕緣並由此受到保護,對於外界客戶端來講,當他們須要關心服務器對象是誰時,它們獲得的結果老是反向代理服務器,而非後端服務器。apache

一個典型的實現以下:後端

2.1 簡單的反向代理配置

ProxyPass指令用於映射請求到後端服務器。最簡單的代理示例是對全部請求"/"都映射到一個後端服務器上:瀏覽器

ProxyPass "/"  "http://www.example.com/"
ProxyPassMatch "^/((?i).*\.php)$" "fcgi://127.0.0.1:9000/var/www/a.com/$1"

爲了地址重定向時也能正確使用反向代理,應該使用ProxyPassReverse指令,該指令的做用見下文。安全

ProxyPass "/"  "http://www.example.com/"
ProxyPassReverse "/"  "http://www.example.com/"

或者只爲特定的URI進行代理,例以下面的配置,只有/images開頭的路徑纔會代理轉發,其餘的全部請求都在本地處理。

ProxyPass "/images"  "http://www.example.com/"
ProxyPassReverse "/images"  "http://www.example.com/"

假如本地服務器地址爲http://www1.example.com,當請求http://www1.example.com/images/a.gif時,將代理爲http://www.example.com/a.gif

在沒有重定向的狀況下,ProxyPassReverse是能夠省略的,不然通常狀況下應該將其設置爲和ProxyPass相同。ProxyPassReverse提供的是一種功能,它並不依賴於ProxyPass(但通常都同時存在)。它的做用是防止重定向時客戶端沒法正確訪問。例如,http://www.example.com/images/a.gif被代理爲http://192.168.100.17/a.gif,若是此時a.gif被重定向到b.gif,那麼代理服務器返回給客戶端的將是http://192.168.100.17/b.gif。但客戶端是沒法訪問後端內網主機192.168.100.17的,因而出現file not found錯誤。若是此時使用ProxyPassReverse,那麼代理服務器響應給客戶端的請求會被調整爲http://www.example.com/images/b.gif,這樣的請求再發給代理服務器,就能正確訪問。

2.2 負載均衡:後端成員

上面的配置中沒有添加後端服務器節點,沒法享受反向代理的優勢。所以,有必要添加後端節點。添加的方法是使用< proxy >容器將後端節點定義成一個負載均衡組,各節點是該組中成員,而後代理目標指向組名便可。

例如:

<Proxy balancer://myset>
    BalancerMember http://www2.example.com:8080
    BalancerMember http://www3.example.com:8080
    ProxySet lbmethod=bytraffic
</Proxy>

ProxyPass "/images/"  "balancer://myset/"
ProxyPassReverse "/images/"  "balancer://myset/"

balancer://myset告訴httpd,它建立了一個負載均衡節點集合,名稱爲myset,此集合中有兩個後端成員。在上面的配置中,任意/images的請求都會代理至2個成員中的一個。ProxySet指令指定myset均衡組使用的均衡算法爲bytraffic,即基於I/O流量字節數權重的算法。ProxySet指令設置的是Proxy容器的公共屬性

httpd有3種負載均衡算法:

  • byrequests:默認。基於請求數量計算權重。
  • bytraffic:基於I/O流量大小計算權重。
  • bybusyness:基於掛起的請求(排隊暫未處理)數量計算權重。

對於上面的示例,還能夠稍加修改,使其支持更多功能。例如添加權重比例,使得某後端節點被轉發到的權重是另外一節點的3倍,等待後端節點返回數據的超時時間爲1秒。

<Proxy balancer://myset>
    BalancerMember http://www2.example.com:8080
    BalancerMember http://www3.example.com:8080 loadfactor=3 timeout=1
    ProxySet lbmethod=byrequests
</Proxy>

ProxyPass "/images"  "balancer://myset/"
ProxyPassReverse "/images"  "balancer://myset/"

2.3 故障轉移

還能夠再次調整實現故障轉移,例如當全部負載節點都失敗時,指定一個備份節點(standby node)。參考以下配置:

<Proxy balancer://myset>
    BalancerMember http://www2.example.com:8080
    BalancerMember http://www3.example.com:8080 loadfactor=3 timeout=1
    BalancerMember http://hstandby.example.com:8080 status=+H
    BalancerMember http://bkup1.example.com:8080 lbset=1
    BalancerMember http://bkup2.example.com:8080 lbset=1
    ProxySet lbmethod=byrequests
</Proxy>

ProxyPass "/images/"  "balancer://myset/"
ProxyPassReverse "/images/"  "balancer://myset/"

其中成員一、二、四、5是負載節點,成員3是備份節點。當全部負載節點都不健康時,將轉發請求給備份節點,並由備份節點處理請求,httpd設置備份節點的方式很簡單,只需將狀態設置爲"H",表示hot-standby。還需注意的是負載節點四、5,它們額外的參數爲lbset=1,不寫時默認爲0,這是負載均衡時的優先級設置,負載均衡時老是先轉發給低數值的節點,也就是說數值越小,優先級越高。因此上面的配置中,當節點一、2正常工做時,只在它們之間進行負載,此時節點四、5處於閒置狀態。只有當節點一、2都失敗時,纔會在節點四、5之間進行負載。

2.4 提供負載狀態顯示頁面

<Location "/bm">
    SetHandler balancer-manager
    Require host localhost
    Require ip 192.168.100
</Location>

而後在瀏覽器中輸入http://server/bm便可,返回結果如圖。

2.5 proxy相關指令

2.5.1 ProxyPass指令

該指令將遠程服務器映射到本地主機上,但本地主機不是真實的服務器,而是遠程主機的一個鏡像。這個鏡像一般稱爲反向代理服務器或網關。該指令不能用於< Directory >、< Files >容器中,且使用該指令時一般會關閉正向代理,即ProxyRequests=off

語法:

ProxyPass [path] !|url [key=value [key=value ...]]

path參數爲本地主機的URL路徑,url參數爲遠程服務器的url一部分,不能包含查詢參數。若是第一個參數path尾隨了斜線,則url部分也必須尾隨斜線,反之亦然。若是該指令封裝在< Location >容器中,則第一個參數path能夠省略,由於Location中已經指定了URL路徑。若是第二個參數爲"!",則表示此path不使用反向代理功能。

例如:

<Location "/mirror/foo/">
    ProxyPass "http://backend.example.com/foo/"
</Location>

當訪問http://server/mirror/foo/bar時,將轉發到http://backend.example.com主機上,並請求該主機的/foo/bar文件。下面的配置指令與此等價。

ProxyPass "/mirror/foo/" "http://backend.example.com/foo/"

若是想讓某個子目錄不進行反向代理,而是在本地處理。能夠設置第二個參數爲"!"。例如,下面的配置中,/mirror/foo會被代理,但/mirror/foo/i則不會被代理。

ProxyPass "/mirror/foo/i" "!"
ProxyPass "/mirror/foo" "http://backend.example.com"

再須要說明的是鏈接池,httpd會爲後端節點建立鏈接池,httpd會鏈接鏈接池中的各個節點。後端節點屬性相同的共享一個鏈接池。後端節點的屬性由key=value參數指定。如下是常見的一些屬性設置,完整的屬性見官方手冊

  • keepalive=Off|On:默認爲Off。設置httpd和後端節點之間是否開啓長鏈接,注意,這和web服務的長鏈接不同,此處設置的是反向代理服務器和後端節點二者鏈接,當httpd將請求轉發給鏈接池中的一個節點,並等待返回數據,當數據返回完成後,鏈接當即關閉,若是開啓了長鏈接,鏈接暫時不關閉,只有等待均衡算法下次輪到該節點時纔會再使用該鏈接。一般只有在httpd和後端節點間使用了防火牆時才設置爲On。
  • lbset=N:默認爲0。設置後端節點的優先級。數值N越低的,優先級越高。httpd老是會先嚐試優先級高的,只有優先級高的節點不可用時,才一會嘗試優先級低的。
  • ping=N:默認爲0。設置和ajp13協議(不支持http協議)通訊時健康情況檢查時間間隔。該ping只能檢查是否能ping通對方,也就是檢測是否能與對方通訊。單位爲秒,能夠帶上後綴"ms"表示毫秒。更多的健康情況檢查應該使用mod_proxy_hcheck模塊。
  • retry=N:默認爲60秒。當檢測到後端某節點錯誤狀態(error status)時,將在每N秒後才轉發一次請求給該節點。設置爲0表示正常轉發請求,不用任何等待時間。該屬性一般設置用來維護服務器下線而後再上線的狀況。
  • status=VALUE:將節點手動置爲什麼種狀態。包括如下幾種狀態,各狀態可以使用"+"(默認)來賦予屬性,使用"-"來取消屬性。例如"+H","S-E"。

    • D: 該節點被禁用,再也不接受任何請求。
    • S: 該節點處於管理維護的目的被中止。
    • I: 將該節點設置爲無視錯誤(ignore-errors)模式,此模式下httpd將認爲該節點可用,總會轉發請求給該節點。
    • H: 該節點處於hot-standby模式,該節點只有在其餘全部後端節點都失效時才啓用。所以,該節點爲備份節點。
    • E: 將該節點設置爲錯誤狀態(error-state)。
    • N: 將該節點設置爲drain模式,該模式只接受已預約粘滯會話的請求sticky session,其餘全部請求都會被忽略。
  • timeout=ProxyTimeout:設置httpd等待後端節點返回數據的超時時間。

若是使用了"balancer://",例如前面的balancer://myset,將建立一個虛擬的鏈接池。虛擬鏈接池中的各節點可共享部分屬性,也能夠爲每一個節點設置上面所說的屬性。共享屬性使用ProxySet指令設置,常見的包括下面幾種:

  • lbmethod=METHOD:設置負載均衡算法。有三種:byrequests(默認)按照請求數量計算均衡節點;bytraffic按照io流量計算均衡節點;bybusyness按照繁忙程度計算計算均衡節點。
  • nofailover=On|Off:默認爲off。session不可用時是否轉移到其餘具備相同session的節點上。若是後端節點不支持session複製,應將此項設置爲on。
  • stickysession:設置session粘滯的名稱,如JSESSIONID、PHPSESSIONID。

例如:

<Proxy balancer://myset>
    BalancerMember http://www2.example.com:8080
    BalancerMember http://www3.example.com:8080 loadfactor=3 timeout=1
    BalancerMember http://hstandby.example.com:8080 status=+H
    BalancerMember http://bkup1.example.com:8080 lbset=1
    BalancerMember http://bkup2.example.com:8080 lbset=1
    ProxySet lbmethod=byrequests
</Proxy>

ProxyRequests off
ProxyPass "/images/"  "balancer://myset/"
ProxyPassReverse "/images/"  "balancer://myset/"

2.5.2 ProxyPassMatch指令

正則匹配模式的ProxyPass。例如:

ProxyPassMatch "^/(.*\.gif)$" "http://backend.example.com/$1"
ProxyPassMatch "^/((?i).*\.php)$" "fcgi://127.0.0.1:9000/var/www/a.com/$1"

惟一須要注意的是,在正則匹配以前,遠程url參數必須是可以解析的URL地址。例以下面兩條指令,第一條指令將失敗,由於在正則解析前,url參數沒法解析爲正確的URL地址,這是一個bug,能夠經過修改正則表達式的分組部分將"/"分離出去,正以下面的第二個指令。

ProxyPassMatch "^(/.*\.gif)$" "http://backend.example.com:8000$1"
ProxyPassMatch "^/(.*\.gif)$" "http://backend.example.com:8000/$1"

2.5.3 ProxySet指令

設置Proxy後端節點的屬性。一般用來設置共享屬性,但也能夠設置某一個節點的屬性。

例如:

<Proxy "balancer://hotcluster">
    BalancerMember "http://www2.example.com:8080" loadfactor=1
    BalancerMember "http://www3.example.com:8080" loadfactor=2
    ProxySet lbmethod=bytraffic
</Proxy>
<Proxy "http://backend">
    ProxySet keepalive=On
</Proxy>
ProxySet "balancer://foo" lbmethod=bytraffic timeout=15

2.5.4 < Proxy >容器

< Proxy >容器用於封裝一組proxy相關指令,這些指令主要用於設置訪問權限、負載均衡成員組以及它們的屬性。

例如,下面的設置了只有yournetwork.example.com下的主機才能經過該(正向或反向代理)服務器訪問任意請求的內容(使用了*進行通配)。

<Proxy "*">
  Require host yournetwork.example.com
</Proxy>
<Proxy "balancer://hotcluster">
    BalancerMember "http://www2.example.com:8080" loadfactor=1
    BalancerMember "http://www3.example.com:8080" loadfactor=2
    ProxySet lbmethod=bytraffic
</Proxy>

2.5.5 ProxyStatus指令

ProxyStatus {on|off|full}決定是否開啓server-status中關於proxy的狀態信息,默認爲off,full是on的同義詞。

例如:

ProxyStatus on
<Location "/server-status">
        SetHandler server-status
        Require all granted
</Location>

如下是關於proxy相關的狀態示例:

----------------------------------------------------------------------

                 Proxy LoadBalancer Status for balancer://myset

   SSes Timeout Method     
   -    0       byrequests 

   Sch  Host           Stat         Route Redir F Set Acc Wr Rd http 192.168.100.14 Init Ok 1 0 0 0 0 http 192.168.100.15 Init Ok 3 0 0 0 0 http 192.168.100.54 Init Stby Ok 1 0 0 0 0 http 192.168.100.16 Init Ok 1 1 0 0 0 http 192.168.100.21 Init Ok 3 1 0 0 0 ---------------------------------------------------------------------- SSes Sticky session name Timeout Balancer Timeout Sch Connection scheme Host Backend Hostname Stat Worker status Route Session Route Redir Session Route Redirection F Load Balancer Factor Acc Number of uses Wr Number of bytes transferred Rd Number of bytes read

2.5.6 ProxyVia指令

是否在響應首部中添加"Via:"字段。能夠設置爲On/Off等。例如如設置爲On時:

[root@xuexi ~]# curl -I http://192.168.100.17/index.html
HTTP/1.1 200 OK
Date: Sun, 01 Oct 2017 18:10:17 GMT
Server: Apache/2.4.27 (Unix)
Last-Modified: Sun, 01 Oct 2017 14:10:48 GMT
ETag: "29-55a7cd31f2329"
Accept-Ranges: bytes
Content-Length: 41
Content-Type: text/html; charset=UTF-8
Via: 1.1 customer.sharktech.net 

2.6 ProxyPass指令的排序和共享問題

ProxyPass指令有個須要注意的問題,在匹配生效時,最早被匹配到的指令當即生效,後面的都將失效。但若是ProxyPass指令放在< Location >容器中時,因爲容器中只能放置一個ProxyPass指令(由於path參數同樣),此時匹配越精確的越優先。

例以下面的指令,若是將兩個ProxyPass指令位置調換,則/mirror/foo/i也仍會被代理。

ProxyPass "/mirror/foo/i" "!"
ProxyPass "/mirror/foo" "http://backend.example.com"

能夠將它們分別定義到< Location >容器中,這樣就無需考慮位置順序,而是考慮匹配的精確程度,由於Location容器自身有加載順序優先級。例如,下面的配置是可行的。

<Location "/mirror/foo/">
    ProxyPass "http://backend.example.com/"
</Location>
<Location "/mirror/foo/i">
    ProxyPass "!"
</Location>

還需考慮一個共享的問題。下面兩個指令中的url參數各有長短,且第一個url是第二個url的子串。這時第二個ProxyPass的屬性部分老是會使用第一個指令的屬性。所以/examples/bar的請求被轉發到backend.example.com/examples/bar時,它的屬性timeout=60而非10。這樣的屬性共享能夠減小建立鏈接池,相對來講更有效一些。

ProxyPass "/apps" "http://backend.example.com/" timeout=60
ProxyPass "/examples" "http://backend.example.com/examples" timeout=10

3.健康情況檢查模塊

ProxyPass指令自帶了ping屬性,可用於簡單判斷後端節點是否健康,只要Ping能通訊就認爲是健康的。但顯然,對於Http服務來講,健康的指標並不能簡單地經過它來判斷。例如,檢測某個頁面是否正常、是否容許某方法等。所以,httpd提供了一個專門的健康情況檢查模塊mod_proxy_hcheck用於個性化訂製檢查指標。

檢查指標也即檢查方法有如下幾種,由hcmethod指定:

  • TCP:檢查是否能與後端節點創建TCP套接字,這就是問對方"你還活着嗎"。
  • OPTIONS:發送一個HTTP OPTIONS請求給後端節點。
  • HEAD:發送一個HTTP HEAD請求給後端節點。
  • GET:發送一個HTTP GET請求給後端節點。

該健康情況檢查模塊認爲,只要HTTP方法的檢查指標返回2xx或3xx狀態碼都認爲是健康的。

指定了檢查方法後,還需訂製檢查的細節,例如檢查的時間間隔。包括如下幾項:

  • hcinterval:默認爲30秒。發送檢查的時間間隔,單位爲秒。
  • hcuri:健康檢查時,追加在URL後的URI。一般用於GET檢查方法。
  • hcpasses:默認爲1。表示只有檢查了N次後都是經過的,才認爲該節點是健康的可再次啓用。
  • hcfails:默認爲1。表示只有檢查了N次後都是失敗的,才認爲該節點已經不健康,因而禁止使用該節點。

例如,如下是幾個健康檢查的配置示例:

<Proxy balancer://foo>
  BalancerMember http://www.example.com/ hcmethod=GET hcuri=/status.php
  BalancerMember http://www1.example.com/ hcmethod=TCP hcinterval=5 hcpasses=2 hcfails=3
  BalancerMember http://www2.example.com/
</Proxy>

ProxyPass "/" "balancer://foo"
ProxyPassReverse "/" "balancer://foo"
相關文章
相關標籤/搜索