高性能緩存加速器varnish(概念篇)
一、varnish簡介
varnish是一款高性能的開源HTTP加速器,現在很多門戶網站已經部署了varnish,並且反應都很好,甚至反應比squid還穩定,且效率更高,資源暫用更少。
作者Poul-Henning Kamp是FreeBSD的內核開發者之一。Varnish採用全新的軟件體系架構,和現在的硬件提交配合緊密。在1975年時,儲存媒介只有兩種:內存與硬盤。但現在計算 機系統的內存除了主存外,還包括了cpu內的L1、L2,甚至有L3快取。硬盤上也有自己的快取裝置,因此squid cache自行處理物件替換的架構不可能得知這些情況而做到最佳化,但操作系統可以得知這些情況,所以這部份的工作應該交給操作系統處理,這就是 Varnish cache設計架構。
挪威最大的在線報紙 Verdens Gang (http://www.vg.no) 使用3臺Varnish代替了原來的12臺squid,性能居然比以前更好,這是Varnish最成功的應用案例。
二、varnish的特點
Varnish是一個輕量級的Cache和反向代理軟件。先進的設計理念和成熟的設計框架是Varnish的主要特點。現在的Varnish總共代碼量不大,雖然功能在不斷改進,但是還需要繼續豐富和加強。下面是Varnish的一些特點:
1. 基於內存進行緩存,重啓後數據將消失
2. 利用虛擬內存方式,I/O性能好
3. 支持設置0~60秒的精確緩存時間
4. VCL配置管理比較靈活
5. 32位機器上緩存文件大小最大爲2G
6. 具有強大的管理功能,例如top、stat、admin、list等
7. 狀態機設置巧妙,結構清晰
8. 利用二叉堆管理緩存文件,可達到積極刪除目的
三、varnish和squid的對比
Squid是一個高性能的代理緩存服務器,它和varnish之間有諸多的異同點,如下:
1、相同點:
1) 都是一個反向代理服務器
2) 都是開源軟件
2、不同點,也是Varnish的優點:
1) Varnish的穩定性很高,兩者在完成相同負荷的工作時,Squid服務器發生故障的機率要高於Varnish,因爲使用Squid要經常重啓。
2) Varnish訪問速度更快,Varnish採用了“Visual Page Cache”技術,所有緩存數據都直接從內存讀取,而squid是從硬盤讀取,因而Varnish在訪問速度方面會更快。
3) Varnish可以支持更多的併發連接,因爲Varnish的TCP連接釋放要比Squid快。因而在高併發連接情況下可以支持更多TCP連接。
4) Varnish可以通過管理端口,使用正則表達式批量的清除部分緩存,而Squid是做不到的。
5) squid屬於是單進程使用單核CPU,但Varnish是通過fork形式打開多進程來做處理,所以是合理的使用所有核來處理相應的請求。
四、Varnish的不足和解決方案
1、varnish的不足
與傳統的Squid相比,Varnish也是有缺點的,如下:
1) varnish進程一旦掛起、崩潰或者重啓,緩存數據都會從內存中完全釋放,此時所有請求都會發送到後端服務器,在高併發情況下,會給後端服務器造成很大壓力。
2) 在varnish使用中如果單個url的請求通過HA/F5(負載均衡)每次請求不同的varnish服務器中,被請求varnish服務器都會被穿透到後端,而且同樣的請求會在多臺服務器上緩存,也會造成varnish的緩存的資源浪費,也會造成性能下降。
2、解決方案
綜上所述在訪問量很大的情況下推薦使用varnish的內存緩存方式啓動,而且後面需要跟多臺squid服務器。主要爲了防止前面的varnish服務、服務器被重啓的情況下,前期肯定會有很多的穿透這樣squid可以擔當第二層cache,而且也彌補了varnish緩存在內存中重啓都會釋放的問題。這樣的問題可以在負載均衡上做url哈希,讓單個url請求固定請求到一臺varnish服務器上,可以解決該問題。
五、varnish的工作流程
varnish啓動有2個進程,master(management)進程和child(worker)進程。master讀入存儲配置命令,進行初始化,然後fork,監控child。child則分配線程進行cache工作,child還會做管理線程和生成很多worker線程。
child進程主線程初始化過程中,將存儲大文件整個加載到內存中,如果該文件超出系統的虛擬內存,則會減少原來配置mmap大小,然後繼續加載,這時候創建並初始化空閒存儲結構體,放在存儲管理的struct中,等待分配。
接着varnish某個負責接口新http連接的線程開始等待用戶,如果有新的http連接,但是這個線程只負責接收,然後喚醒等待線程池中的work線程,進行請求處理。
worker線程讀入uri後,將會查找已有的object,命中直接返回,沒有命中,則會從後端服務器中取出來,放到緩存中。
如果緩存已滿,會根據LRU算法,釋放舊的object。對於釋放緩存,有一個超時線程會檢測緩存中所有object的生命週期,如果緩存過期(ttl),則刪除,釋放相應的存儲內存。