一. Lua语言
1. C编写脚本语言
2. 作用: 灵活嵌入应用 -> 扩展和定制功能
3. 不提供库, 不适合作为开发独立应用的语言
4. 即时编译: JIT项目
5. 特点:
(1) 面向过程 procedure-oriented
(2) 函数式编程 functional-programming
(3) 自动内存管理: 通用类型的表table -> 实现数组, 哈希表, 集合, 对象
(4) 语言内置模式匹配
(5) 闭包
(6) 函数也可以看做是一个值
(7) 多线程 -> 协同线程
(8) 闭包和table -> 支持数据抽象, 虚函数, 继承和重载
6.应用场景:
(1) 游戏开发
(2) 独立应用脚本
(3) Web应用脚本
(4) 扩展和数据库插件: MySQL Proxy
(5) 安全系统: 入侵检测系统
(6) Redis嵌套调用实现类似事务的功能
(7) Web容器中应用处理 过滤, 缓存逻辑
7. 安装步骤:
(1) yum install -y gcc
(2) yum install libetermcap-devel ncurses-devel libevent-devel readline-devel
(3) curl -R -O http://www.lua.org/ftp/lua-5.3.5.tar.gz
(4) tar -zxf lua-5.3.5.tar.gz
(5) cd lua-5.3.5
(6) make linux test
(7) make install
8. lua基本语法:
(1)交互式编程: 直接输入语法执行
(2) 脚本式编程: 编写脚本文件, 再执行
(3) 注释:
1) 单行注释: --
2) 多行注释: --[[]]--
(4) 关键字:
1) nil -> 声明变量值无效
2) and / break / do / else / elseif / end / false / for / function / if / in / local / not / or / repeat / return / then / true / until / while
(5) 变量:
1) 全局变量: a=1
2) 局部变量: local b=2
3) 动态类型 -> 不用定义变量类型
4) nil -> 无效值
5) boolean -> true/false
6) number -> 双精度类型的实浮点数
7) string -> 由 '' 或 "" 表示
8) function -> 函数
9) userdata -> 储存在变量中的C数据结构
10) thread -> 独立线路, 执行协同程序
11) table -> 表 -> 关联数组associatIve array -> index=number/string/table
(6) 流程控制:
1) if(o) then
print('0为true')
else
print('o不为true')
end
(7) 函数:
--定义函数比较两个值的大小
function max(num1, bum2)
if(num1>num2) then
result=num1;
else
result=num2;
end
return result;
end
--调用函数
print(max(10,5));
(8) require函数: //引入其他模块
require "<模块名>"
二. NGinx+Lua+Redis实现广告缓存[部署在Linux虚拟机上]
1. nginx: 高性能http服务器, 5万并发
2.Tomcat集群超过5台服务器后, 性能不升反降
3. nginx功能:
(1) 负载均衡器load balance: 接收请求 -> 分发 -> Tomcat集群
(2) 反向代理: 客户端请求nginx服务器 -> nginx根据请求的url地址判断 -> 去访问代理的目标服务器
(3) HTTP服务器: 存放静态资源(html, css, js, img) -> 放在nginx/html目录下
4. Openresty
(1) 含义: ngx_openresty. 基于NGinx的web平台
(2) Openresty = NGinx+Lua
(3) 作用:
1) 支持Lua模块
2) 调动NGinx支持的C模块
3) web服务器跑在nginx服务器内部
4) 1万-100万的并发
(4) Linux安装Openresty:
1) 执行仓库命令:
yum install yum-utils
yum-config-manager --add--repo
https://openresty.org/package/centos/openresty.repo
2) 执行安装:
yum install openresty
3) 默认安装目录:
/usr/local/openresty
4) 默认携带nginx:
目录 /usr/local/openresty/nginx
5) 修改nginx.conf配置文件: /usr/local/openresty/nginx/conf/nginx.conf
#配置文件第一行改为
user root root //执行nginx时, 会加载根目录root下的Lua脚本
#在80端口的server中 添加访问的lua文件
location/ad_update{
content_by_lua_file /root/lua/ad_update.lua; #基于content属性加载lua文件
}
location/ad_read{
content_by_lua_file /root/lua/ad_read.lua;
}
5. 实现加载广告数据:
1. tb_ad表: position字段 -> 区分广告位置
2. 实现步骤:
(1) 缓存预热: Lua预加载广告数据 -> 从MySQL取出数据 -> 存入Redis
1) 基于Lua连接MySQL:
a. 查询广告分类id -> 读取广告列表 -> 转换json字符串
b. 创建 ad_update.lua
nginx.header.content_type="application/json;charset=utf8" #传递json数据
local cjson = require("cjson") #引入json支持
local mysql = require("resty.mysql") #引入mysql支持
local uri_args = ngx.req.get_uri_args() #获取请求路径的参数 赋值给局部变量
local position = uri_args["position"] #获取请求参数的特定字段 "position"
local db = mysql:new() #开启mysql的新连接
db:set_timeout(1000) #设置数据库连接超时时间
local_props = {
host = "192.168.200.128",
port = 3306,
database = "changgou_business",
user = "root",
password = "root"
}
local res = db:connect(props) #基于四大参数连接mysql
local select_sql = "select url, image from tb_ad status ='1' and position='"..position.."' and start_time<=NOW() AND end_time>=NOW()"
res = db:query(select_sql) #传递执行的SQL语句
db:close() #关闭连接池
local redis = require("resty_redis") #引入redis模块
local red = redis:new() #开启redis连接
red:set_timeout(2000) #设置redis连接超时时间
local ip = "192.168.200.128" #设置连接ip地址
local port = 6379 #redis端口号
red:connect(ip, port) #连接redis
res:set("ad_"..position, cjson.encode(res)) #设置存入redis的内容
res:close() #关闭redis连接
ngx.say("{flag:true}") #返回信息
c. 重启测试: systemctl restart openresty
或: cd nginx/sbin -> ./nginx -s reload
2) 基于Luq连接Redis:
a. 创建 ad_read.lua文件
ngx.header.content_type="application/json;charset=utf8
local uri_args = ngx.req.get_uri_qrgs();
local position = uri_args["position"];
local redis = require("resty.redis");
local red = redis:new()
red:set_timeout(2000)
local ok, err = red:connect("192.168.200.128", 6379)
local rescontent = red:get("ad_"..position) #查询redis的广告数据存入变量
nginx.say(rescontent) #输出变量
red:close()
(2) 二级缓存查询: 客户端查询 -> 先查询openresty本地缓存 -> 无则查询Redis -> 再存入本地缓存
-> 再返回到客户端
1) 修改ad_read.lua:
ngx.header.content_type="application/json;charset=utf8
local uri_args = ngx.req.get_uri_qrgs();
local position = uri_args["position"];
local cache_ngx = ngx.shared.dis_cache; #开启本地缓存
local adCache = cache_ngx:get('ad_cache_'..position); #在本地缓存中查询数据
if(adCache==""or addCache==nil then #判断当前结果为空或无效
local redis = require("resty.redis");
local red = redis:new()
red:set_timeout(2000)
local ok, err = red:connect("192.168.200.128", 6379)
local rescontent = red:get("ad_"..position)
nginx.say(rescontent)
red:close()
cache_ngx:set('ad_cache_'..postition, rescontent, 10*60); #存入本地缓存
else
ngx.say(addCache)
end
(3) 修改nginx.conf:
添加: lua_shared_dict dis_cache 5m; #共享内存开启, 包含redis初始化模块
(4) 上传静态资源到nginx -> 本地缓存需加载:
1) 使用MobaXterm
2) 保存到 usr/local/openresty/nginx/html
三. NGinx限流
1. 使用场景: 首页并发量大, 避免宕机 -> nginx控制速率和并发连接数
2. 网关令牌桶算法 -> 控制填充令牌 -> 访问消耗令牌 -> 够则访问 -> 不够则拒绝
3. nginx控制速率: 漏桶算法 -> 请求流入桶中 -> 控制请求流出桶的速率 -> 大于接口响应速率时拒绝
4. 令牌桶控制令牌进入的速度, 漏桶控制访问流出的速度
5.实现: 添加配置到nginx.conf
#在nginx.conf中添加以下配置
#声明进行限流控制 -> zone代表桶的大小1MB=16000个IP地址 -> rate每秒访问2次 即每500毫秒处理一个请求
limit_req_zone $binary_remote_addr zone=myRateLimit: 10m rate=2r/s
server{
listen 8081;
server_name localhost;
charset utf-8;
location / {
limit_req zone=myRateLimit; #把上面的配置放入属性中
root html;
index index.html index.htm;
}
}
6. 处理突发流量:
(1). 场景: 正常流量 -> 突然增大 -> 请求被拒绝
(2) 添加 burst属性:
limit_req zone=myRateLimit burst=5; #添加burst属性, 正常访问速率外可以额外处理5个
(3) 6个请求同时到达 -> 先处理1个 -> 剩下5个放入队列 -> 每500ms取出1个;
(4) 请求数>6个, 则直接返回503
(5) 添加 nodelay属性: 不会每500毫秒处理突发的请求, 而是无延迟处理
limit_req zone=myRateLimit burst=5 nodelay; #添加nodelay属性, 无延迟处理突发流量
7. 每次修改配置后记得重启nginx:
systemctl restart openresty
或: cd nginx/sbin -> ./nginx -s reload