HAProxy 1.9發佈,支持端到端 HTTP/2,改進緩衝區和連接管理

HAProxy Technologies正式宣佈推出HAProxy 1.9。新版本帶來了基於原生HTTP表示(HTX)的端到端HTTP/2支持,併爲未來的創新——如HTTP/3(QUIC)——鋪平了道路。它還帶來了緩衝區和連接管理方面的改進,包括到後端的連接池、線程優化、Runtime API,等等。

HAProxy是世界上速度最快、使用最爲廣泛的軟件負載均衡器,於2001年12月首次發佈。從那時起,負載均衡器格局發生了重大變化。17年來,HAProxy一直在演化和創新,現在終於迎來了HAProxy 1.9。

新版本的重點是爲我們以後能夠繼續提供一流的性能和交付尖端功能奠定基礎。得益於1.9版本的核心改進,一些令人興奮的功能包括Layer 7重試機制、迴路斷路、gRPC、新的數據平面API,等等。

我們還發現需要更頻繁地發佈更新。在未來,HAProxy將從一年發佈一次改爲一年兩次。之前,主要版本會在每年的11月或12月份左右發佈,但從現在開始,我們將每年發佈兩次。請注意,這次的版本向後兼容舊的配置。

接下來,我們將深入探討新版本帶來的改進。

緩衝區改進

HAProxy已經支持到客戶端的HTTP/2。新版本的主要目標是支持端到端的HTTP/2,包括到後端服務器的HTTP/2。我們還希望能夠支持未來版本的HTTP,例如HTTP/3(QUIC)。

我們的研發團隊付出了巨大的努力來實現這一目標,其中一個非常重要的方面涉及HAProxy處理緩衝區的方式。

緩衝區是一個存儲區域,分爲兩部分:輸入數據和輸出數據。緩衝區可以在任何地方開始和結束。在之前版本的HAProxy中,有22種可能的緩衝區,如下圖所示:

上圖顯示了1.9版本之前的各種緩衝區及其分配方式。我們決定重寫緩衝區處理邏輯並簡化緩衝區分配。下圖顯示了最新的緩衝區變更:

最新的變更將緩衝區的數量減少到7個,只需維護一個版本的代碼。

除了這些重構之外,緩衝區的標頭(即描述緩衝區狀態的附加字段)已從存儲區域中分離出來。這意味着對於相同的數據不再強制要求使用單一的表示,多個參與者可以在不同的狀態下使用相同的存儲。這通常被用在底層的多路複用中,通過讀取器和寫入器對相同數據塊附加別名來避免內存複製(也即“零複製”),從而提升了HTTP/2的性能。

實現這一點並非易事,但卻帶來了很多好處。它爲更容易實現端到端HTTP/2鋪平了道路。它還簡化了其他一些東西,比如內部API、錯誤消息處理和渲染統計頁面。

連接管理

HAProxy 1.9中的連接管理獲得了一些重大改進。新的實現已從面向回調的模型轉變爲異步事件模型(包含了完成回調)。這種新設計將會非常有用,並減少連接層中可能出現的bug數量。

新設計的一些好處包括:較低的send()延遲(幾乎從不進行輪詢)、更少的層間往返(更好的I-cache效率)、在上層內直接使用、消除代碼重複,以及提供較低層的細粒度錯誤報告。它還爲不同協議提供了重試失敗連接的能力(例如,如果ALPN表明同時支持HTTP/2和HTTP/1,那麼在其中一個發生故障時,會自動切換到另一個)。

如果沒有設置,http-reuse指令的默認值爲safe。這意味着到後端服務器的會話的第一個請求始終通過自己的連接發送,後續請求可以重用其他現有的空閒連接。這是幾年來一直推薦的方式,現在是時候將其變爲默認設置。

此外,HAProxy現在也提供了連接池。當前端連接消失後,HAProxy和服務器之間的空閒連接並不會立即被關閉,它們在服務器端保持打開狀態,以供其他請求使用。

原生HTTP表示(HTX)

在研究支持未來版本HTTP所需的路由時,我們決定對HTTP消息的內部處理機制進行重新設計。之前,HTTP消息作爲字節流進行傳輸,數據的分析和處理任務被混合在同一個階段中進行。

HTTP信息作爲字節流被收集起來,並通過偏移量來操作它們。主結構包含了兩個通道:請求/響應和HTTP事務。第一個通道對請求和響應消息進行緩衝,將它們視爲字符串。HTTP事務通道有兩種狀態:一個是響應/請求,另一個包含了標頭的偏移量。

因爲所有東西都是以偏移量的方式進行保存,所以添加、刪除和重寫HTTP數據就會變得很麻煩,需要不斷移動到標頭的末尾,在處理響應消息時甚至需要移動到HTTP正文的末尾。隨着時間的推移,cookie、keep-alive、壓縮和緩存都需要操作標頭,這項任務因此變得十分昂貴。

新的設計(我們稱之爲HTX)爲HTTP協議創建了內部的原生表示。它提供了一系列強類型、精心設計的標頭字段,支持間隙和無序。現在修改標頭很簡單,只需要將舊標頭刪除,並在末尾添加新標頭即可。

這讓針對HTTP協議的操作變得更加簡單,我們可以維護端到端的HTTP傳輸和語義,並在將HTTP/2轉換爲HTTP/1.1或將HTTP/1.1轉換爲HTTP/2時獲得更高的性能。它將處理和分析相分離,現在分析和格式化發生在連接層,而處理髮生在應用層。


由於我們還在進行測試,所以默認情況下尚未啓用HTX。你可以在defaults、frontend、backend、listen部分添加下面的選項來啓用它:

option http-use-htx

在啓用後,你就可以在後端服務器上使用HTTP/2。將alpn h2添加到服務器配置行中(或者如果你希望讓HAProxy與服務器協商協議,可以添加alpn h2,http/1.1)。

server server1 192.168.1.16:443 ssl verify none  alpn h2

這是一個端到端HTTP/2的完整示例(frontend+backend):

frontend fe_main
    mode http
    option  http-use-htx 
    bind *:80 
    bind *:443 ssl crt /etc/hapee-1.8/certs/www.example.com.pem alpn h2,http/1.1
    default_backend be_main

backend be_main
    mode http
    option http-use-htx
    server server1 192.168.1.13:443 ssl verify none alpn h2

HAProxy 1.9還支持proto h2指令,這個指令讓HAProxy可以使用沒有TLS的HTTP/2與支持HTTP/2的後端(如Varnish和H2O)通信。你可以使用以下服務器配置啓用這項功能:

server server1 192.168.1.13:80 proto h2

多線程改進

1.9版本對線程進行了重大改進。這些改進使得HAProxy能夠提供卓越的性能。爲實現這一目標,我們對任務調度程序進行了重新設計。它現在的工作被分爲三個級別:

  • 在所有線程之間共享的優先級感知級別;
  • 無鎖、優先級感知級別;
  • 可用於I/O的已啓動任務。

現在大多數調度可以在沒有鎖的情況下進行,可以更好地擴展。此外,我們對調度程序的等待隊列進行了優化。它們現在大部分都是無鎖的。內存分配器是無鎖的,並使用了熱對象線程緩存,從而帶來更快的結構初始化。文件描述符事件緩存基本上也是無鎖的,允許更快的併發I/O操作。最後,文件描述符的鎖已更新,因此使用的頻率較低。總的來說,HAProxy 1.9的線程性能提升了差不多60%。

緩存改進

我們在HAProxy 1.8中引入了小對象緩存(Small Object Cache)。當時,很多人希望獲得這些功能,而我們也知道這隻一個開始:代理層中的緩存。在內部,我們將其稱爲favicon緩存,因爲它僅限用於緩存小於tune.bufsize的對象,默認爲16KB。此外,在第一個版本中,它只能緩存返回HTTP 200 OK響應碼的對象。

而在HAProxy 1.9中,你可以緩存最大爲2GB的對象,使用max-object-size進行設置。total-max-size用於指定緩存的總大小,最大爲4095MB。HAProxy現在可以緩存返回以下狀態碼的響應:204、404、405、414和501。

HTTP 103

HAProxy現在支持HTTP 103狀態碼,也稱爲Early Hints(RFC8297),它允許你在服務器做出響應之前發送一系列對象鏈接到客戶端。這項特性仍處在早期採用階段,不過Early Hints看起來可能會取代HTTP/2服務器推送。

因爲以下的一些因素,Early Hints會比服務器推送更好:

  • 服務器推送可以加速資源的傳遞,但僅限於服務器允許的資源。換句話說,它必須遵循同源策略,某些情況下會對CDN的使用造成影響。而Early Hints可以直接指向CDN託管的對象。
  • Early Hints讓瀏覽器可以使用對象的本地緩存。而服務器推送會要求將請求傳輸至源,無論客戶端是否緩存了響應。

要啓用Early Hints,請在HAProxy配置文件中添加類似以下這樣的內容:

http-request early-hint Link "</style.css>; rel=preload; as=style"
http-request early-hint Link "</script.js>; rel=preload; as=script"

Runtime API改進

Runtime API也得到了更新。首先是修改了master/worker模型,簡化worker的交互,並獲得更好的進程可觀察性。master現在有自己的套接字,可以直接用這個套接字與它進行通信。而且套接字可以管理與每個worker之間的通信,甚至是那些正在退出的worker。

要使用這個新功能,需要使用-W和-S選項啓動HAProxy。

$ haproxy -W -S /var/run/haproxy-master-socket  -f /etc/haproxy/haproxy.cfg

然後通過master套接字連接到Runtime API,如下所示:

新的show proc命令顯示了每個進程的正常運行時間。

新的reload命令重新加載HAProxy,並加載了新的配置文件。它與向master進程發送SIGUSR2信號是完全一樣的效果,只是可以在上傳新配置文件後由外部程序觸發。

命令可以通過master套接字發給worker,在命令前面加上@符號,加上worker的編號。以下是向第一個worker發出show info命令的示例:

我們還添加了有效載荷支持,可以使用Runtime API插入多行文本。在更新map文件時這會非常有用。目前還不支持通過Runtime API更新TLS證書,但HAProxy 2.0有可能會支持!

要使用有效載荷更新map文件,你需要先map的ID,然後使用add map命令添加新行,行間用\n分隔:

$ echo "show map" | socat /var/run/haproxy.sock stdio
# id (file) description
-1 (/etc/haproxy/maps/hosts.map) pattern loaded from file '/etc/haproxy/maps/hosts.map' used by map at file '/etc/hapee-1.8/hapee-lb.cfg' line 94

$ echo -e "add map #-1 <<\ntest1 be_one\ntest2 be_two\n" | socat  /var/run/haproxy.sock stdio

$ echo "show map #-1" | socat /var/run/haproxy.sock stdio
0x217aa80 test1 be_one
0x2190010 test2 be_two

你也可以附加文件內容,比如:

$ echo -e "add map #-1 <<\n$(cat data.map)\n" | socat /var/run/haproxy.sock stdio

Runtime API中還新增了一個新的show activity命令。它可用於顯示每個線程被系統搶佔的總CPU時間,以及所有任務所經歷的平均處理延遲。

同樣,如果在global中配置啓用或通過Runtime API啓用了profiling,那麼就可以在日誌中看到CPU時間和延遲。要在global中啓用profiling,你需要添加:

global
    profiling.tasks on

通過Runtime API啓用:

$ echo "set profiling tasks on" |socat /var/run/haproxy.sock -

驗證是否已啓用:

$ echo "show profiling" |socat /var/run/haproxy.sock -

服務器隊列優先級控制

HAProxy 1.9允許你對隊列中的連接進行優先級排序。例如,你可以讓JavaScript或CSS文件優先於圖像傳給客戶端。或者,你可以用它改善高級客戶的加載時間。另外,可以用它給機器人安排較低的優先級。

通過添加http-request set-priority-class指令爲JS或CSS文件設置更高的服務器隊列優先級。爲了避免由連續高優先級請求導致的飢餓等待,可以通過set-priority-offset指令爲某些請求設置等待時間上限。將這項功能與ACL規則結合使用,你就可以靈活地決定何時以及如何安排連接的優先級。

acl is_jscss path_end .js .css
acl is_image path_end .png .jpg .jpeg
http-request set-priority-class 1 if is_jsscss
http-request set-priority-class 10 if is_image
http-request set-priority-class 100 if !is_jscss !is_image

數字越小,優先級越高。因此,在這裏,JavaScript和CSS文件被賦予最高優先級,其次是圖像,然後是其他資源。

隨機負載均衡算法

我們添加了一個新的隨機負載均衡算法。這個算法會選擇一個隨機數作爲一致哈希函數的鍵。在這個模式下,會用到服務器權重。動態權重更改會立即生效,新添加的服務器也會立即生效。隨機負載均衡算法對於大型服務器機羣或經常需要添加和刪除服務器的場景來說非常有用。使用多個負載均衡器可以降低所有流量被重定向到同一服務器的風險。

hash-balance-factor指令通過保持分配給服務器的負載接近於平均值來進一步提高負載均衡的公平性,當服務器的響應時間高度可變時,這會非常有用。

要啓用隨機負載均衡算法,請在backend中將balance設置爲random。

balance random

雲原生日誌

HAProxy已經具備了將日誌寫到syslog服務器的能力。但是,在使用Docker的微服務架構中,將syslog安裝到容器中是一種反模式。用戶要求使用其他方法來發送日誌。我們已經從用戶那裏收到了相當多這類請求,所以花了一些時間選擇了一種最佳的實現方式——非阻塞——我們很高興已經找到了解決方案!

HAProxy 1.9提供了三種發送日誌的新方法:將它們發送到文件描述符、stdout或stderr。可以使用標準的log語句添加這些新方法。

要將日誌記錄到stdout,請使用stdout參數:

log stdout local0

對於stderr也類似。另一種方法是將日誌發送到文件描述符,如下所示:

log fd@1 local0

fd@1參數是stdout的別名,fd@2是stderr的別名。它們還有兩種新的日誌格式:raw和short。

log stdout  format raw  local0

新的Fetch

HAProxy中的Fetch提供了來自內部狀態或L4、L5、L6和L7的信息。新版本新增了date_us、cpu_calls、lat_ns_avg等Fetch。

新的轉換器

轉換器可用於在HAProxy中轉換數據,通常用在Fetch之後。新版本新增了strcmp、concat、length、crc32c等轉換器。

雜項改進

新版本的HAProxy還添加了其他各種改進,包括:

  • 新的stick-table計數器gpc1和gpc_rate。
  • resolvers部分現在支持resolv.conf。
  • busy-polling——在啓用了頻率縮放或支持深度空閒狀態的機器上可將請求處理延遲減少30-100微秒。
  • HAProxy的Lua引擎進行了以下更新:
    • Server類可更改服務器的maxconn值。
    • TXN類可調整服務器連接隊列優先級。
    • 新類StickTable允許通過鍵來訪問和轉儲stick-table的內容。

迴歸測試套件

Varnish附帶了一個叫作varnishtest(https://varnish-cache.org/docs/trunk/reference/varnishtest.html)的工具,用於對整個Varnish代碼庫進行迴歸測試。我們發現它也是用來測試HAProxy特定用例的完美工具。我們與Varnish團隊合作,爲varnishtest提供補丁,對其進行擴展,並用它來測試HAProxy。

我們還開始創建和發佈可在用戶環境中運行的測試代碼。如果你瞭解HAProxy,編寫測試代碼就很容易。所以,如果你有興趣爲HAProxy做貢獻但不知道從哪裏開始,你可以嘗試先拉取HAProxy的代碼,然後自己編寫測試!

要使用迴歸測試套件,需要安裝varnishtest,它已經包含在Varnish軟件包中。安裝完成後,你需要創建一個測試vtc文件。這是一個示例:

varnishtest "Stick Table: Crash when accessing unknown key."
feature ignore_unknown_macro

server s0 {
    rxreq
    txresp
} -start

haproxy h0 -conf {
    defaults
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms

    frontend test
        mode http
        bind "fd@${fe1}"
        stick-table type ip size 1m expire 1h store gpc0
        http-request deny if { src,table_trackers(test) eq 1 }
        http-request deny if { src,in_table(test) }
        http-request deny deny_status 200
} -start

client c0 -connect ${h0_fe1_sock} {
    txreq -url "/"
    rxresp
    expect resp.status == 200
} -run

要運行它,需要將HAPROXY_PROGRAM環境變量設置爲你要測試的二進制文件的路徑。然後調用varnishtest。

export HAPROXY_PROGRAM=$PWD/haproxy 
varnishtest /home/user/haproxy/reg-tests/stick-table/b00000.vtc
#    top  TEST /home/user/haproxy/reg-tests/stick-table/b00000.vtc passed (0.112)

HAProxy 2.0預覽

以下是將在HAProxy 2.0中帶來的功能,計劃於2019年5月發佈:

  • HAProxy數據平面API;
  • gRPC;
  • L7重試;
  • FastCGI集成;
  • 迴路斷路;
  • 將TLS證書與私鑰分離;
  • 使用Runtime API更新TLS證書和私鑰。

結論

在開源社區和HAProxy Technologies的大力支持下,HAProxy始終處於性能和創新的最前沿。我們很高興爲你帶來1.9版本!它開啓了一個新的篇章,你將看到更頻繁的版本更新頻率。它將支持端到端HTTP/2,改進了緩衝區和連接管理,更新了Runtime API和小對象緩存,提供了新的隨機負載均衡算法,甚至通過Runtime API和新的Fetch獲得更好的可觀察性。

英文原文:https://www.haproxy.com/blog/haproxy-1-9-has-arrived/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章