一、概述
??Tengine 是一個由淘寶網發起的 Web 服務器項目。它基于 Nginx 然后針對大訪問量網站的需求,添加了很多高級功能和特性,從 2011 年 12 月開始,Tengine 正式開源。Tengine 的性能和穩定性已經100多家大型網站如淘寶網,天貓商城、Youku、AliExpress、 Lazada 、Alibaba Cloud等得到了生產型檢驗。Tengine定位于打造一個高效、穩定、安全、易用的 Web 平臺 目前已100% 兼容 Nginx的配置語法和模塊,用戶還可無縫遷移現有Nginx服務,同時享受增強功能,但需要注意安全漏洞,近期安全通報顯示部分版本存在漏洞,請及時加固更新。另外,Tengine 沒有像 Spring Cloud Gateway 那樣為微服務架構提供原生支持(比如直接與 Eureka、Consul 等服務發現組件集成),但 Tengine 仍然可以通過 反向代理的方式 與微服務架構組合使用,尤其是在 Kubernetes 環境中,通過 Ingress 的方式實現負載均衡和路由功能。
- 繼承 Nginx-1.24.0 的所有特性,100% 兼容 Nginx 的配置;
- 動態模塊加載(DSO)支持。加入一個模塊不再需要重新編譯整個 Tengine,支持動態調整 servers, locations and upstreams而無需 reloading 或restarting worker 進程;
- 支持HTTP/3 (QUIC v1 和draft-29方式);支持異步SSL/TLS模式,可以使用QAT(intel QuickAssist Technology)來卸載和加速SSL,顯著提升性能。
- 支持基于標準和自定義的 HTTP header, cookie, query and weights.來動態配置路由,可動態添加和追加自定義的http 頭和請求參數;無需重新加載引擎的就可向HTTP響應添加自定義報頭;支持動態配置TLS versions, timeout setting, SSL Redirects, CORS and enabling/disabling robots for the server and location;支持proxy_connection的隧道連接;
- 更多負載均衡算法支持。如會話保持,一致性 hash 等;
- 輸入過濾器機制支持。通過使用這種機制 Web 應用防火墻的編寫更為方便;
- 動態腳本語言 Lua 支持。擴展功能非常高效簡單;
- 支持管道(pipe)和 syslog(本地和遠端)形式的日志以及日志抽樣;
- 組合多個 CSS、JavaScript 文件的訪問請求變成一個請求;
- 可以對后端的服務器進行主動健康檢查,根據服務器狀態自動上線下線;
- 自動根據 CPU 數目設置進程個數和綁定 CPU 親緣性;支持內核旁路的高速UDP傳輸,
- 監控系統的負載和資源占用從而對系統進行保護,包括: asynchronous log & rollback, DNS caching, memory usage;
- 顯示對運維人員更友好的出錯信息,便于定位出錯機器;
- 更強大的防攻擊(訪問速度限制)模塊;
- 更方便的命令行參數,如列出編譯的模塊列表、支持的指令等;
- 可以根據訪問文件類型設置過期時間;
- 支持直接提交未緩沖的數據給到HTTP和FastCGI 后端服務器,避免了本地緩沖需先將文件數據寫入磁盤緩沖區,然后再從緩沖區讀取數據進行處理,這樣可以減少磁盤I/O操作,提高文件處理速度;
關聯資源:tengine倉庫、tengine產品官網、tengine-ingress統一接入[Tengine-Ingress結束](https://mp.weixin.qq.com/s/VbNXHvjdCD07LOXaOIGXCw)
二、架構及原理
2.1 tengine對Nginx的主要改進模塊
2.2 改進優化
1)計時器優化
Timers(計時器)是網絡服務器中一個很重要的基礎設置,它用來管理讀寫超時和應用邏輯的超時等。其常見操作有添加超時、刪除超時以及查找最小的超時值。Nginx使用Red-black tree(紅黑樹)作為其計時器的數據結構。紅黑樹對應于添加、刪除和查找最小值的算法復雜度都是O(logn)。在Tengine中,我們將Nginx的計時器數據結構改為了4-heap
(四叉最小堆)。四叉堆是二叉堆的變種,比二叉堆有更淺的深度和更好的CPU Cache命中率。最小堆的添加、刪除的復雜度和紅黑樹一樣都是O(log n),但在查找最小值時,它的算法復雜度是0(1),即只要取出堆頂的第一個元素即可,因此比Nginx的紅黑樹更適合頻繁獲取最小值的場景,特別是在處理大量連接時,用最小堆性能提升比較明顯。
2)瀏覽器和爬蟲的判斷優化
判斷瀏覽器的類型是Web服務器的一個常見需求。Nginx中判斷瀏覽器的方法是對關注的瀏覽器種類在User-Agent頭中做暴力查找(strstr) 。strstr本身的算法復雜度是0(n2),Nginx查找的是多個串,因此其最終算法復雜度是0(n3)。隨
著現在移動端的瀏覽器增多,原有模塊的復雜度成指數增長,性能不高。在Tengine中,我們開發了一個全新的user_agent模塊
,使用了trie
(前綴
樹)來搜索多個可能的瀏覽器匹配串。它將所有的匹配字符串構造出一個自動機,每次匹配,它的算法復雜度只需要O(n)
。因此復雜度不會隨著匹
配串數量的增加而增加。
3)自動綁定CPU親緣性
原有的Nginx CPU綁定需要手工操作,在Tengine中我們將Worker進程和CPU進行自動綁定,可以減少因CPU的Cache失效帶來的性能損失,從而提高性能。另外,這樣也減少了運維配置的工作量。
4)Lua模塊(ngx_lua) 將Lua直接嵌入進Nginx核中
這樣,借助Lua的協程和Nginx的事件模型實現同步、非阻塞的I/O操作,開發者在Nginx配置文件中可串行同步編寫Lua腳本來處理業務邏輯,既可以用它來黏合各種上游(Proxy、Drizzle、Redis、Memcached等)的輸出,也可以使用它的Cosocket接口來編寫訪問上游的客戶端。得益于Lua解釋器極低的開銷和JIT技術(LuaJIT),用戶不用編寫復雜的C模塊就能獲得極高的吞吐性
能。也可以動態更改邏輯,不用再重新編譯Nginx代碼,從而帶來了極大的靈活性。
Lua模塊在初始化時為每個Nginx工作進程創建一個Lua/LuaJIT實例(LuaVM),同一進程處理的所有請求將共享該實例
,并且Lua模塊將用戶Lua代碼包裝為協程工廠緩存在Nginx內,一個請求到來時協程工廠為它分配一個獨立協程來運行業務邏輯。在需要進行阻塞的I/O操作時,Lua模塊自動將I/O操作委托給Nginx的事件處理模型,并保存正在運行的協程上下文,返回到Nginx工作進程中處理其他請求,等到I/O操作完成時,又會恢復該協程繼續運行。
5)動態模塊支持
Tengine中加入了動態模塊功能,對模塊實現了動態編譯,加入模塊不再需要靜態編譯整個Tengine代碼。使用方法類似Apache,在使用時可以當場
動態編譯想加人的模塊,非常方便。
- 1.我們提供類似apxs的編譯工具,將模塊編譯成動態鏈接庫。
- 2.在Tengine啟動時通過
動態鏈接庫
讀入模塊的模塊結構體,這個結構體包含了模塊處理的所有信息。- 3.Tengine有內置的模塊加載順序表,也可在配置文件中顯式的指定模塊的加載順序,保證模塊加載順序正常。
- 4.Tengine內部通過兩個版本號(Major和Minor)來控制動態鏈接庫(.so文件)的前后兼容性。當Major版本號相同時,較新版本的Tengine兼容較舊版本的.so文件(Tengine的Minor大于.so文件)。只有當Tengine的API發生重大變化時,Major的版本號才發生變化。增加新的API只會增加Minor版本號。
2.3 Tengine-Ingress 高性能高可用的云原生網關架構
三、部署配置
3.1 編譯安裝
yum -y install gcc pcre-devel openssl-devel
useradd -r -s /sbin/nologin nginx
#下載源碼包編譯
cd /usr/local/src
wget https://tengine.taobao.org/download/tengine-2.4.1.tar.gz
md5sum tengine-2.4.1.tar.gz #8a3c754741539723af977246dfb260dd
tar xf tengine-2.4.1.tar.gz
cd tengine-2.4.1/
#或
git clone https://github.com/alibaba/tengine.git
cd tengine./configure --prefix=/usr/local/tengine-2.4.1 --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcremake && make install
ln -s /usr/local/tengine-2.4.1/sbin/* /usr/sbin/
#啟動
nginx#動態添加 Lua 模塊
yum -y install lua-devel
./configure --prefix=/usr/local/tengine-2.4.1 --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-http_lua_module=shared
#將動態模塊的so文件拷貝到目標目錄,這個目錄可以通過'--dso-path'設置。默認是在Tengine安裝目錄下面的modules目錄
make dso_install
#或如下這樣簡化生產動態模塊,--add-dynamic-module 參數編譯模塊
./configure --add-dynamic-module=/path/to/module
make modules
#更新配置文件以加載 Lua 模塊,生成的動態模塊文件通常位于 objs/ 目錄下
vim /usr/local/tengine-2.4.1/conf/nginx.conf #如下所示
dso {load ngx_http_lua_module.so;
}
#或配置文件中使用 load_module 指令加載模塊:
server {listen 443 ssl http2; # 啟用 HTTP/2server_name example.com;load_module modules/ngx_http_lua_module.so;ssl_certificate /path/to/cert.pem;ssl_certificate_key /path/to/key.pem;location / {root /usr/share/nginx/html;}
}
#檢查配置并重啟 Tengine:
nginx -t
nginx -s reload#Concat 模塊:Concat 模塊用于合并多個文件在一個響應報文中,類似于 Apache 的 mod_concat 模塊。這有助于減少 HTTP 請求數量,提高網站加載速度和用戶體驗
./configure --help | grep http_concat #檢查當前tengine支持的Concat 模塊版本
#編譯
./configure --prefix=/usr/local/tengine-2.4.1 --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-http_lua_module=shared --with-http_concat_module=shared
make dso_install
#完成后,更新配置
location /static/css/ {concat on;concat_max_files 20;
}location /static/js/ {concat on;concat_max_files 30;
}
#加載
nginx -t
nginx -s reload## 查看加載模塊
tengine -V 2>&1 | grep dynamic
3.2 配置示例
worker_processes auto;
worker_rlimit_nofile 65535;
events {worker_connections 65535;
}
http {
#以備日志切割
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" '' "$http_user_agent" "$http_x_forwarded_for"';access_log /var/log/nginx/access.log main;
gzip_min_length 1k;# 負載均衡,默認輪詢:請求被依次分配給每個服務器;IP 哈希(ip_hash):根據客戶端 IP 地址分配流量,使同一 IP 的用戶訪問同一臺服務器
upstream backend {server 172.18.1.101:8080 weight=5; # 權重為5server 172.18.1.102:8080 weight=3; # 權重為3server 172.18.1.103:8080 backup; # 備用服務器
}
#或
upstream backend {ip_hash; # 啟用 IP 哈希server 172.18.1.101:8080;server 172.18.1.102:8080;
}# 開啟健康檢查,rise=2:連續檢查 2 次成功視為健康;fall=5:連續檢查 5 次失敗視為故障;timeout=1000:檢查超時時間(單位毫秒);check_http_send:發送的 HTTP 請求內容;check_http_expect_alive:期望的響應狀態碼。check interval=3000 rise=2 fall=5 timeout=1000 type=http;check_http_send "HEAD / HTTP/1.0\r\n\r\n";check_http_expect_alive http_2xx http_3xx;# 使用負載均衡
server {listen 80;location / {proxy_pass http://backend;}
}
#waf示例
location / {access_by_lua_block {#Lua 腳本實現 WAF 規則local args = ngx.req.get_uri_args()if args["id"] and tonumber(args["id"]) < 0 thenngx.exit(403)end}
}
#流量限速:限制每個 IP 的并發請求數或每秒請求數,防止惡意請求或流量突增
http {# 定義限速區域,$binary_remote_addr 表示根據客戶端 IP 地址限速,限速區域大小為 10MBlimit_req_zone $binary_remote_addr zone=req_zone:10m rate=10r/s; server {listen 80;location / {limit_req zone=req_zone burst=5; # 每秒限制 10 個請求,允許 5 個突發請求proxy_pass http://backend;}}
}#緩存加速:可以將后端服務器的響應存儲到本地磁盤或內存中,從而加速用戶的訪問
http {proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m use_temp_path=off;server {listen 80;location / {proxy_cache my_cache; # 啟用緩存proxy_cache_valid 200 302 10m; # 狀態碼 200 和 302 的內容緩存 10 分鐘proxy_cache_valid 404 1m; # 狀態碼 404 的內容緩存 1 分鐘proxy_pass http://backend;}#防盜鏈,定義允許訪問的 Referer,none:允許沒有 Referer 的請求;blocked:允許 Referer 被代理隱藏的請求。location /images/ {valid_referers none blocked *.example.com;if ($invalid_referer) {return 403;}}
}
#日志切割
vi /etc/logrotate.d/nginx #保存半年
/var/log/nginx/*.log {dailymissingokrotate 190compressdelaycompressnotifemptycreate 0640 www-data www-datasharedscriptspostrotate/usr/local/sbin/nginx -s reopenendscript
}
3.3 圖形管理工具
1)Tengine Dashboard功能
2)Prometheus監控方案+Grafana可視化面板
3)ELK日志分析方案
四、應用案例
4.1、電商場景
1)大促期間動態限流配置
upstream mall {check interval=3000 rise=2 fall=3;server 172.18.1.101:8080;
}
location ~* \.(jpg|css)$ {expires 30d;
}
2)靜態資源加速方案
4.2 金融行業
1)雙向證書校驗實現
2)敏感數據加密傳輸
3)長連接保持配置
4.3 MQTT協議支持案例
五、FAQ
1)兼容性問題
2)與原生Nginx模塊沖突處理
3)版本升級注意事項
4)性能問題
5)高并發場景優化建議
6)TIME_WAIT狀態處理
7)動態加載模塊失敗排查
8)自定義日志格式配置