zoukankan      html  css  js  c++  java
  • 多级缓存-nginx(OpenResty)本地缓存

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

    1、nginx.conf 

    #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;
        access_log "D:/dev/openresty-1.19.9.1/logs/item.log";  
        error_log "D:/dev/openresty-1.19.9.1/logs/item.error" info; 
        
        #加载lua 模块
        lua_package_path "D:/dev/openresty-1.19.9.1/lualib/?.lua;;";  
        #加载c模块     
        lua_package_cpath "D:/dev/openresty-1.19.9.1/lualib/?.so;;"; 
        # 添加共享字典,也就是本地缓存,名称叫做:item_cache,大小150m
        lua_shared_dict item_cache 150m;
     
        
        server {
            listen       80;
            server_name  localhost;
            
            location /item {
                proxy_pass http://192.168.8.70:8081;
                proxy_redirect  off;
                proxy_send_timeout 3000;
                proxy_read_timeout 3000;
                proxy_connect_timeout 3000;
            }
    
            location ~ /item/(d+) {
                # 响应类型,这里返回json
                default_type application/json;
                # 响应数据由 lua/item.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;
            }
        }
    }

    2、item.lua脚本

    -- 引入自定义工具模块
    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
    
    -- 封装函数,先查询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
    
    
    --获取路径参数
    local id=ngx.var[1]
    
    -- 根据id查询商品
    local paths = "/item/"..id
    local itemJSON=read_data1("item:id:"..id,60,paths,nil)
    
    
    --根据id查询商品库存
    paths = "/item/stock/"..id
    local itemStockJSON=read_data1("item:stock:id:"..id,paths,nil)
    
    
    -- JSON转换为lua的table
    local item = cjson.decode(itemJSON)
    local itemStock = cjson.decode(itemStockJSON)
    
    
    -- 组合数据
    item.stock = itemStock.stock -- 商品库存
    item.sold = itemStock.sold -- 商品销量
     
    -- 把item系列化JSON,并返回结果
    ngx.say(item.name)

    3、common.lua工具类

    --引入redis模块
    local redis = require("resty.redis")
    --初始化Redis对象
    local red = redis:new()
    --设置Redis超时时间
    red:set_timeouts(5000,5000,5000)
    
    
    -- 释放Redis连接API
    -- 关闭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数据的API
    -- 查询redis的方法 ip和port是redis地址,key是查询的key
    local function read_redis(ip, port, key)
        -- 获取一个连接
        local ok, err = red:connect(ip, port)
        -- ok, err = red:auth("123456") -- redis设置的密码
        if not ok then
            ngx.log(ngx.ERR, "连接redis失败 : ", err)
            return nil
        end
        
        -- 查询redis
        local resp, err = red:get(key)
        -- 查询失败处理
        if not resp then
            resp = nil
            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)
        ngx.log(ngx.INFO, "http请求进来了path:", path,",params:", params)
        local resp = ngx.location.capture(path,{
            method = ngx.HTTP_GET,
            args = params,
        })
        
        ngx.log(ngx.INFO, "http请求返回结果,resp.status:", resp.status, ",resp.body:", resp.body)
        if not resp then
            -- 记录错误信息,返回404
            ngx.log(ngx.ERR, "http not found, path: ", path , ", args: ", args)
            ngx.exit(404)
        end
         
        return resp.body
    end
    
    
    
    -- 将方法导出
    local _M = {  
        read_http = read_http,
        read_redis = read_redis
    }  
    return _M

     

  • 相关阅读:
    深入研究.NET Core的本地化机制
    .Net Core中的Api版本控制
    如何在.NET Core控制台程序中使用依赖注入
    .NET Core中的数据保护组件
    深入理解.NET Core的基元: deps.json, runtimeconfig.json, dll文件
    Entitiy Framework Core中使用ChangeTracker持久化实体修改历史
    Spark(Hive) SQL中UDF的使用(Python)
    Spark(Hive) SQL数据类型使用详解(Python)
    Spark如何解决常见的Top N问题
    SparkContext自定义扩展textFiles,支持从多个目录中输入文本文件
  • 原文地址:https://www.cnblogs.com/linjiqin/p/15474037.html
Copyright © 2011-2022 走看看