电商高并发秒杀3 多级缓存

2020-03-23  本文已影响0人  香沙小熊

1. 缓存设计原则

2. 多级缓存方案

3. Redis集中式缓存

4. Guava cache(JVM级缓存)

@Service
public class CacheServiceImpl implements CacheService {

    private Cache<String,Object> commonCache = null;

    @PostConstruct
    public void init(){
        commonCache = CacheBuilder.newBuilder()
                //设置缓存容器的初始容量为10
                .initialCapacity(10)
                //设置缓存中最大可以存储100个KEY,超过100个之后会按照LRU的策略移除缓存项
                .maximumSize(100)
                //设置写缓存后多少秒过期
                .expireAfterWrite(60, TimeUnit.SECONDS).build();
    }

    @Override
    public void setCommonCache(String key, Object value) {
            commonCache.put(key,value);
    }

    @Override
    public Object getFromCommonCache(String key) {
        return commonCache.getIfPresent(key);
    }
}

5. nginx proxy cache缓存

vim nginx.conf
#声明一个cache缓存节点的内容
#做一个二级目录,先将对应的url做一次hash,取最后一位做一个文件目录的索引;
#在取一位做第二级目录的索引来完成对应的操作,文件内容分散到多个目录,减少寻址的消耗;
#在nginx内存当中,开了100m大小的空间用来存储keys_zone中的所有的key
#文件存取7天,文件系统组多存取10个G
#在http中声明proxy_cache_path 
proxy_cache_path /usr/local/openresty/nginx/tmp_cache levels=1:2 keys_zone=tmp_cache:100m inactive=7d max_size=10g;


#在location中多指定一个结点
location / {
    proxy_cache tmp_cache;
    proxy_cache_key $uri;
#只有后端返回的状态码是这些,对应的cache操作才会生效,缓存周期10天
    proxy_cache_valid 200 206 304 302 7d;
}

[root@localhost nginx]# sbin/nginx -s reload
请求之后 看到nginx磁盘中有 缓存有数据
[root@localhost nginx]# cd tmp_cache/
[root@localhost tmp_cache]# ls
8
[root@localhost tmp_cache]# cd 8
[root@localhost 8]# ls
f6
[root@localhost 8]# cd f6
[root@localhost f6]# ls
86e4d1b3ba4f1464e409c74be4ef6f68
[root@localhost f6]# cat 86e4d1b3ba4f1464e409c74be4ef6f68
©b^ÿÿÿÿÿÿÿÿ)(w^ksr¯` 
KEY: /item/get
HTTP/1.1 200 
Access-Control-Allow-Methods: HEAD, POST, GET, OPTIONS, DELETE, PUT
Access-Control-Max-Age: 3600
Access-Control-Allow-Headers: x-requested-with
Access-Control-Allow-Credentials: true
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 22 Mar 2020 08:56:09 GMT

{"status":"success","data":{"id":6,"title":"苹果8","price":8888.00,"stock":1000,"description":"苹果89999","sales":0,"imgUrl":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1584609244675&di=1dec5a523bb7153cc51efd60d2086be2&imgtype=0&src=http%3A%2F%2Fimages01.mopimg.cn%2Fimgs%2F20180209%2F20180209_1bf319190fa11cea019b055c7101855d.JPEG","promoStatus":0,"promoPrice":null,"promoId":null,"startDate":null}}
注意:nginx proxy cache缓存在本地磁盘中,不是在内存中,性能还不如反向代理获取数据。

6. nginx lua缓存

6.1 什么是协程

协程,线程空间站的执行单元,有自己独立的运行空间,本身依托于线程,在编写对应代码就无需考虑异步的方式,完全可以同步编写;

6.2 Nginx协程机制

Nginx协程

Nginx协程机制

Nginx处理阶段

typedef enum {
    NGX_HTTP_POST_READ_PHASE = 0,   //读取请求头,例如get还是post,cookie中有哪些方法
    NGX_HTTP_SERVER_REWRITE_PHASE,   //执行rewrite - rewrite_handler,uri与location匹配前,修改uri的阶段,用于重定向
    NGX_HTTP_FIND_CONFIG_PHASE,  //根据uri替换location
    NGX_HTTP_REWRITE_PHASE,      //根据替换结果继续执行rewrite - rewrite_handler,上一阶段找到location块后再修改uri
    NGX_HTTP_POST_REWRITE_PHASE, //执行rewrite后处理,防止重写URL后导致的死循环
    NGX_HTTP_PREACCESS_PHASE,    //认证预处理   请求限制,连接限制 -limit_conn_handler -limit_req_handler
    NGX_HTTP_ACCESS_PHASE,       //认证处理 - auth_basic_handler,access_handler,让HTTP模块判断是否允许这个请求进入Nginx服务器
    NGX_HTTP_POST_ACCESS_PHASE,  //认证后处理, 认证不通过, 丢包, 向用户发送拒绝服务的错误码,用来响应上一阶段的拒绝
    NGX_HTTP_TRY_FILES_PHASE,    //尝试try标签,为访问静态文件资源而设置
    NGX_HTTP_CONTENT_PHASE,      //内容处理 - static_handler 处理HTTP请求内容的阶段
    NGX_HTTP_LOG_PHASE           //日志处理 - log_handler 处理完请求后的日志记录阶段
} ngx_http_phases;
6.3 Nginx lua插载点

Nginx与Lua编写脚本的基本构建块是指令。 指令用于指定何时运行用户Lua代码以及如何使用结果。 下面是显示指令执行顺序的图。

image.png

Nginx提供了许多再执行lua脚本的挂载方案,用的最多的几个nginx lua插载点

测试
建一个lua内容输出结点文件staticitem.lua

[root@localhost openresty]# cd lua
[root@localhost lua]# vim staticitem.lua
vim nginx.conf
#在server中多指定一个location
    location /staticitem/get{
            default_type "text/html"; 
            content_by_lua_file  ../lua/staticitem.lua;
        }

[root@localhost nginx]# sbin/nginx -s reload
直接返回静态资源文件:
image.png
6.4 OpenResty nginx缓存,shared dic共享内存字典

也是key和value类型的缓存。优势:基于nginx内存的直接缓存,并且是离用户最近的节点,缺点:但是更新机制不太好,占用nginx的内存
使用lua脚本,/usr/local/openresty/lua/itemsharedic.lua

--从缓存中获取
function get_from_cache(key)
     local cache_ngx = ngx.shared.my_cache
     local value = cache_ngx:get(key)
     return value
end
--设置缓存
function set_to_cache(key,value,expire)
     if not expire then
           expire = 0
     end
     local cache_ngx = ngx.shared.my_cache
     local succ,err,forcible = cache_ngx:set(key,value,expire)
     return succ
end

--获取请求的参数/item/get?id=6
local args = ngx.req.get_uri_args()
local id = args["id"]
local item_model = get_from_cache("item_"..id) 

--从缓存中获取
if item_model == nil then
    --调用后台
    local resp = ngx.location.capture("/item/get?id="..id) 
    item_model = resp.body
    set_to_cache("item_"..id,item_model,1*60)
end
ngx.say(item_model)

修改nginx.conf, 引入lua脚本

http {

    lua_shared_dict my_cache 128m; #定义nginx共享字典缓存
    server {
    listen       80;
        server_name  localhost;
    location /luaitem/get {
                     default_type "application/json";
                     content_by_lua_file ../lua/itemsharedic.lua;
     }
  }
}
image.png
6.5.nginx直接获取redis缓存数据

openresty redis支持:
若nginx可以连接到redis上,进行只读不写,若redis内没有对应的数据,那就回源到miaoshaserver上面,然后对应的miaoshaserver也判断一下redis内有没有对应的数据,

若没有,回源mysql读取,读取之后放入redis中 ,那下次h5对应的ajax请求就可以直接在redis上做一个读的操作,nginx不用管数据的更新机制,下游服务器可以填充redis,nginx只需要实时的感知redis内数据的变化,在对redis添加一个redis slave,redis slave通过redis master做一个主从同步,更新对应的脏数据。

优点:避免访问后台应用的网络时间,减少消耗。虽然增加redis的负担,但是redis集群有多台主备redis分担,影响不大

新建itemnginx.lua文件

local args = ngx.req.get_uri_args();
local id = args["id"]
local redis = require "resty.redis"
local cache = redis:new()
local ok,err = cache:connect("47.99.51.246",6379)
if not ok then
    ngx.log(ngx.ERR,"connect error")
    return
end
local item_model = cache:get("item_"..id)
ngx.log(ngx.ERR, item_model)
if item_model == ngx.null or item_model == nil then
    local resp = ngx.location.capture("/item/get?id="..id)
    item_model = resp.body
end
ngx.say(item_model)

修改nginx.conf,引入lua文件

location /luaitem/get {
                default_type "application/json";
                #content_by_lua_file ../lua/itemsharedic.lua;
                content_by_lua_file ../lua/itemnginx.lua;
        }
上一篇下一篇

猜你喜欢

热点阅读