• OpenResty 快速入门


    一、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. 安装

    1. cd openresty-1.11.2.5
    2. ./configure
    3. make
    4. make install

    4. 配置环境变量,OpenResty默认安装在/usr/local/openresty目录下

    1. vi /etc/profile
    2. export PATH=/usr/local/openresty/nginx/sbin:$PATH
    3. source /etc/profile

    二、hello world

    修改/usr/local/openresty/nginx/conf/nginx.conf

    1. worker_processes 1;
    2. events {
    3. worker_connections 1024;
    4. }
    5. http {
    6. include mime.types;
    7. default_type application/octet-stream;
    8. sendfile on;
    9. server {
    10. listen 80;
    11. server_name localhost;
    12. location / {
    13. root html;
    14. index index.html index.htm;
    15. }
    16. location /hello {
    17. default_type text/html;
    18. content_by_lua 'ngx.say("

      hello, OpenResty

      ")'
      ;
    19. }
    20. error_page 500 502 503 504 /50x.html;
    21. location = /50x.html {
    22. root html;
    23. }
    24. }
    25. }

    启动nginx,访问ip/hello,可以看到如下输出,说明配置成效 

    三、编写lua脚本,作为输出

    在ngxin目录下创建lua目录,并编写hello.lua,内容如下

    ngx.say('<h1>hello,OpenResty luah1>')

    修改nginx.conf中的/hello请求

    1. location /hello {
    2. default_type text/html;
    3. content_by_lua_file /usr/local/openresty/nginx/lua/hello.lua;
    4. }

    请求hello返回如下,说明修改生效

     四、lua操作mysql数据库 (lua-resty-mysql 的使用)

    lua-resty-mysql相关操作说明

    1. 创建mysql连接对象 mysql:new()

    1. --如果创建失败,返回nil,错误信息err
    2. db, err = mysql:new()

    2. 建立连接 db:connect(options)

    1. --语法格式
    2. ok, err, errcode, sqlstate = db:connect(options)
    3. --options 必填项
    4. -- host:mysql地址
    5. -- port:mysql端口
    6. -- database:数据库名称
    7. -- user:用户名
    8. -- password:密码
    9. --options 可选项
    10. -- charset:编码集
    11. -- max_packet_size:mysql最大返回的数据大小,默认1M
    12. -- ssl:是否使用ssl加密,默认false
    13. -- pool:数据库连接池,如果不设置,默认为:user:database:host:port、user:database:path
    14. -- pool_size:数据库连接池大小(针对每个worker,不是整个nginx服务器)
    15. 如果不设置backlog,总的数据库连接不会有限制
    16. 如果不设置,并且backlog没有设置,则不会创建连接池
    17. 如果不设置,但是设置了backlog,poolsize默认为lua_socket_pool_size
    18. 当连接不够时,超过存活时间的连接会断开,断开后可以建立新的连接
    19. -- backlog:设置后可以限制总的数据库连接

    3. 设置超时时间 db:set_timeout(time)

    1. --超时时间,单位毫秒
    2. db:set_timeout(time)

    4. 设置空闲存活时间 db:set_keepalive(max_idle_timeout, pool_size)

    1. --max_idle_timeout 最大空闲时间
    2. --pool_size 连接池大小
    3. ok, err = db:set_keepalive(max_idle_timeout, pool_size)

    5. 获取当前连接重复使用次数 db:get_reused_times()

    1. -- 如果当前连接不来自于连接池,返回0
    2. -- 如果当前连接来自连接池,返回一个非0
    3. -- 这方法可用来判断当前连接是不是来自于连接池
    4. -- 如果出错,返回nil和错误信息
    5. times, err = db:get_reused_times()

    6. 发送查询语句,不需要等待响应结果 db:send_query(sql)

    1. -- 如果发送成功,返回发送成功的响应数据
    2. -- 如果发送失败,返回nil、错误信息err
    3. -- 使用read_result读取响应结果
    4. bytes, err = db:send_query(sql)

    7. 读取响应结果 db:read_result()

    1. -- res为查询到的结果数据,可以为一个,也可以为多个
    2. -- 如果出错了,结果为nil,错误信息,错误信息状态码,sql错误码
    3. res, err, errcode, sqlstate = db:read_result()
    4. -- nrows为限制结果数量
    5. res, err, errcode, sqlstate = db:read_result(nrows)

    8. send_query 和 read_result的简化:db:query(sql)

    1. -- 如果出错了,结果为nil,错误信息,错误信息状态码,sql错误码
    2. res, err, errcode, sqlstate = db:query(sql)
    3. res, err, errcode, sqlstate = db:query(sql, nrows)

    9. 关闭连接 db:close()

    1. -- 关闭成功,返回1
    2. ok, err = db:close()

    10. 防止sql注入

    因为我们nginx可以直接操作数据库,而链接中带过来的参数如果存在特殊字符,就会导致我们数据库不安全

    1. local name = ngx.unescape_uri(ngx.var.arg_name)
    2. local quoted_name = ngx.quote_sql_str(name)
    3. local sql = "select * from users where name = " .. quoted_name

    11. 案例

    创建数据库openresty,并创建表user和相关数据

    1. CREATE TABLE `users` (
    2. `id` int NOT NULL AUTO_INCREMENT,
    3. `username` varchar(255) DEFAULT NULL,
    4. `birthday` date DEFAULT NULL,
    5. `salary` double(10,2) DEFAULT NULL,
    6. PRIMARY KEY (`id`)
    7. ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
    8. INSERT INTO `users` (`id`, `username`, `birthday`, `salary`) VALUES ('1', 'xiaowang', '1991-03-15', '9000.00');
    9. INSERT INTO `users` (`id`, `username`, `birthday`, `salary`) VALUES ('2', 'xiaoma', '1992-07-15', '8000.00');

    编写mysql.lua

    cjson 可以转json字符串

    1. ngx.header.content_type="application/json;charset=utf8"
    2. local mysql = require "resty.mysql"
    3. local db, err = mysql:new()
    4. if not db then
    5. ngx.say("failed to instantiate mysql: ", err)
    6. return
    7. end
    8. db:set_timeout(10000)
    9. local ok, err, errcode, sqlstate = db:connect{
    10. host = "192.168.8.59",
    11. port = 3306,
    12. database = "openresty",
    13. user = "xxx",
    14. password = "xxx"
    15. }
    16. if not ok then
    17. ngx.say("failed to connect: ", err, ": ", errcode, " ", sqlstate)
    18. return
    19. end
    20. ngx.say("connected to mysql.")
    21. local bytes,err = db:send_query("select * from users")
    22. if not bytes then
    23. ngx.say("bad result: ", err)
    24. return
    25. end
    26. ngx.say("send ",bytes," bytes.")
    27. local res,err,errcode,sqlstate = db:read_result()
    28. if not res then
    29. ngx.say("bad result: ",err," :",errcode, ":" ,sqlstate," .")
    30. end
    31. local cjson = require 'cjson'
    32. for i,v in ipairs(res) do
    33. ngx.say(v.id..","..v.username..","..v.birthday..",".. v.salary)
    34. end
    35. ngx.say("查询数据为:",cjson.encode(res))
    36. db:close()

    编写配置文件nginx.conf

    1. location = /mysql{
    2. content_by_lua_file /usr/local/openresty/nginx/lua/mysql.lua;
    3. }

    访问/mysql,可以得到如下打印信息

     四、lua操作redis (resty.redis的使用)

    1. 创建redis对象 redis:new()

    1. -- 如果创建失败,返回nil,错误信息err
    2. red, err = redis:new()

    2. 建立连接 red:connect()

    1. -- host ip地址
    2. -- port 端口号
    3. -- options_table 可选参数
    4. ok, err = red:connect(host, port, options_table?)
    5. -- optional_tables:可选参数
    6. -- ssl:boolean,是否使用ssl加密连接,默认false
    7. -- ssl_verify:是否验证ssl证书,默认false
    8. -- server_name: Specifies the server name for the new TLS extension
    9. Server Name Indication (SNI) when connecting over SSL
    10. -- pool:连接池名称,如果不设置,默认为host:port、unix-socket-path
    11. -- pool_size:连接池大小,
    12. 1.如果不设置,并且backlog也没有设置,连接池不会创建
    13. 2.如果不设置,backlog设置了,连接池大小默认为:lua_socket_pool_size
    14. 3.连接池最多持有pool size个连接,但不会限制总连接,可通过设置backlog限制总连接超过pool size的连接会进入队列排队,如果队列满了,则报错。
    15. -- backlog:超过连接池pool size的连接会进入队列排队,队列满了会报错:too many waiting connect operations

    3. 设置超时时间: red:set_timeout(time)

    1. -- time 单位毫秒
    2. red:set_timeout(time)

    4. 设置不同的情形的超时时间 red:set_timeouts(connect_timeout, send_timeout, read_timeout)

    1. -- connect_timeout 连接超时时间
    2. -- send_timeout 写操作超时时间
    3. -- read_timeout 读操作超时时间
    4. red:set_timeouts(connect_timeout, send_timeout, read_timeout)

    5. 设置空闲存活时间

    1. -- max_idle_timeout 存活时间单位ms
    2. -- 连接池大小
    3. -- 会将当前连接放进连接池中
    4. ok, err = red:set_keepalive(max_idle_timeout, pool_size)

    6. 连接重用次数

    1. -- 获取当前连接的重复使用次数
    2. -- 错误返回nil和错误信息err
    3. times, err = red:get_reused_times()

    7. 流水线操作

    1. -- 初始化流水线
    2. red:init_pipeline()
    3. red:init_pipeline(n)
    4. -- 提交流水线
    5. res, err = red:commit_pipeline()
    6. -- 取消流水线
    7. red:cancel_pipeline()

    8. 字符串操作

    1. -- 设置key-value
    2. -- 失败返回nil和错误信息err
    3. ok, err = red:set(key,value)
    4. -- 根据key获取value
    5. -- 失败返回nil和错误信息err
    6. res, err = red:get(key)

    9. 权限认证

    1. -- 认证失败返回nil和错误信息err
    2. res, err = red:auth(password)

    10. 案例

    1. 编写redis.lua脚本文件

    1. ngx.header.content_type="application/json;charset=utf8"
    2. -- 引入 Redis
    3. local redis = require "resty.redis"
    4. --创建Redis对象
    5. local red = redis:new()
    6. --设置超时数据为3s
    7. red:set_timeout(3000)
    8. --设置redis连接信息
    9. local ok,err = red:connect("192.168.8.59",6379)
    10. --判断是否连接成功
    11. if not ok then
    12. ngx.say("failed to connection redis",err)
    13. return
    14. end
    15. ngx.say("connected to redis.")
    16. --存入 数据
    17. ok,err = red:set("username","TOM")
    18. --判断是否存入成功
    19. if not ok then
    20. ngx.say("failed to set username",err)
    21. return
    22. end
    23. --从 redis中获取数据
    24. local res,err = red:get("username")
    25. --将数据写会消息体中
    26. ngx.say(res)
    27. red:close()

    2. nginx.conf增加/redis请求路径

    1. location = /redis{
    2. content_by_lua_file /usr/local/openresty/nginx/lua/redis.lua;
    3. }

    3. 请求/redis

     五、常用的nginx lua api

    1. 获取路径占位符 /item/1001

    local id = ngx.var[1]

    2. 获取请求头信息

    local headers = ngx.req.get_headers()

    3. 获取get请求参数

    1. -- 返回table类型
    2. local args = ngx.req.get_uri_args()
    3. -- xx 表示url上的参数名称 ,多个同名会返回第一个的值
    4. -- ?xx=1&xx=2&xx=3 会返回1 ,而 get_uri_args 返回["1","2","3"]
    5. local xx = ngx.var.arg_xx

    4. 获取请求体

    1. -- 读取请求体
    2. ngx.req.read_body()
    3. -- 获取表单参数,返回table类型
    4. local postParams = ngx.req.get_post_args()

    5. 获取json参数

    1. -- 读取请求体
    2. ngx.req.read_body()
    3. -- 获取请求体中json参数,返回string类型
    4. local jsonBody = ngx.req.get_body_data()

    6. 获取请求方式

    1. -- 获取请求方式()GET POST PUT DELETE 等
    2. local method,err = ngx.req.get_method();

    7.  日志打印

    1. -- 日志级别从高到低
    2. -- ngx.STDERR
    3. -- ngx.EMERG
    4. -- ngx.ALERT
    5. -- ngx.CRIT
    6. -- ngx.ERR
    7. -- ngx.WARN
    8. -- ngx.NOTICE
    9. -- ngx.INFO
    10. -- ngx.DEBUG
    11. ngx.log(ngx.ERR,'这是日志的信息')

    8. 案例

    1. 编写lua脚本

    1. ngx.header.content_type="application/json;charset=utf8"
    2. local cjson = require "cjson"
    3. --请求方法
    4. local method = ngx.req.get_method()
    5. ngx.say("请求方式 : ",method)
    6. ngx.say("=======================")
    7. --请求的http协议版本
    8. ngx.say("http协议版本 : ",ngx.req.http_version())
    9. ngx.say("=======================")
    10. --get请求uri参数
    11. if (method == "GET") then
    12. ngx.say("get请求参数")
    13. local uri_args = ngx.req.get_uri_args()
    14. for k, v in pairs(uri_args) do
    15. ngx.say(k, ": ", v)
    16. end
    17. elseif(method == "POST") then
    18. ngx.req.read_body()
    19. local post_args = ngx.req.get_post_args()
    20. if post_args ~= nil then
    21. ngx.say("post请求参数表单方式")
    22. for k, v in pairs(post_args) do
    23. if type(v) == "table" then
    24. ngx.say(k, ":", table.concat(v,","))
    25. else
    26. ngx.say(k, ": ", v)
    27. end
    28. end
    29. end
    30. ngx.say("=======================")
    31. ngx.say("post get_body_data")
    32. local p_body_data = ngx.req.get_body_data()
    33. ngx.say(p_body_data)
    34. end
    35. ngx.say("=======================")
    36. --请求头
    37. local headers = ngx.req.get_headers()
    38. ngx.say("headers: ")
    39. for k,v in pairs(headers) do
    40. if type(v) == "table" then
    41. ngx.say(k, " : ", table.concat(v, ","))
    42. else
    43. ngx.say(k, " : ", v)
    44. end
    45. end
    46. ngx.say("=======================")

    2. 配置nginx.conf

    1. location = /req{
    2. content_by_lua_file /usr/local/openresty/nginx/lua/request.lua;
    3. }

    3. get请求

    4. post请求,表单形式

     

    5. post请求 json

     六、lua_resty_kafka 集成

    1. 安装kafka依赖

    1. #下载lua_resty_kafka ,当前目录/opt
    2. wget https://github.com/doujiang24/lua-resty-kafka/archive/master.zip
    3. #解压
    4. unzip master.zip
    5. #复制脚本文件到openresty的lualib/resty 目录下
    6. cp -rf /opt/lua-resty-kafka-master/lib/resty/kafka/ /usr/local/openresty/lualib/resty/

    2. 编写lua脚本

    1. ngx.header.content_type="application/json;charset=utf8"
    2. local producer = require("resty.kafka.producer")
    3. -- kafka的集群信息,单机也是可以的
    4. local broker_list = {
    5. {host = "192.168.168.160", port = 9092},
    6. }
    7. -- 定义最终kafka接受到的数据是怎样的json格式
    8. local log_json = {}
    9. -- 增加read_body之后即可获取到消息体,默认情况下可能会是nil
    10. log_json["body"] = ngx.req.read_body()
    11. log_json["body_data"] = ngx.req.get_body_data()
    12. -- 定义kafka同步生产者,也可设置为异步 async
    13. -- 注意!!!当设置为异步时,在测试环境需要修改batch_num,默认是200条,若大不到200条kafka端接受不到消息
    14. -- encode()将log_json日志转换为字符串
    15. -- 发送日志消息,send配套之第一个参数topic:
    16. -- 发送日志消息,send配套之第二个参数key,用于kafka路由控制:
    17. -- key为nill(空)时,一段时间向同一partition写入数据
    18. -- 指定key,按照key的hash写入到对应的partition
    19. -- batch_num修改为1方便测试
    20. local bp = producer:new(broker_list, { producer_type = "async",batch_num = 1 })
    21. -- local bp = producer:new(broker_list)
    22. local cjson = require("cjson.safe")
    23. local sendMsg = cjson.encode(log_json)
    24. local ok, err = bp:send("lua_test",nil, sendMsg)
    25. if not ok then
    26. ngx.say("the message send error :",err)
    27. ngx.log(ngx.ERR, 'kafka send err:', err)
    28. elseif ok then
    29. ngx.say("the message send successful")
    30. else
    31. ngx.say("internal error ")
    32. end

    3. 修改nginx.conf

    1. location = /kfk{
    2. content_by_lua_file /usr/local/openresty/nginx/lua/kfk.lua;
    3. }

    4. 编写Java消费端,使用SpringBoot继承kafka

    pom依赖

    1. <dependency>
    2. <groupId>org.springframework.kafkagroupId>
    3. <artifactId>spring-kafkaartifactId>
    4. dependency>

    application.yml

    1. spring:
    2. kafka:
    3. bootstrap-servers: 192.168.168.160:9092
    4. consumer:
    5. group-id: auto-dev

    listener

    1. @Component
    2. @Slf4j
    3. public class ConsumerListener {
    4. @KafkaListener(topics = {"lua_test"})
    5. public void onMessage(ConsumerRecord record){
    6. log.info("【topic】 {} 【消息】{}",record.topic(), record.value());
    7. }
    8. }

    3. 测试结果

    发送请求

    消费者消费消息

    七、nginx的相关命令

    1. #到nginx目录下,使用默认配置文件启动
    2. ./sbin/ngxin
    3. #启动时指定配置文件
    4. ./sbin/ngxin -c /opt/nginx/nginx.conf
    5. #设置前缀路径
    6. ./sbin/ngxin -p /home/www
    7. #重启Nginx
    8. nginx -s reopen
    9. #程序加载配置文件(nginx.conf),然后以优雅的方式重启Nginx。
    10. nginx -s reload
    11. #强制停止Nginx服务
    12. nginx -s stop
    13. #优雅的停止Nginx服务
    14. nginx -s quit

    八、总结

    OpenResty是个利器,大家好好把握!哈哈哈

  • 相关阅读:
    基于kafka的日志收集分析平台
    Xray联动RAD实现自动扫描教程
    CI868K01-eA 3BSE048845R2 106M1081-01
    boost之string_ref
    【测试工具】UnixBench 测试
    LVS负载均衡集群
    C/C++跨平台构建工具CMake入门
    【阅读】一周翻过《构建之法》,笔记整理
    深入理解正则表达式:高效处理文本数据的利器
    数据分析报告的规范
  • 原文地址:https://blog.csdn.net/axibazZ/article/details/126938520