- Redis 是 C 语言开发的一个开源的(遵从 BSD 协议)高性能键值对(key-value)的内存数据库,可以用作数据库、缓存、消息中间件等
- 性能优秀,数据在内存中,读写速度非常快,支持并发 10W QPS。单进程单线程,是线程安全的,采用 IO 多路复用机制。丰富的数据类型,支持字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等。支持数据持久化。支持大数据(最大1G)。可以将内存中数据保存在磁盘中,重启时加载。主从复制,哨兵,高可用。可以用作分布式锁。可以作为消息中间件使用,支持发布订阅
- 为什么快?数据在内存;IO多路复用机制;单进程单线程操作都是原子性,减少了线程上下文切换,不用加锁;使用简单的resp协议通讯快;6.X之后增加了IOThreads用来处理读写,更快了;
-
不同操作系统不同的多路复用器 Solaries10 evport linux epoll Mac、OSXFreeBSD kqueue 其他 select - 数据类型:
数据类型 类型 简介 特性 场景 string 二进制安全,最大512M 可以包含任何数据,jpg图片或者序列化对象或者bitmap session一致性,秒杀,限流,统计活跃数,权限管理 hash 键值对 适合存储对象,可以只查看修改某个属性值,性能会降低 存储,读取,修改用户属性;聚合场景; list 双向链表 增删快 最新消息排行,数据共享,迁出 set hash表实现,元素不重复 添加,删除,查找复杂度都是O(1),通过了交、并、差集的操作 共同好友;抽奖; sorted set score、rank、元素 数据大时用跳表实现,包含入链、建层的过程;最高64层; 排行榜;评论分页 -
使用:结合SpringBoot,一种是通过RedisTemplate;另一种是Spring Cache集成Redis
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency> //SpringBoot 2.x以后底层不再使用Jedis,而是换成了Lettuce
-
Redis默认分片16个,最大连接数默认为8;max-active: 100;
-
缓存策略:1,求留余数法(hashcode对HASH表数据长度取模)2,一致性hash算法(0~(2^32)-1hash环,顺时针映射,虚拟节点)
-
缓存淘汰策略:
-
noeviction # 不会继续服务写请求 (DEL 请求可以继续服务),读请求可以继续进行。这样可以保证不会丢失数据,但是会让线上的业务不能持续进行。这是默认的淘汰策略。
-
volatile-lru # 尝试淘汰设置了过期时间的 key,最少使用的 key 优先被淘汰。没有设置过期时间的 key 不会被淘汰,这样可以保证需要持久化的数据不会突然丢失。
-
volatile-ttl # 跟上面一样,除了淘汰的策略不是 LRU,而是 key 的剩余寿命 ttl 的值,ttl 越小越优先被淘汰。
-
volatile-random # 跟上面一样,不过淘汰的 key 是过期 key 集合中随机的 key。
-
# volatile策略只会针对带过期时间的 key 进行淘汰
-
allkeys-lru 区别于 volatile-lru,这个策略要淘汰的 key 对象是全体的 key 集合,而不只是过期的 key 集合。这意味着没有设置过期时间的 key 也会被淘汰。
-
allkeys-random 跟上面一样,不过淘汰的策略是随机的 key。
-
# allkeys策略会对所有的 key 进行淘汰
-
-
缓存和数据库数据一致性问题:分布式环境下非常容易出现缓存和数据库建数据不一致。我们无法保证强一致性,只能采用合适的策略包括:合适的缓存更新策略,更新数据库后及时更新缓存,缓存失败增加重试机制。
-
缓存雪崩:同时间大量key失效,造成大面积访问数据库;处理策略:把key的失效时间加个随机值;将热点数据均匀分布在不同的Redis库;设置热点数据永不过期;
-
缓存穿透:缓存和数据库里都没有的数据被不断请求;处理方案:接口层增加校验,比如用户鉴权;对参数做校验;布隆过滤器:利用高效的数据结构和算法判断key是否在数据库存在;原理:存储key的hash值,由于存在hash碰撞,返回结果有一点概率错误(有的不一定有,没有的一定没有)。
-
缓存击穿:同一热点Key被不断请求,key一旦失效,造成大并发访问数据库。处理:设置热点key永不过期;加锁,setnx:
-
先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?
set指令有非常复杂的参数,可以同时把setnx和expire合成一条指令来用的 -
分布式锁:有三个要点:set命令要用
set key value px milliseconds nx
;value要具有唯一性;释放锁时要验证value值,不能误解锁;未解决集群节点的异步问题,引入redlock算法 -
redlock算法类似哨兵模式,即多数可用才算可用,解除锁则要全部解除。具体参考redlock
-
redisson是架设在Redis基础上的一个Java驻内存数据网格,底层用lua脚本实现,对redlock做了封装。具体参考redisson 使用redlock源码解析
-
Redis通讯协议:RESP 是redis客户端和服务端之前使用的一种通讯协议;
RESP 的特点:实现简单、快速解析、可读性好 -
4.x之前rdb和aof不能同时使用,默认使用rdb;rdb记录数据快照,快。aof记录操作指令,慢。4.x之后增加了混合使用模式:先存rdb快照,再使用aof记录操作。
-
redis自带压测工具benchmark
-
redis主从集群:强一致性(C)会破坏可用性(A),默认用弱一致性。CAP原理:三者不可兼得。最终一致性(P)。zookeeper、hdfs、哨兵都采用最终一致性,即一个节点两秒内连不上其他节点就不能提供服务;如果一个数据过半节点是某个值,那么它的全部节点都会改成这个值。
-
分片集群:1客户端实现,2代理层实现,3集群分片实现:hash槽
-
AKF:三个维度,主从,业务分区,同一业务分片。
-
redis默认使用场景是内网,忽略了安全性,但是也有一些方式保障安全:1绑定到特定的网卡2redis没有密码的时候会进入保护模式,只允许本地回环地址访问;3为了防止hash碰撞攻击,Redis 每次启动, 都使用不同的伪随机数种子(pseudo-random seed)来执行 hash 运算
-
6.0更新特性:
1)重新设计了客户端缓存
2)如果用于复制的RDB文件不再有用,它将被立刻删除
3)ACL,增加了权限控制,可以对每个命令做控制。还增加了ACL日志
4)改进了复制协议PSYNC2,以前只能做全量同步,现在可以频繁的部分同步数据
5)带有超时的Redis命令
6)RDB文件加载速度更快了
7)增加了IO线程组,将主线程的I/O读写任务拆分出来给一组独立的线程执行,使得多个socket的读写可以并行化,但是主线程的命令依旧是串行执行;I/O线程要么同时在读socket,要么同时在写,不会同时读或写;I/O线程只负责读写socket解析命令,不负责命令处理;I/O线程数可以自行配置