一、考点聚焦
缓存的使用场景;Redis的使用;缓存使用中的坑
1.为什么要使用缓存?使用场景?
2.Redis的常用数据类型,使用方式
3.缓存使用问题:数据一致性问题;缓存穿透、击穿、雪崩问题
二、什么是缓存?为什么要使用缓存?
本章主要讨论的是内存缓存(常见的有Redis和Memcached)
1.缓解关系数据库(常见的是Mysql)并发访问的压力:热点数据
2.减少响应时间:内存IO速度比磁盘快
3.提升吞吐量:Redis等内存数据库单机就可以支撑很大并发
操作时间对比:
| 操作 | 响应时间 |
|---|---|
| 打开一个网站 | 几秒 |
| 在数据库中查询一条记录(有索引) | 十几毫秒 |
| 机械苏特给次寻址定位 | 4毫秒 |
从机械磁盘顺序读取1MB数据 | 2毫秒 |
从SSD磁盘顺序读取1MB数据 | 0.3毫秒 |
从远程分布式缓存Redis读取一个数据 | 0.5毫秒 |
从内存中读取1MB数据 | 十几微秒 |
Java程序本地方法调用 | 几微秒 |
网络传输2KB数据 | 1微秒 |
三、Redis和Memcached主要区别?
| 对比参数 | Redis | Memcached |
|---|---|---|
| 类型 | 1、支持内存 2、非关系型数据库 | 1、把持内存 2、 key-value键值对形式3、缓存系统 |
| 数据存储类型 | 1、String2、 List3、 Set4、 Hash5、 Sort Set【俗称ZSet】 | 1、文本型 2、二进制类型【新版增加】 |
| 查询【操作】类型 | 1、批量操作 2、事务支持【虽然是假的事务】 3、每个类型不同的 CRUD | 1、CRUD2、少量的其他命令 |
| 附加功能 | 1、发布/订阅模式 2、主从分区 3、序列化支持 4、脚本支持【 Lua脚本】 | 多线程服务支持 |
网络IO模型 | 单进程模式 | 多线程、非阻塞IO模式 |
| 事件库 | 自封简易事件库AeEvent | 贵族血统的LibEvent事件库 |
| 持久化支持 | 1、RDB2、 AOF | 不支持 |
四、请简述Redis常用数据类型和使用场景?
考察对Redis使用的掌握程度
1.String(字符串):用来实现简单的KV键值对存储,比如计数器
2.List(链表):实现双向链表,比如用户的关注,粉丝列表
3.Hash(哈希表):用来存储彼此相关信息的键值对
比如:用HSET key filed value格式存储用户相关信息:
HSET name[id: user_name]4.Set(集合):存储不重复元素,比如用户的关注者
5.Sorted Set(有序集合):实时信息排行榜
五、延伸考点:Redis内置实现
对于中高级工程师,需要了解Redis各种类型的C底层实现方式
1.String:整数或者sds(Simple Dynamic String)
2.List:ziplit或者double linked list
说明:ziplist:通过一个连续的内存块实现list结构,其中的每个entry节点头部保存前后节点长度信息,实现双向链表功能。
3.Hash:ziplist或者hashtable
4.Set:intset或者hashtable
5.SortedSet:skiplist跳跃表
6.深入学习请参考:《Redis设计与实现》
自我检查:你知道这些数据结构操作的时间和空间复杂度么?
六、Redis实现的跳跃表是什么结构?
Sorted Set为了简化实现,使用skiplist而不是平衡树实现
七、Redis有哪些持久化方式?
Redis支持两种方式实现持久化
1.快照方式:把数据快照放在磁盘二进制文件中,dump.rdb。
快照的实现试是指定时间间隔把Redis数据库状态保存到一个压缩的二进制文件中。优点是可以恢复某个时间间隔的数据,缺点是一旦数据库宕机,该时间间隔的数据就会丢失。也可以直接在Redis的客户端执行save或bgsave保存快照。
2.AOF(Append Only File):每一个写命令追加到appendonly.aof中。
这种方式不会因为宕机而丢失很多数据,缺点是文件会比较大
3.可以通过修改Redis配置实现选择哪种持久化方式
八、什么是Redis事务?
和Mysql的事务有什么不同?
1.将多个请求打包,一次性、按序执行多个命令的机制
2.Redis通过MULTI, EXEC,WATCH等命令实现事务功能
3.Python redis-py pipeline=conn.pipeline(transaction=True)设置事务的功能
九、Redis如何实现分布式锁?
1.使用setnx实现加锁,可以同时通过expire添加超时
2.锁的value值可以使用一个随机的uuid或者特定的命名
3.释放锁的时候,通过uuid判断是否是该锁,是则执行delete释放锁
十、使用缓存的模式?
常用的缓存使用模式
1.Cache Aside:同时更新缓存和数据库(推荐使用)
2.Read/Write Through:先更新缓存,缓存负责同步更新数据库
3.Write Behind Caching:先更新缓存,缓存定期异步更新数据库
如何处理数据库和缓存之间的数据一致性问题?
可能导致问题:先更新数据库后更新缓存,并发写操作可能导致缓存读取的是脏数据。
解决方法:一般先更新数据库然后删除缓存
十一、如何解决缓存穿透问题?
大量查询不到的数据的请求落到后端数据库,数据库压力增大
1.由于大量缓存查不到就去数据库取,数据库也没有要查的数据。
比如:很多无脑爬虫通过自增id的方式爬取网站,网站查不到相关id的数据
2.解决:对于没有查到返回为None的数据也缓存
3.插入数据的时候删除是一项耳朵和,或者设置较短的超时时间。
十二、如何解决缓存击穿的问题?
某些非常热点的数据key 过期,大量请求打到后端数据库
1.热点数据key 失效导致大量请求打到数据库增加数据库压力
2.解决:
分布式锁:获取锁的线程从数据库拉数据更新缓存,其他线程等待
异步后台更新:后台任务针对过期的key 自动刷新(实现简单)
十四、如何解决缓存雪崩问题?
缓存不可用或者大量缓存key 同时失效,大量请求直接打到数据库
场景:
缓存不可用:有多个缓存服务器,其中一台或多台挂了,这时大量的请求落到少数的缓存服务器上,缓存可能承受不了了。
大量缓存key同时失效:设置缓存时可能会给类似的失效时间,导致短时间里有大量的缓存key失效
解决:
1.多级缓存:不同级别的key 设置不同的超时时间
2.随机超时:key的超时时间随机设置,防止同时超时
3.架构层:提升系统可用性。监控、报警完善