【性能优化,打造亿级秒杀系统】(二)多级缓存设计

缓存设计原则

  • 用内存
  • 将缓存推到距离用户最近的地方
  • 脏缓存的清理

多级缓存

redis 缓存

把它当作集中式缓存的中间件,K-V 数据库。是一个易丢失的存储设备

单机模式

本地缓存

public interface CacheService {
    //存方法
    void setCommonCache(String key, Object value);

    //取方法
    Object getFromCommonCache(String key);
}

@Service
public class CacheServiceImpl implements CacheService {

    private Cache<String, Object> commonCache = null;

    @PostConstruct
    public void init(){
        commonCache = CacheBuilder.newBuilder()
                //设置初始容量为10
                .initialCapacity(10)
                //设置最大的KEY数量为100
                .maximumSize(100)
                //设置过期时间为60s 采用的是在写后开始算起,而不是访问后
                .expireAfterWrite(60, TimeUnit.MINUTES)
                .build();
    }
    @Override
    public void setCommonCache(String key, Object value) {
        commonCache.put(key, value);
    }

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

然后我们在itemController中用上本地缓存与redis缓存

//商品详情页浏览
    @RequestMapping(value = "/get",method = {RequestMethod.GET})
    @ResponseBody
    public CommonReturnType getItem(@RequestParam(name = "id")Integer id){
        ItemModel itemModel = null;
        //先取本地缓存
        itemModel = (ItemModel) cacheService.getFromCommonCache("item_"+id);
        if(itemModel == null){
            //根据商品的id到redis内获取
            itemModel = (ItemModel) redisTemplate.opsForValue().get("item_"+id);
            //若redis内不存在对应的itemModel,则访问下游service
            if(itemModel == null){
                itemModel = itemService.getItemById(id);
                //设置itemModel到redis内
                redisTemplate.opsForValue().set("item_"+id,itemModel);
                redisTemplate.expire("item_"+id,10, TimeUnit.MINUTES);
            }
            cacheService.setCommonCache("item_"+id, itemModel);
        }
        ItemVO itemVO = convertVOFromModel(itemModel);
        return CommonReturnType.create(itemVO);
    }

sentinal哨兵模式

在这里插入图片描述

在这里插入图片描述
这里选择哪个master依靠的是Hash算法
在这里插入图片描述

集群cluster模式

在这里插入图片描述
如果redis3出现了问,因为miaosha.jar存储的是错误的,redis2就会给他一个reask请求。
在这里插入图片描述

热点本地缓存

  • 热点数据
  • 对于脏数据不敏感
  • 内存可控

nginx proxy chche 缓存

依靠文件系统存索引级的文件

#声明一个cache缓存节点的内容
proxy_cache_path /usr/local/openresty/nginx/tmp_cache levels=1:2 keys_zone=tmp_cache:100m inactive=7d max_size=10g;
 location / {
           proxy_pass http://backend_server;
           proxy_cache tmp_cache;
           proxy_cache_key $uri;
           proxy_cache_valid 200 206 304 302 7d;

}

这种方法因为是在磁盘中寻找,所以比较慢,我们不采用。

nginx lua 缓存

  • lua 协程机制

  • nginx协程机制

  • nginx lua 插载点

在这里插入图片描述
比如说这里的staticitem.lua ,我们还需要在nginx.conf 的配置文件中写上下面的配置,然后我们在url 打出miaoshaserver/staticitem/get

		location /staticitem/get{
            default_type "text/html";
            content_by_lua_file ../lua/staticitem.lua;
        }

在这里插入图片描述

  • OpenResty
  1. helloword级别

首先在Lua目录下新建一个helloword.lua 脚本文件 里面写上ngx.exec("/item/get?id=6");
然后在nginx.conf 配置文件下写

location /helloword{
	content_by_lua_file ../lua/helloword.lua;
}

然后在浏览器中输入就可以看到:
在这里插入图片描述

  1. shared dic(共享内存字典)

编写lua 脚本

在nginx.conf 中配置:

lua_shared_dict my_cache 128m;
location /luaitem/get{
	default_type "application/json";
	content_by_lua_file ../lua/itemsharedic.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, exptime)
        if not exptime then
                exptime = 0
        end
        local cache_ngx = ngx.shared.my_cache
        local succ, err, forcible = cache_ngx:set(key, value, exptime)
        return succ
end

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 是否收到了请求呢?我们可以看logs 目录下的access.log 日志文件。如何看报错信息呢?我们可以看error.log 目录 好比 后端tomcat 的接受请求就是看我们自定义的 tomcat 目录 **

  1. openresty redis 支持

首先建立一个Luad脚本文件,里面写上需要编写的脚本代码:

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("192.168.0.232", 6379)
local item_model = cache:get("item_"..id)
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 文件中 配置上访问路径啥的。

location /luaitem/get{
	default_type "application/json";
	content_by_lua_file ../lua/itemredis.lua;
}

然后在url 上访问:http://miaoshaserver/luaitem/get?id=6 就会出现该缓存的结果
在这里插入图片描述

发布了118 篇原创文章 · 获赞 5 · 访问量 8732

猜你喜欢

转载自blog.csdn.net/weixin_43672855/article/details/104452118