如何集成varnish到已有的網站架構

jopen 9年前發布 | 16K 次閱讀 緩存服務器 Varnish

如何集成varnish到已有的網站架構

在我們現有的架構中通常是已經成熟穩定的架構,如何將高性能的緩存服務器部署在已有的環境上呢,同時部署容易,如何始終讓用戶看到的是最新的內容,即便是緩存命中的狀態?

因此,我們直接解決上面兩個問題!

如何將高性能的緩存服務器部署在已有的環境上呢?

通過實際使用情況,將varnish部署上線通常有兩種拓撲圖:

1、user---->web--->varnish--->application_server
這種情況更適合網站已經使用了cdn的情況,varnish主要充當緩存網頁頁面的功能。

or

2、user---->varnish--->web--->application_server
這種情況適合通常性的小網站,并沒有富裕的資金,或者說為了充分的節約開支,畢竟如果效果理想,這部分的資源完全可以作為程序員薪水的部分(wan quan bu ke neng!)

對于如何安裝varnish,請參考官方文檔或者之前的blog。兩種方式無外乎在于如何調度網站流量,以及配置源server而已。

如何始終讓用戶看到的是最新的內容,即便是緩存命中的狀態?

有了上面的兩種結構,我們來說如何更新緩存的問題,這也是基本所有問題的所在。

舉個實際例子,通常作為一個cms站點,都會有訪問域名(www)和管理域名(console),這里我們簡稱前臺(客服妹子)和后臺(diaosi chengxuyuan),并且使用上面的第二種架構。 那么我們的架構就是這樣的:

如何集成varnish到已有的網站架構

前 臺用戶通過internet訪問您的網站,首先經過varnish的處理,如果cache中hit,ok,返給用戶,訪問結束,如果miss,進行和之前 沒有使用varnish的訪問流程。(注:此處只畫出必要的部分。當然像redis緩存等其他組件這些東西包含在上面的架構也是沒有任何問題的。)

后臺編輯用戶,通過后臺發布更新,操作數據,并且更新到數據庫中。

現在問題來了(wa jue ji shu na jia qiang?!):

在沒有使用緩存時,用戶每次都通過應用服務器獲取到最新的內容。后臺修改也是直接更新到數據庫。

對比

使用緩存后,實際某篇文章被緩存后,并且在有效期內,用戶的請求是不會到達web服務器,更別說應用服務器。這就是說即便你的編輯在后臺更新了十萬次該文章,如果文章仍然在緩存期內,前臺用戶是不會有任何變化。

解決這個問題通常有兩種方式:

1、對緩存對象設置一個較小的緩存失效時間。(被動更新)
2、通過varnish的接口對已經緩存的對象進行操作。(主動更新)

可以衡量二者的優劣,

被動更新簡單維護量小會存在用戶得到非最新資源的情況;
主動更新效果顯著維護量較被動更新更大,不過向筆者這種大神級別高端玩家(da gao wan)來說,被動更新顯然是不能忍受的額。

實際例子

實際上我們通過后臺管理系統可以向varnish發送更新某資源的請求即可,如下圖:

如何集成varnish到已有的網站架構

具體到配置:我們的前后臺web服務器均使用openresty,具體就不多介紹了,引用一句話"春哥是我見過開源精神最強的人"

首 先對于我們需要修改的文章都是有對應的文章id,在后臺編輯更新都會發起post請求,或者get請求。通過后臺openresty在收到更新文章請求 時,發送一個同步的非阻塞的子請求到前臺varnish,并在varnish中配置用于接收該請求,執行varnish的ban操作。

我們來看配置文件。

后臺的openresty:

server {
    listen 80;
    server_name console.example.com;

    location ~ /articles/(\d+)/[change_status|edit] {
        error_log   logs/error.log debug;

        proxy_set_header X-Real-IP $http_x_forwarded_for;
        proxy_set_header X-Forwarded-For $http_x_forwarded_for;
        proxy_set_header Host $host;
        set $article_id $1;
        rewrite_by_lua '
            ngx.location.capture("/console.example.com/foo/"..ngx.var.article_id, { args = { cmd = "update" } })
        ';
        proxy_pass http://127.0.0.1:9090;
    }

當然這只是最核心能說明問題的代碼,不了解的可以查閱ngx.location.capture ,通過在該location中加入rewritebylua,具體它和proxy_pass的執行順序是rewrite在前。筆者在實際測試中發現,nginx的第三方模塊echo也提供發起了子請求的功能,但實際始終在proxy_pass之后,并不能實現需要的功能。

前臺的varnish,同樣取核心部分:

    sub vcl_recv {
        if (req.method == "GET" && client.ip ~ "192.168.11.11" && req.url ~ "/console.example.com/foo/\d+"  ) {
        set req.http.purge-url = regsub(req.url,"/console.example.com/foo/(\d+).*","\1.html");
        ban("req.url ~ " + req.http.purge-url);
        set req.backend_hint = default;
        return(pass);
    }
}

這里主語clint.ip當然你可以設置為一個集群,這個參考官方文檔。

acl ban {
    "localhost";
    "192.168.11.168";
}

這樣后端更新時會通知varnish更新相關的資源,主動更新功能實現。 由于設置了return(pass),在前端的web中最好配置一段location來匹配該請求,可以簡單的return 200即可。

前端web:

server{
    ...
    location = /console.example.com/foo/\d+ {
        return 200;
    }
}

對于有需要更新圖片等靜態資源的情況。可以編寫一個通用的ban或者purge接口。具體可參考官方文章。

后續

配置文件基于varnish4,建議需要上生成環境的,多閱讀官方文檔。當然也可以瞅瞅我的部分博客,總之,多測試!!word is cheap ,show me your code。

來自:http://my.oschina.net/monkeyzhu/blog/512965

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!