squid 優化指南

(轉)squid 優化指南[zz]

Squid 高級優化指南/Squid Advanced Tuning Guide

Squid 高級優化指南

by kang[at]kangkang[dot]org , 轉載請保留

類似的題目網上已經有很多了,爲啥我還要寫這麼一篇?其實是前段時間接手了一個 squid 優化的事情,在網上搜索了一下,發現很多
squid 優化只限於在 squid
參數和系統參數上面的調整。但是這個實在只是細枝末節的事情,只要不是太弱智的配置導致無法緩存,squid的性能不會有太大差距,也就提高10%左右,只有實際的業務針對
squid 進行一些調整,squid 纔會真正爆發出他的能量,很多時候有 100%-200% 的提升。

本文基本是一些方向性的指導,並不涉及像具體配置文件的細節,因此本文裏面的內容大部分不能往配置文件裏面 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 個數就可以了.但是並沒有實際測試過.

磁盤緩存開多大? 這個問題沒有固定答案. 需要經過試驗來確定, 一般來說開大一些沒有太大問題. 只要你的硬盤足夠

(待續)

最後致謝一下 windtear ,這位是 squid 之王, Lord of Squid,
業務分拆是從他那裏學來的。致敬。(假如有人轉載請不要刪除這個,否則你也太沒良心了)


---------------以下是a總分析

A. 數據反饋

康神教導我們:反饋是做一切事情的基礎,優化也不例外。那麼具體看一些什麼反饋數據呢?很遺憾,這個問題沒有固定的答案,基本上需要具體問題具體分析。具體來說,用
cacti 之類的看 squid snmp 數據是第一步。主要的數據有:

* BHR (Byte Hit Rate)/RHR (Request Hit Rate),這兩個分別表示有多少數據量/請求數是被
squid hit cache 的。要特別注意的是,squid hit cache 並不等於 squid 不往主服務器發請求。具體情況在
squid 2.5/2.6 裏面參看 isTcpHit() 函數。舉個例子,如果 RHR 顯示 90%,那麼可能有 20% 的請求
squid 還是往主服務器發送了請求詢問它過期的 cache
內容是否有變化的,只不過主服務器的迴應是沒有變化。主服務器的判斷一般需要一次數據庫查詢或者文件系統的 stat
調用。高負荷服務器到最後如果瓶頸在主服務器磁盤 I/O,這些貌似 HIT 的請求也會對主服務器造成一定量的衝擊。單純盲目追求高
BHR/RHR 是不可靠的。
* Service Time,這個是各類請求的迴應時間,但是這個時間受到外部網絡速度的影響,所以也不一定代表真實的性能。另外,如果出現
Miss Service Time 比別的幾個 Service Time
指標高出很多,表示去主服務器的請求耗時比較長,一般是代表瓶頸在主服務器那裏,但這也不是絕對的。如果 squid 服務器磁盤 I/O
性能跟不上或者 CPU 不夠強勁(squid 2 核心是可憐的單進程),那麼也可能是 squid 本身的調度出了問題。
* Storage,在特定情況下可以估算 squid 每天緩存多少東西,在配置緩存大小等問題的時候會有幫助。

總的來說,squid snmp 數據是需要根據具體情況分析的,而且 squid snmp
的數據也不多,有時候往往需要配合別的監控來綜合分析問題,比方網絡出入流量,服務器的各類性能分析,主服務器和 squid access
log。有一次我在某站 squid 調整了一個參數,結果那天 squid 的反應奇好,BHR 更是上了前所未有的
98%。但是後來反覆推敲發現這個參數並沒有作用,結合各類 log 分析發現是因爲那天 frjj 貼了新照片,而且被盜鏈,導致巨大比例的
frjj 照片的請求被 squid 有效的緩存,squid 網絡出流量激增也支持這個結論。說了半天,中心意思是高負荷服務器的 squid
優化是一個長期而艱鉅的任務,某些參數的優化需要幾天的數據才能得出有意義的結論,所以需要有足夠的耐心和針對實際情況的系統化的優化步驟。

B. 緩存策略

康神教導我們:一般來說,(緩存策略)如果後端不是配置很麻煩,建議還是在後端做,前端的配置修改大多數都是違背 http
協議的,如果出現問題,也比較難排查。HTTP 緩存協議比較權威的可以參考 RF2616 第十三章,特別是 13.2 和 13.3
節。具體實現可以參考比方 Firefox 代碼 nsHttpResponseHead.cpp 的 ComputeCurrentAge() 和
ComputeFreshnessLifetime() 函數看看各類情況的處理方式。mod_expires
的配置就需要深刻理解這些基本概念,否則可能反而會增加請求數。如果沒有特別的理由,靜態文件的過期時間一般是設置爲 access time
加上一定量的時間。這個一定量的時間由具體情況決定。比如網站建設初期,各類靜態文件可能需要比較短的過期時間以方便網站更新;而一旦美工敲定圖片,圖片的過期時間可以大膽的設置爲幾個月。在配置完成以後如果沒有很大的把握也可以實際瀏覽一下分析請求序列看是否瀏覽器端和
squid 服務器都做到了有效的緩存,特別注意 cache 相關的請求和回覆頭,包括 squid 提供的 X-Cache 頭。

另外,雖然違反 HTTP 協議的 squid 配置一般都不推薦,但是具體到細節上,這也不是絕對的原則。下面舉例說說必須違反 HTTP 協議的情況。

* 使用 javascript
做鏡像網站測速,一般實現方式是從各個鏡像站下載一個圖片看哪一個最快。最理想的情況是圖片在瀏覽器端不要緩存(以便下次準確測速),但是這個請求又完全沒必要打到主服務器上。那麼可以在
squid 裏針對這個圖片 url 配置強制緩存 refresh_pattern reload-into-ims
ignore-reload。當然這個例子很土鱉,只是舉個例子。
* reload_into_ims (這裏說的是 squid 的配置參數,不是 refresh_pattern 裏面的
option)。這個參數雖然違反 HTTP 協議但是對大部分網站來說是可以設置爲 on 的,只要後端服務器對
If-Modified-Since 頭的判斷正確並且沒有潛在安全問題即可。
* 瀏覽器 F5 刷新和 javascript 的 location.reload()
刷新可能會重新請求所有的網頁內嵌元素並且可能帶 no-cache 請求頭,一般來說 reload_into_ims 設置成 on
已經足夠保證對主服務器不造成衝擊,但是如果有必要可能還是需要在 squid 配置強制緩存。
* 針對土鱉客戶端的優化。比如早期的 fterm 預覽圖片會發送 Pragma: no-cache 的請求頭,這勢必導致所有
fterm 預覽圖片的請求如數全部打在後端服務器上,所以解決方法是 squid 這裏做手腳針對這類 url
配置強制緩存。一個細節問題是如果不能緩存的圖片(比方有察看權限限制的)和能緩存的圖片的 url 結構完全一樣,那麼在 squid
強制緩存這類 url 的話又會有潛在的安全問題,這裏涉及到後面會講到的網站結構優化,針對這個問題需要修改網站的代碼以明確區分這兩類
url。還有另外一個例子是早期的 firefox 發送 XMLHttpRequest 請求也會發送 no-cache
的頭,後來的版本改了。當年這一類 ajax 請求的 url 也是需要配置強制緩存的。
* 最後一個問題是,如果在特殊情況下必須同時在後端服務器發送 Expires 頭,並且又在 squid 中配置這類 url 的
refresh_pattern,那麼需要特別小心。比如,如果 squid 強制緩存時間比 mod_expires
配置的過期時間長,那麼可能造成 squid 發送已經過期的內容,導致瀏覽器本來可以有效緩存的內容卻需要不斷的向服務器檢查更新。

最後,有些後端服務器沒辦法配置 mod_expires。這可能是因爲沒有配置權限,也可能是因爲後端服務器軟件太土鱉,總之這樣的情況下就必須用
squid 配置 refresh_pattern 了。

C. 網站代碼及結構優化

康神教導我們:很多 squid 優化(的文章)只限於在 squid
參數和系統參數上面的調整。但是這個實在只是細枝末節的事情,只要不是太弱智的配置導致無法緩存,squid
的性能不會有太大差距。網站優化一般來說也是屬於這種類型的優化,對於主服務器負荷瓶頸在磁盤
I/O,或者網絡瓶頸是大量大圖片文件的情況,優化網站 html 結構可能對性能提升沒有半點作用。不過即便如此,有一個爲 squid
考慮的網站結構,可以使得 squid 服務器的配置比較容易,也可以比較容易的實現多 squid
業務分拆,有的時候業務分拆並不是爲了性能,而是爲了更好的分析問題以便進一步優化網站。下面簡要說說有可能提高性能的網站代碼優化。

* 減少頁面大小。這個問題實在是到處都有好文章,我就不詳細說了。常見技巧是分離 css/js
到單獨文件減少動態主頁面大小同時保證靜態內容有效緩存;頁面 layout 設計儘量使用 div+css;有大量冗餘 html 元素的部分使用
javascript 來輸出。最後這個頁面 javascript 化可能需要考慮搜索引擎優化 (SEO) 的問題,總的來說需要在減少流量和
SEO 之間尋找一個好的平衡點,這個只有做網站的人自己最清楚。
* 減少同一份數據的不同表現形式。大量使用 ajax 的站點有時候考慮 SEO 往往要重寫一套給搜索引擎看的頁面,這勢必導致
squid 這裏要存兩套頁面。但是如果功力足夠還是可以做到大部分頁面重用。舉例來說,網站可能希望用戶讀文章不切換頁面而使用
XMLHttpRequest 載入,這個就可以在 <a href 寫上文章內容的頁面以便搜索引擎扒站同時也允許用戶在新窗口打開這個文章,而
onclick 事件則觸發 XMLHttpRequest
載入頁面並分析顯示內容。只要代碼寫的足夠漂亮,這裏用一個文章頁面就可以實現所有的功能。
* 標準化 url。這個可以算前一條的補充。寫網站如果不小心,可能同一個資源會有不同的 url。比方某篇文章,從主頁進去的 url
是 article?bid=3&id=50,從搜索結果進去卻是
article?id=50&bid=3。這樣兩個頁面,不但影響外部搜索引擎排名(自己和自己打架),更會影響 squid 效率,因爲
squid 需要單獨存這兩類頁面。
* 網站建設初期充分考慮到將來的 squid 優化。舉例來說,很多網站都在頁面帶用戶登錄信息顯示,這樣的頁面如果不使用
javascript 技巧就完全不可以在 squid 這裏 cache。而實際上,如果這些動態內容可以在 javascript 裏面通過
cookie 判斷出來,那麼完全可以用 javascript 來寫。這方面的細節工作做得越好,就有越多的頁面可以被 squid
安全的緩存。當然這方面的優化有時候也只有網站運行起來才能發現,維護網站的時候多分析
log,多觀察,就可以發現這些細小的可以優化的地方,水滴石穿,大量小細節的優化也可以帶來可觀的性能提升。

D. 一些雜問題

* 同步 squid 和主服務器的時鐘。從原理上說即使主服務器、squid
以及瀏覽器端的時鐘都不同步,應該也不會造成緩存策略上的問題,但是爲了防止詭異問題的發生,還是配置一下 squid 和主服務器的 ntpd
爲好。ntp 是一個極輕量級的協議,現在網絡上 ntpd server 也遍地都是,保證服務器時鐘準確到 1
秒之內也可以保證別的一些程序的事務處理邏輯。
* 密切注意搜索引擎的動向。有一些搜索引擎做的比較弱智,有的時候會突然發很多請求過來。搜索引擎扒站很容易扒到冷僻內容,所以即使請求量只是普通瀏覽用戶請求量的零頭,也可能會對主服務器造成衝擊。大部分搜索引擎還是比較守規矩的,甚至有些搜索引擎公司還可以與他們接觸配置扒站方案。不老實的搜索引擎可以通過
squid 或者主服務器 log 找出來,特別不老實的可能 iptables 都能發現。解決方法比如可以針對搜索引擎 user agent
判斷,或者乾脆 iptables 咔嚓掉。
* Cache replacement policy,對大論壇站點,雖然 lru 算法佔用 cpu 較低,但是 service
time 可能會不如帶 dynamic aging 的算法穩定。據觀察,lru
算法在運行幾天之後的早晨如果突然碰到大量新請求,新請求會很難進入
cache,或者進入了也很快被踢出,導致非常容易形成惡性正反饋拖垮後臺服務器。但是假如每天清晨清 cache,並且保證磁盤 cache
的量稍大於每天能存下來的量,那麼 lru
算法應該也不會比別的算法差(事實上什麼算法都一樣了)。當然這只是我的一家之言,一般來說這個問題還是需要根據 squid
服務器性能和網站具體情況多次反覆試驗選擇最合適的算法。一般來說小規模和超大規模的站點優化這個參數可能不會有什麼顯著的性能提升,所以不建議耗費太多時間優化這個。
* 一定時間清理 cache 並重啓 squid。這個有可能只是 squid 2.5
並且是高負荷破機器上需要考慮的一個方案。某站曾經有段時間每天高峯期 Miss Service Time
都會飆升,但是主服務器卻沒有超負荷的現象,最後推測可能是 squid 自己調度的問題。後來每三天清理 cache 並重啓 squid
似乎大大減少了這種現象。後據權威人士批覆,這個可能是因爲 squid cache replacement
算法過於古老,不適應高速更新的大型論壇所致。
* 多域名宣傳的服務器。如果網站允許有多個域名但是所有的域名都指向同一個網站,那麼要注意 squid
不要配置成多域名模式,否則它會把每個域名的 cache
都分開處理,導致效率低下而且不能有效利用緩存存儲空間。題外話,單個網站宣傳多個域名也會影響搜索引擎排名等等,所以本質上也是不推薦這麼做的。
* maximum_object_size_in_memory,maximum_object_size
這兩個參數的配置也是具體問題具體分析的。具體到某站上,常見的大文件就是附件了,由於附件最大允許大小是 5120 KB,所以
maximum_object_size 配置了 5123 KB 以保證即使最大的附件加上各 HTTP
頭也能有效的被緩存。最早這個參數是配置成 5120 KB 的,然後曾經有一次發生 BHR 驟降的情況,後來分析發現是有人貼了 5120 KB
RAR 分卷壓縮的李宇春同學的視頻,而且恰好又有無數玉米下載,大量這類請求因爲超容所以都壓到了主服務器上。另外
maximum_object_size_in_memory 的配置需要考慮網站具體情況和 squid 服務器的性能,這也需要實際試驗出來。

最後廢話一句,現在硬件降價很快,給機羣升級擴容提升硬件性能往往比找個豬頭優化 squid 配置更有效果,而且見效也快。所以在 squid
大配置沒有問題的前提下,有錢的話應該首選硬件優化方案而不是軟件細節優化。

發佈了27 篇原創文章 · 獲贊 3 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章