多级缓存总结

  1. win机作为客户端, 使用 nginx , localhost:80

反向代理到 服务器端的 192.168.111.110:8081 nginx

 

  1. 服务器端的nginx 是一个集群, 配置一个拦截 /item/(\d+) 的请求

反向代理到win机的 tomcat 的 192.168.111.1:8081 和 192.168.111.1:8082

 

  1. 于是我们的业务逻辑就是
    1. 对于 /item/(\d+) 这种请求, 我们 先去 服务器端的nginx查 key , 这个要定义好
    2. 如果没有, 则去 redis (192.168.111.110:6380)
    3. 再没有 , 则去 使用http请求访问 tomcat , 控制器方法

 

 

 

需要指出的是 , 即便没有tomcat , 在缓存预备好后, nginx和redis 仍然可以 让用户成功访问网页 , 因为动态数据已经缓存了, 而静态数据本身就在nginx的html里

 

eeed8bdd38bb4486a2fc868b8bb05ac7.png
  1. 在 win机的 nginx的配置 , 在页面里直接使用 localhost访问, 80为默认端口 , 不需要写

这里反向代理到 服务器的nginx , 192.168.111.110:8081

#user  nobody;

worker_processes  1;

events {

    worker_connections  1024;

}

http {

    include       mime.types;

    default_type  application/octet-stream;

    sendfile        on;

    #tcp_nopush     on;

    keepalive_timeout  65;

    upstream nginx-cluster{

        server 192.168.111.110:8081;

    }

    server {

        listen       80;

        server_name  localhost;

    location /api {

            proxy_pass http://nginx-cluster;

        }

        location / {

            root   html;

            index  index.html index.htm;

        }

        error_page   500 502 503 504  /50x.html;

        location = /50x.html {

            root   html;

        }

    }

}

 

  1. 服务器的nginx配置   , nginx地址 192.168.111.110:8081  ,

 反向代理到 win机的 tomcat 的 192.168.111.1:8081 和 192.168.111.1:8082

 

conf文件位置 /usr/local/openresty/nginx/conf/nginx.conf

182440d65bd04b44b2793a0432e62b44.png

  1. 需要搭载 lua模块和c模块
  2. 共享字典: 开启nginx本地缓存  , 使用的是键值对显示缓存
  3. server 里 , 使用 8081端口 ,  监听请求 : /item     还有 /api/item/(\d+) 和 /
  4. /api/item/(\d+) ,对于该请求路径, 我们进行特殊配置, 指明 配置文件的格式和位置

 

#user  nobody;

worker_processes  1;

error_log  logs/error.log;

events {

    worker_connections  1024;

}

http {

    include       mime.types;

    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

   

    #lua 模块

    lua_package_path "/usr/local/openresty/lualib/?.lua;;";

    #c模块    

    lua_package_cpath "/usr/local/openresty/lualib/?.so;;";  

    # 共享字典,也就是本地缓存,名称叫做:item_cache,大小150m

    lua_shared_dict item_cache 150m;  

 

    upstream tomcat-cluster { # 这里的地址 是 win机的 tomcat地址 , 是 192.168.111.1

        hash $request_uri;

        server 192.168.111.1:8081;

        server 192.168.111.1:8082;

    }

 

    server {

        listen       8081;

        server_name  localhost;

 

        location /item { # 将 /item 请求 反向代理 到 Windows 的 tomcat里    

            proxy_pass http://tomcat-cluster;

        }

 

        location ~ /api/item/(\d+) {  # 匹配一个正则表达式的路径,item后面的路径意义是 : 匹配大于等于一个字符的数字 , 也就是我们要取的id ,这样可以传进lua里

            #配置对 /api/item 下的请求的 默认的响应配置

            default_type application/json;

           

            #响应结果 由lua/item.lua文件来决定, 我们就是在这里编写lua脚本查数据库

            content_by_lua_file lua/item.lua;

        }

 

        location / {

            root   html;

            index  index.html index.htm;

        }

        error_page   500 502 503 504  /50x.html;

        location = /50x.html {

            root   html;

        }

    }

}

 

 

  1. 现在看 /api/item/(\d+) ,对于该请求路径, 我们进行特殊配置, 该 配置文件的位置是

位置是 /usr/local/openresty/nginx/lua/item.lua

faa3c277a1414c4ebcf28af8e961fa40.png

  1. 导入common库 , cjson, 共享字典
  2. 这个lua脚本 , 封装了查询逻辑 ,  从 nginx-->redis-->tomcat , 这样一个顺序
  3. 查什么 ? 查的是 item和stock , 这个 点点 是 拼接字符串

-- 查询商品信息

local itemJSON = read_data("item:id:" .. id, 1800,  "/item/" .. id, nil)

-- 查询库存信息

local stockJSON = read_data("item:stock:id:" .. id, 60, "/item/stock/" .. id, nil)

 

 

====================================================================

 

 

 

-- 导入common函数库

local common = require('common')

local read_http = common.read_http

local read_redis = common.read_redis

-- 导入cjson库

local cjson = require('cjson')

-- 导入共享词典,本地缓存

local item_cache = ngx.shared.item_cache

-- 封装查询函数

function read_data(key, expire, path, params)

    -- 查询本地缓存

    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", 6380, key)

        -- 判断查询结果

        if not val then

            ngx.log(ngx.ERR, "redis查询失败,尝试查询http, key: ", key)

            -- redis查询失败,去查询http

            val = read_http(path, params)

        end

    end

    -- 查询成功,把数据写入本地缓存

    item_cache:set(key, val, expire)

    -- 返回数据

    return val

end

-- 获取路径参数

local id = ngx.var[1]

-- 查询商品信息

local itemJSON = read_data("item:id:" .. id, 1800,  "/item/" .. id, nil)

-- 查询库存信息

local stockJSON = read_data("item:stock:id:" .. id, 60, "/item/stock/" .. id, nil)

-- JSON转化为lua的table

local item = cjson.decode(itemJSON)

local stock = cjson.decode(stockJSON)

-- 组合数据

item.stock = stock.stock

item.sold = stock.sold

-- 把item序列化为json 返回结果

ngx.say(cjson.encode(item))

 

 

 

 

  1. 我们在common.lua里 , 封装了 由nginx 查询 redis的 基本逻辑

文件位置 /usr/local/openresty/lualib/common.lua

  1. 连接redis使用的是连接池
  2. 获取redis连接 -->

封装查询redis的函数 (read_redis 这个函数就在 item.lua里被调用了) -->

还封装了 以http请求 , 查询 tomcat 控制器方法的 函数

 

2705be28f0ee4a41a446ed487ee871bd.png

 

 

-- 导入redis

local redis = require('resty.redis')

-- 初始化redis

local red = redis:new()

red:set_timeouts(1000, 1000, 1000)

-- 关闭redis连接的工具方法,其实是放入连接池

local function close_redis(red)

    local pool_max_idle_time = 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连接池失败: ", err)

    end

end

-- 查询redis的方法 ip和port是redis地址,key是查询的key

local function read_redis(ip, port, key)

    -- 获取一个连接

    local ok, err = red:connect(ip, port)

    if not ok then

        ngx.log(ngx.ERR, "连接redis失败 : ", err)

        return nil

    end

    -- 查询redis

    local resp, err = red:get(key)

    -- 查询失败处理

    if not resp then

        ngx.log(ngx.ERR, "查询Redis失败: ", err, ", key = " , key)

    end

    --得到的数据为空处理

    if resp == ngx.null then

        resp = nil

        ngx.log(ngx.ERR, "查询Redis数据为空, key = ", key)

    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, "http查询失败, path: ", path , ", args: ", args)

        ngx.exit(404)

    end

    return resp.body

end

-- 将方法导出

local _M = {  

    read_http = read_http,

    read_redis = read_redis

}  

return _M

 

 

 

  • 27
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值