Docker 封裝高併發 OpenResty_Nginx_Lua
1. 準備
Docker 中有 openresty 的鏡像, 我開始用這個鏡像安裝 lua, lua 安裝成功, 但是 加載不上 resty.mysql 模塊. 若想加載需要更新 ubuntu 資料庫, 由於網絡總是斷, 所以換了一個思路. 用 Centos 鏡像裝一個.
這個過程比較多.
- Docker 運行 centos 鏡像.
- 安裝 Lua.
- 安裝 luarocks.
- 安裝 cjson 和 RestyMysql 模塊.
- 安裝 openresty.
- 打開防火牆.
- 編譯 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
打開用到的所有端口號. 比少了強.
80
Nginx3306
MySQL6002
主機映射 Docker 80 端口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
- /home/docker/openresty/nginx: Nginx 下的配置文件夾. (含有
nginx.conf
)- /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 用於讀取緩存數據.
讀取過程:
- 讀取 Nginx 緩存, 若沒有讀取 Redis 緩存.
- 讀取 Redis 緩若存在, 將數據緩存到 Nginx 中. 若不存在讀取數據庫.
- 讀取數據庫後將數據緩存到 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