OpenResty 快速入门,--backlog&
OpenResty 快速入门,--backlog&
一、OpenResty安装
OpenResty® - 中文官方站
1.下载安装包
wget https://openresty.org/download/openresty-1.11.2.5.tar.gz
2. 解压
tar -zxvf openresty-1.11.2.5.tar.gz
3. 安装
cd openresty-1.11.2.5
./configure
make
make install
4. 配置环境变量,OpenResty默认安装在/usr/local/openresty目录下
vi /etc/profile
export PATH=/usr/local/openresty/nginx/sbin:$PATH
source /etc/profile
二、hello world
修改/usr/local/openresty/nginx/conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
location /hello {
default_type text/html;
content_by_lua 'ngx.say("<h1> hello, OpenResty </h1>")';
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
启动nginx,访问ip/hello,可以看到如下输出,说明配置成效
三、编写lua脚本,作为输出
在ngxin目录下创建lua目录,并编写hello.lua,内容如下
ngx.say('<h1>hello,OpenResty lua</h1>')
修改nginx.conf中的/hello请求
location /hello {
default_type text/html;
content_by_lua_file /usr/local/openresty/nginx/lua/hello.lua;
}
请求hello返回如下,说明修改生效
四、lua操作mysql数据库 (lua-resty-mysql 的使用)
lua-resty-mysql相关操作说明
1. 创建mysql连接对象 mysql:new()
--如果创建失败,返回nil,错误信息err
db, err = mysql:new()
2. 建立连接 db:connect(options)
--语法格式
ok, err, errcode, sqlstate = db:connect(options)
--options 必填项
-- host:mysql地址
-- port:mysql端口
-- database:数据库名称
-- user:用户名
-- password:密码
--options 可选项
-- charset:编码集
-- max_packet_size:mysql最大返回的数据大小,默认1M
-- ssl:是否使用ssl加密,默认false
-- pool:数据库连接池,如果不设置,默认为:user:database:host:port、user:database:path
-- pool_size:数据库连接池大小(针对每个worker,不是整个nginx服务器)
如果不设置backlog,总的数据库连接不会有限制
如果不设置,并且backlog没有设置,则不会创建连接池
如果不设置,但是设置了backlog,poolsize默认为lua_socket_pool_size
当连接不够时,超过存活时间的连接会断开,断开后可以建立新的连接
-- backlog:设置后可以限制总的数据库连接
3. 设置超时时间 db:set_timeout(time)
--超时时间,单位毫秒
db:set_timeout(time)
4. 设置空闲存活时间 db:set_keepalive(max_idle_timeout, pool_size)
--max_idle_timeout 最大空闲时间
--pool_size 连接池大小
ok, err = db:set_keepalive(max_idle_timeout, pool_size)
5. 获取当前连接重复使用次数 db:get_reused_times()
-- 如果当前连接不来自于连接池,返回0
-- 如果当前连接来自连接池,返回一个非0值
-- 这方法可用来判断当前连接是不是来自于连接池
-- 如果出错,返回nil和错误信息
times, err = db:get_reused_times()
6. 发送查询语句,不需要等待响应结果 db:send_query(sql)
-- 如果发送成功,返回发送成功的响应数据
-- 如果发送失败,返回nil、错误信息err
-- 使用read_result读取响应结果
bytes, err = db:send_query(sql)
7. 读取响应结果 db:read_result()
-- res为查询到的结果数据,可以为一个,也可以为多个
-- 如果出错了,结果为nil,错误信息,错误信息状态码,sql错误码
res, err, errcode, sqlstate = db:read_result()
-- nrows为限制结果数量
res, err, errcode, sqlstate = db:read_result(nrows)
8. send_query 和 read_result的简化:db:query(sql)
-- 如果出错了,结果为nil,错误信息,错误信息状态码,sql错误码
res, err, errcode, sqlstate = db:query(sql)
res, err, errcode, sqlstate = db:query(sql, nrows)
9. 关闭连接 db:close()
-- 关闭成功,返回1
ok, err = db:close()
10. 防止sql注入
因为我们nginx可以直接操作数据库,而链接中带过来的参数如果存在特殊字符,就会导致我们数据库不安全
local name = ngx.unescape_uri(ngx.var.arg_name)
local quoted_name = ngx.quote_sql_str(name)
local sql = "select * from users where name = " .. quoted_name
11. 案例
创建数据库openresty,并创建表user和相关数据
CREATE TABLE `users` ( `id` int NOT NULL AUTO_INCREMENT, `username` varchar(255) DEFAULT NULL, `birthday` date DEFAULT NULL, `salary` double(10,2) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; INSERT INTO `users` (`id`, `username`, `birthday`, `salary`) VALUES ('1', 'xiaowang', '1991-03-15', '9000.00'); INSERT INTO `users` (`id`, `username`, `birthday`, `salary`) VALUES ('2', 'xiaoma', '1992-07-15', '8000.00');
编写mysql.lua
cjson 可以转json字符串
ngx.header.content_type="application/json;charset=utf8" 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(10000) local ok, err, errcode, sqlstate = db:connect{ host = "192.168.8.59", port = 3306, database = "openresty", user = "xxx", password = "xxx" } if not ok then ngx.say("failed to connect: ", err, ": ", errcode, " ", sqlstate) return end ngx.say("connected to mysql.") local bytes,err = db:send_query("select * from users") if not bytes then ngx.say("bad result: ", err) return end ngx.say("send ",bytes," bytes.") local res,err,errcode,sqlstate = db:read_result() if not res then ngx.say("bad result: ",err," :",errcode, ":" ,sqlstate," .") end local cjson = require 'cjson' for i,v in ipairs(res) do ngx.say(v.id..","..v.username..","..v.birthday..",".. v.salary) end ngx.say("查询数据为:",cjson.encode(res)) db:close()
编写配置文件nginx.conf
location = /mysql{ content_by_lua_file /usr/local/openresty/nginx/lua/mysql.lua; }
访问/mysql,可以得到如下打印信息
四、lua操作redis (resty.redis的使用)
1. 创建redis对象 redis:new()
-- 如果创建失败,返回nil,错误信息err
red, err = redis:new()
2. 建立连接 red:connect()
-- host ip地址
-- port 端口号
-- options_table 可选参数
ok, err = red:connect(host, port, options_table?)
-- optional_tables:可选参数
-- ssl:boolean,是否使用ssl加密连接,默认false
-- ssl_verify:是否验证ssl证书,默认false
-- server_name: Specifies the server name for the new TLS extension
Server Name Indication (SNI) when connecting over SSL
-- pool:连接池名称,如果不设置,默认为host:port、unix-socket-path
-- pool_size:连接池大小,
1.如果不设置,并且backlog也没有设置,连接池不会创建
2.如果不设置,backlog设置了,连接池大小默认为:lua_socket_pool_size
3.连接池最多持有pool size个连接,但不会限制总连接,可通过设置backlog限制总连接超过pool size的连接会进入队列排队,如果队列满了,则报错。
-- backlog:超过连接池pool size的连接会进入队列排队,队列满了会报错:too many waiting connect operations
3. 设置超时时间: red:set_timeout(time)
-- time 单位毫秒
red:set_timeout(time)
4. 设置不同的情形的超时时间 red:set_timeouts(connect_timeout, send_timeout, read_timeout)
-- connect_timeout 连接超时时间
-- send_timeout 写操作超时时间
-- read_timeout 读操作超时时间
red:set_timeouts(connect_timeout, send_timeout, read_timeout)
5. 设置空闲存活时间
-- max_idle_timeout 存活时间单位ms
-- 连接池大小
-- 会将当前连接放进连接池中
ok, err = red:set_keepalive(max_idle_timeout, pool_size)
6. 连接重用次数
-- 获取当前连接的重复使用次数
-- 错误返回nil和错误信息err
times, err = red:get_reused_times()
7. 流水线操作
-- 初始化流水线
red:init_pipeline()
red:init_pipeline(n)
-- 提交流水线
res, err = red:commit_pipeline()
-- 取消流水线
red:cancel_pipeline()
8. 字符串操作
-- 设置key-value
-- 失败返回nil和错误信息err
ok, err = red:set(key,value)
-- 根据key获取value
-- 失败返回nil和错误信息err
res, err = red:get(key)
9. 权限认证
-- 认证失败返回nil和错误信息err
res, err = red:auth(password)
10. 案例
1. 编写redis.lua脚本文件
ngx.header.content_type="application/json;charset=utf8" -- 引入 Redis local redis = require "resty.redis" --创建Redis对象 local red = redis:new() --设置超时数据为3s red:set_timeout(3000) --设置redis连接信息 local ok,err = red:connect("192.168.8.59",6379) --判断是否连接成功 if not ok then ngx.say("failed to connection redis",err) return end ngx.say("connected to redis.") --存入 数据 ok,err = red:set("username","TOM") --判断是否存入成功 if not ok then ngx.say("failed to set username",err) return end --从 redis中获取数据 local res,err = red:get("username") --将数据写会消息体中 ngx.say(res) red:close()
2. nginx.conf增加/redis请求路径
location = /redis{ content_by_lua_file /usr/local/openresty/nginx/lua/redis.lua; }
3. 请求/redis
五、常用的nginx lua api
1. 获取路径占位符 /item/1001
local id = ngx.var[1]
2. 获取请求头信息
local headers = ngx.req.get_headers()
3. 获取get请求参数
-- 返回table类型 local args = ngx.req.get_uri_args() -- xx 表示url上的参数名称 ,多个同名会返回第一个的值 -- ?xx=1&xx=2&xx=3 会返回1 ,而 get_uri_args 返回["1","2","3"] local xx = ngx.var.arg_xx
4. 获取请求体
-- 读取请求体 ngx.req.read_body() -- 获取表单参数,返回table类型 local postParams = ngx.req.get_post_args()
5. 获取json参数
-- 读取请求体 ngx.req.read_body() -- 获取请求体中json参数,返回string类型 local jsonBody = ngx.req.get_body_data()
6. 获取请求方式
-- 获取请求方式()GET POST PUT DELETE 等 local method,err = ngx.req.get_method();
7. 日志打印
-- 日志级别从高到低 -- ngx.STDERR -- ngx.EMERG -- ngx.ALERT -- ngx.CRIT -- ngx.ERR -- ngx.WARN -- ngx.NOTICE -- ngx.INFO -- ngx.DEBUG ngx.log(ngx.ERR,'这是日志的信息')
8. 案例
1. 编写lua脚本
ngx.header.content_type="application/json;charset=utf8" local cjson = require "cjson" --请求方法 local method = ngx.req.get_method() ngx.say("请求方式 : ",method) ngx.say("=======================") --请求的http协议版本 ngx.say("http协议版本 : ",ngx.req.http_version()) ngx.say("=======================") --get请求uri参数 if (method == "GET") then ngx.say("get请求参数") local uri_args = ngx.req.get_uri_args() for k, v in pairs(uri_args) do ngx.say(k, ": ", v) end elseif(method == "POST") then ngx.req.read_body() local post_args = ngx.req.get_post_args() if post_args ~= nil then ngx.say("post请求参数表单方式") for k, v in pairs(post_args) do if type(v) == "table" then ngx.say(k, ":", table.concat(v,",")) else ngx.say(k, ": ", v) end end end ngx.say("=======================") ngx.say("post get_body_data") local p_body_data = ngx.req.get_body_data() ngx.say(p_body_data) end ngx.say("=======================") --请求头 local headers = ngx.req.get_headers() ngx.say("headers: ") for k,v in pairs(headers) do if type(v) == "table" then ngx.say(k, " : ", table.concat(v, ",")) else ngx.say(k, " : ", v) end end ngx.say("=======================")
2. 配置nginx.conf
location = /req{ content_by_lua_file /usr/local/openresty/nginx/lua/request.lua; }
3. get请求
4. post请求,表单形式
5. post请求 json
六、lua_resty_kafka 集成
1. 安装kafka依赖
#下载lua_resty_kafka ,当前目录/opt wget https://github.com/doujiang24/lua-resty-kafka/archive/master.zip #解压 unzip master.zip #复制脚本文件到openresty的lualib/resty 目录下 cp -rf /opt/lua-resty-kafka-master/lib/resty/kafka/ /usr/local/openresty/lualib/resty/
2. 编写lua脚本
ngx.header.content_type="application/json;charset=utf8" local producer = require("resty.kafka.producer") -- kafka的集群信息,单机也是可以的 local broker_list = { {host = "192.168.168.160", port = 9092}, } -- 定义最终kafka接受到的数据是怎样的json格式 local log_json = {} -- 增加read_body之后即可获取到消息体,默认情况下可能会是nil log_json["body"] = ngx.req.read_body() log_json["body_data"] = ngx.req.get_body_data() -- 定义kafka同步生产者,也可设置为异步 async -- 注意!!!当设置为异步时,在测试环境需要修改batch_num,默认是200条,若大不到200条kafka端接受不到消息 -- encode()将log_json日志转换为字符串 -- 发送日志消息,send配套之第一个参数topic: -- 发送日志消息,send配套之第二个参数key,用于kafka路由控制: -- key为nill(空)时,一段时间向同一partition写入数据 -- 指定key,按照key的hash写入到对应的partition -- batch_num修改为1方便测试 local bp = producer:new(broker_list, { producer_type = "async",batch_num = 1 }) -- local bp = producer:new(broker_list) local cjson = require("cjson.safe") local sendMsg = cjson.encode(log_json) local ok, err = bp:send("lua_test",nil, sendMsg) if not ok then ngx.say("the message send error :",err) ngx.log(ngx.ERR, 'kafka send err:', err) elseif ok then ngx.say("the message send successful") else ngx.say("internal error ") end
3. 修改nginx.conf
location = /kfk{ content_by_lua_file /usr/local/openresty/nginx/lua/kfk.lua; }
4. 编写Java消费端,使用SpringBoot继承kafka
pom依赖
<dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> </dependency>
application.yml
spring: kafka: bootstrap-servers: 192.168.168.160:9092 consumer: group-id: auto-dev
listener
@Component @Slf4j public class ConsumerListener { @KafkaListener(topics = {"lua_test"}) public void onMessage(ConsumerRecord<String, String> record){ log.info("【topic】 {} 【消息】{}",record.topic(), record.value()); } }
3. 测试结果
发送请求
消费者消费消息
七、nginx的相关命令
#到nginx目录下,使用默认配置文件启动
./sbin/ngxin
#启动时指定配置文件
./sbin/ngxin -c /opt/nginx/nginx.conf
#设置前缀路径
./sbin/ngxin -p /home/www
#重启Nginx
nginx -s reopen
#程序加载配置文件(nginx.conf),然后以优雅的方式重启Nginx。
nginx -s reload
#强制停止Nginx服务
nginx -s stop
#优雅的停止Nginx服务
nginx -s quit
八、总结
OpenResty是个利器,大家好好把握!哈哈哈
评论暂时关闭