線上跑了多年的一個閘道器業務,隨著部門的拆分,逐漸有了一個痛點。該閘道器業務主要處理app端請求,app端發起的請求,採用http協定,post方法,content-type採用application/x-www-form-urlencoded
,表單中有一個固定的欄位,叫功能號,即funcNo=1000100這樣,然後表單中其他業務欄位就根據funcNo的不同而各有不同。
後端有一個接入層nginx,nginx將請求轉給一個閘道器服務進行處理,閘道器會解析出funcNo欄位。我們的funcNo欄位也是有講究的,前4位元(1000)是系統編碼,後面3位(100)是介面編號。閘道器就根據系統編碼轉發給不同的系統進行處理。
閘道器採用的技術是早起的servlet容器,容器叫resin,我之前也沒有接觸過,總之就是類似於tomcat,不過輕量一些。
說起來,這個閘道器的職責和現在流行的接入層閘道器,比如現在的spring cloud gateway等,職責也差不太多。只是早期都是組態檔那種,把後端的各個系統全都先設定好;而不像現在的閘道器,會採用動態設定。
現在有啥問題呢?每次新上一個服務,都需要在這個服務中設定新服務的系統編碼、新服務的後端ip+埠等,當然了,具體細節更加複雜,它還需要設定新服務中的各個介面編號,以及各個介面需要使用哪些filter等。
總之,這個服務的程式碼架構還是穩定的,但是設定經常需要變更。
以前,這個服務歸技術部管,後來部門拆分了,多出一個部門B,這個服務還歸技術部管;但是部門B新上服務的話,就要來找技術部對這個服務加設定,變更上線。
我們就想著,讓部門B能自己上線是最好,免得總來找我們,因此,想到的辦法就是,將這個閘道器服務再部署一套給部門B用,然後前端nginx替換為openresty,openresty根據請求中的funcNo,判斷系統編碼屬於哪個部門,然後就把請求轉發到對應的閘道器服務。
1、首先,將閘道器服務做成無狀態的,目前的閘道器,還使用了servlet session技術,是有狀態的,這一步目前已經做了修改,把使用servlet session的程式碼,換成了jwt,有待測試環境驗證,這個本篇先不講;
2、其次,開發環境模擬安裝openresty,屆時,使用openresty替換nginx。openresty相當於增強版本的nginx,可以寫lua程式碼,解析請求中的funcNo欄位,然後決定分發到哪個部門的閘道器服務。
本篇文章,主要是聚焦於第二個事情,即如何用openresty完美替換線上的nginx,說起來簡單,實則複雜,因為線上nginx執行多年,很多設定項,我們openresty屆時必須把線上nginx的設定也遷移過來才行,而且要保證功能都正常,不能說之前在nginx處理得好好的,到了openresty就不行了。
我們首先要解決的是,線上伺服器,怎麼安裝openresty的問題。
一般來說,官網都是讓你用yum這類包管理器安裝,如下:
https://openresty.org/en/installation.html提到其提供了預編譯好的版本,yum安裝即可:
OpenResty® provides official pre-built packages for some of the common Linux distributions (Ubuntu, Debian, CentOS, RHEL, Fedora, OpenSUSE, Alpine, and Amazon Linux).
但是,由於線上伺服器都是沒有外網的,你想yum安裝是不行的(要麼就是yum中的版本太老了),所以,基本是採用rpm安裝。
rpm安裝的話,那麼,如何獲取一個rpm包呢?
我們在開發環境機器上,可以利用yum來獲取rpm包。
先設定repo倉庫:
wget https://openresty.org/package/centos/openresty.repo
sudo mv openresty.repo /etc/yum.repos.d/
# update the yum index:
sudo yum check-update
然後,我們不執行yum install openresty
,而是執行如下命令,將rpm包下載到指定目錄:
yum install --downloadonly --downloaddir=/root/mypackage/ openresty
下載的結果如下:
[root@server172 openresty-1.21.4.1]# ls /root/mypackage/*.rpm
/root/mypackage/openresty-1.21.4.1-1.el7.x86_64.rpm
/root/mypackage/openresty-pcre-8.45-1.el7.x86_64.rpm
/root/mypackage/openresty-openssl111-1.1.1s-1.el7.x86_64.rpm
/root/mypackage/openresty-zlib-1.2.13-1.el7.x86_64.rpm
下載了rpm後,進行rpm安裝:
cd /root/mypackage
rpm -ivh openresty-*
預設安裝目錄即在/usr/local/openresty
下:
可以看到,其中在bin目錄下建立了一個連結檔案openresty,連結到openresty下的nginx可執行檔案,這裡也可以看出,openresty是基於nginx的增強。
我們執行下openresty -V,檢視這種安裝方式下的編譯選項:
格式化之後,如下:
[root@server172 openresty]# openresty -V
nginx version: openresty/1.21.4.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
built with OpenSSL 1.1.1n 15 Mar 2022 (running with OpenSSL 1.1.1s 1 Nov 2022)
TLS SNI support enabled
configure arguments: --prefix=/usr/local/openresty/nginx
--with-cc-opt='-O2 -DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/zlib/include -I/usr/local/openresty/pcre/include
-I/usr/local/openresty/openssl111/include'
--add-module=../ngx_devel_kit-0.3.1
--add-module=../echo-nginx-module-0.62
--add-module=../xss-nginx-module-0.06
--add-module=../ngx_coolkit-0.2
--add-module=../set-misc-nginx-module-0.33
--add-module=../form-input-nginx-module-0.12
--add-module=../encrypted-session-nginx-module-0.09
--add-module=../srcache-nginx-module-0.32
--add-module=../ngx_lua-0.10.21
--add-module=../ngx_lua_upstream-0.07
--add-module=../headers-more-nginx-module-0.33
--add-module=../array-var-nginx-module-0.05
--add-module=../memc-nginx-module-0.19
--add-module=../redis2-nginx-module-0.15
--add-module=../redis-nginx-module-0.3.9
--add-module=../ngx_stream_lua-0.0.11
--with-ld-opt='-Wl,-rpath,/usr/local/openresty/luajit/lib
-L/usr/local/openresty/zlib/lib -L/usr/local/openresty/pcre/lib
-L/usr/local/openresty/openssl111/lib -Wl,-rpath,/usr/local/openresty/zlib/lib:/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl111/lib'
--with-cc='ccache gcc -fdiagnostics-color=always'
--with-pcre-jit
--with-stream
--with-stream_ssl_module
--with-stream_ssl_preread_module
--with-http_v2_module
--without-mail_pop3_module
--without-mail_imap_module
--without-mail_smtp_module
--with-http_stub_status_module
--with-http_realip_module
--with-http_addition_module
--with-http_auth_request_module
--with-http_secure_link_module
--with-http_random_index_module
--with-http_gzip_static_module
--with-http_sub_module
--with-http_dav_module
--with-http_flv_module
--with-http_mp4_module
--with-http_gunzip_module
--with-threads
--with-compat
--with-stream
--with-http_ssl_module
但是,我們還是不能用rpm方式安裝,因為,因為目前在跑的nginx,我支援是支援ipv6的,而上面rpm安裝的這個openresty,沒看到ipv6的選項啊。這種安裝方式,好像也沒辦法再去增加對其他模組的支援,如ipv6.
那隻能利用原始碼方式來安裝了。
要編譯,得拿到編譯選項,等到運維同事有空後,終於拿到了線上nginx的設定:
線上一共兩臺nginx機器,在第一臺執行nginx -V檢視設定:
nginx version: nginx/1.16.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC)
built with OpenSSL 1.1.1d 10 Sep 2019
TLS SNI support enabled
configure arguments: --prefix=/opt/software/nginx --with-http_stub_status_module --with-stream --with-http_ssl_module --with-http_realip_module --with-ipv6 --add-module=./nginx-http-concat-master --with-openssl=/opt/software/openssl-1.1.1d --with-pcre=/opt/software/pcre-8.10
第二臺執行後,檢視設定:
nginx version: nginx/1.12.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC)
built with OpenSSL 1.0.2k 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/opt/software/nginx --with-http_stub_status_module --with-stream --with-http_ssl_module --with-http_realip_module --add-module=./nginx-http-concat-master --with-openssl=/opt/software/openssl-1.0.2k --with-pcre=/opt/install/pcre-8.10
兩臺的差別,主要是:
nginx版本不一致
--with-openssl中ssl路徑不同
第一臺多了--with-ipv6選項
ok,編譯選項拿到了,接下來,就開始準備原始碼編譯。
先下載openresty原始碼包(自己在官網看檔案找):
wget https://openresty.org/download/openresty-1.21.4.1.tar.gz
tar -xvf openresty-1.21.4.1.tar.gz
cd openresty-1.21.4.1/
另外,由於線上nginx的如下編譯選項還依賴了openssl、pcre、nginx-http-concat-maste等,而當時也沒注意要運維同事幫我們把這些線上目錄拿下來,所以,我們還要在網上找下這些模組的原始碼。
--add-module=./nginx-http-concat-master --with-openssl=/opt/software/openssl-1.0.2k --with-pcre=/opt/install/pcre-8.10
新增的第三方模組原始碼:
openssl:
wget --no-check-certificate https://www.openssl.org/source/openssl-1.1.1d.tar.gz
tar -zxvf openssl-1.1.1d.tar.gz
解壓後存放到:
/root/mypackage/openresty-source/openssl-1.1.1d
pcre:
wget https://sourceforge.net/projects/pcre/files/pcre/8.10/pcre-8.10.tar.gz/download --no-check-certificate
tar -zxvf pcre-8.10.tar.gz
解壓後存放到:
/root/mypackage/openresty-source/pcre-8.10
nginx-http-concat:
https://github.com/alibaba/nginx-http-concat
/root/mypackage/openresty-source/nginx-http-concat-master
解壓後存放到:
/root/mypackage/openresty-source/nginx-http-concat-master
準備好上面的依賴模組後,編輯好下面的命令:
./configure --with-http_stub_status_module --with-stream --with-http_ssl_module --with-http_realip_module --with-ipv6 --with-openssl=/root/mypackage/openresty-source/openssl-1.1.1d --with-pcre=/opt/software/pcre-8.10 --add-module=/root/mypackage/openresty-source/nginx-http-concat-master
configure完成後,發現:
其中提示--with-ipv6
選項已經過期,這個不影響,因為nginx的高版本已經預設開啟了ipv6。
那是不是意味著直接用rpm的方式安裝也可以呢,這個呢,反正就是看rpm方式安裝出來的nginx -V的編譯選項,到底是不是包含了線上nginx的全部選項,如果是的話,也可以。我這邊就還是用原始碼方式算了,更靈活一些。
執行make,可能需要等待幾分鐘
make
make完成後,make install即可。
make install
完成後,即在/opt/software/openresty
目錄下安裝好了,切換到bin目錄下,裡面有可執行openresty,其實就是個指向/opt/software/openresty/nginx/sbin/nginx
的軟連線。
這一步的大體思路,就是找運維同事拿到線上的nginx設定,然後根據這份設定,來修改openresty的設定。
這塊有個簡單的方式,使用beyond compare進行對比(nginx.conf),看看有哪些差異,然後設定成和線上一致,測試openresty即可。
原始檔就不看了,這裡說下看到的陌生的設定。看到nginx.conf裡http塊下有:
#設定監控nginx狀態URL
location /__nginxstatus
{
stub_status on;
access_log off;
}
請求這個介面,發現響應如下:
看起來,就是一些狀態資訊,不知道是拿來幹啥的,難道是健康監測?
我網上查了下,原來這個不是nginx預設模組,是需要在configure的時候,使用如下模組才有的:
./configure --with-http_stub_status_module
參考檔案如下:
http://nginx.org/en/docs/http/ngx_http_stub_status_module.html
https://blog.redis.com.cn/doc/index.html
https://blog.redis.com.cn/doc/optional/stubstatus.html
這個模組也線上上nginx的configure中出現了。
這個模組的作用是,有時候nginx是部署在l5這類硬體負載均衡軟體後的,nginx正常獲取使用者端ip的話,那可能就拿到的是l5的ip,要怎麼獲取真實使用者端的ip呢?
一般l5這種,會在請求nginx時,往header里加一個X-Real-IP
或者X-Forwarded-For
這樣的header,裡面的value就是使用者端的真實ip。
所以,nginx啟用這個模組後,就會從這些header裡獲取使用者端ip。
http://nginx.org/en/docs/http/ngx_http_realip_module.html
https://blog.redis.com.cn/doc/optional/realip.html
這個模組在configure裡有,是淘寶開發的,https://github.com/alibaba/nginx-http-concat。
用途是,當nginx作為一個靜態檔案伺服器時,如使用者端請求1.js、2.js,就會是兩個請求和響應,當檔案多的時候,比較耗效能。
所以,nginx開啟這個模組後,支援如下方式存取:http://host:80/??1.js,2.js,此時,該模組就可以一把拿到1.js、2.js,合併後返回給使用者端。
效果如下(來自於https://blog.csdn.net/qq_34556414/article/details/105892602):
# curl http://www.ttlsa.com/static/??css/ttlsa_concat.css,css/a.css
/** this is css ttlsa_concat.css **/
/** this is css a.css *
但我在組態檔中,沒找到相關的設定項,不知道是不是線上從未使用過這個功能。
#開啟SSL支援
ssl on;
ssl_certificate test.crt;
ssl_certificate_key test.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssi on;
ssi_silent_errors on;
ssi_types text/shtml;
應該是沒在使用了,老掉牙的技術了,有興趣隨便看看:
https://blog.csdn.net/qq_33616529/article/details/79061608
https://cloud.tencent.com/developer/article/1915087
gzip on;
gzip_min_length 1K;
gzip_buffers 4 8k;
gzip_types text/* text/css application/javascript application/x-javascript application/xml;
gzip_comp_level 9;
gzip_proxied any;
gzip_vary on;
gzip_http_version 1.1;
參考檔案:
http://nginx.org/en/docs/http/ngx_http_gzip_module.html
這部分就主要包括,https驗證、功能驗證,具體就不展開了,和業務強相關。如果一切驗證ok,就可以準備上線了。