前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Nginx高级应用:lua + OpenResty

Nginx高级应用:lua + OpenResty

作者头像
Java_慈祥
发布2024-08-06 13:51:21
1670
发布2024-08-06 13:51:21
举报
文章被收录于专栏:Web前后端、全栈出发

Nginx高级应用

应用场景:

该技术不仅仅是应用于, 广告缓存 只是常用于做广告的缓存!

广告缓存载入与读取

对于一个应用来多,每天都会有很多的用户来访问, 那么访问最多的就是首页了!

而对于首页这种,高访问,且 页面数据并不是,经常的变化! 为了减轻服务器的压力,直接将其制作成一个 静态的页面进行展示!

基本流程:

  • Nginx 都学习过了:可以通过反向代理实现,网关负载均衡的 服务器! 用户发送请求,首先通过 nginx , 通过nginx代理,负载均衡,请求对应的网关…模块。
  • 本次就是在用户登录/常用的操作, 请求时经过 nginx请求,在nginx中完成 调用redis数据操作,直接返回结果! 但,niginx并不具备 编程语言的特性 if else逻辑判断,访问数据库 redis; 它只是一个负载均衡器; 所以,需要通过lua 嵌入式语言 来完成
  • 首先访问nginx ,我们可以采用缓存的方式,先从nginx本地缓存中获取,获取到直接响应
  • 如果没有获取到,再次访问redis,我们可以从redis中获取数据,如果有 则返回,并缓存到nginx中
  • 如果没有获取到,再次访问mysql 我们从mysql中获取数据,再将数据存储到redis中。
  • 而这里面,我们都可以使用LUA脚本嵌入到程序中执行这些查询相关的业务。

Lua

简介:

  • Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放 c 作为底层语言,写的东西都快! 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

特性

  • 轻量级: 使用 C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里。
  • 可扩展: ** Lua提供了非常易于使用的扩展接口和机制** 内置了大量开发好的,脚本文件 mysql redis.... (通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。
  • 其它特性: 支持面向过程(procedure-oriented)编程和函数式编程(functional programming) 自动内存管理;只提供了一种通用类型的表(table) 实现数组,哈希表,集合,对象 通过闭包和table可以很方便地支持面向对象编程所需要的一些关键机制,比如数据抽象,虚函数,继承和重载等

应用场景

游戏开发独立应用脚本Web 应用脚本扩展和数据库插件如:MySQL Proxy 和 MySQL WorkBench

安装

并不需要安装,windows 只需要配置一下系统的环境变量即可: 环境变量也只是为了可以在系统的任意对方可以使用! Path: D:\WSMwork\lua(本人的安装路径

**lua53 或 lua53 -i **都可以启动lua

入门Lua

创建hello.lua文件
打印:print("输出内容!");
  • 创建文件,输入 print("hello");
  • 直接 cmd 运行:

执行命令:lua53 文件名.lua

LUA的基本语法(了解)

介绍:

  • lua有交互式编程和脚本式编程:
  • 交互式编程就是 启动lua直接输入语法,就能直接执行
  • 脚本式编程需要编写脚本,然后再执行命令 执行脚本才可以。 一般采用脚本式编程。(例如:编写一个hello.lua的文件,输入文件内容,并执行lua53 hell.lua即可lua53 不同版本的lua 执行要指定版本号!
  • 语法都是一样的,只是操作方式不同…下面了解lua 基本语法!

脚本式编程 创建 .lua文件, 进行执行...

注释:

hello.lua

代码语言:javascript
复制
-- 单行注释
--[[
	 多行注释
	 多行注释
]]--

定义变量

同Java 一样有,全局变量和局部变量:

  • 全局 整个文件可以使用!
  • 局部 指定方法内可以使用! hello.lua
代码语言:javascript
复制
-- 全局变量赋值
a=1
-- 局部变量赋值
local b=2 
-- ..拼接
print(a..b)
print(a..':'..b)

a='张三' 字符可以使用,单引号 或 双引号来表示,utf-8可能会乱码,建议文件编码 ANSl 如果变量没有初始化:则 它的值为nil 这和java中的null不同。

案例

数值运算还是通过 + - * /

Lua中的数据类型

  • Lua 是动态类型语言,变量不要类型定义,只需要为变量赋值。
  • 值可以存储在变量中,作为参数传递或结果返回。
  • Lua 中有 8 个基本类型分别为: nil、boolean、number、string、userdata、function、thread 和 table。

type( 值 ) 返回值的类型

代码语言:javascript
复制
print(type("Hello world"))      --> string
print(type(10.4*3))             --> number		包含double int 
print(type(print))              --> function
print(type(type))               --> function
print(type(true))               --> boolean
print(type(nil))                --> nil

流程控制

if语句 类似于Orcal的存储过程!
  • if 语句 由一个布尔表达式作为条件判断,其后紧跟其他语句组成。
代码语言:javascript
复制
-- 条件括号,可选:加或不加
if(布尔表达式)then  
   --[ 在布尔表达式为 true 时执行的语句 --]
end
if…elseif…eles…end语句
  • if 语句可以与 elseif 语句, else搭配使用, 在 if 条件表达式为 false 时执行 else 语句代码块。

if——else

代码语言:javascript
复制
if(布尔表达式)then
   --[ 布尔表达式为 true 时执行该语句块 --]
else
   --[ 布尔表达式为 false 时执行该语句块 --]
end

if——esleif——elseif——else——end

代码语言:javascript
复制
local age =15

if (age>=18) then
	print('成年人')
elseif age<18 then
	print('未成年')
else
	print('未出生')	
end 
测试:

循环

while循环[满足条件就循环] do … end
  • while 循环语句在判断条件为 true 时会重复执行循环体语句。
代码语言:javascript
复制
while(条件true执行)do
   print(‘执行循环内容…’)
end
for循环
  • for 循环语句可以重复执行指定语句,重复次数可在 for 语句中控制。
代码语言:javascript
复制
for var=exp1,exp2,exp3 do  
	print(‘执行循环内容…’)
end 
--[[
	var 从 exp1 变化到 exp2
	每次变化以 exp3 为步长递增 var 并执行一次 “执行体”。
	exp3 是可选的,如果不指定,默认为1。
]]--
repeat…until语句[满足条件结束]
  • repeat…until 循环语句不同于 for 和 while循环
  • for 和 while 循环的条件语句在当前循环执行开始时判断 repeat 无论如何都会执行一次until 条件成立true 则结束循环!
代码语言:javascript
复制
repeat
   print(‘执行循环内容…’)
until( true退出循环 )

函数

  • lua中也可以定义函数,类似于java中的方法。
代码语言:javascript
复制
--[[ 函数返回两个值的最大值 --]]
function max(num1, num2)
   if (num1 > num2) then
      result = num1;
   else
      result = num2;
   end

   return result; 
end
-- 调用函数
print("两值比较最大值为 ",max(10,4))
print("两值比较最大值为 ",max(5,6))

执行之后的结果:

table

  • table 是 Lua 的一种数据结构用来帮助我们创建不同的数据类型,如:数组、字典、对象等。
代码语言:javascript
复制
-- 初始化表mytable = {}

-- 指定值mytable[1]= "Lua"

-- 移除引用mytable = nil
测试Demo
代码语言:javascript
复制
table={}

table[0]="张三1"
table[1]="张三2"
table[2]="张三3"

--table 是一个对象
print(table)

--通过下标来获取值
print(table[0])

--table = nil 来清空表/对象
table = nui
print(table)
print(table[0])

模块

模块定义

  • 模块类似于一个封装库 Lua 5.1 开始,Lua 加入了标准的 模块管理机制,可以把一些公用的代码放在一个文件里; 以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。
创建一个文件叫module.lua

别忘了中文乱码,文件格式设置ASCII码 module.lua

代码语言:javascript
复制
-- 文件名为 module.lua
-- 定义一个名为 module 的模块,和文件名一样!
module = {}
 -- 定义一个常量
module.constant = "这是一个常量"
 -- 定义一个函数 module.func1
function module.func1()
	print("这是一个公有函数")
end
-- 定义一个局部(私有) 方法
-- 因此是不能从外部访问模块里的这个私有函数,必须通过模块里的公有函数来调用
local function func2()
	print("这是一个私有函数!")
end
-- 模拟调用私有方法...
function module.func3()
func2()
end
 
return module
  • 模块的结构就是一个 table 的结构,
  • 因此可以像操作调用 table 里的元素那样来操作调用模块里的常量或函数。
require 函数

require 用于引入其他的模块,类似于java中的类要引用别的类的效果。 要引入的模块,要放在一个文件夹下,可以是子文件!不然找不到!

代码语言:javascript
复制
require("<模块名>")
-- 或
require "<模块名>"

OpenResty

简介

  • OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台 内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。 用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
  • 简单来说: OpenResty 就是 Niginx, 集成了Lua的Niginx 使其具备了编程特性 由 OpenResty 团队自主开发) OpenResty下载

系统配置

目录结构:

D:\WSMwork\openresty-1.15.8.2-win64\lualib\resty 路径下包含了很多的lua 模块

配置:

配置lua库位置:修改openresty-1.15.8.2-win64\conf\nginx.conf 文件

接下来的大部分操作都是在: 自定义的lua.conf文件中执行

lua.conf

自定义的lua.conf

代码语言:javascript
复制
#给nginx 分内存 128m 兆  缓存大小!用于存放热点数据(频繁使用的数据!)
lua_shared_dict my_cache 128m;

#nginx服务
server {
	listen	9090;		#指定端口9090,默认80
	server_name	_;

	#静态模板地址设置...
	set $template_location "/templates";
	set $template_root "D:/templates";		#填写对应的地址...
	
	#nginx分流的请求路径...
	location /mylua{
		default_type text/html;
		#通过 content_by_lua_block{ lua的执行代码 }   ngx.say('是lua的浏览器输出方法!')
		content_by_lua_block{
			local age = 20
			if age>=18 then
				ngx.say('>=18');
			else 
				ngx.say('<18');
			end 
		}
	}
}
  • 这就是一个正常的 nginx的配置代码:
  • content_by_lua_block{ } lua的执行操作就写在这里 是nginx拥有了编程语言的特性! OpenResty1.9.3.2以前是 content_by_lua{ } 可通过 nginx -v 查看版本号!
  • ngx.say(‘是lua的浏览器输出方法!’) 就像Java的 Out打印流一样!

启动/刷新 nginx

启动命令

OpenResty目录下 cmd

  • nginx.exe 没有异常就是执行成功!

重启刷新命令

当修改了文件,频繁调用 nginx.exe是启动,开启进行造成堵塞!正确的方法是刷新,重启 OpenResty目录下 cmd

  • nginx.exe -s reload

测试

nginx端口占用,启动报错:bind() to 0.0.0.0:80 failed (10013: An attempt was made to access a …)

  • nginx.conf文件下还有默认的 80端口启动.. 可能会与电脑里某个端口冲突, 直接更改即可! 或者:停止进程 Windows操作! netstat -aon | findstr :80 80表示端口 tasklist|findstr "进程号"

OpenResty引入lua 文件:

在nginx 配置中写lua 代码不方便书写,可以直接在外面写好,调用即可!

代码语言:javascript
复制
location /mylua2{
	default_type text/html;
	content_by_lua_file D:/WSMwork/myweb.lua;
}
#content_by_lua_file 引入外部的lua文件, 分号结尾;

content_by_lua_file

引入外部的.lua 文件

定义一个文件 myweb.lua外部文件~ 刷新nginx

openresty中发起http请求

  • 有些场景是需要nginx在进行请求转发 这样就需要nginx需要有发起http请求的能力
  • nginx服务发起http请求区分内部请求 和 外部请求

为了方便测试,启动一个微服来查看

lua 脚本

myweb.lua

代码语言:javascript
复制
--设置编码格式!
ngx.header.content_type="text/html;charset=utf8"

--调用ngx 模块中的方法,返回请求url
local uri_args = ngx.req.get_uri_args()
--获取请求参数!
local zz = uri_args["zz"]
--获取http 模块,require( );
local http = require("resty.http")
--http模块 new( ) 一个httpc对象
local httpc = http.new()

--..拼接参数 wd
local resp = httpc:request_uri("http://127.0.0.1:9002/info/hello/"..zz,{
	method = "GET",	--get请求;
	keepalive=false	--无论如何都请求;
})
--返回参结果,打印结果!
local val = resp.body
ngx.say(val)

测试

注意这里的参数是在 nginx,9090端口的请求参数!

require(“resty.http”)

就是这个lua模块负载发送请求, OpenResty 中存在着很多的,lua脚本模块…

获取POST请求参数

跟get 非常类似…

代码语言:javascript
复制
ngx.req.read_body()					--获取请求url
local arg = ngx.req.get_post_args()	--参数集合 Map类型!
--声明几个用于存储的空对象
id=nil		
deptname=nil
--循环参数集合!
for k,v in pairs(arg) do 
	--判断参数,key 进行参数赋值!
	if k=="id" then
		id = v
	end
	if k=="deptname" then
		deptname = v
	end 
end 
--页面输出!
ngx.say("deptname: ", deptname)
ngx.say("id: ", id)

使用postman 进行Post请求:

openresty中使用redis模块

  • 在一些高并发的场景中,我们常常会用到缓存技术
  • 现在我们常用的分布式缓存redis是最知名的 我们需要引入redis模块 require “resty.redis”

lua 脚本

myweb.lua

代码语言:javascript
复制
-- 定义私有方法
local function close_redis(red)
    if not red then
        return
    end
    -- 释放连接(连接池实现),毫秒
    local pool_max_idle_time = 10000 
    -- 连接池大小
    local pool_size = 100 
    local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
    local log = ngx_log
    if not ok then
        log(ngx_ERR, "set redis keepalive error : ", err)
    end
end


-- 连接redis
local redis = require('resty.redis')	--引入模块
local red = redis.new()
red:set_timeout(1000)

local ip = "127.0.0.1"
local port = "6379" 
-- local pwd= "ok"		本人没有密码直接注释!	

-- 连接测试 ip 端口是否正确...
ok, err = red:connect(ip,port)
if not ok then
    ngx.say("failed to auth: ", err)
    return close_redis(red)
end

-- 密码是否正确 没有密码直接注释!
--[[
ok, err = red:auth(pwd)
if not ok then
    ngx.say("failed to auth: ", err)
    return close_redis(red)
end
]]--
--获取redis第一个库,redis一共16给库
red:select('0')
red:set("msg","test ngx hello")	--set存入一个msg key,值:test ngx hello
-- get根据key查找... 并处理异常
local resp, err = red:get("msg")  
if not resp then  
    ngx.say("get msg error : ", err)  
    return close_redis(red)  
end
--打印关闭资源!
ngx.say("msg : ", resp)
close_redis(red)

记得要启动redis 哦!

安装目录下:redis-server.exe

查看所以key

测试:

直接网关请求!

openresty中操作mysql

数据库

既然要数据库操作,那么就搞个数据库吧!mysql

lua 脚本

myweb.lua

代码语言:javascript
复制
--创建连接mysql模块
local mysql = require "resty.mysql"
-- connect to mysql;
local db, err = mysql:new()

if not db then
	return false	--没连上关闭!
end
--超时时间
db:set_timeout(1000)	
--设置连接信息
local ok, err, errno, sqlstate = db:connect{
	host = "127.0.0.1",	--ip
	port = 3306,		--端口
	database = "book",	--连接的数据库
	user = "root",		--用户
	password = "ok",	--密码
	max_packet_size = 1024 * 1024	--字节大小 1m 
}
--验证是否连接上
if not ok then
	ngx.say("connect mysql failed")
	return false	--没连上关闭
end

if db == false then
    ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
    return
end

ngx.say("----------查询数据----------------","<br/>")

res, err, errcode, sqlstate =
    db:query("SELECT * FROM bookinfo")		--实际情况,可能还需要拼接参数....

--没有数据,返回...异常!
if not res then
    ngx.say("bad result: ", err, ": ", errcode, ": ", sqlstate, ".")
    return
end
--获取JSON 模块
local cjson = require "cjson"
--JSON翻译,页面输出
ngx.say("result: ", cjson.encode(res))

--如果是新增...
--[[
--如果没有返回结果,新增异常提示!
if not res then 
    ngx.say("insert failed")
    return 
end
--返回影响行数
ngx.say("insert rows :", res.affected_rows,", id", res.insert_id, "<br/>")
]]--

结果测试:

扩展:

  • 推荐使用 nginx 引用外部的lua使用 方便排错,如果出现错误,直接控制台运行lua 脚本即可! 结构清晰…
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-08-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Nginx高级应用
  • 应用场景:
    • 广告缓存载入与读取
      • 基本流程:
      • Lua
        • 简介:
          • 特性
            • 应用场景
              • 安装
                • 入门Lua
                  • 创建hello.lua文件
                  • 打印:print("输出内容!");
              • LUA的基本语法(了解)
                • 介绍:
                  • 脚本式编程 创建 .lua文件, 进行执行...
                    • 注释:
                      • 定义变量
                        • 案例
                      • Lua中的数据类型
                        • 流程控制
                          • if语句 类似于Orcal的存储过程!
                          • if…elseif…eles…end语句
                        • 循环
                          • while循环[满足条件就循环] do … end
                          • for循环
                          • repeat…until语句[满足条件结束]
                        • 函数
                          • 表 table
                            • 测试Demo
                          • 模块
                            • 创建一个文件叫module.lua
                            • require 函数
                        • OpenResty
                          • 简介
                            • 系统配置
                              • 目录结构:
                              • 配置:
                          • lua.conf
                          • 启动/刷新 nginx
                            • 启动命令
                              • 重启刷新命令
                                • 测试
                                • OpenResty引入lua 文件:
                                  • content_by_lua_file
                                    • 定义一个文件 myweb.lua外部文件~ 刷新nginx
                                    • openresty中发起http请求
                                      • 为了方便测试,启动一个微服来查看
                                        • lua 脚本
                                          • 测试
                                            • require(“resty.http”)
                                              • 获取POST请求参数
                                                • 使用postman 进行Post请求:
                                                • openresty中使用redis模块
                                                  • lua 脚本
                                                    • 记得要启动redis 哦!
                                                      • 查看所以key
                                                        • 测试:
                                                        • openresty中操作mysql
                                                          • 数据库
                                                            • lua 脚本
                                                              • 结果测试:
                                                              • 扩展:
                                                              相关产品与服务
                                                              负载均衡
                                                              负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
                                                              领券
                                                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档