本文基本是一些方向性的指導,并不涉及像具體配置檔案的細節,是以本文裡面的内容大部分不能往配置檔案裡面 copy-paste。。
首先要明确一下,squid 能夠用來作什麼。很多人沒有搞明白 squid 的工作原理,隻是聽說 squid 性能不錯可以用來給網站提速,就直接在自己的 website 前面套了一個 squid ,這基本沒有任何用處,即使你都是靜态頁面,後面apache上面沒有開 mod_expires,一樣緩存不了,squid隻能起到一個連接配接管理的用處。
一般說來,網站用 squid 加速,目的有二
1: squid 本身具有緩存功能,可以将webserver輸出的内容緩存起來,在緩存沒有過期之前來的通路,都直接用緩存裡面的内容,這樣可以有效減少 webserver 機器上面的請求數量。這是 squid 的主要功用。
2: 網絡慢的使用者會長時間占用 webserver 的 TCP 連接配接,webserver 對每個連接配接占用的資源比較大,如果長時間不能釋放出來服務其他請求,性能會有比較大的影響。前面放一個 squid, webserver 就可以迅速處理完邏輯以後,把資料快速發送給 squid, 然後去處理别的邏輯,而 squid 每個 TCP 連接配接占用的資源很少,不用擔心占用太多資源。這個用途也叫做連接配接管理,有一些網絡裝置也可以做這個事情,價格都很貴。
下面針對 squid 的兩種功用,來講述如何調整業務邏輯和 squid 參數
零:預操作
在搞 squid 之前,不管你用什麼編譯配置,需要什麼特殊選項,都請 –enable-snmp ,并配置好 mrtg 之類,可以圖形化的顯示 squid 狀态,例如 Request Hit Ratio(RHR), Byte Hit Ratio(BHR), 等等,回報是做一切事情的基礎,優化也不例外。
一:緩存
A: 使用 Expires header 來控制緩存
squid在緩存webserver内容的時候,需要後端webserver輸出一些控制資訊告訴他頁面是不是可以被緩存,以及可以緩存多久。否則 squid 是不會自作主張給你緩存内容的。一個頁面到底能不能緩存,隻有開發網站的人才知道,是以開發人員有責任在動态頁面裡面輸出 Expires 和 Cache-Control header。簡單舉一個 php 的例子以說明這兩個 header 的值是什麼含義,其中$expiretime 的機關是秒。
header(”Expires: ” . gmt_date_format(time()+$expiretime));
header(”Cache-Control: max-age=” . “$expiretime”);
對于靜态檔案,有兩種方式來讓 squid 自動給靜态檔案緩存,一種是使用 apache 的 mod_expires ,可以針對路徑或者針對檔案類型/擴充名來自動輸出 cache 頭。詳細的請參考 mod_expires 的說明 。另一種是用 squid 的 refresh_pattern 來指定。詳細的還是請參考 squid 的配置檔案。一般來說,如果後端不是配置很麻煩,建議還是在後端做,前端的配置修改大多數都是違背http協定的,如果出現問題,也比較難排查。
B 根據 squid 通路的模式,進行業務拆分
進行了 Expires Header 的處理以後,squid 就真正可以起到加速的作用了,你可能也能感覺到,網站的通路速度明顯加快。但是不要滿足于這點成績,檢視 squid 的 snmp 統計圖,通常 hit ratio 并不會太高,有 50% 就了不起了。這就是我們需要進一步優化的,我們的目标是讓大部分 squid 都達到 9X% 的命中率。
為什麼 squid 命中這麼低呢,這大概有兩種原因。大多數的網站都是有一些頁面不能夠被緩存的,例如登入頁面。這些頁面請求也從 squid 走,成為分母的一部分,直接就降低了命中率,我們首先可以做的事情是,把這些不能夠緩存的頁面請求,拆分到單獨一個 squid 上面,或者通路量不大的話,幹脆把 apache 暴露出來。這樣能夠緩存的那個 squid 命中率馬上上升一截。
有人可能會說,把不能緩存的頁面分拆開去,就光為了讓能緩存的那個數字好看,這不是掩耳盜鈴麼?其實這麼做是有意義的,首先就是去掉了不能緩存頁面的幹擾,使得我們進一步優化 squid 的依據更加準确。其次是不可緩存請求和可緩存請求之間的重要性通常是有差距的,分拆了以後,它們之間不容易互相搶占資源,不會因為下載下傳圖檔的連接配接太多把 squid 占滿,影響更重要的登入請求。第三就是可緩存内容通常是圖檔等頁面元素, 浏覽器在 load 它們的時候,對每個站點的并發連接配接會有控制,如果分開成不同的IP,可以多一些請求同時執行。提高少許顯示速度。
其實觀察 sohu, sina 之類的頁面,你會發現它們的頁面也是分拆的,可以看到頁面裡面的圖檔都是指向 images.sohu.com 之類的位址,雖然它們可能和其他頁面一樣背景都指向同一個 apache。
這樣做完,緩存命中率大概能上升到 70%-80% 了,運氣好的時候完全可以上 90%。
另一種導緻 squid 命中低的原因和這個比較類似,同樣都是可緩存的内容,有的可能是軟體下載下傳站上面的大檔案,有的是新聞站點上面的小圖檔,如果同一個 squid 對這樣差别巨大的檔案加速的話,會嚴重幹擾 squid 的緩存政策,兩者不能兼顧,要不就是大檔案占據了 cache ,把小檔案都擠出了 cache, 要不就是小檔案特别多,大檔案無法進入 cache, 導緻大檔案經常 miss 。這個比不能緩存的頁面還要惡心,是以即使在伺服器資源有限的情況下,也要優先拆分這兩類型通路。一般來說,檔案大小分界線定在 1M 左右就可以了,如果是有軟體下載下傳這樣特别大的檔案,可以在 4M - 10M 左右再拆分一次。對于不同通路類型的 squid, 其系統優化參數也會有所不同,這個我們後面還會講到。
隻要悉心按照通路模式來拆分業務,大部分起緩存作用的 squid 都可以達到很高的命中率,至少都可以到達 9X%。
C 根據不同的需求,調整參數優化緩存
完成 A 和 B 兩步優化以後, squid 的命中率經常可以達到 9x%, 可以說我們已經給 squid 創造了非常優秀的外部環境,下面我們就要從 squid 本身入手,通過調整它的緩存參數和緩存政策,甚至系統的參數,來讓 squid 發揮出更好的性能。
在 B 步驟中,我們把 squid 劃分成了三種用途,緩存大檔案,緩存小檔案,不緩存檔案,這其中最後一種用途情況下面 squid 不起到緩存效果,隻用來做連接配接管理,是以我們把它放到後面的連接配接管理裡面叙述,這裡隻讨論和緩存相關的 squid 參數。
squid 有記憶體緩存和磁盤緩存兩級緩存, 通常來說, 隻要是專門給 squid 用的機器, 記憶體緩存都建議開得比較大, 大記憶體緩存總是有好處的嘛, 但是注意不要使得系統開始吃 swap ,像Linux這樣一開始吃 swap 性能就下降比較嚴重的系統尤其要注意. 這個程度需要自己試驗确定.
通常 1G 記憶體的Linux機器用來跑 squid ,記憶體緩存可以開到 512M.
有些libc比較差的平台, 例如比較老的 freebsd 系統, 其 malloc 函數的品質不高,可能會造成比較多的記憶體碎片,導緻 squid 運作一段時間以後配置設定不出來記憶體挂掉. 這時候推薦在編譯時候使用 dlmalloc package. 即使如此, 仍然要再縮小 squid 的記憶體緩存,以防不幸發生.
磁盤緩存的情況比較複雜, squid 有 ufs, aufs, coss, diskd, null 五種存儲後端, 其中 ufs, aufs, diskd 都是在檔案系統上面儲存很多小檔案, coss 是 squid 自己實作了一個簡單的檔案系統,可以使用一個大檔案或者一個磁盤裝置來存儲. null 則是給不想要磁盤緩存的情況準備的. coss 看起來好像比較拽, 但是以前試驗并不足夠穩定,是以并不推薦使用. 剩下的三種存儲方式,具體選擇哪種需要根據作業系統的特性來進行.
ufs 是最傳統的存儲方式, 我們知道, squid 是一個單程序的程式, 它使用 ufs 存儲後端時, 直接在程序裡面讀寫檔案. 這是一種很簡單的方式, 缺點是當讀寫磁盤被阻塞的時候, squid 不能夠處理請求, 會造成服務品質波動比較大. 是以出現了 aufs 和 diskd 兩種存儲後端, 原理都是 squid 主服務循環不負責讀寫檔案, 而是通過消息隊列或者tcp/pipe連接配接将資料傳送給其他的線程(aufs)/程序(diskd), 然後其他線程/程序進行讀寫. 很顯然,這兩種存儲方式有一定的通信開銷, 是以不一定就比 ufs 好, 需要具體問題具體分析
前面說到, ufs/aufs/diskd都是在檔案系統上面存儲很多小檔案,是以檔案系統本身的特性嚴重影響了squid緩存的性能,對于 Linux ,強烈推薦用 reiserfs 等适合處理小檔案的檔案系統, bsd 則至少要打開 softupdate, 以及 dirhash 等一切對很多小檔案有好處的選項. 在比較新的系統上面, reiserfs 等檔案系統的性能已經足夠優越, 通常 ufs 就已經可以應付需要. 對于一些老系統,使用 aufs 或者 diskd 是比較好的選擇,如果系統的線程庫比較好(如Linux,Solaris),那麼使用 aufs, 否則 diskd.
也有一些例外情況, 比如多 cpu 的 Linux 2.6 系統, 線程庫很優秀, 雖然 ufs 本身已經比較快了,但是 squid 單程序無法利用另外的 cpu , 不如使用 aufs , 讓另外的 cpu 也可以起到一些作用, aufs 在編譯的時候可以選擇使用幾個讀寫線程. 這個個人覺得稍微超過 cpu 個數就可以了.但是并沒有實際測試過.
磁盤緩存開多大? 這個問題沒有固定答案. 需要經過試驗來确定, 一般來說開大一些沒有太大問題. 隻要你的硬碟足夠