亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 操作系統 > 正文

OpenResty(nginx+lua)入門

2024-06-28 14:32:10
字體:
來源:轉載
供稿:網友

OpenResty 官網:http://openresty.org/

OpenResty 是一個nginx和它的各種三方模塊的一個打包而成的軟件平臺。最重要的一點是它將lua/luajit打包了進來,使得我們可以使用lua腳本來進行web的開發。有了lua,我們可以借助于nginx的異步非阻塞的功能,達到使用 lua 異步并發訪問后端的 MySQL, PostgreSQL, Memcached, Redis等等服務。特別是特有的 ngx.location.capture_multi 功能讓人印象深刻,其可以達到極大的減少瀏覽器的http連接數量,并且可以異步并發的訪問后臺 java/php/Python 等等接口。OpenResty 架構的web可以輕松超越Node.js的性能,并且對后端語言沒有限制,你可以使用Java/PHP/Python等等各種語言。OpenResty(nginx+lua)可以替代node.js的前端渲染的功能。

OpenResty (aka. ngx_openresty) is a full-fledged web application server by bundling the standard Nginx core, lots of 3rd-party Nginx modules, as well as most of their external dependencies.

By taking advantage of various well-designed Nginx modules, OpenResty effectively turns the nginx server into a powerful web app server, in which the web developers can use the Lua PRogramming language to script various existing nginx C modules and Lua modules and construct extremely high-performance web applications that are capable to handle 10K+ connections.

OpenResty aims to run your server-side web app completely in the Nginx server, leveraging Nginx's event model to do non-blocking I/O not only with the HTTP clients, but also with remote backends like MySQL, PostgreSQL, Memcached, and Redis.

1. 安裝OpenResty

先安裝依賴:yum install readline-devel pcre-devel openssl-devel gcc

解壓: tar zxvf ngx_openresty-1.9.3.1.tar.gz

建立一個軟連接:ln -s ngx_openresty-1.9.3.1 openresty

進入目錄:cd openresty

編譯:

./configure /             --with-cc-opt="-I/usr/local/include" /             --with-ld-opt="-L/usr/local/lib" /             --prefix=/opt/openresty 

... ...
Configuration summary
  + using system PCRE library
  + using system OpenSSL library
  + md5: using OpenSSL library
  + sha1: using OpenSSL library
  + using system zlib library

  nginx path prefix: "/opt/openresty/nginx"
  nginx binary file: "/opt/openresty/nginx/sbin/nginx"
  nginx configuration prefix: "/opt/openresty/nginx/conf"
  nginx configuration file: "/opt/openresty/nginx/conf/nginx.conf"
  nginx pid file: "/opt/openresty/nginx/logs/nginx.pid"
  nginx error log file: "/opt/openresty/nginx/logs/error.log"
  nginx http access log file: "/opt/openresty/nginx/logs/access.log"
  nginx http client request body temporary files: "client_body_temp"
  nginx http proxy temporary files: "proxy_temp"
  nginx http fastcgi temporary files: "fastcgi_temp"
  nginx http uwsgi temporary files: "uwsgi_temp"
  nginx http scgi temporary files: "scgi_temp"

其中 --prefix=/opt/openresty 指定了安裝目錄,不指定的話默認會安裝到 /usr/local/openresty 目錄下。

編譯安裝: make && make install

[root@localhost src]# cd /opt/openresty/[root@localhost openresty]# lsbin  luajit  lualib  nginx

可以看到 /opt/openresty 目錄下四個文件夾,其中包括了 luajit,nginx。

啟動openresty: /opt/openresty/nginx/sbin/nginx -c /opt/openresty/nginx/conf/nginx.conf -p /opt/openresty/nginx/

[root@localhost src]# ps -elf|grep nginx1 S root      2076     1  0  80   0 - 34999 -      21:24 ?        00:00:00 nginx: master process /opt/openresty/nginx/sbin/nginx -c /opt/openresty/nginx/conf/nginx.conf -p /opt/openresty/nginx/5 S nobody    2077  2076  0  80   0 - 35045 -      21:24 ?        00:00:00 nginx: worker process                                    0 S root      2079  1678  0  80   0 -  1088 -      21:24 pts/1    00:00:00 grep nginx

驗證可以訪問: curl 127.0.0.1

2. content_by_lua 和 content_by_lua_file

nginx 如何嵌入 lua 腳本。方法就是在nginx的配置文件nginx.conf 中使用 content_by_lua 或者 cotent_by_lua_file 指令:

1) content_by_lua 一般在很簡單的lua腳本時使用:

        location /lua {                set $test "hello, world.";                content_by_lua '                        ngx.header.content_type = "text/plain";                        ngx.say(ngx.var.test);                ';        }

訪問 http://localhost/lua 可以看到輸出到頁面的  hello, world.

2)cotent_by_lua_file 適應于復雜的 lua 腳本,專門放入一個文件中:

        location /lua2 {            #lua_code_cache off;            content_by_lua_file lua/hello.lua;        }

路徑相對于 /opt/openresty/nginx

[root@localhost lua]# pwd/opt/openresty/nginx/lua[root@localhost lua]# cat hello.luangx.say('hello ngx_lua!!!!');

本例子中 hello.lua 只包含一句: ngx.say('hello ngx_lua!!!!');

訪問 /lua2 :

[root@localhost lua]# curl localhost/luahello ngx_lua!!!!

可以看到訪問成功。

在 nginx.conf 文件的 server {.. ...} 中加入 lua_code_cache off; 可以方便調試lua腳本,修改lua腳本之后,不需要 reload nginx.

openresty 中的 nginx 嵌入 luajit 的原理:

每一個nginx的進程中都嵌入了一個 luajit的虛擬機,來執行lua腳本。nginx將lua腳本的執行交給了luajit vm.

3. ngx_lua 的指令 和 API

上面我們說到 nginx 嵌入 lua 腳本可以使用 content_by_lua 和 content_by_lua_file,它們其實是指令(Directives),類似的指令還有很多,

具體參見:https://www.nginx.com/resources/wiki/modules/lua/#directives

這些指令都是 nginx 訪問 lua 腳本的入口。

ngx_lua API:

指令是 nginx 訪問 lua 腳本的入口。那么lua腳本如何調用nginx中的函數呢?就是通過 ngx_lua 的API 。

具體介紹參見:https://www.nginx.com/resources/wiki/modules/lua/#nginx-api-for-lua

The various *_by_lua and *_by_lua_file configuration directives serve as gateways to the Lua API within the nginx.conf file. The NGINX Lua API described below can only be called within the user Lua code run in the context of these configuration directives.

The API is exposed to Lua in the form of two standard packages ngx and ndk. These packages are in the default global scope within ngx_lua and are always available within ngx_lua directives.

其實nginx和Lua的交互開發主要就是指令和API,當然還有lua腳本的語法。指令是nginx訪問lua的入口,API是lua調用nginx的函數,lua是腳本編程語言。

指令其實很簡單,所以主要就是熟悉ngx_lua的 API 和Lua語法。

4. lua 訪問 redis

lua-resty-redis 模塊:https://github.com/openresty/lua-resty-redis (有文檔可以參考)

在nginx.conf中加入:

        location /redis_test{            content_by_lua_file lua/redis_test.lua;        }

redis_test.lua 內容:

[root@localhost lua]# cat redis_test.lualocal redis = require "resty.redis"local red = redis:new()red:set_timeout(1000)local ok, err = red:connect("127.0.0.1", 6379)if not ok then        ngx.say("failed to connect: ", err)        returnendngx.say("set result: ", ok)local res, err = red:get("dog")if not res then        ngx.say("failed to get doy: ", err)        returnendif res == ngx.null then        ngx.say("dog not found.")        returnendngx.say("dog: ", res)[root@localhost lua]#

訪問:

[root@localhost lua]# curl localhost/redis_testset result: 1dog: an animal[root@localhost lua]#

我們看到訪問成功。

5. lua 訪問mysql

openresty的mysql模塊:lua-resty-mysql :https://github.com/openresty/lua-resty-mysql(有文檔可以參考)

在nginx.conf加入如下配置:

        location /mysql_test {            content_by_lua_file lua/mysql_test.lua;        }

mysql_test.lua腳本內容:

[root@localhost lua]# pwd/opt/openresty/nginx/lua[root@localhost lua]# cat mysql_test.lualocal mysql = require "resty.mysql"local db, err = mysql:new()if not db then        ngx.say("failed to instantiate mysql: ", err)        returnenddb:set_timeout(1000)local ok, err, errno, sqlstate = db:connect{        host = "127.0.0.1",        port = 3306,        database = "ngx_lua",        user = "root",        passWord="digdeep",        max_packet_size = 1024 * 1024}if not ok then        ngx.say("failed to connect: ", err, ": ", errno, " ", sqlstate)        returnendngx.say("connected to mysql.")local res, err, errno, sqlstate = db:query("drop table if exists cats")if not res then        ngx.say("bad result: ", err, ": ", errno, ": ", sqlstate, ".")        returnendres, err, errno, sqlstate = db:query("create table cats " .. "(id int not null primary key auto_increment, "                                        .. "name varchar(30))")if not res then        ngx.say("bad result: ", err, ": ", errno, ": ", sqlstate, ".")        returnendngx.say("table cats created.")res, err, errno, sqlstate = db:query("insert into cats(name) " .. "values (/'Bob/'),(/'/'),(null)")if not res then        ngx.say("bad request: ", err, ": ", errno, ": ", sqlstate, ".")        returnendngx.say(res.affected_rows, " rows inserted into table cats ", "(last insert id: ", res.insert_id, ")")res, err, errno, sqlstate = db:query("select * from cats order by id asc", 10)if not res then        ngx.say("bad result ", err, ": ", errno, ": ", sqlstate, ".")        returnendlocal cjson = require "cjson"ngx.say("result: ", cjson.encode(res))local ok, err = db:set_keepalive(1000, 100)if not ok then        ngx.say("failed to set keepalive: ", err)        returnend

測試:

[root@localhost lua]# curl localhost/mysql_testconnected to mysql.table cats created.3 rows inserted into table cats (last insert id: 1)result: [{"name":"Bob","id":1},{"name":"","id":2},{"name":null,"id":3}]

測試通過。

5. lua 的 capture 和 capture_multi(子查詢)

capture_multi 是 openresty 一個十分強大的功能。它能極大的減少前端瀏覽器發送的http請求的數量,突破了瀏覽器對于同一個服務器并發請求數量的限制,因為他可以將前端的多個http請求減少為只要一個http請求到nginx,然后nginx使用capture_multi特性,對后端發起多個異步并發請求,然后統一將結果返回給前端。下面看一個例子:

首先在nginx.conf中加入下面的 location 配置,并且配置好 nginx 訪問 php 的配置:

        location /capture {            content_by_lua_file lua/capture.lua;            #access_by_lua_file lua/capture.lua;        }        location ~ /.php$ {            root           html;            fastcgi_pass   127.0.0.1:9000;            fastcgi_index  index.php;            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;            include        fastcgi_params;        }

capture.lua 的代碼如下:

[root@localhost lua]# pwd/opt/openresty/nginx/lua[root@localhost lua]# cat capture.lualocal res1,res2,res3,res4 = ngx.location.capture_multi{        {"/mysql_test", {args="t=1&id=1"}},        {"/redis_test", {args="t=2&id=2"}},        {"/lua", {args="t=3&id=3"}},        {"/index.php", {args="t=3&id=3"}},}ngx.header.content_type="text/plain"ngx.say(res1.body)ngx.say(res2.body)ngx.say(res3.body)ngx.say(res4.truncated)ngx.say(res4.status)ngx.say(res4.header["Set-Cookie"])--ngx.say(res4.body)

index.php 代碼:

[root@localhost html]# pwd/opt/openresty/nginx/html[root@localhost html]# cat index.php<?php        echo phpinfo();?>

訪問:

[root@localhost html]# curl localhost/captureconnected to mysql.table cats created.3 rows inserted into table cats (last insert id: 1)result: [{"name":"Bob","id":1},{"name":"","id":2},{"name":null,"id":3}]set result: 1dog: an animalhello ngx_lua!!!!false200nil

可以看到訪問成功了。/mysql_test,/redis_test, /lua, /index.php 四個請求的結果都輸出了。

注意:

ngx.location.capture_multi{... ...} 中的多個異步并發請求可以是 nginx.conf 中配置的 location(比如 /mysql_test, /redis_test, /lua),也可以不是 location配置的路徑,比如 index.php 就不是。index.php 就是一個簡單的后臺php 腳本。當然也可以是一個 java 實現的后臺接口。

6. openresty的緩存 lua_shared_dict

定義一個緩存:

在nginx的配置文件 nginx.conf 的 http 端下面加入指令:

lua_shared_dict ngx_cache 128m;

就定義了一個 名稱為 ngx_cache 大小為128m的內存用于緩存,注意該緩存是所有nginx work process所共享的。

在lua腳本中訪問緩存:

local ngx_cache = ngx.shared.ngx_cachelocal value = ngx_cache:get(key)local succ, err, forcible = ngx_cache:set(key, value, exptime)

下面測試一下,首先在 nginx.conf的server端中加入:

        location /cache {            content_by_lua_file lua/cache.lua;        }

然后編寫 cache.lua 腳本:

[root@localhost lua]# cat cache.lualocal redis = require "resty.redis"local red = redis:new()function set_to_cache(key, value, exptime)        if not exptime then                exptime = 0        end        local ngx_cache = ngx.shared.ngx_cache        local succ, err, forcible = ngx_cache:set(key, value, exptime)        return succendfunction get_from_cache(key)        local ngx_cache = ngx.shared.ngx_cache;        local value = ngx_cache:get(key)        if not value then                value = get_from_redis(key)                set_to_cache(key, value)                return value        end        ngx.say("get from cache.")        return valueendfunction get_from_redis(key)        red:set_timeout(1000)        local ok, err = red:connect("127.0.0.1", 6379)        if not ok then                ngx.say("failed to connect: ", err)                return        end        local res, err = red:get(key)        if not res then                ngx.say("failed to get doy: ", err)                return ngx.null        end        ngx.say("get from redis.")        return resendfunction set_to_redis(key, value)        red:set_timeout(1000)        local ok, err = red:connect("127.0.0.1", 6379)        if not ok then                ngx.say("failed to connect: ", err)                return        end        local ok, err = red:set(key, value)        if not ok then                ngx.say("failed to set to redis: ", err)                return        end        return okendset_to_redis('dog', "Bob")local rs = get_from_cache('dog')ngx.say(rs)

測試:

[root@localhost ~]# curl localhost/cacheget from redis.Bob[root@localhost ~]# curl localhost/cacheget from cache.Bob[root@localhost ~]# curl localhost/cacheget from cache.Bob

第一次從 redis中獲取,以后每次都從cache中獲取。

可以使用 ab 測試一下rps(Requests per second):

 ab -n 1000 -c 100 -k http://127.0.0.1/cache

7. 解決緩存失效風暴 lua-resty-lock

緩存失效風暴是指緩存因為時間過期而失效時,會導致所有的請求都去訪問 后臺的redis或者mysql,而導致CPU性能即刻增長的現象。所以關鍵是當緩存失效時,用lock保證只有一個線程去訪問后臺的redis或者mysql,然后更新緩存。需要使用到 lua-resty-lock 模塊的加鎖、解鎖功能。

lua-resty-lock 文檔:https://github.com/openresty/lua-resty-lock

首先在nginx.conf 的 http 端下面加入指令:

lua_shared_dict ngx_cache 128m;     # cachelua_shared_dict cache_lock 100k;    # lock for cache

然后在nginx.conf的server端中加入:

        location /cache_lock {            content_by_lua_file lua/cache_lock.lua;        }

cache_lock.lua代碼:

[root@localhost lua]# cat cache_lock.lualocal redis = require "resty.redis"local red = redis:new()local resty_lock = require "resty.lock"local ngx_cache = ngx.shared.ngx_cachefunction set_to_cache(key, value, exptime)        if not exptime then                exptime = 0        end        local succ, err, forcible = ngx_cache:set(key, value, exptime)        return succendfunction get_from_cache(key)        local ngx_cache = ngx.shared.ngx_cache;        local value = ngx_cache:get(key)        if not value then       -- cache miss                local lock = resty_lock:new("cache_lock")                local elapsed, err = lock:lock(key)                if not elapsed then                        return fail("failed to acquire the lock: ", err)                end                value = get_from_redis(key)                if not value then                        local ok, err = lock:unlock()                        if not ok then                                return fail("failed to unlock: ", err)                        end                        ngx.say("no value found")                        return                end                local ok, err = ngx_cache:set(key, value, 1)                if not ok then                        local ok, err = lock:unlock()                        if not ok then                                return fail("failed to unlock: ", err)                        end                        return faile("failed to update ngx_cache: ", err)                end                local ok, err = lock:unlock()                if not ok then                        return faile("failed to unlock: ", err)                end                return value        end        ngx.say("get from cache.")        return valueendfunction get_from_redis(key)        red:set_timeout(1000)        local ok, err = red:connect("127.0.0.1", 6379)        if not ok then                ngx.say("failed to connect: ", err)                return        end        local res, err = red:get(key)        if not res then                ngx.say("failed to get doy: ", err)                return ngx.null        end        ngx.say("get from redis.")        return resendfunction set_to_redis(key, value)        red:set_timeout(1000)        local ok, err = red:connect("127.0.0.1", 6379)        if not ok then                ngx.say("failed to connect: ", err)                return        end        local ok, err = red:set(key, value)        if not ok then                ngx.say("failed to set to redis: ", err)                return        end        return okendset_to_redis('dog', "Bob")local rs = get_from_cache('dog')ngx.say(rs)
View Code
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美日韩在线视频一区| 色婷婷综合久久久久中文字幕1| 自拍偷拍亚洲欧美| 欧美激情精品久久久久久变态| 日韩欧美在线看| 中文字幕日韩在线播放| 欧美成人一区二区三区电影| 伊人久久综合97精品| 欧美国产在线电影| 4438全国亚洲精品在线观看视频| 国产精品黄页免费高清在线观看| 欧美黑人巨大xxx极品| 精品久久久久久中文字幕一区奶水| 久久综合九色九九| 性欧美亚洲xxxx乳在线观看| 久久手机精品视频| 欧美成人亚洲成人| 欧美激情xxxx性bbbb| 性欧美在线看片a免费观看| 日韩成人免费视频| 亚洲最大福利视频网站| 92裸体在线视频网站| 国产日韩一区在线| 国产视频观看一区| 亚洲免费视频观看| 久久亚洲影音av资源网| 欧美亚洲午夜视频在线观看| 亚洲综合中文字幕在线观看| 日韩av最新在线| 中文字幕亚洲二区| 欧美国产日韩一区二区| 国产成人涩涩涩视频在线观看| 自拍偷拍亚洲欧美| 国产精品国产福利国产秒拍| 国产亚洲美女久久| 亚洲午夜av电影| 九九热精品视频在线播放| 色青青草原桃花久久综合| 久久人人爽人人爽人人片av高清| 亚洲自拍偷拍色片视频| www日韩中文字幕在线看| 亚洲女人被黑人巨大进入| 欧美性猛交xxx| 精品国产福利在线| 91在线观看免费高清完整版在线观看| 欧美最猛性xxxx| 中文字幕日韩av| 日韩高清免费观看| 一本一本久久a久久精品综合小说| 九九久久精品一区| 亚洲春色另类小说| 精品五月天久久| 日本国产高清不卡| 中文字幕亚洲欧美日韩在线不卡| 日韩免费在线免费观看| 国产精品自产拍在线观| 2019亚洲男人天堂| 欧美电影《睫毛膏》| 视频在线观看99| 精品一区二区三区四区在线| 性日韩欧美在线视频| 国产精品久久久久久久天堂| 亚洲国产成人在线播放| 国产精品入口夜色视频大尺度| 色婷婷亚洲mv天堂mv在影片| 国产91精品不卡视频| 亚洲第一av网| 一本久久综合亚洲鲁鲁| 97久久超碰福利国产精品…| 主播福利视频一区| 欧美一级高清免费| 日本精品va在线观看| 国产成人精品999| 午夜精品一区二区三区在线| 国产精品偷伦视频免费观看国产| 国产精品久久二区| 国模精品一区二区三区色天香| 精品久久久精品| 欧美成年人视频网站欧美| 亚洲国产欧美精品| 亚洲偷熟乱区亚洲香蕉av| 日本高清不卡的在线| 久久久亚洲欧洲日产国码aⅴ| 亚洲人成在线观看| 亚洲专区中文字幕| 在线视频亚洲欧美| 中文字幕亚洲色图| 国产成人福利夜色影视| 久久中文字幕国产| 欧美大荫蒂xxx| 国产视频观看一区| 日韩av毛片网| 韩国19禁主播vip福利视频| 亚洲白虎美女被爆操| 久久人体大胆视频| 欧美性生交大片免费| 欧美午夜影院在线视频| 欧美激情免费观看| 欧美激情极品视频| 久久高清视频免费| 欧美国产日韩在线| 精品久久久久久久久久| 伊人久久久久久久久久| 九色精品美女在线| 日本精品中文字幕| 亚洲国产成人精品女人久久久| 久久精品国产精品| 日韩av在线直播| 亚洲欧美精品一区| 色先锋久久影院av| 亚洲美女激情视频| 久久久久久久av| 国产欧美欧洲在线观看| 日韩成人av网| 亚洲日韩欧美视频一区| 色综合亚洲精品激情狠狠| 日韩欧美高清在线视频| 国产欧美韩国高清| 精品国产欧美一区二区五十路| 福利一区福利二区微拍刺激| 久久久久久久久综合| 欧美一区二区大胆人体摄影专业网站| 日韩av在线免费观看| 国产精品久久久久福利| 欧美电影在线免费观看网站| 欧美激情一二区| 亚洲3p在线观看| 欧美激情在线播放| 亚洲自拍中文字幕| 亚洲午夜国产成人av电影男同| 蜜月aⅴ免费一区二区三区| 国产美女精品视频免费观看| 久久精品亚洲国产| 欧美日韩综合视频网址| 91在线无精精品一区二区| 清纯唯美亚洲综合| 久久久久久久国产精品视频| 亚洲福利视频网站| 国产+成+人+亚洲欧洲| 亚洲免费电影在线观看| 亚洲最新在线视频| 日韩国产精品一区| 欧美在线中文字幕| 精品国产91久久久久久老师| 亚洲国产欧美日韩精品| 欧美日韩精品二区| 日本一欧美一欧美一亚洲视频| 欧美激情第一页xxx| 欧美久久精品一级黑人c片| 精品在线欧美视频| 欧美成人免费全部| 日韩一二三在线视频播| 一本色道久久综合亚洲精品小说| 国产日产久久高清欧美一区| 久久久久久亚洲精品中文字幕| 成人a在线视频| 亚洲第一色中文字幕| 国产精品狼人色视频一区| 91老司机在线| 国产精品久久久久久av下载红粉| 亚洲欧美日韩成人| 日韩av综合中文字幕| 91亚洲国产精品| 91成人精品网站|