OpenResty搭建高性能服務(wù)端

Socket編程

Linux Socket編程領(lǐng)域?yàn)榱颂幚泶罅窟B接請(qǐng)求場(chǎng)景张弛,需要使用非阻塞I/O和復(fù)用晾腔,select犁苏、pollepoll是Linux API提供的I/O復(fù)用方式聂儒,自從Linux2.6中加入了epoll之后虎锚,高性能服務(wù)器領(lǐng)域得到廣泛的應(yīng)用,Nignx就是使用epoll來實(shí)現(xiàn)I/O復(fù)用支持高并發(fā)衩婚。

對(duì)于“高性能”服務(wù)端而言窜护,我們所關(guān)注的并不是語言的性能,而是緩存和語言支持異步非阻塞非春。

緩存

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

  • 內(nèi)存>SSD>機(jī)械磁盤
  • 本機(jī)>網(wǎng)絡(luò)
  • 進(jìn)程內(nèi) > 進(jìn)程間

緩存系統(tǒng)的目標(biāo)是希望在進(jìn)程內(nèi)的命中率是最高的柱徙,那么此時(shí)緩存系統(tǒng)整體的效率也是最高的。

異步非阻塞

希望訪問數(shù)據(jù)庫(kù)奇昙、訪問網(wǎng)絡(luò)护侮,訪問一些比較慢的IO設(shè)備時(shí),不要在等待上耗費(fèi)大量時(shí)間储耐。而是使用事件驅(qū)動(dòng)的方式羊初,當(dāng)系統(tǒng)完成某項(xiàng)任務(wù)后再來通知我們。這樣就可以將服務(wù)器CPU的空閑資源什湘,用來服務(wù)客戶端連接长赞。

OpenResty

OpenResty是基于Ngnix和Lua的高性能web平臺(tái),內(nèi)部集成精良的LUa庫(kù)禽炬、第三方模塊涧卵、依賴項(xiàng)勤家。用于方便搭建能夠處理高并發(fā)腹尖、擴(kuò)展性極高的動(dòng)態(tài)web應(yīng)用、web服務(wù)伐脖、動(dòng)態(tài)網(wǎng)關(guān)热幔。可以使用Lua腳本調(diào)用Ngnix支持的C以及Lua模塊讼庇,快速構(gòu)建10K~1000K單機(jī)并發(fā)連接的高性能web應(yīng)用系統(tǒng)绎巨。OpenResty的目標(biāo)是讓web服務(wù)直接運(yùn)行在Nginx服務(wù)內(nèi)部,利用Ngnix的非阻塞IO模型蠕啄,對(duì)HTTP客戶端請(qǐng)求和后端DB進(jìn)行一致的高性能響應(yīng)场勤。

OpenResty的出現(xiàn)可以說是顛覆了高性能服務(wù)端的開發(fā)模式戈锻。OpenResty實(shí)際上是Nginx+LuaJIT的完美組合。

OpenResty工作方式

由于Nginx采用的是master-worker模型和媳,也就是一個(gè)master主進(jìn)程管理多個(gè)worker進(jìn)程格遭,基本的事件處理都是放在worker中,master僅負(fù)責(zé)一些全劇初始化留瞳,以及對(duì)worker的管理拒迅。在OpenResty中,每個(gè)worker使用一個(gè)LuaVM她倘,每個(gè)請(qǐng)求被分配到worker時(shí)璧微,將在這個(gè)LuaVM中創(chuàng)建一個(gè)coroutine協(xié)程。協(xié)程之間數(shù)據(jù)隔離硬梁,每個(gè)協(xié)程具有獨(dú)立的全局變量_G前硫。

Lua中的協(xié)程和多線程下的線程類似,都有自己的堆棧荧止、局部變量开瞭、指令指針...,但是和其他協(xié)程程序共享全局變量等信息罩息。線程和協(xié)程主要不同在于:多處理器的情況下嗤详,概念上來說多線程是同時(shí)運(yùn)行多個(gè)線程,而協(xié)程是通過代碼來完成協(xié)程的切換瓷炮,任何時(shí)刻只有一個(gè)協(xié)程程序在運(yùn)行葱色。并且這個(gè)在運(yùn)行的協(xié)程只有明確被要求掛起時(shí)才會(huì)被掛起。

根據(jù)實(shí)際測(cè)試娘香,OpenResty性能接近于Nginx 性能之王c module苍狰,甚至超過。

OpenResty 架構(gòu)

  • 負(fù)載均衡

LVS+HAProxy將流量轉(zhuǎn)發(fā)給核心Nginx1和Nginx2烘绽,即實(shí)現(xiàn)了流量的負(fù)載均衡淋昭。

負(fù)載均衡
  • 單機(jī)閉環(huán)

所有想要的數(shù)據(jù)都能從本服務(wù)器直接獲取,大多數(shù)時(shí)候無需通過網(wǎng)絡(luò)或去其他服務(wù)器獲取安接。

單機(jī)閉環(huán)
  • 分布式閉環(huán)

單機(jī)閉環(huán)會(huì)遇到2個(gè)主要問題

  1. 數(shù)據(jù)不一致
    例如沒有主從架構(gòu)導(dǎo)致不同服務(wù)器數(shù)據(jù)不一致

  2. 遇到存儲(chǔ)瓶頸
    磁盤或內(nèi)存遇到天花板

解決數(shù)據(jù)不一致比較好的辦法是采用主從或分布式集中存儲(chǔ)翔忽,而遇到存儲(chǔ)瓶頸就需要進(jìn)行按業(yè)務(wù)鍵進(jìn)行分片,將數(shù)據(jù)分散到多臺(tái)服務(wù)器盏檐。

分布式閉環(huán)
  • 接入網(wǎng)關(guān)

接入網(wǎng)關(guān)又叫接入層歇式,即接收流量的入口,在入口處做如下事情:

接入網(wǎng)關(guān)

OpenResty環(huán)境搭建

安裝前準(zhǔn)備胡野,必須安裝perl材失、libpcrelibssl庫(kù)硫豆。

# 從系統(tǒng)路徑中查看必備庫(kù)是否已經(jīng)安裝
$ sudo ldconfig -v

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

下載并解壓OpenResty后進(jìn)入其目錄

$ 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

默認(rèn)會(huì)被安裝到/usr/local/openresty目錄下

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

啟動(dòng)Nginx

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

Nginx啟動(dòng)若出現(xiàn)

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

說明80端口并占用龙巨,查看80端口被占用的端口并重啟笼呆。原因在于nginx先監(jiān)聽了ipv4的80端口之后又監(jiān)聽了ipv6的80端口,于是就重復(fù)占用了旨别。

$ 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工具或在瀏覽器訪問默認(rèn)80端口

$ curl 127.0.0.1

瀏覽器輸入http://127.0.0.1/

將Nginx工具配置到當(dāng)前用戶的系統(tǒng)環(huán)境變量中

$ 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)

開發(fā)文檔

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選項(xiàng)中配置lua_code_cache選項(xiàng)。

$ 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;是會(huì)引擎Nginx的性能的昼榛,在生產(chǎn)環(huán)境中是需要將其開啟的境肾。

小節(jié)

在OpenResty中開發(fā)是分為兩步的,第一步是修改Nginx配置胆屿,第二步是使用Lua開發(fā)自己的腳本奥喻。

OpenResty入門

參考資料

創(chuàng)建工作目錄

OpenResty安裝之后就有配置文件及相關(guān)目錄,為了工作目錄和安裝目錄互不干擾非迹,另外創(chuàng)建OpenResty工作目錄环鲤,并另寫配置。

$ mkdir -p ~/openresty/test/logs ~/openresty/test/conf
$ vim ~/openresty/test/conf/nginx.conf
# 設(shè)置Nginx worker工作進(jìn)程數(shù)量憎兽,即CPU核數(shù)冷离。
worker_processes 1;

# 設(shè)置錯(cuò)誤日志文件路徑
error_log logs/error.log;
# 配置Nginx服務(wù)器與用戶的網(wǎng)絡(luò)連接
events{
    # 設(shè)置每個(gè)工作進(jìn)程的最大連接數(shù)
    worker_connections 10224;
}

http{
    # 虛擬機(jī)主機(jī)塊定義
    server{
        # 監(jiān)聽端口
        listen 8001;
        # 配置請(qǐng)求的路由
        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

若代碼中出現(xiàn)錯(cuò)誤則需要直接查看Nginx的錯(cuò)誤日志進(jìn)行查看

$ 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系統(tǒng)下查看Nginx進(jìn)程

λ tasklist /fi "imagename eq nginx.exe"

映像名稱                       PID 會(huì)話名              會(huì)話#       內(nèi)存使用
========================= ======== ================ =========== ============
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
成功: 已終止進(jìn)程 "nginx.exe",其 PID 為 9072纯命。

ngx lua API

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末西剥,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子亿汞,更是在濱河造成了極大的恐慌瞭空,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疗我,死亡現(xiàn)場(chǎng)離奇詭異咆畏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)吴裤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門旧找,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人麦牺,你說我怎么就攤上這事钮蛛。” “怎么了枕面?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵愿卒,是天一觀的道長(zhǎng)缚去。 經(jīng)常有香客問我潮秘,道長(zhǎng),這世上最難降的妖魔是什么易结? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任枕荞,我火速辦了婚禮柜候,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘躏精。我一直安慰自己渣刷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布矗烛。 她就那樣靜靜地躺著辅柴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瞭吃。 梳的紋絲不亂的頭發(fā)上碌嘀,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音歪架,去河邊找鬼股冗。 笑死,一個(gè)胖子當(dāng)著我的面吹牛和蚪,可吹牛的內(nèi)容都是我干的止状。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼攒霹,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼怯疤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起催束,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤旅薄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后泣崩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體少梁,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年矫付,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凯沪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡买优,死狀恐怖妨马,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情杀赢,我是刑警寧澤烘跺,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站脂崔,受9級(jí)特大地震影響滤淳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜砌左,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一脖咐、第九天 我趴在偏房一處隱蔽的房頂上張望铺敌。 院中可真熱鬧,春花似錦屁擅、人聲如沸偿凭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)弯囊。三九已至,卻和暖如春胶果,著一層夾襖步出監(jiān)牢的瞬間常挚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工稽物, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留奄毡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓贝或,卻偏偏與公主長(zhǎng)得像吼过,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子咪奖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容