Squid合并回源技术
http://blog.chinaunix.net/uid-8474831-id-3830240.html
1. 合并回源的概念
對于CDN的cache服務器而言,減少回源,提高命中率是一個重要的功能,尤其是在處理大文件的時候。這次我們就講一講squid是怎樣讓盡可能多的對于相同url的請求共用同一個回源請求的。
當然,如果一個object已經完整地存在了squid的磁盤上,在它過期之前是不會回源的。我們要討論的是正在從原站下載過程中的object,當另外一個客戶端來下載它的時候。其他cache軟件可能會忽略當前正在下載的object,而另起一個回源請求去下載。這樣的話,在第一個客戶端完整地下完這個object的時候,cache會回源多次。而squid則可以將這些請求合并起來,用一個回源請求服務所有的客戶端。
2. Squid的store_client層
Squid合并回源請求,主要靠的就是store_client層。
Store_client層的工作原理是:當有多個request請求文件的不同部分時,store_client層會對他們采取不同的處理。
圖1表示一個1G的object被多個請求同時訪問的情形。
request1是第一個訪問這個object的請求,由他發起了回源,現在回源已經下載了200M的內容;
request2是一個從頭開始的請求,它開始得比較晚,只請求了100M
request3是一個range請求,它請求的是還沒有從原站下到的部分;
?
圖 ?1
?
注意,雖然是request1發起了回源,但回源請求并不是request1本身,而是由fwdStart函數發起的一個單獨的回源請求。即使request1斷掉了,回源也是可以繼續的,直到下載完整個object為止。
這3個請求都要通過store_client層的storeClientCopy函數從store拿數據。
2.1 數據從內存來
request1的copy_offset是199M,而從150M到200M的數據全都在內存里,因此它進入的分支在storeClientCopy3函數里,它是:
直接就用stmemCopy將內存中的數據copy到sc->copy_buf中,然后storeClientCallback回調客戶端的函數(其實就是clientSendMoreData)??梢钥吹?#xff0c;根本不需要讀磁盤。
2.2????? 數據從磁盤來
request2的copy_offset是100M,比inmem_lo要低,它進入的分支很簡單,就是storeClientCopy3函數的最后一行:
storeClientFileRead顧名思義,就是去讀文件了。
storeClientFileRead會調用storeRead,進入多線程的aufs異步io,拿到文件內容之后還是會調用storeClientCallback回調。
2.3????? 數據還在原站
request3很顯然,數據在磁盤和內存都沒有。所以它所能做的就是等待了。它的分支是
點擊(此處)折疊或打開
既沒有讀磁盤,也沒有讀內存,就return掉了。那么什么時候這個客戶端會繼續呢?就是當回源鏈接每從原站讀到一塊數據,會調用storeAppend,進而調用InvokeHandler,由于request2的store_client是當前storeEntry的client之一,invokeHandler會對request2的store_client重新調用storeClientCopy2和storeClientCopy3,如果到了那個時候它所需要的數據在內存或硬盤了,客戶端就會繼續收到數據。
?
3.??? 折疊回源機制collapsed_forwarding
剛才說的是store_client層,它的作用是,管理已經在訪問同一個object的所有客戶端,讓他們取到各自需要的數據。
那么,怎樣讓所有的客戶端訪問到同一個object呢?
squid會為每一個object創建一個StoreEntry結構,并放到store_hash這個哈希表中,供后來的request查找。當request1從原站下載到了數據時,它的StoreEntry肯定是已經創建好了。這個階段要讓其他請求找到這個object是很容易的。
但問題就是request1的客戶端請求已經發到了squid,而原站數據還沒有下載到的這個期間,如果其他請求來了怎么辦呢?其實squid為這個問題引入了一個配置項,叫做collapsed_forwarding,可以on或者off。這個配置項的意思就是,所有請求共用一個回源請求。
3.1 collapsed_forwarding on
當配制成on的時候,只要request1的客戶端請求發到了,這時候url也知道了,就立即創建它的StoreEntry,并放到hash表中。即使回源的數據還沒拿到,其他請求也能找到它的StoreEntry。
但是,這時候就有一個問題了,萬一request1請求的是動態內容怎么辦?難道讓其他請求也拿到跟request1一樣的內容么?
當然不會!squid在clientCacheHit中做了防范。clientCacheHit是當一個回調函數,在請求hit了,并拿到reply頭的時候由storeClientCallback回調。
假如request2就是一個這樣的請求,它發生在在request1拿到原站的數據之前,并找到了request1創建的StoreEntry,而且“以為”自己hit了。而回源的reply中有Cache-Control:no-cache,那么當request2在進入clientCacheHit時,它找到的StoreEntry中一定會有RELEASE_REQUEST這個標識。這個標識是httpCachableReply函數發現no-cache之后設置的。當發現這個標識的時候,就會從clientCacheHit轉入clientProcessMiss,重新回源,不會跟request1取到相同的數據。代碼如下
?
3.2????? collapsed_forwarding off
當配制成off的時候,與on相反,當request1發過來的時候,不立刻將 StoreEntry放到hash表中,只有當回源請求拿到了reply頭,確認是可緩存的內容后,才將StoreEntry放到hash表中。
雖然回源拿到響應頭的時間通常很短,但終究有可能發生“誤會”,request1和request2都回源了。那么這種情況下會不會兩個回源請求產生沖突,比如寫同一個cache文件之類的問題呢?
其實也不會。squid對這種情況也做了防范。
在發現一個object可緩存時,會調用httpMakePublic,進而調用StoreSetPublicKey。StoreSetPublicKey主要是負責將一個StoreEntry放入hash表。這時候它會先檢查hash表中是否已經有了key相同的object,如果有,要先刪除舊的再插入新的。
刪除舊的object之后,request1和request2的回源都不會停止,以保證客戶端下到完整的數據。
那么,它們會不會寫到相同的文件里呢?
還是不會。因為squid為新的object分配文件名不是直接將key轉換為文件名,而是用一個filebitmap來分配一個文件號,用這個文件號來生成文件名。分配過的文件號是不會被再次分配出去的。
還有最后一個問題,就算文件名不同,request1回源取到的數據還會不會被寫到磁盤上呢?
看到這里,你會知道squid是很聰明的,所以答案當然還是不會了。因為舊的entry一旦被打上RELEASE_REQUEST標,同時會清掉ENTRY_CACHABLE標,它的swapout就不會再進行了。這是在storeSwapOutMaintainMemObject里保證的。
其中storeSwapOutAble的定義如下:
4. 思考題?
最后,請大家想一想,什么樣的業務模式適合collapsed_forwardingon,什么樣的適合off呢?
總結
以上是生活随笔為你收集整理的Squid合并回源技术的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python安装教程之anaconda篇
- 下一篇: android实现多画面播放,快手同框怎