美文网首页个人学习
nginx缓存商品详情(冷热数据)

nginx缓存商品详情(冷热数据)

作者: dark68 | 来源:发表于2021-06-04 08:25 被阅读0次

    docker中安装nginxesopenresty不在介绍默认安装完成。

    • 热点数据:经常查询或者需要更新的数据
    • 冷门数据:不经常修改或者不经常查询的数据

    对于冷热数据我们有不同的处理,我们知道库存是随着用户下单而变化的,这个是需要实时的,我们姑且成为热点数据,而商品名称却不是。

    对于商品本身的数据我们在获取这块的处理会不同,对于库存和价格这种热点数据我们会在页面加载完成之后进行异步加载,而对于冷门数据,我们会使用nginx将数据局与html页面一起进行缓存。
    对于商品而言,我们对于活动的商品信息也会在nginx中开辟出一个缓存,这样在用户访问活动商品的时候,就不用再去请求数据库,浪费更多的网络资源与时间。而冷商品仅仅交给数据库进行处理就 OK了,不过对于不会经常更新的数据还是会缓存一份数据到Redis中的。


    代码展示:

    php完成商品详情数据api接口

        //热点商品的Redis key
        protected $productKey;
        //商品的计数器 ,访问量  缓存时间7天 超过1w就进行Redis缓存
        protected $productCountKey;
    
        //商品计数,访问量缓存七天,七天超过1w就进行redis缓存
        public function productItems(Request $request){
            //获取商品id
            if($product_id = $request->input('product_id')){
                $this->productKey = "Lmrs::product::info::".$product_id;
                $this->productCountKey = "Lmrs::product::count::".$product_id;
                //先判断redis中是否有相关数据,没有则去数据库中(es)中查询
                $productInfo = Redis::get($this->productKey);
    
                if ($productInfo == null or $productInfo == false){
                    #此处es暂代数据库
                    $builder = (new ElasticsearchService('products'))->IsStatus()->productIdSearch($product_id);
                    $restful =app('es')->search($builder->getParams());
                    $restful = collect($restful["hits"]["hits"])->pluck('_source')->all();
                    //缓存7天,七天累计计数
                    $exists = Redis::set($this->productCountKey,1,"NX","EX",100800);
                    //七天访问量超过一万的数据存入缓存
                    if(Redis::incr($this->productCountKey) >= 10000){
                        Redis::set($this->productKey,serialize($restful),"EX",100800);
                    }
    
                    return response()->json($restful[0]);
                }
                return response()->json(unserialize($productInfo)[0]);
            }else{
                return response()->json([
                    "restful" => false,
                    "data" => "参数异常"
                ]);
             }
        }
    

    nginx+lua获取调用这个api
    在服务器的/docker/www/lua目录下创建一个lua脚本(products.lua),写下如下代码:

    local uri_args = ngx.req.get_uri_args()   --获取url中传递的参数,如商品id
    local productId = uri_args["product_id"]
    
    local cache_ngx = ngx.shared.productCache   --调用nginx中配置的productCache缓存
    local cjson = require("cjson")              --引入lua的json依赖
    local productCacheKey = "lmrs::product::info::"..productId        --通过我们获取的商品id,拼接一个nginx缓存的key
    local productCache = cache_ngx:get(productCacheKey)               --在nginx缓存中查询这个key的数据
    if productCache == "" or productCache == nil then                 --判断是否查询到数据
        local http = require("resty.http")                            --引入lua的http依赖
        local httpc = http.new()
        local url = "http://172.17.0.6/api/productInfo?product_id="..productId   --请求的地址(与laravel中定义的路由对应)
        local resp,err = httpc:request_uri(url,{
            method = "POST",                                          --什么方式请求
            body = body,
            headers = {                                                --请求头
                ["Content-Type"] = "application/x-www-form-urlencoded",
            }
        })
        productCache = resp.body                                      --取得数据主体
        cache_ngx:set(productCacheKey,productCache,10  * 60)          --存入nginx缓存中
    end
    local productCacheJson = cjson.decode(productCache)                --解析json的数据为table
    local productInfo = {                                              --制定需要发返回的数据
        product_id  = productId,
        product_name = productCacheJson["name"],
        product_long_name = productCacheJson["long_name"],
        product_sold_count = productCacheJson["sold_count"],
        product_review_count = productCacheJson["review_count"]
    }
    local template = require("resty.template")                         --引入lua的前端模板渲染依赖
    template.render("template.html",productInfo)                       --渲染模板
    

    在openresty容器中移入相关依赖:

    docker exec -it openresty bash
    cd /usr/local/openresty/lualib/resty
    wget https://raw.githubusercontent.com/bungle/lua-resty-template/master/lib/resty/template.lua
    wget https://raw.githubusercontent.com/bungle/lua-resty-template/master/lib/resty/template/html.lua
    
    wget https://raw.githubusercontent.com/pintsized/lua-resty-http/master/lib/resty/http_headers.lua
    wget https://raw.githubusercontent.com/pintsized/lua-resty-http/master/lib/resty/http.lua
    wget https://raw.githubusercontent.com/pintsized/lua-resty-http/master/lib/resty/http_connect.lua
    

    如果拒绝访问在在hosts加上

    199.232.4.133 raw.githubusercontent.com
    

    退出容器后,重启Openresty

    docker restart openresty
    

    nginx中引入lua脚本进行测试
    openresty中的nginx配置如下:

    #定义共享空间
    lua_shared_dict dis_cache 10m;
    lua_shared_dict productCache 200m;
    
    lua_package_path "/usr/local/openresty/lualib/?.lua;";
    lua_package_cpath "/usr/local/openresty/lualib/?.so;";
    
    server
    {
        listen       90;
        listen       [::]:90;
        server_name  localhost;
        root /docker/www/webserver;
        index index.html;
    
        #html模板存放位置
        set $template_root "/docker/www/products";
    
        location /lmrs_home_index {
           content_by_lua_file /docker/www/lua/lmrs_home_index.lua;
        }
    
        location /productinfo{
            default_type 'text/html';
            content_by_lua_file /docker/www/lua/products.lua;
        }
    }
    

    nginx容器的配置如下:(注意这里的nginx不是Openresty中的nginx,而是我们通过docker安装的nginx容器配置)

    proxy_cache_path /cache/productinfo levels=1:2 keys_zone=productinfo:200m max_size=5g inactive=60m use_temp_path=off;
    
    upstream openresty{
        server 172.17.0.5:90 weight=5 max_fails=3 fail_timeout=30s;
    }
    
    server {
    ···
    ···
    ···
        location /productinfo {
            proxy_cache productinfo;
            proxy_cache_valid 200 206 304 302 1d;
            proxy_cache_key $request_uri;
            add_header X-Cache-Status $upstream_cache_status;
            proxy_pass http://openresty;
        }
    ···
    ···
    ···
    }
    

    前端模板配置
    lua的template依赖是需要我们配置好html的模板的,在这个模板我们会配置好需要缓存起来的冷数据,比如商品名称这些。使用ajax去异步加载价格和库存。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>{* product_name *}</title>
        <script type="text/javascript" src="http://192.168.35.137:90/static/js/jquery_4.js"></script>
    </head>
    <body>
    商品名称:{* product_name *}
    销量:{* product_sold_count *}
    评价:{* product_review_count *}
    <input id="product_id" type="hidden" value="{* product_id *}">
    <script type="text/javascript">
        var product_id = document.getElementById("product_id").value;
        $.ajax({
            type: "post",
            url: "http://192.168.35.137/api/productInfo",
            data:{"product_id":product_id},
            success: function(data) {
                var html = "<p>";
                html += "价格:"+data.price;
                $("body").append(html);
            }
        });
    </script>
    
    </body>
    </html>
    

    效果展示


    image.png

    相关文章

      网友评论

        本文标题:nginx缓存商品详情(冷热数据)

        本文链接:https://www.haomeiwen.com/subject/czbzsltx.html