5 查询性能优化-多级缓存

缓存设计的时候考虑的问题

用快速存取设备 用内存

将缓存推到离用户最近的地方

脏缓存清理

 

多级缓存

redis缓存

热点内存本地缓存

nginx proxy cache缓存

nginx lua缓存

 

redis缓存

当做集中式缓存的中间件 并将其作为内存级别的存储 易失性的

redis是和mysql相同的集中式存储概念 所有的set和get都会到这一台redis服务器上进行 区别仅是它是key-value数据库 且易失性设备

 

redis具有三种模式 单机版和Sentinal哨兵模式 集群cluster模式

redis支持主从机制 所以redis服务器可以有多台slave 我们希望如果主服务器挂掉之后可以自动切换到slave服务器 所以必要要有sentinel哨兵

心跳破坏掉之后

 

如果我们想要使用多台redis服务器 进行分流 按照上面的架构图 应用服务器需要进行计算 得到此次操作应该去哪台服务器 数据之间的一致性受到了挑战 并且产生了一些开销

而在集群cluster模式下 所有的redis服务器的状态都是相通的(Paxos算法) 虽然仍然会有服务器之间的开销 但是应用不需要管理redis服务器集群的状态了

 

实现redis集中式缓存商品详情页

//与之前的usermodel相同 这里也需要让itemmodel实现序列化接口
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);

    }

实现redisconfig类 更改序列化方式

    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        //首先解决key的序列化方式
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);

        //解决value的序列化方式
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = 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.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        objectMapper.registerModule(simpleModule);

        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);

        return redisTemplate;
    }

 

本地数据热点缓存

需要考虑

热点数据

脏读不敏感

内存可控 jvm堆栈的内存大小宝贵

 

本地数据的缓存其实就是有更新策略的hashmap 那么使用的其实就是封装好的Cache类 guava cache

由谷歌提供 可控制大小和超时时间 可配置lru策略 线程安全

 

nginx proxy cache

需要考虑

nginx反向代理前置 就是说这个服务器必须要进行反向代理才能做缓存

这种缓存是依靠文件系统存索引级的文件 将数据存入文件系统汇总

依靠服务器的内存缓存文件地址 

 

在nginx的配置文件中加上

proxy_cache_path /usr/local/openresty/nginx/tmp_cache levels=1:2 keys_zone=tmp_cache:100m inactive=7d max_size=10g;

在server结点里面添加
        proxy_cache tmp_cache;
        proxy_cache_key $uri;
        proxy_cache_valid 200 206 304 302 7d;

压测可知性能变差 因为访问文件而不是访问内存 速度较慢 

 

引入了缓存的nginx的脚本语言nginx lua

它和nginx一样拥有协程机制 无需考虑异步的机制

nginx的每个worker进程都是在epoll或kqueue这种时间模型之上封装成协程

每一个请求都有一个协程进行处理 机试ngx_lua运行lua相对C有一定的开销 但是仍然可以保证高并发能力

 

nginx协程机制

nginx每个工作进程创建一个lua虚拟机

工作进程内的所有协程共享同一个vm

每个外部请求由一个lua携程处理 之间数据隔离

lua代码调用io等异步接口时 协程被挂起 上下文数据保存

自动保存 不阻塞工作进程

io异步操作完成后还原协程上下文 代码继续执行

 

lua的挂载点

 

OpenResty

由Nginx核心加很多第三方模块组成 默认继承了lua开发环境 使得nginx可以作为一个WebServer使用

借助于Nginx的事件驱动模型和非阻塞IO 可以实现高性能的Web应用程序

OpenResty听过了大量组件 如MySQL Redis Memcached等等 使得在Nginx上开发web应用更加简单方便

实践内容

shared dic 共享内存字典,所有worker进程可见,lru淘汰

openresty redis支持

 

热点数据缓存在nginx本地内存中 非热点、高流量数据读redis slave 在与master主从同步的过程中实现对脏数据的更新

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值