nginx 集成lua操作mysql的过程解析

目录
  • 前言
  • 实现思路
  • ngx_lua模块概念
  • OpenRestry安装步骤
    • 1、下载OpenRestry
    • 2、解压缩文件
    • 3、进入OpenResty目录执行配置
    • 4、 执行命令:make && make install
    • 5、进入OpenResty的目录配置nginx
    • 6、启动nginx并测试
  • ngx_lua常用指令
  • 代码实现
  • lua操作redis
  • lua-resty-redis环境准备
  • lua-resty-redis常用API
  • ngx_lua操作Mysql
  • lua-resty-mysql API说明

前言

lua是一夸小巧,灵活且高效的脚本语言,用标准C语言编写并以源代码形式开发,在很多业务场景下配合适当的设计,可以带来意想不到的效果;

举个常见的例子,现在几乎很多公司都会用到nginx作为代理服务器,假如现在有这么个需求,需要做黑名单过滤,或者在网关这一层做流控,这该怎么做呢?

实现思路

  • 直接在nginx做配置黑名单,通过编写逻辑块实现;
  • 在服务端(Java)中编写过滤器,在过滤器中统一拦截;
  • 在服务端(Java)中编写拦截器,在拦截器中统一拦截;

这里列举了3种实现的思路,至于实现方案,可能还有更多,但是我们想想,在nginx中编写逻辑块貌似不是很多人擅长的;在代码层面做不是不可以,而是这样一来,在涉及到高并发的业务高峰期,这必然会对后端服务造成较大的压力,那么还有没有其他更好的处理办法呢?

这就是要说的lua,即nginx作为网关仍然作为代理服务器,由于nginx可以集成lua,于是使用lua进行配合,来完成上面的业务实现的设计;

ngx_lua模块概念

  • ngx_lua模块由淘宝技术团队开发,通过将lua解释器集成进Nginx;
  • 可采用lua脚本实现业务逻辑,由于lua的紧凑、快速以及内建协程,所以在保证高并发服务能力的同时极大地降低了业务逻辑实现成本;
  • OpenRestry
  • OpenResty是一个基于Nginx与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua库、第三方模块以及大多数的依赖项;用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关;
  • OpenResty内部已经集成了Nginx和Lua,所以使用起来会更加方便;

简单来说,直接安装并使用OpenRestry,就可以达到同时使用Nginx与Lua的效果,同时基于OpenRestry,还可以在内部操作其他中间件,比如mysql,redis,kafka等,这样就使得业务架构在设计上具备了更大的灵活性;

OpenRestry安装步骤

1、下载OpenRestry

wget https://openresty.org/download/openresty-1.15.8.2.tar.gz

2、解压缩文件

tar -zxf openresty-1.15.8.2.tar.gz

3、进入OpenResty目录执行配置

这一步有点类似于nginx的源码安装,进行相关的环境变量的配置,这里直接使用默认的就好;

./configure

4、 执行命令:make && make install

5、进入OpenResty的目录配置nginx

进入nginx目录,可以看到里面的目录和nginx自身安装完毕后的配置几乎一样

进入conf,找到nginx.conf配置文件,添加如下内容:

location /lua {
    default_type 'text/html';
    content_by_lua 'ngx.say(" <h1>hello,openRestry lua</h1>")';
}

6、启动nginx并测试

进入nginx的sbin目录下启动nginx

启动完成后,浏览器访问下服务器即可,可以看到nginx本身服务已启动

然后访问上面配置的lua地址,可以看到也能够正常的访问到,说明openrestry的模块已经安装完毕

ngx_lua常用指令

使用Lua编写Nginx脚本的基本构建块是指令,指令用于指定何时运行用户Lua代码以及如何使用结果,下面针对一些常用的指令做简单的说明

1、init_by_lua*

该指令在每次Nginx重新加载配置时执行,用来完成一些耗时操作模块加载,或初始化一些全局配置

2、init_worker_by_lua*

该指令用于启动一些定时任务,如心跳检查、定时拉取服务器配置等

3、set_by_lua*

该指令只要用来给变量赋值,这个指令一次只能返回一个值,并将结果 值给Nginx中指定变量

4、rewrite_by_lua*

用于执行内部URL重写或者外部重定向,典型的如伪静态化URL重 写,本阶段在rewrite处理阶段的最后默认执行(和nginx自身的rewrite功能有类似的地方)

5、access_by_lua*

该指令用于访问控制,例如,只允许内网IP访问

6、content_by_lua*

该指令是使用最多的指令,大部分任务是在这个阶段完成的,其他过程往往为这个阶段准备数据,正式处理往往都在本阶段执行

7、header_filter_by_lua*

用于设置应答消息的头部信息

8、body_filter_by_lua*

该指令对响应数据进行过滤,如截断、替换

9、log_by_lua*

该指令用于log请求处理阶段,用Lua代码处理日志,但并不替换原有 log处理

10、balancer_by_lua*

该指令主要作用是用来实现上游服务器的负载均衡器算法

11、ssl_certificate_by_*

该指令作用在Nginx和下游服务开始一个SSL握手操作时将允许本配置项的Lua代码

一个使用指令的需求

接下来针对上面提到的各种指令,来做一个简单的需求

nginx接收到请求后,根据参数中gender传入的值,如果gender传入的是1 则在页面上展示 “先生” , 如果gender传入的是0,则在页面上展示“女士”

代码实现

注意:使用指令编写的基本步骤是,在nginx.conf模块中,自定义localtion块中编写lua的相关代码即可

location /getByGender {
          default_type 'text/html';
          set_by_lua $param "

                local uri_args = ngx.req.get_uri_args()
                local gender = uri_args['gender']
                local name = uri_args['name']
                if gender =='1' then
                       return name..':先生'
                elseif gender=='0' then
                       return name..':女士'
                else
                       return name
                end
          ";
          charset utf-8;
          return 200 $param;
 }

然后启动nginx做一下测试

1)访问服务,不携带任何参数

这时候无任何返回信息

2)访问服务,携带name参数

3)访问服务,携带name和gender参数

更多的指令可以参照此类方式编写,但是前提需要掌握一点lua的基本语法

lua操作redis

Redis在系统中经常作为数据缓存、内存数据库使用,在各类互联网项目中扮演着非常重要的作用;

Lua-resty-redis库是OpenResty提供的一个操作Redis的接口库,可根据自己的业务情况做一些逻辑处理,适合做复杂的业务逻辑。所以下面将以Lua-resty-redis来进行说明。

lua-resty-redis环境准备

1、提前安装好redis并启动服务

2、测试下redis客户端

lua-resty-redis提供了访问Redis的详细API,包括创建对接、连 接、操作、数据处理等。这些API基本上与Redis的操作是对应起来的

lua-resty-redis常用API

1、lua中导入redis依赖

redis = require "resty.redis"

2、new,创建一个Redis对象

redis,err = redis:new()

3、创建redis连接

  • ok:连接成功返回 1,连接失败返回nil;
  • err:返回对应的错误信息;

ok,err=redis:connect(host,port[,options_table])

4、设置请求操作Redis的超时时间

redis:set_timeout(time)

5、close,关闭连接

  • 关闭当前连接,成功返回1;
  • 失败返回nil和错误信息;

ok,err = redis:close()

补充说明:

在lua-resty-redis中,所有的Redis命令都有自己的方法;方法名字和命令名字相同,只是全部为小写;

具体实现效果展示

在nginx.conf模块下,添加如下的location内容

location /redis {
    default_type "text/html";
    content_by_lua_block {
        local redis = require "resty.redis"     -- 引入 Redis
        local redisObj = redis:new()            --创建Redis对象
        redisObj:set_timeout(3000)              --设置超时数据为3s
        local ok,err = redisObj:connect("IP",6379)    --设置redis连接信息
        if not ok then                          --判断是否连接成功
            ngx.say("failed to connection redis",err)
            return
        end
        ok,err = redisObj:set("username","TOM")     --存入 数据
        if not ok then                              --判断是否存入成功
            ngx.say("failed to set username",err)
            return
        end
        local res,err = redisObj:get("username")    --从 redis中获取数据
        ngx.say(res) --将数据写会消息体中
        redisObj:close()
    }
}

重启nginx,进行测试,直接在浏览器访问一下如下地址,可以看到数据成功写入到redis


ngx_lua操作Mysql

MySQL是一个使用广泛的关系型数据库。在ngx_lua中,MySQL有两种访问模式,分别是

  • 用ngx_lua模块和lua-resty-mysql模块: 这两个模块是安装OpenResty时默认安装的;
  • 使用drizzle_nginx_module(HttpDrizzleModule)模块:需要单独

安装,这个库现不在OpenResty中

lua-resty-mysql

lua-resty-mysql是OpenResty开发的模块,使用灵活、功能强大,适合复杂的业务场景,同时支持存储过程访问;

lua-resty-mysql实现数据库查询

1、准备好mysql服务

2、提前创建一张表

CREATE TABLE `users` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  `salary` double(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

并提前准备几条数据

INSERT INTO `mydb`.`users` (`id`, `username`, `birthday`, `salary`) VALUES ('1', 'xiaowang', '1991-03-15', '9000.00');
INSERT INTO `mydb`.`users` (`id`, `username`, `birthday`, `salary`) VALUES ('2', 'xiaoma', '1992-07-15', '8000.00');

lua-resty-mysql API说明

1、引入"resty.mysql"模块

local mysql = require "resty.mysql"

2、创建MySQL连接对象

遇到错误时,db为nil,err为错误描 述信息

db,err = mysql:new()

3、创建连接对象

ok,err=db:connect(options)

options是一个参数的 Lua表结构,里面包含数据库连接的相关信息

  • host:服务器主机名或IP地址
  • port:服务器监听端口,默认为3306
  • user:登录的用户名
  • password:登录密码
  • database:使用的数据库名

4、设置子请求的超时时间(ms)

包括connect方法

db:set_timeout(time)

5、关闭当前MySQL连接并返回状态

如果成功,则返回1;如果出现任 何错误,则将返回nil和错误描述

db:close()

6、异步向远程MySQL发送一个查询

如果成功则返回成功发送的字节 数;如果错误,则返回nil和错误描述

bytes,err=db:send_query(sql)

7、从MySQL服务器返回结果中读取一行数据

  • res返回一个描述OK包 或结果集包的Lua表
  • rows指定返回结果集的最大值,默认为4
  • 如果是查询,则返回一个容纳多行的数组。每行是一个数据列的 key-value对
res, err, errcode, sqlstate = db:read_result() res, err, errcode, sqlstate = db:read_result(rows)

返回结果类似下面这样

{
{id=1,username="TOM",birthday="1988-11- 11",salary=10000.0}, {id=2,username="JERRY",birthday="1989-11- 11",salary=20000.0}
}

如果是增删改,则返回类似如下数据

{
	insert_id = 0,
	server_status=2,
	warning_count=1,
	affected_rows=2,
	message=nil
}

返回值说明:

  • res:操作的结果集
  • err:错误信息
  • errcode:MySQL的错误码,比如1064
  • sqlstate:返回由5个字符组成的标准SQL错误码,比如 42000

具体操作案例

将下面的内容添加到server块,然后重启nginx

location /mysql {
     content_by_lua_block{
		default_type "text/html";
        local mysql = require "resty.mysql"
        local db = mysql:new()
        local ok,err = db:connect{
            host="127.0.0.1",
            port=3306,
            user="root",
            password="123456",
            database="mydb"
        }
            db:set_timeout(3000)
            db:send_query("select * from users where id =1")
            local res,err,errcode,sqlstate = db:read_result()
            ngx.say(res[1].id..","..res[1].username..","..res[1]. birthday..","..res[1].salary)
            db:close()
    }
}

可以看到,通过访问mysql这个路径,成功查询到数据库中ID为1的这条数据

使用cjson对查询结果进行格式化

从上面的返回结果来看,这种形式的返回数据在解析的时候其实并不是很友好,于是可以使用lua-cjson处理查询结果

使用步骤

步骤一:引入cjson

local cjson = require “cjson”

步骤二:调用cjson的encode方法进行类型转换

cjson.encode(res)

下面对上面程序模块做简单的改造

location /mysql-cjson {
		default_type "text/html";
     content_by_lua_block{
     	local cjson = require "cjson"
        local mysql = require "resty.mysql"
        local db = mysql:new()
        local ok,err = db:connect{
            host="127.0.0.1",
            port=3306,
            user="root",
            password="123456",
            database="mydb"
        }
            db:set_timeout(3000)
            db:send_query("select * from users")
            local res,err,errcode,sqlstate = db:read_result()
            ngx.say(cjson.encode(res))
            for i,v in ipairs(res) do
                ngx.say(v.id..","..v.username..","..v.birthday..",".. v.salary)
            end
            db:close()
    }
}

然后再次进行测试,这时候就以json的格式对数据进行了展现

增删改操作

location /mysql-cjson {
		default_type "text/html";
     content_by_lua_block{
     	local cjson = require "cjson"
        local mysql = require "resty.mysql" 

        local db = mysql:new() 

        local ok,err = db:connect{
            host="127.0.0.1",
            port=3306,
            user="root",
            password="123456",
            database="mydb"
        }
            db:set_timeout(3000)
            -- 查询操作
            db:send_query("select * from users where id=1")
			-- 插入数据
			--local res,err,errcode,sqlstate = db:query("insert into users(id,username,birthday,salary) values(3,'lifei','1995-10-17',3000)")
			-- 修改数据
			--local res,err,errcode,sqlstate = db:query("update users set username='lisi' where id = 1")
			-- 删除数据
			--local res,err,errcode,sqlstate = db:query("delete from users where id = 2")
            db:close()
    }
}

到此这篇关于nginx 集成lua操作mysql的过程解析的文章就介绍到这了,更多相关nginx lua操作mysql内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Nginx+lua 实现调用.so文件

    最近在和智能硬件部门一起,做一个室内定位的服务,该服务根据手机端传过来的beacon设备列表,根据一定的算法计算出具体的商场,并将商场ID和beason设备列表作为参数,调用.so文件中的计算方法,得出位置数据(坐标:x.y.z),返回给手机端. 因为服务对QPS要求比较高,并且都是纯查询操作,于是决定使用Nginx+lua+Redis的架构(该架构在公司内部已成主流,比较成熟).下面我将对lua调用.so文件的方式,做一下介绍. lua调用.so文件,主要有两种方式: 1.Lua直接调用动态链

  • 使用Nginx和Lua进行JWT校验介绍

    目录 前言 Lua脚本 nignx.conf配置 Dockerfile配置 前言 因为不涉及到数据库和其它资源的依赖,jwt本身也是无状态的.因此鉴权服务没有再基于Java或者其它语言来做.而是使用lua脚本对nginx做了一个增强:使用lua脚本来校验token是否有效,无效直接返回401,有效则原样转发. Lua脚本 这里的secret我遇到了很大的坑.一开始直接从Java后端项目中复制了密钥出来,但是一直提示signature mismatch:,后来发现后端应用中使用base64deco

  • Lua和Nginx结合使用的超级指南

     Nginx作为API代理 有很多原因说明你为什使用nginx作为API代理.首先因为他是开源的:其次,Nginx有大量的安装基础,他背后有一个强大的社区支持,在性能方面也表现的非常出色.对于我们来说,这是显而易见的,如果开源软件有相同的解决方案我们为啥还要用那些私有的软件. 另外一个极大的优势就是nginx对lua的支持,nginx+lua是一个非常好的组合,它允许使用一个高性能的脚本语言扩展nginx.nginx有很多方法是自带的,但是使用lua没有限制的. 原理很简单.有没有这样的情况你更

  • Nginx添加lua模块的实现方法

    安装 lua wget http://luajit.org/download/LuaJIT-2.0.5.tar.gz tar -zxvf LuaJIT-2.0.5.tar.gz cd LuaJIT-2.0.5 make && make install PREFIX=/usr/local/LuaJIT etc/profile 加入 # lua export LUAJIT_LIB=/usr/local/LuaJIT/lib export LUAJIT_INC=/usr/local/LuaJIT

  • Nginx使用Lua模块实现WAF的原理解析

    目录 一.WAF产生的背景 二.什么是WAF 三.工作原理 四.WAF作用 五.WAF和传统防火墙的区别 六.WAF和DDos 七.Nginx WAF功能 八.Nginx Waf防护流程 九.基于Nginx实现的WAF 9.1安装依赖包 9.2安装LuaJIT2.0 9.3安装ngx_devel_kit 9.4安装lua-nginx-module 9.5安装Nginx 9.6安装ngx_lua_waf 9.7测试效果 前言:最近一段时间在写加密数据功能,对安全相关知识还是缺少积累,无意间接触到了

  • nginx 集成lua操作mysql的过程解析

    目录 前言 实现思路 ngx_lua模块概念 OpenRestry安装步骤 1.下载OpenRestry 2.解压缩文件 3.进入OpenResty目录执行配置 4. 执行命令:make && make install 5.进入OpenResty的目录配置nginx 6.启动nginx并测试 ngx_lua常用指令 代码实现 lua操作redis lua-resty-redis环境准备 lua-resty-redis常用API ngx_lua操作Mysql lua-resty-mysql

  • 原生Java操作mysql数据库过程解析

    这篇文章主要介绍了原生Java操作mysql数据库过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.引入数据库驱动的jar包 以通过maven引入mysql driver为例 1.1 到http://mvnrepository.com 搜索 mysql 1.2 复制所需maven配置文件到工程的 pom.xml <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-

  • Python基于DB-API操作MySQL数据库过程解析

    Python提供了一个标准数据库API,称为DB-API,用于处理基于SQL的数据库. 与任何底层数据库的交互都可以使用DB-API,因为DB-API在代码与驱动程序之间提供了一个抽象层,可以根据需要替换底层数据库,而无需丢弃现有的代码. DB-API与底层数据库交互示例: ①代码 ⇆ ②使用DB-API ⇆ ③数据库驱动程序 ⇆ ④底层数据库(如MySQL等) 使用DB-API操作MySQL数据库例子 1.Windows安装MySQL数据库驱动程序MySQL-Connector/Python

  • python操作gitlab API过程解析

    这篇文章主要介绍了python操作gitlab API过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 使用 python-gitlab 模块来调用gitlab的API来管理gitlab install pip install python-gitlab # 如果是安装到Python3使用可以使用如下命令 pip3 install python-gitlab 配置 为了保护API 用到的 private_token,一般会将其写到系统的配

  • MySql如何实现远程登录MySql数据库过程解析

    导读:有时候,为了开发项目,我们需要在一台服务器上部署MySql数据库服务器,然后使用本地电脑远程访问和管理MySql数据库,那么如何实现MySql的远程登录呢? 1.使用命令行远程登录MySql数据库 首先你需要在远程数据库上创建一个用户(不建议使用root用户),并给该用户授予可以远程登录的权限,可以参考我的另一套教程<MySql全套攻略--添加新用户.为用户创建数据库和给用户分配权限>,博客地址为点击打开链接. 这里需要注意,如果是在Ubuntu上部署MySql服务器,需要修改其配置文件

  • Linux shell操作mysql数据库深入解析

    在shell开发中,很多时候我们需要操作mysql数据库(比如:查询数据.导出数据等),但是我们又无法进入mysql命令行的环境,就需要在shell环境中模拟mysql的环境,使用mysql相关命令,本文总结几种shell操作mysql的方法,供大家参考. 方案1 复制代码 代码如下: mysql -uuser -ppasswd -e"insert LogTable values(...)" 优点:语句简单缺点:支持的sql相对简单 方案2准备一个sql脚本,名字为update.sql

  • 使用SQLAlchemy操作数据库表过程解析

    需求场景: 使用sqlalchmy从现有的表中获取数据(不是自己建表).百度了一下,网上都是使用sqlalchemy自己先创建表,然后导入数据表的模型类进行增删改查:现在不是自己建表,该如何操作呢? 操作方案 通过sqlalchmey执行原生的sql语句,增删改查的原生语句携带表名,就不需要导入数据表的模型类了. 使用的包: SQLAlchemy (1.3.10) + mysql-connector-python (8.0.19) 提供以下干货: 演示了向原生sql语句传递变量的用法 即动态执行

  • Python操作SQLite数据库过程解析

    SQLite是一款轻型的数据库,是遵守ACID的关系型数据库管理系统. 不像常见的客户-服务器范例,SQLite引擎不是个程序与之通信的独立进程,而是连接到程序中成为它的一个主要部分.所以主要的通信协议是在编程语言内的直接API调用. Python标准库包含一个SQLite包装器:使用模块sqlite3实现的PySQLite. 下面是一个操作SQLite数据库的例子:创建表.插入记录.查询记录. import sqlite3 #创建直接到数据库文件的连接,如果文件不存在则自动创建 conn =

  • Python如何操作docker redis过程解析

    使用操作命令借助subprocess模块进行操作 #encoding:utf-8 import subprocess def cmd(command): subp = subprocess.Popen(command,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,encoding="utf-8") subp.wait(2) if subp.poll() == 0: return subp.communicate() e

  • Nginx服务器添加Systemd自定义服务过程解析

    一.以nginx为例 使用yum命令安装的nginx Systemd服务文件以.service结尾,比如现在要建立nginx为开机启动,如果用yum install命令安装的,yum命令会自动创建nginx.service文件,直接用命令: systemcel enable nginx.service //开机自启 使用源码编译安装的 1.手动创建nginx.service服务文件.并将其放入 /lib/systemd/system 文件夹中. nginx.service内容如下: [Unit]

随机推荐