天天看點

OpenResty搭建高性能服務端【轉】

Socket程式設計

Linux Socket程式設計領域為了處理大量連接配接請求場景,需要使用非阻塞I/O和複用,​

​select​

​、​

​poll​

​epoll​

​是Linux API提供的I/O複用方式,自從Linux2.6中加入了epoll之後,高性能伺服器領域得到廣泛的應用,Nignx就是使用​

​epoll​

​來實作I/O複用支援高并發。

對于“高性能”服務端而言,我們所關注的并不是語言的性能,而是緩存和語言支援異步非阻塞。

緩存

針對緩存要明白通信速度的快慢順序

  • 記憶體>SSD>機械磁盤
  • 本機>網絡
  • 程序内 > 程序間

緩存系統的目标是希望在程序内的命中率是最高的,那麼此時緩存系統整體的效率也是最高的。

異步非阻塞

希望通路資料庫、通路網絡,通路一些比較慢的IO裝置時,不要在等待上耗費大量時間。而是使用事件驅動的方式,當系統完成某項任務後再來通知我們。這樣就可以将伺服器CPU的空閑資源,用來服務用戶端連接配接。

OpenResty

OpenResty是基于Ngnix和Lua的高性能web平台,内部內建精良的LUa庫、第三方子產品、依賴項。用于友善搭建能夠處理高并發、擴充性極高的動态web應用、web服務、動态網關。可以使用Lua腳本調用Ngnix支援的C以及Lua子產品,快速建構10K~1000K單機并發連接配接的高性能web應用系統。OpenResty的目标是讓web服務直接運作在Nginx服務内部,利用Ngnix的非阻塞IO模型,對HTTP用戶端請求和後端DB進行一緻的高性能響應。

OpenResty的出現可以說是颠覆了高性能服務端的開發模式。OpenResty實際上是Nginx+LuaJIT的完美組合。

OpenResty搭建高性能服務端【轉】

OpenResty工作方式

由于Nginx采用的是​

​master-worker​

​模型,也就是一個​

​master​

​主程序管理多個​

​worker​

​程序,基本的事件處理都是放在​

​worker​

​中,​

​master​

​僅負責一些全劇初始化,以及對​

​worker​

​的管理。在OpenResty中,每個​

​worker​

​使用一個LuaVM,每個請求被配置設定到​

​worker​

​時,将在這個​

​LuaVM​

​中建立一個​

​coroutine​

​協程。協程之間資料隔離,每個協程具有獨立的全局變量​

​_G​

​。

Lua中的協程和多線程下的線程類似,都有自己的堆棧、局部變量、指令指針...,但是和其他協程程式共享全局變量等資訊。線程和協程主要不同在于:多處理器的情況下,概念上來說多線程是同時運作多個線程,而協程是通過代碼來完成協程的切換,任何時刻隻有一個協程程式在運作。并且這個在運作的協程隻有明确被要求挂起時才會被挂起。

根據實際測試,OpenResty性能接近于Nginx 性能之王c module,甚至超過。

OpenResty 架構

  • 負載均衡

LVS+HAProxy将流量轉發給核心Nginx1和Nginx2,即實作了流量的負載均衡。

OpenResty搭建高性能服務端【轉】
  • 單機閉環

所有想要的資料都能從本伺服器直接擷取,大多數時候無需通過網絡或去其他伺服器擷取。

OpenResty搭建高性能服務端【轉】
  • 分布式閉環

單機閉環會遇到2個主要問題

  1. 資料不一緻

    例如沒有主從架構導緻不同伺服器資料不一緻

  2. 遇到存儲瓶頸

    磁盤或記憶體遇到天花闆

解決資料不一緻比較好的辦法是采用主從或分布式集中存儲,而遇到存儲瓶頸就需要進行按業務鍵進行分片,将資料分散到多台伺服器。

OpenResty搭建高性能服務端【轉】
  • 接入網關

接入網關又叫接入層,即接收流量的入口,在入口處做如下事情:

OpenResty搭建高性能服務端【轉】

OpenResty環境搭建

  • ​​http://openresty.org​​
  • ​​http://openresty.org/cn/download.html​​

安裝前準備,必須安裝​

​perl​

​libpcre​

​libssl​

​庫。

# 從系統路徑中檢視必備庫是否已經安裝
$ sudo ldconfig -v

# 安裝必備庫
$ sudo apt install libpcre3-dev libssl-dev perl make build-essential curl libreadline-dev libncurses5-dev
      

下載下傳并解壓OpenResty後進入其目錄

$ wget https://openresty.org/download/ngx_openresty-1.13.6.1.tar.gz
$ tar -zxvf ngx_openresty-1.13.6.1.tar.gz
$ mv openresty-1.13.6.1 openresty
$ cd openresty
$ ./configure
      

預設會被安裝到​

​/usr/local/openresty​

​目錄下

# 編譯并安裝
$ sudo make && make install
$ cd /usr/local/openresty
      

啟動Nginx

$ sudo /usr/local/openresty/nginx/sbin/nginx
$ ps -ef | grep nginx
$ service nginx status
      

Nginx啟動若出現

nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] still could not bind()
      

說明80端口并占用,檢視80端口被占用的端口并重新開機。原因在于nginx先監聽了ipv4的80端口之後又監聽了ipv6的80端口,于是就重複占用了。

$ sudo netstat -ntlp | grep 80
$ sudo killall -9 nginx
      

重新編輯Nginx配置檔案

$ sudo vim /etc/nginx/conf/nginx.conf

listen 80;
listen [::]:80 ipv6only=on default_server;
      

使用​

​curl​

​工具或在浏覽器通路預設80端口

$ curl 127.0.0.1
      

浏覽器輸入​

​http://127.0.0.1/​

将Nginx工具配置到目前使用者的系統環境變量中

$ sudo vim ~/.bashrc
export PATH=$PATH:/usr/local/openresty/nginx/sbin
$ source ~./bashrc
$ cd ~
$ nginx -s reload
nginx: [alert] kill(12267, 1) failed (1: Operation not permitted)
      

開發文檔

  • ​​https://www.nginx.com/resources/wiki/modules/lua/​​

ubuntu 安裝 vcode 或 sublime text 編輯器

content_by_lua

$ vim /usr/local/openresty/nginx/conf/nginx.conf
location /test {
  default_type text/html;
  content_by_lua 'ngx.say("hello openresty")';
}

# 重新開機Nginx
$ /usr/local/openresty/nginx/sbin/nginx -s reload

# 浏覽器通路 127.0.0.1/test
      

content_by_lua_file

$ vim nginx.conf
location /test {
  content_by_lua_file 'html/test.lua';
}
$ vim ../html/test.lua
ngx.say("hello lua")
$ sudo /usr/local/nginx/sbin/nginx -s reload
$ curl 127.0.0.1/test
hello lua
      

為避免每次修改都需要重新開機Nginx,可在Nginx的​

​server​

​選項中配置​

​lua_code_cache​

​選項。

$ vim nginx.conf
server{
  lua_code_cache off;
  location /test{
    content_by_lua_file 'html/test.lua';
  }
}
$ sudo /usr/local/openresty/nginx/sbin/nginx -s reload
nginx: [alert] lua_code_cache is off; this will hurt performance in /usr/local/openresty/nginx/conf/nginx.conf:48
      

注意​

​lua_code_cache off;​

​是會引擎Nginx的性能的,在生産環境中是需要将其開啟的。

小節

在OpenResty中開發是分為兩步的,第一步是修改Nginx配置,第二步是使用Lua開發自己的腳本。

OpenResty入門

參考資料

  • ​​OpenResty最佳實踐​​
  • ​​Nginx Lua​​

建立工作目錄

OpenResty安裝之後就有配置檔案及相關目錄,為了工作目錄和安裝目錄互不幹擾,另外建立OpenResty工作目錄,并另寫配置。

$ mkdir -p ~/openresty/test/logs ~/openresty/test/conf
$ vim ~/openresty/test/conf/nginx.conf
# 設定Nginx worker工作程序數量,即CPU核數。
worker_processes 1;

# 設定錯誤日志檔案路徑
error_log logs/error.log;
# 配置Nginx伺服器與使用者的網絡連接配接
events{
# 設定每個工作程序的最大連接配接數
    worker_connections 10224;
}

http{
# 虛拟機主機塊定義
    server{
# 監聽端口
        listen 8001;
# 配置請求的路由
        location /{
            default_type text/html;
            content_by_lua_block{
                ngx.say("hello world");
            }
        }
    }
}
$ nginx -p ~/openresty/test
$ curl 127.0.0.1:8001
hello world
      
$ vim nginx.conf
location /test{
  content_by_lua_file "lua/test.lua";
}
$ cd .. && mkdir lua && cd lua
$ vim test.lua
local args = ngx.req.get_uri_args()
local salt = args.salt
if not salt then
  ngx.exit(ngx.HTTP_BAD_REQUEST)
end
local md5str = ngx.md5(ngx.time()..salt)
ngx.say(md5str)

$ sudo /usr/local/openresty/nginx/sbin/nginx -s reload
$ curl -i 127.0.0.1/test?salt=lua
HTTP/1.1 200 OK
Server: openresty/1.13.6.2
Date: Sun, 27 Jan 2019 10:07:17 GMT
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Connection: keep-alive

b55b77f75e46b96b11778ca7edfe8d55
      

若代碼中出現錯誤則需要直接檢視Nginx的錯誤日志進行檢視

$ vim nginx/logs/error.log
2019/01/27 17:37:15 [error] 15764#0: *6 failed to load external Lua file "/usr/local/openresty/nginx/test.lua": cannot open /usr/local/openresty/nginx/test.lua: No such file or...
      

Windows系統下檢視Nginx程序

λ tasklist /fi "imagename eq nginx.exe"

映像名稱                       PID 會話名              會話#       記憶體使用
========================= ======== ================ =========== ============
nginx.exe                     9072 Console                    1      7,840 K
nginx.exe                     7692 Console                    1     12,304 K
nginx.exe                     8120 Console                    1      7,840 K
nginx.exe                     4552 Console                    1     12,188 K
nginx.exe                     9588 Console                    1      7,828 K
nginx.exe                     6256 Console                    1     12,216 K
nginx.exe                     7308 Console                    1      7,828 K
nginx.exe                    10192 Console                    1     12,212 K

λ taskkill /im nginx.exe /f
成功: 已終止程序 "nginx.exe",其 PID 為 9072。
      

ngx lua API

繼續閱讀