最近kangle web服務器已經發布了新版2.3.1,其性能比老版本提高8倍之多,靜態文件處理能力達apache的8-10倍。如此高的性能怎麼來的 呢?kangle有哪些祕密武器呢?其實做爲現代化的其它web服務器如nginx,lighttpd,cherokee等其原理都差很少,可能實現細節 有些區別而已。
第一件祕密武器:epoll/IOCP/kqueue新模型
傳統的web服務器採用同步socket處理,即每一線程服務於一個客戶(apache就是這樣),或者是使用傳統的select/poll模型。 在鏈接數小的狀況,性能也不會不好,但隨着鏈接數的上升,性能會直線降低,超過必定數量時,會致使服務器沒法提供服務。這就是著名的C10K問題。現代化 的web服務器都採用效率更高的模型,linux下面是epoll,windows下面是IOCP,bsd系統的是kqueue. kangle新版也採用這種模型,鏈接數上升,性能只是會降低一點,基本上很穩定的提供服務。
第二件祕密武器: 非阻塞socket
即便採用了新模型也能更好的處理服務了,但爲何還要非阻塞socket呢?咱們知道,對於發送數據(調用send),大多數的狀況下是不會阻塞的,由於 數據是直接放到socket的緩衝裏面,只有緩衝滿了的狀況下會阻塞。問題就是咱們已經使用了新模型能夠檢測到該socket能發的時候才發啊?和阻塞有 什麼關係呢?這就是關鍵了,由於新模型只能保證發送一次數據不會阻塞,你沒法檢測一次發送多條數據,這個很關鍵,由於你的數據不可能完整的,如http頭 和http body可能要分屢次包發送。若是一檢測只能發一次,效率會受些影響,若是咱們用非阻塞socket,一次檢測咱們能夠一直髮送數據,屢次調用send, 直到發完,或者檢測到EAGAIN錯誤。這樣節省epoll/kqueue系統調用次數,效率大大提高。
第三件祕密武器: writev代替write/send
上次咱們已經優化了一次檢測能夠屢次發送數據,節省了epoll/kqueue調用了,但還不夠,夠貪的吧,能不能作到一次檢測,一次發送多條數據,這就 是用writev,而不用傳統的write/send調用了。你們能夠man writev能夠看到這個函數的幫助。咱們能夠在調用前構建多條數據數組,又節省幾回write/send調用。IOCP的WSASend函數也是能夠實 現相同的功能。
第四件祕密武器: TCP_CORK/TCP_NOPUSH
下面咱們從socket身上再下功夫,咱們能夠利用linux特有的TCP_CORK和bsd下面的TCP_NOPUSH功能。http協議層咱們 能夠知道一次請求會發送多少數據給用戶,但下面的tcp/ip層沒法理解http協議,tcp/ip會按照它的算法,決定是否會合並一些小包發送。可否讓 tcp/ip也能"理解"http協議?嗯,這就是第三件祕密武器了,TCP_CORK/TCP_NOPUSH,咱們能夠在開始發送http頭前設置一 下,設置一下socket的TCP_CORK/TCP_NOPUSH,至關於在數據流上加一個塞子,這樣數據是不會發送到對方,咱們再發送http其它數 據,等這些數據所有發送完了,咱們再把塞子拔掉,取消TCP_CORK/TCP_NOPUSH。節省帶寬。至於TCP_CORK和TCP_NOPUSH的 詳細用法,你們能夠搜索一下其它文檔。
第五件祕密武器: 緩存(Cache) 緩存(Cache)能夠大大提升咱們的性能,http協議已經有緩存機制。但實現比較複雜,kangle新版採用了內存和磁盤兩級緩存機制,磁盤緩 存主要用在反向代理等要遠程鏈接的地方,對於本機的文件,主要使用內存緩存。緩存淘汰機制使用LRU算法。kangle內部維護兩個鏈表,一個是map 表,一個是雙向鏈表,map表查找時使用,一但某個網頁再次請求(命中),就會插到雙向鏈表的最前面。每次要刪除緩存網頁時從雙向鏈表的後面開始,即那些 最近沒有命中的網頁。