美文网首页
第四讲-缓存

第四讲-缓存

作者: liwsh | 来源:发表于2021-07-12 20:14 被阅读0次

1.缓存适用场景

1.度密集型
2.存在热点数据
3.对响应时间要求高
4.对一致性要求不严格
5.需要分布式锁的时候

2.热点key

热点key,是指某个或者某些少量的key热度特别高,相比其他key而言访问特别频繁
解决思路:
a.热点key备份,key后面跟一个随机数,将key备份到好几个分配上。访问的时候也拿key+随机数进行访问。
b.热点key拆分,根据业务逻辑进行key拆分
c.本地缓存
堆内缓存:使用简单,jdk HashTable、Guava Cache等
堆外缓存:可以支持更大缓存空间,Ehcache、MapDB等

3.大key问题

string类型value特别大,大于512k。集合类型元素特别多,大于1w。
问题:由于redis单线程,获取key的时候,会导致其他命令阻塞
解决手段:根据业务场景拆分key,hash或者其他模式进行key的路由。

4. redis高效原因

a. 内存操作,非阻塞IO(IO多路复用),利用select poll epoll处理事件流。
b. Redis采用单线程处理命令,避免了不必要的上下文切换和竞争条件,也不存在多进程切换导致的CPU消耗

5. 分布式锁

5.1 redis用于高性能场景,保证AP。如果redis master宕机不保证强一致性,可能同时2个线程都获取到锁。
zookeeper用于强一致性和高可用场景,保证CP。
5.2 redis加锁使用SETNX加锁,同时设置一个超时时间(SET命令加NX选项,加上超时时间),超过该时间则自动释放锁,锁的value值可以设置为客户端的标识,释放锁的时候进行判断。
5.3 解锁的时候使用lua脚本解锁,保证判断和解锁动作原子性
5.4 redis锁缺点:1.过期时间设置太长或者太短都不合理,太长阻塞其他线程获取锁,太短任务还未执行完锁已经释放。2.获取不到锁无法阻塞。3.锁无法重入。基于以上问题,有人开发了一个Redisson jar包。Redisson是Redis官网推荐的java语言实现分布式锁的项目,是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)具体参考:https://ifeve.com/%E6%85%A2%E8%B0%88-redis-%E5%AE%9E%E7%8E%B0%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81-%E4%BB%A5%E5%8F%8A-redisson-%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/
5.5 服务器宕机,锁如何释放。redis靠超时时间被动释放,Redisson释放得更快一些,通过设置比较短的超时时间,然后守护线程不停的续租。zookeeper靠心跳检测,连接断开自动释放锁
5.6 锁等待实现。1.Redisson依靠pubsub订阅一个channel,锁释放后信号量释放。其他线程都在等待信号量,一旦释放就好唤醒获取锁。
2.在Zookeeper中方案就是Watch机制,监听一个节点是否产生变化,若变化会收到一个通知,当获取不到锁之后监听锁的那个临时节点即可,不过需要注意一个惊群效应,什么是惊群效应呢?假设A节点获取到锁,同时B、C、D、E也在获取锁,此时BCDE节点阻塞等待释放锁,当A节点释放锁之后,BCDE会同时起来争夺锁,但其实只有一个节点会获得到锁,就会浪费N-1个节点的系统资源去获取锁,惊动群而做无用功,解决方案是按顺序来,首先获取锁失败之后注册一个顺序节点,按照自己的顺序,向前一个节点注册Watch,这样一个个来即可解决惊群效应。具体参考:https://zhuanlan.zhihu.com/p/152240168

6. redis实现消息队列

redis作为消息队列:不保证不丢,生产者没有ack保证消息一定到达,消费端没有offset告知消费成功,是一个轻量级队列。Redis消息队列仅适用于轻量级、对时延有高要求、但是对消息可靠性不做高要求的场景
lpush 左边生产
rpush 右边生产
lpop 左边消费
rpop 右边消费
brpop 右边消费,阻塞等待一定时间
RPOPLPUSH 右边消费,消费的同时元素放入备份队列,消费成功后从备份队列删除。

7. redis实现排行榜

sorted set通过SkipList(跳跃表)和HashTable(哈希表)的双端口数据结构实现,删除、添加和更新一个元素的时间复杂度为O(log(N)),都是非常快速的操作;又由于成员的位置都是有序的,所以访问一个元素并获取其分数值时间复杂度为O(1);当要求排序的时候,Redis无需要做任何工作了,因为已经全部排好序了

7. redis实现最新项目列表

web项目通常有,列出最新的关注者列表,最新回复列表等。这个用redis队列实现,队列有一个容量,永远保留最新的数据。

8. guava cache

8.1相比java的map优点:
1.自动加载数据进入缓存
2.缓存控制总量,使用LRU算法淘汰内存
3.根据key访问时间计算过期时间
8.2数据结构:

image.png
8.3回收机制:
容量回收:到达容量上限,使用LRU算法淘汰缓存
定时回收:expireAfterAccess:多久没有访问后回收,expireAfterWrite:写访问多久后回收
引用回收:弱引用存储key/value,没有其他引用时,缓存可以被回收
8.4回收机制
调用get方法的时候进行回收,发现数据过期后会锁住segement去加载数据,其他线程会阻塞,容易导致线程阻塞。建议使用refreshAfterWrite替换expireAfterWrite,当前线程阻塞去获取数据,其他线程返回旧值。如果同时很多key都过期了,很多线程去加载数据也会阻塞,这个时候可以把加载数据的任务提交给线程池,所有的线程返回旧值
参考:https://albenw.github.io/posts/df42dc84/

9. 缓存的一些坑

9.1缓存一致性

3种方案对比:
a.先更新数据库后更新缓存不一致场景:两个线程A和B都做更新动作,A更新数据库,B更新数据库,B更新缓存,A更新缓存。
b.先删缓存后更新数据库不一致场景:A线程更新,B线程查询。A线程删除缓存,B线程查询不到缓存从数据库查询旧数据更新缓存,A线程更新数据库。
c.先更新数据库后删除缓存不一致场景:A线程更新,B线程查询。缓存刚好失效,B线程查询DB获得旧值,A线程更新数据库,删除缓存key,B线程将旧值设置缓存。这个概率比较小了,一般采取这种方案,如果一定要解决这种不一致,可以延迟删除缓存key
c方案里面删除缓存key如果失败了怎么办,如何补偿。一般的方案是消费mysql binlog通过mq异步删除。
参考文档:https://blog.csdn.net/koli6678/article/details/88202245

9.2缓存雪崩

同时很多key缓存失效,或者一个key缓存失效,同时大流量涌入数据库,导致数据库宕机。
方案对比:
1.保证只有一个查询查不到数据的时候去load DB。一般用redis的setnx命令加锁
2.缓存的value中设置一个时间,比key的过期数据小。如果发现过期了,加锁进行缓存更新,其他请求依然返回旧数据。
3.方案2的改进,如果发现过期了,提交异步任务进行缓存更新,主线程返回旧数据。

9.3缓存穿透

查询一个一定不存在的数据,如果每次缓存差不多,就去查询DB,导致DB压力激增。
解决方案:
1.DB不存在的时候,缓存一个空,设置过期时间
2.布隆过滤器

10. redis数据结构

1.ziplist
压缩队列,与linklist相比,无指针记录上下节点,通过偏移量进行计算和取值,是一片连续的内存空间。
2.intset
set元素少的时候使用intset
3.sorted set
有序的键值对,value是一个浮点数称为score。内部使用ziplist或者skiplist+hashtable实现

问题:
扩容如何不影响服务
迁移过程中,槽会被标记为迁移中,如果访问的key属于此槽,访问看在不在,如果不在重定位到新槽。

相关文章

  • 第四讲-缓存

    1.缓存适用场景 1.度密集型2.存在热点数据3.对响应时间要求高4.对一致性要求不严格5.需要分布式锁的时候 2...

  • SLAM前端 - 直接法

    参考:高翔——《视觉SLAM十四讲》第8讲 视觉里程计2高翔——《视觉SLAM十四讲》系列讲解视频及PPT ch8...

  • SLAM前端 - 相机运动估计 & 特征点位置估计

    参考:高翔——《视觉SLAM十四讲》第7讲 视觉里程计1高翔——《视觉SLAM十四讲》系列讲解视频及PPT ch7...

  • 第3章 下载缓存

    第3章 下载缓存 3.1 缓存还是不缓存 当爬取目的不是为了获取即时的,最新的数据时,可以使用缓存。缓存之后可以离...

  • 2021-05-09

    2021年共读第10本 【穷查理宝典】共读第19天 1摘要: 第四讲 跨学科思维

  • Hibernate @Cache 注解

    本文主要摘自Hibernate缓存,整理些要点出来 Hibernate查询缓存依赖于二级缓存。当启用查询缓存后,第...

  • HTTP缓存机制

    一、缓存可以用来干什么? http缓存机制是web性能优化的重要手段。 二、缓存规则解析 客户端第...

  • Glide源码剖析 缓存篇

    Glide主要分为内存缓存和硬盘缓存; 既然是缓存功能,就必然会有用于进行缓存的Key​ 这里在第11行调用了fe...

  • mybatis 二级缓存日记

    在mapper.xml中开启二缓存,mapper.xml下的sql执行完成会存储到它的缓存区,如: 开启缓存后,第...

  • 籽林读书笔记《品味四讲》

    《品味四讲》蒋勋 第1天,年初九,2019.2.13 第8~27P“生活美学的起点” 回到大自然,回到生活本身,发...

网友评论

      本文标题:第四讲-缓存

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