Docker 封裝高併發 OpenResty (Nginx Lua)

1. 準備

Docker 中有 openresty 的鏡像, 我開始用這個鏡像安裝 lua, lua 安裝成功, 但是 加載不上 resty.mysql 模塊. 若想加載需要更新 ubuntu 資料庫, 由於網絡總是斷, 所以換了一個思路. 用 Centos 鏡像裝一個.

這個過程比較多.

  1. Docker 運行 centos 鏡像.
  2. 安裝 Lua.
  3. 安裝 luarocks.
  4. 安裝 cjson 和 RestyMysql 模塊.
  5. 安裝 openresty.
  6. 打開防火牆.
  7. 編譯 lua 文件, 進行執行.

2. Docker 運行 centos 鏡像

docker pull centos
docker run -d -it --net=host --name=centos centos

3. 安裝 Lua

進入 Centos 鏡像

docker exec -it centos /bin/bash

安裝 Lua

curl -R -O http://www.lua.org/ftp/lua-5.1.tar.gz
tar zxf lua-5.1.tar.gz
cd lua-5.1
yum install -y gcc make
yum install -y readline-devel libtermcap-devel ncurses-devel libevent-devel
make linux
make install

運行 lua 命令, 進入控制檯便運行成功.

防止後面的操作出現問題. 先打包鏡像, 後續類似.

docker commit -a 'ykenan centos_lua' centos centos_lua

4. 安裝 luarocks

curl -R -O https://luarocks.github.io/luarocks/releases/luarocks-3.3.1.tar.gz
tar -zxvf luarocks-3.3.1.tar.gz
cd luarocks-3.3.1
yum install unzip
./configure
make
make install

5. 安裝 cjson 和 RestyMysql 模塊

luarocks install lua-cjson
luarocks install lua-resty-mysql

若網絡慢, 可以去 https://luarocks.org/modules 鏈接搜索下載下來再安裝.

6. 安裝 openresty

yum -y install readline-devel pcre-devel openssl-devel gcc pcre
wget https://openresty.org/download/ngx_openresty-1.9.7.1.tar.gz
tar xzvf ngx_openresty-1.9.7.1.tar.gz
cd ngx_openresty-1.9.7.1/
./configure --prefix=/opt/openresty --with-luajit --without-http_redis2_module --with-http_iconv_module
make
make install
yum install yum-utils
yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo

Nginx 中 nginx.conf 文件再 /opt/openresty/nginx/conf/ 文件夾下.

cat /opt/openresty/nginx/conf/nginx.conf

7. 打開防火牆

這步驟防止後面, restymysql 鏈接 MySQL 出現的報錯.

yum install firewalld
systemctl start firewalld

打開用到的所有端口號. 比少了強.

  1. 80 Nginx
  2. 3306 MySQL
  3. 6002 主機映射 Docker 80 端口
  4. 6379 Redis
firewall-cmd --zone=public --add-port 80/tcp --permanent;
firewall-cmd --zone=public --add-port 3306/tcp --permanent;
firewall-cmd --zone=public --add-port 6002/tcp --permanent;
firewall-cmd --zone=public --add-port 6379/tcp --permanent;
firewall-cmd --reload;

查看防火牆的開放端口號

firewall-cmd --zone=public --list-all;

這裏面會遇見 systemctl 運行的報錯
https://blog.csdn.net/YKenan/article/details/107078114

先將容器打成鏡像, 之後再用可以運行 systemctl 的方式運行該鏡像即可.

8. 編譯 lua 文件, 進行執行

防火牆打開之後重新打成鏡像並運行.

docker run -d -it -p 6002:80 --privileged=true -v /home/docker/openresty/nginx:/opt/openresty/nginx/conf -v /home/docker/openresty/data:/root/data --name openresty centos_openresty /usr/sbin/init
  1. /home/docker/openresty/nginx: Nginx 下的配置文件夾. (含有 nginx.conf)
  2. /home/docker/openresty/data: 運行 lua 的文件夾. (含有 update_ad.lua)
docker exec -it openresty /bin/bash
yum install vim
vim ~/.bashrc
# 添加的內容-start
alias nginx='/opt/openresty/nginx/sbin/nginx'
# 添加的內容-end 保存推出
source ~/.bashrc
nginx -t
nginx -s reload

瀏覽器訪問
在這裏插入圖片描述

nginx.conf 文件內容


user root;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
error_log  logs/error.log  info;

pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #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  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

	#定義緩存模塊
	lua_shared_dict dis_cache 128m;

    server {
        listen       80;
        server_name  192.168.19.129;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

		location /update_ad {
		    content_by_lua_file /root/data/update_ad.lua;
		}
		
		location /read_ad {
		    content_by_lua_file /root/data/read_ad.lua;
		}
		
        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}

update_ad.lua 文件
restymysql 的使用 https://github.com/openresty/lua-resty-mysql

--ngx.header.content_type="text/plain;charset=utf8"
ngx.header.content_type="application/json;charset=utf8"
local cjson = require("cjson")
local mysql = require("resty.mysql")
local uri_args = ngx.req.get_uri_args()
local id = uri_args["id"]

local db, err = mysql:new()
if not db then
	ngx.say('{"failed to instantiate mysql":"'..err..'"}')
	return
end

db:set_timeout(3000)

local props = {
	host = "192.168.19.129",
	port = 3306,
	database = "commerce_ad",
	user = "root",
	password = "MySQL_6468",
	charset = "utf8"
}

local ok, err, errcode, sqlstate = db:connect(props)

if not ok then
	ngx.say('{"err":"'..err..'", "errcode":"'..errcode..'", "sqlstate":"'..sqlstate..'"}')
	return
end

local select_sql = "select url, pic_pos from tb_ad where status = '1' and category_id = "..id.." order by sort_order"
res, err, errcode, sqlstate = db:query(select_sql)
if not res then
	ngx.say('{"err":"'..err..'", "errcode":"'..errcode..'", "sqlstate":"'..sqlstate..'"}')
	return
end
db:close()

local redis = require("resty.redis")
local red = redis:new()
red:set_timeout(2000)
local ip = "192.168.19.129"
local port = 6379
red:connect(ip, port)
red:set("content_"..id, cjson.encode(res))
red:close()

ngx.say('[{"MySQL":"'..select_sql..'", "flag":"true"}]')

運行結果

http://192.168.19.129:6002/update_ad?id=1

在這裏插入圖片描述
在這裏插入圖片描述

9. 進行緩存數據讀取

read_ad.lua 用於讀取緩存數據.

讀取過程:

  1. 讀取 Nginx 緩存, 若沒有讀取 Redis 緩存.
  2. 讀取 Redis 緩若存在, 將數據緩存到 Nginx 中. 若不存在讀取數據庫.
  3. 讀取數據庫後將數據緩存到 Redis 中.

添加 Nginx 緩存模塊

#定義緩存模塊
lua_shared_dict dis_cache 128m;

read_ad.lua 文件內容

--ngx.header.content_type="text/plain;charset=utf8"
ngx.header.content_type="application/json;charset=utf8"
local uri_args = ngx.req.get_uri_args();
local id = uri_args["id"];
--獲取本地緩存 (加載 Nginx 緩存模塊, 該模塊需要自己定義)
local cache_ngx = ngx.shared.dis_cache;
--根據 ID 獲取本地緩存數據
local content_cache = cache_ngx:get('content_cache_'..id);
--進行判斷
if content_cache == "" or content_cache == nil then
	local redis = require("resty.redis");
	local red = redis:new();
	red:set_timeout(2000);
	local ip = "192.168.19.129";
	local port = 6379;
	red:connect(ip, port);
	local rescontent = red:get("content_"..id);
	--進行判斷
	if ngx.null == rescontent then
		local cjson = require("cjson")
		local mysql = require("resty.mysql")
		local db, err = mysql:new()
		if not db then
			ngx.say('{"failed to instantiate mysql":"'..err..'"}')
			return
		end
		db:set_timeout(2000)
		local props = {
			host = "192.168.19.129",
			port = 3306,
			database = "commerce_ad",
			user = "root",
			password = "MySQL_6468",
			charset = "utf8"
		}
		local ok, err, errcode, sqlstate = db:connect(props)
		if not ok then
			ngx.say('{"err":"'..err..'", "errcode":"'..errcode..'", "sqlstate":"'..sqlstate..'"}')
			return
		end
		local select_sql = "select url, pic_pos from tb_ad where status = '1' and category_id = "..id.." order by sort_order"
		res, err, errcode, sqlstate = db:query(select_sql)
		if not res then
			ngx.say('{"err":"'..err..'", "errcode":"'..errcode..'", "sqlstate":"'..sqlstate..'"}')
			return
		end
		local responsejson = cjson.encode(res);
		--添加 Redis 緩存
		red:set("content_"..id, responsejson);
		ngx.say(responsejson);
		db:close();
	else
		--將 Redis 查詢出來的緩存放在 Nginx 中
		cache_ngx:set('content_cache_'..id, rescontent, 10*60);
		ngx.say(rescontent);
	end
	red:close();
else
	ngx.say(content_cache);
end

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章