【Redis】多级缓存之OpenResty:nginx查询Tomcat与Redis以及nginx本地缓存

news/2024/7/5 8:56:59

目录

一、认识OpenResty

二、请求参数处理

三、查询Tomcat

四、Redis缓存预热

五、查询Redis缓存

六、nginx本地缓存


一、认识OpenResty

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

二、请求参数处理

OpenResty提供了各种API来获取不同类型的请求参数

参数格式示例获取代码示例
路径占位符/test/101

利用正则表达式匹配:location ~ /test/(\d+) {

content_by_lua_file lua/test.lua;获取后转向该路径下的test.lua文件,在该lua文件中可以通过ngx.var[1]获取到参数101

}

请求头id:101

在lua脚本中使用

local header = ngx.req.get_headers()

可以获取到请求头header是一个table类型

Get请求?id=101

与上述相同

local params = ngx.req.get_uri_args()

其中params也是一个table类型

Post请求id=101

首先需要读取请求体通过以下代码

ngx.req.read_body()

然后获取参数

local post = ngx.req.get_post_args()

其结果也是table类型

JSON数据{"id":101}

首先需要读取请求体通过以下代码

ngx.req.read_body()

然后获取参数

local json=ngx.req.get_body_data()返回结果是一个string类型是json数据,后续会提到如何序列化与反序列化

三、查询Tomcat

nginx提供了内部的API用以发送http请求

local resp = ngx.location.capture("/path",{

        method=ngx.HTTP_GET, -- 请求方式

        args={id=1,age=10},         -- get请求的传参方式

        body="id=1&age=10"       -- post请求的传参方式

})

上述代码中的path是路径但是这个路径并不包含IP与端口,这个请求会被nginx内部的server监听并处理,我们这里要将去查询tomcat所以要在nginx中编写一个server对这个路径反向代理到Tomcat

location /path{

        proxy_pass http://IP:8080

}

其中返回的resp包含以下内容:

resp.status:响应状态码

resp.header:响应头,是一个table数据

resp.body:响应体,也就是数据

我们可以将http查询的请求封装为一个函数,放到OpenResty的库中后续可以之间使用,首先我们需要在对应的目录下创建common.lua文件,然后在该文件中封装该方法并导出

-- 封装方法发送http请求
local function read_http(path, params)
    local resp = ngx.location.capture(path,{
        method=ngx.HTTP_GET,
        args=params
    })
    
    -- 处理响应
    if not resp then
        -- 打印日志返回404
        ngx.log(ngx.ERR,"error")
        ngx.exit(404)
    end
    -- 返回数据
    return resp.body
end

-- 将方法导出
local _M = {
    read_http = read_http
}
return _M

此时我们可以查询Tomcat中的信息

-- 导入所需要的库
local common = require('common')
-- 序列化与反序列化库
local cjson = require('cjson')

-- 获取之前封装的方法
local read_http = common.read_http

-- 获取get请求里的id:/item?id=101
local id = ngx.req.get_uri.args().id

-- 查询Tomcat
local itemJson = read_http("/item",id)

-- 将Tomcat返回的json数据转为table类型
local item = cjson.decode(itemJson)

-- 给数据中加入一个属性比如状态:state=1
item.state = 1

-- 将数据转为json格式返回
ngx.say(cjson.encode(item))

 在多级缓存的实战中Tomcat不止一个通常会有集群,那么这个时候我们需要去配置负载均衡,那么 默认的轮询机制是否可以呢,假设此时有俩台Tomcat查询同一个id对应的信息按照轮询机制则两台Tomcat会各查询一次,也就是说JVM进程缓存会在两台Tomcat上缓存2次,但是这两个数据是同一个,这就导致Tomcat集群的性能低,那么我们可以不可以通过修改负载均衡的策略让同一id对应的请求去查询统一Tomcat呢,那么两次查询去同一给Tomcat,第二次之间从JVM进程缓存里获取提高性能。我们可以通过设置达到这样的效果

 

配置反向代理,将指定路径代理到Tomcat集群

location /path{

        proxy_pass http://tomcat-cluster;

}

集群

upstream tomcat-cluster{

        hash $request_uri;

        server ip:端口

        ……

}

四、Redis缓存预热

服务刚启动时,Redis中并没有缓存,如果所有的商品数据在第一次查询时添加缓存,则可能会给数据库带来比较大的压力,也叫做冷启动,在实际的开发过程中,通常会利用大数据统计用户访问的热点数据,在项目启动时将这些热点数据提前查询并缓存,这就是缓存预热

@Component
public class RedisHandler implements InitializingBean{
    
    @Autowired
    private StringRedisTemplate redis;

    @Override
    public void afterPropertiesSet(){
        // 查询数据库进行缓存
    }

}

五、查询Redis缓存

在上述我们了解了如何查询Tomcat,在业务中我们首先会去查询nginx的本地缓存,然后查询Redis缓存,如果都没有数据那才去查询Tomcat那么我们如何查询Redis呢,OpenResty提供了操作Redis的模块,我们只需要引入模块即可使用

-- 引入redis模块

local redis = require('resty.redis')

-- 初始化redis对象

local red = redis:new()

-- 配置redis超时时间

red:set_timeouts(1000,1000,1000)

接着我们可以继续在common.lua里封装redis的相关方法并导出

-- 引入Redis模块
local redis = require('resty.redis')
local red = redis:new()
red:set_tiemouts(1000,1000,1000)

-- 封装关闭Redis连接的方法:放入连接池中
local function close_redis(red)
    local pool_max_idle_tiem = 10000 -- 连接空闲时间
    local pool_size = 100  -- 连接最大数
    local ok,err = red:set_keepalive(pool_max_idle_time,pool_size)
    if not ok then
        ngx.log(ngx.ERR,'放入Redis连接池失败')
    end
end

-- 封装查询Redis方法
local function read_redis(ip,port,key)
    -- 获取连接
    local ok,err = red:connect(ip, port)
    if not ok then
        ngx.log(ngx.ERR,"连接失败")
        return nil
    end

    -- 查询redis
    local resp,err = red:get(key)
    if not resp then
        ngx.log(ngx.ERR,"查询失败")
    end

    -- 处理数据为空
    if resp == ngx.null then
        resp = nil
        ngx.log(ngx.ERR,"查询为空")
    end

    -- 关闭连接
    close_redis(red)
    return resp
end
   

-- 封装方法发送http请求
local function read_http(path, params)
    local resp = ngx.location.capture(path,{
        method=ngx.HTTP_GET,
        args=params
    })
    
    -- 处理响应
    if not resp then
        -- 打印日志返回404
        ngx.log(ngx.ERR,"error")
        ngx.exit(404)
    end
    -- 返回数据
    return resp.body
end

-- 将方法导出
local _M = {
    read_http = read_http,
    read_redis = read_redis
}
return _M

六、nginx本地缓存

OpenResty为nginx提供了shared dict的功能,可以在nginx的多个worker之间共享数据,实现缓存功能

首先我们需要开启共享词典,在nginx.conf的http下配置

lua_shared_dict cache 200m;  # 名为cache 大小200m

然后我们可以在lua文件中编写业务

-- 获取本地缓存

local cache = ngx.shared.cachae

-- 存入,第三参数为过期时间单位是秒,默认是0永不过期

cache.set('key','value',1000)

-- 读取

local value = cache.get('key')


http://lihuaxi.xjx100.cn/news/1275455.html

相关文章

elasticsearch生命周期的阶段

Hot: The index is actively being updated and queried. 可以设置滚动阈值 hot阶段是必须的,其他的阶段是可选的 hot phase有个坑: rollover 这里指的是如果你想让索引在hot阶段待5min,你可以在hot设置rollover时间触发条件为5min,然后warm阶段设置data into为0,正常情况下没…

我心中的TOP1编程语言—JavaScript

作为一名研发工程师(程序员),平时工作中肯定会接触或了解很多编程语言。每个人都会有自己工作中常用的语言,也会有偏爱的一些编程语言。而我心中的最爱,毫无疑问,就是 JavaScript。 个人认为,一…

TIA博途_字符转换为字符串以及截取字符串有效字符的具体方法示例

TIA博途_字符转换为字符串以及截取字符串有效字符的具体方法示例 情景再现: 在做某些通信相关的项目时,可能会遇到通信接收到的字符串是以字节的形式传送过来的字符,此时就需要我们对接收到的这些字符进行处理,从而获取我们实际需要的字符或字符串。 如下图所示,打开博途…

微服务系列文章之 Springboot集成Jersey

​ Springboot支持Jersey1.x和Jersey2.x&#xff0c;我们这里只介绍Springboot对Jersey2.x的支持。springboot对jersey的集成非常简单。 ​ 项目结构&#xff1a; 1、引入Springboot对Jersey的starter包 <dependencies><dependency><groupId>org.springfram…

CODESYS 数组类型变量(ARRAY)使用介绍

博途PLC数组类型变量使用介绍请参看下面文章博客: 博途1200/1500PLC上升沿下降沿指令编程应用技巧(bool数组)_博途上升沿指令_RXXW_Dor的博客-CSDN博客博途PLC的下降沿和上升沿指令,在控制系统编程时经常会使用。和SMARTS7-200有所不同,遵循IEC-6113标准提供的上升沿下降沿…

java适配达梦数据库

目录 一、数据库安装 二、数据库可视化工具 三、数据迁移 四、工程适配 新增maven依赖 配置文件修改 基于flyway的数据库版本管理 五、注意事项 一、数据库安装 官方文档&#xff1a;安装前准备 | 达梦技术文档 这里有一个点需要注意&#xff0c;如果你之前的数据库或…

中国人民大学与加拿大女王大学金融硕士——在职读研让能力加速提升

不管你是初入职场的小白&#xff0c;还是久经沙场的元老&#xff0c;想要在职场有所作为&#xff0c;就不要忽略自我能力提升。决定一个人当前职场价值不是他拥有了什么&#xff0c;而是他将来能够创造什么。如果你只盯着工作&#xff0c;那么你的眼界和薪资将会被工作所决定&a…

【数据可视化】大作业(意向考研高校的数据可视化)

文章目录 前言一、数据介绍1.1 基本信息1.2 考研信息1.3 导师信息 二、预处理及分析2.1 数据预处理2.1.1 考研信息预处理2.1.2 导师信息预处理 2.2 数据分析 三、可视化方法及结果3.1 可视化方法3.2 可视化结果展示3.2.1 基本信息3.2.2 考研信息3.2.3 导师信息 四、总结五、附录…