• 第五章 查询性能优化之多极缓存


    1.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) {
                // 再从redis缓存中取
                itemModel = (ItemModel) redisTemplate.opsForValue().get("item_"+id);
                if(itemModel == null) {
                    // 最后从数据库取
                    itemModel = itemService.getItemById(id);
                    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);
    
        }

     springboot redis存储数据会编码,去除编码直接string序列化

    @Component
    @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)
    public class RedisConfig {
    	@Bean
    	public RedisTemplate<Object, Object> redisTemplate(
    			RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
    		RedisTemplate<Object, Object> template = new RedisTemplate<>();
    		template.setConnectionFactory(redisConnectionFactory);
    		// 解决key序列化方式
    		StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    		template.setKeySerializer(stringRedisSerializer);
    		Jackson2JsonRedisSerializer jsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    		ObjectMapper objectMapper = new ObjectMapper();
    		SimpleModule simpleModule = new SimpleModule();
    		// 时间序列化格式
    		simpleModule.addSerializer(DateTime.class, new JodaDateTimeJsonSerializer());
    		// 时间反序列化格式
    		simpleModule.addDeserializer(DateTime.class, new JodaDateTimeJsonDeserializer());
    		objectMapper.registerModule(simpleModule);
    		// 序列化时增加类型,方便解析成对应类型
    		objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    		jsonRedisSerializer.setObjectMapper(objectMapper);
    		template.setValueSerializer(jsonRedisSerializer);
    		return template;
    	}
    }

    /** 时间序列化 **/
    public class JodaDateTimeJsonSerializer extends JsonSerializer<DateTime>{

      @Override
      public void serialize(DateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString(value.toString("yyyy-MM-dd HH:mm:ss"));
      }

    }

    /**时间反序列化**/

    public class JodaDateTimeJsonDeserializer extends JsonDeserializer<DateTime> {

      @Override
      public DateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        String dateTime = p.readValueAs(String.class);
        DateTimeFormatter format = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");

        return format.parseDateTime(dateTime);
      }
    }

      

    缺点:redis的存或者取都需要经过网络IO达到redis Server上,并根据redis协议更新对应状态,所以相对操作本地缓存会慢些

    2.本地热点缓存,使用谷歌的guava cache

    @Service
    public class CacheServiceImpl implements CacheService {
        private Cache<String, Object> commonCache = null;
        @PostConstruct
        public void init() {
            commonCache = CacheBuilder.newBuilder()
                    // 初始容量为10
                    .initialCapacity(10)
                    // 最大容量100
                    .maximumSize(100)
                    // 失效时间60秒
                    .expireAfterWrite(60, TimeUnit.MICROSECONDS)
                    .build();
        }
        @Override
        public void setCommonCache(String key, Object value) {
            commonCache.put(key, value);
        }
    
        @Override
        public Object getFromCommonCache(String key) {
            // TODO Auto-generated method stub
            return commonCache.getIfPresent(key);
        }
    }

    CacheService的使用在上面getItem方法的代码中。

    3.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 {
        init_by_lua_file ../lua/init.lua;
        upstream backend_server{
            server 192.168.31.146:8090 weight=1;
            server 192.168.205.12:8090 weight=1;
        }
    
        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;
         }

    
    

    4.nginx直接获取redis缓存数据

    优点:避免访问后台应用的网络时间,减少消耗。虽然增加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;
            }
    

      

  • 相关阅读:
    ASCII码表
    arm linux 下移植busybox 的tftp
    Makefile中的路径
    Wireshark图解教程(简介、抓包、过滤器)【转载】
    在装有windows跟ubuntu的机器上重新安装windows后修复ubuntu的grub
    在linux里建立一个快捷方式,连接到另一个目录
    ubuntu 迁移部分 / 目录下的存储空间到 /home目录
    /etc/ntp.conf
    ntp 配置 autokey 功能【摘录】
    mips-openwrt-linux-gcc test_usbsw.c -o usbsw 编译问题
  • 原文地址:https://www.cnblogs.com/t96fxi/p/12032248.html
Copyright © 2020-2023  润新知