# OpenResty实践

# 引言

我们来说说传统缓存的问题 用户请求达到tomcat后,先查询redis再到数据库,但是tomcat的连接是小于redis的,所以并发度较低,那么就会造成一个Tomcat的性能成为整个系统的瓶颈。 Redis缓存失效后,会直接对数据库进行冲击(也就是缓存击穿现象:没有并且对着没有的地方进行冲击)

# 优化缓存方案

nginx跟tomcat差不多,除了做反向代理之外还能自己编写业务->这里作为缓存;
1.我们的浏览器作为客户端的缓存,比如静态资源,当访问相同的静态资源时做出响应;
2.nginx:缓存我们的动态数据,在请求还没有到底tomcat时候,如果nginx中缓存了该数据就响应,如果没查到就去redis查,之前是在tomcat后查,现在是在nginx后查;
3.进程缓存:在redis缓存没有被命中的时候->到达tomcat,在服务器内部利用类似map保存数据,如果命中就返回;

# 多级缓存说明

 有个静态页面item.html放在了windows上面的Nginx,充当静态资源服务器和反向代理服务器。
 当用户请求的时候将页面返回用户的浏览器,当浏览器渲染页面的时候,发现缺少数据,就会发送Ajax请求来查询数据,那么windows的Nginx不会处理,而是反向代理给Linux中的Nginx集群。该集群也是一个本地缓存数据。所以说是返回数据的第一站。负载均衡根据id固定请求一个服务器。
 如果Nginx本地缓存未命中,则去查询Redis缓存。Redis是缓存第二站。
 如果Redis缓存未命中,再根据id负载均衡的请求,JVM的Tomcat进程缓存。JVM进程缓存第三站。
 如果三级缓存都未命中,再去mysql数据中查询数据。

# 引入OpenResty的好处

1.这样层层缓存到达tomcat的请求就会减少,而Tomcat的性能就不会成为系统的瓶颈,我们之前的层层剥削也就是为了解决因为tomcat而导致并发量较低的情况。 所以说,我们在一定程度上还提高了并发量。
2.减少对于数据库的冲击,在一定程度上防止了缓冲穿透

# 什么是OpenResty

OpenResty是一个基于Nginx的高性能Web平台,用户方便的搭建能够处理高并发、扩展性极高的动态Web应用、Web服务和动态网关。具备以下特点:
  具备Nginx的完整功能
  基于Lua语言进行扩展,集成了大量精良的Lua库、第三方模块
  允许使用Lua自定义业务逻辑、自定义库

OpenResty 的架构主要分为五部分:
    1 Nginx Core:Nginx 的核心,提供了 HTTP 服务器的核心功能,包括处理请求、转发请求、处理静态文件请求等。
    2 LuaJIT:高性能的 Lua 解释器,用于解释执行 Lua 代码,并且能够非常快速地与 Nginx Core 集成。
    3 NGX-Lua: 即ngx_http_lua_module ,将Lua的能力构建到Nginx Core内核里面。
    4 Resty 模块库:包括第三方模块、官方模块和 OpenResty 扩展模块,提供了更多功能,如访问数据库、缓存、内存共享等。
    5 OpenResty应用:基于OpenResty开发的应用,如APISIX API Gateway,Kong Gateway等。
1
2
3
4
5
6

#


# 安装和使用

    -- 下载安装包:从 OpenResty 官方网站下载适合您操作系统版本的安装包,如:64 位操作系统:https://openresty.org/download/openresty-1.17.8.2.tar.gz
    -- 解压安装包:使用 tar 命令解压下载的安装包:
	cd /path/to/installation/package
	tar -zxvf openresty-1.17.8.2.tar.gz
    -- 安装依赖包:安装 OpenResty 所需的依赖包,如:
	yum install gcc pcre-devel openssl-devel
    -- 编译安装:在解压的 OpenResty 目录下执行编译和安装命令:
	cd openresty-1.17.8.2
	./configure
	make
	make install
    -- 配置环境变量:添加 OpenResty 的安装目录到环境变量中,以便在任意目录下使用 OpenResty 命令:
	echo 'export PATH=$PATH:/usr/local/openresty/bin' >> ~/.bashrc
	source ~/.bashrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14

以上步骤完成后,您已经成功安装了 OpenResty。您可以通过在命令行中输入 openresty 来验证是否安装成功。

# Hello World

配置置Nginx:在Nginx配置文件中添加以下代码,以使Nginx可以使用Lua脚本:

location /lua {
    content_by_lua_block{
		gx.say("Hello, World!")
	}
}
1
2
3
4
5

启动OpenResty,在浏览器中访问"http://localhost/lua",将看到"Hello, OpenResty!"的输出。

# redis插件的使用

# 安装redis插件

	luarocks install redis-lua
1

# 在nginx.conf 中加入以下代码:

# 加载 Redis 模块
lua_package_path "/usr/local/openresty/lualib/?.lua;;";

# 配置 Redis 连接
init_by_lua_block {
    local redis = require "resty.redis"
    local red = redis:new()
    red:set_timeout(1000) -- 1 sec
    local ok, err = red:connect("127.0.0.1", 6379)
    if not ok then
        ngx.say("failed to connect: ", err)
        return
    end
}

# 设置请求处理脚本
server {
    listen 80;
    location / {
        default_type text/html;
        content_by_lua_block {
            local redis = require "resty.redis"
            local red = redis:new()
            local res, err = red:get("dog")
            if not res then
                ngx.say("failed to get dog: ", err)
                return
            end

            ngx.say("dog: ", res)
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 重启nginx 设置redis键值

/usr/local/openresty/nginx/sbin/nginx -s reload
Redis 中存储数据
$ redis-cli
127.0.0.1:6379> SET dog "hello world"
OK
1
2
3
4
5

# 访问Nginx查看效果:

curl http://localhost
dog: hello world
1
2

# 开启共享词典

Openresty本身也支持开辟内存添加共享缓存的空间,操作api与redis一致。
本地缓存的作用:减少查询redis、mysql的操作,实际redis也很快,但是毕竟有网络开销。本地缓存会更快一些!

//nginx.conf

http{
	lua_shared_dict mycache 128m; -- 获取缓存对象 使用方法时 ngx.share.XXX
	content_by_lua_block {
		local getCache = ngx.shared.mycache; -- 读取数据
		local name = getCache:get('name')
		ngx.say('读取本地缓存!',name)
		getCache:set('name','zhangsan',10) -- 超时时间10秒
		ngx.say('缓存设定成功!') 
		local name = getCache:get('name') 	-- 读取数据
		}
	}
1
2
3
4
5
6
7
8
9
10
11

# 应用案例

在查询商品时,优先查询OpenResty的本地缓存,需求:
1.修改item.lua中的read_data函数,优先查询本地缓存,未命中时再查询Redis、Tomcat
2.查询Redis或Tomcat成功后,将数据写入本地缓存,并设置有效期
3.商品基本信息,有效期30分钟
4.库存信息,有效期1分钟

解决方案,在tomcat之前再添加缓存,使得部分请求没有经过tomcat,提升tomcat的并发处理能力。
在各个处理环节都添加上缓存,一层一层的进行过滤,减少后面的压力,也能防止部分缓存不可用能有其他缓存抵上

核心代码

-- 封装函数,先查询redis,再查询http
local function read_data1(key, expire, path, params)
    ngx.log(ngx.INFO, "path=", path)
    -- 查询本地缓存
    local val = item_cache:get(key)
    if not val then
        ngx.log(ngx.ERR, "本地缓存查询失败,尝试查询redis,key:", key)
        -- 查询redis
        val = read_redis("127.0.0.1", 6379, key)
        ngx.log(ngx.INFO, "查询Redis数据, val = ", val)
        -- 判断redis是否命中
        if not val then
            ngx.log(ngx.INFO, "Redis查询失败,尝试查询http")
            ngx.log(ngx.INFO, path, params)
            -- Redis查询失败,查询http
            val = read_http(path, params)
        end
    end
    
    ngx.log(ngx.INFO, "val=", val)
    -- 查询成功,把数据写入本地缓存,单位秒
    -- item_cache:set(key, val, expire) 
    -- 返回结果
    return val
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25


打个赏吧 点我,三毛五毛都是流水。