前言
前面几篇文章分析了Redis数据结构,Redis主从复制,哨兵模式,Cluster分片方案,本文将以问题的形式对这些内容进行一个总结。
一、Redis支持哪些数据结构,以及底层的实现
数据结构类型 | 底层数据结构 | 使用场景 |
string | sds(简单动态字符串) | 1、分布式锁2、缓存数据3、计数器4、全局id 5、bitmap统计数据 |
hasher | hashtableziplist(压缩列表) | 1、redission存储分布式锁2、存储行数据 |
zset | ziplistskiplist(多层级跳表) | 1、排行榜 |
set | intset(存整型)hashtable(存非整型) | 1、用户信息2、用户点赞关注信息 |
list | quicklist和ziplist组合 | 1、内存级消息队列,栈 |
geospatial indexes | geoPoint数组 | 存储地理位置,如经纬度 |
hyperloglogs | 基于string实现 | 1、大数据不精确统计数据 |
二、Redis为什么这么快?
1、key的全部操作基于内存存储和操作
2、k/v存储结构,时间复杂度O(1)
3、单线程操作,避免线程上下文切换,上下文切换需要消耗系统资源。这里的单线程是指处理客户端的请求是单线程的,可以把它叫做主线程。单线程的好处?
- 没有创建线程,销毁销毁线程的开销。
- 避免了上下文切换,cpu开销。
- 避免线程之间竞争问题,比如加锁和解锁。死锁等问题。
4、数据据结构精细化设计,比如sds的惰性回收策略,预先分配策略,三种编码类型,hashes,zset多种编码切换,基于字节层面优化存储性能,不浪费一字节内存。
5、非阻塞多路复用io模型
三、Redis内存淘汰策略
淘汰策略 | 淘汰key的范围 |
Volatile-lru | 设置了过期时间的最近最少使用的key,非传统lru算法,基于采样实现 |
All-lru | 所有的key里面最近最少使用key |
Volatile-lfu | 设置了过期时间的使用频率最低的key,基于概率实现 |
All-lfu | 所有的key里面使用频率最低的key |
Volatile-random | 设置了过期时间的随机的key |
All-random | 所有key里面随机的key |
四、Redis实现分布式锁
1、为什么需要分布式锁?
由于在分布式系统中,跨jvm进程之间对共享资源进行互斥访问时,synchronized,lock无法实现。
2、实现分布式锁需要考虑的问题?
- 互斥
- 防止死锁
- 性能
- 可重入锁方式
- 锁续约 看门狗,一个线程,1/3的时间去续约。
3、Redission是怎么用redis实现分布式锁的?
redission加锁形式,使用hashes结构。
通过lua脚本将value设置成加锁的次数,实现可重入锁特性。
释放锁就value减少,直到达到0后,删除key。
释放锁
加锁成功后开启续期定时任务
使用了netty中的时间轮组件来创建定时任务
Redission实现的分布式锁存在什么问题呢?
最大的问题,就是如果你对某个redis master实例,写入了myLock这种锁key的value,此时会异步复制给对应的master slave实例。但是这个过程中一旦发生redis master宕机,主备切换,redis slave变为了redis master。接着就会导致,客户端2来尝试加锁的时候,在新的redis master上完成了加锁,而客户端1也以为自己成功加了锁。此时就会导致多个客户端对一个分布式锁完成了加锁。这时系统在业务上一定会出现问题,导致脏数据的产生。所以这个就是redis cluster,或者是redis master-slave架构的主从异步复制导致的redis分布式锁的最大缺陷:在redis master实例宕机的时候,可能导致多个客户端同时完成加锁。
解决办法是什么呢?
官方是推荐使用红锁算法来解决。
五、Redis哨兵和Cluster有哪些区别?
1、Redis哨兵弥补了Redis主从复制的缺陷,补充了自动故障转移的功能
2、Cluster则弥补了Redis哨兵机制和Redis主从复制中master单节点问题,提供了redis分片的能力,将请求压力和存储压力分摊到多台Redis服务器上。