2.2.1 概述
Redis(Remote Dictionary Server)远程字典服务,是一个开源的、支持网络、可基于内存、亦可持久化的日志型,key-value数据库,并提供多种语言API,与MySQL不同的是,Redis数据存储在内存中,可支持10W次读写每秒,此外Redis支持事务、持久化、LUA脚本、LRU码区,多集群方案等。
2.2.2 Redis常用数据类型
常用五种
1. String(字符串)
二进制安全,最大存储512M,String内部编码有三种,int、embstr(小于等于39字符字符串)、raw(大于39字符字符串)
C语言的字符串基于char[] ,而Redis字符串使用SDS(Simple Dynamic String)封装
unsigned int len 标记buff长度
unsigned int free buff中未使用元素长度
char buf[] 存放数据的坑
SDS可以在时间复杂度O(1)获取字符串长度而char[]O(n)
2. Hash(哈希)
hash的value本身又是一个键值对结构,类似hashmap
内部编码:ziplist(压缩表) hashtable(哈希表)
3. List(列表)
存储多个有序字符串,一个列表最多存储2e32-1个元素
内部编码:zipList(压缩表) LinkedList(链表)
4. Set(集合)
多个元素,无序,不重复
内部编码:intSet(整数集合) hashTable(哈希表)
5.ZSet(有序结合)
有序,不重复
内部编码:ZipList(压缩表),sripList(跳跃表)链表+多级索引
特殊三种
1.Geo 地理信息
2.HyperlogLog 基数统计算法的数据结构
3. BitMaps 用一个bit位表示映射状态,理解为一个比特为单位的数组
2.2.3 Redis为什么快
1. Redis基于内存
2. 高效数据编码和编码结构
数据结构:压缩表、SDS、哈希表、跳跃表
3.合理的线程结构
单线程+IO多路复用
4. 虚拟内存机制
冷热数据分离
2.2.4 缓存穿透、缓存雪崩、缓存击穿
1.缓存穿透
原因:查询大量不存在key,穿透缓存,直达数据库,造成数据库压力
解决:a.设置参数校验,避免非法key传入
b.设置空值缓存,过期时间
c.bloomFilter,使用布隆过滤器判别数据是否存在,存在才去查
BloomFilter
底层由二进制向量和随机映射函数组成,可高效查询一个key是否存在set中,类似集合的contain。
优点:时间复杂度低,不存储数据(安全),存储空间小。
缺点:存在一定误判率(误判,有->一定是true,没有->可能是true)。
实现:BloomFilter.create(Funnels.类型,预期数据量,误判率)
2.缓存雪崩
原因:大量key同时到期,访问数据库,造成数据量压力过大
解决:设置离散过期时间
3.缓存击穿
原因:热点key过期,恰巧大量此热点key同时访问,直达数据库
解决:a.热点key永不过期(异步线程更新过期时间)
b.设置互斥锁,缓存过期不直接访问db,通过Redis原子操作 setnx
2.2.5 Redis过期策略和内存淘汰策略
1.过期策略
a.定时过期:到期立即清除,内存友好,占用CPU资源
b.惰性过期:到期不删除,下次访问时判断是否过期,过期则清楚,内存不友好,CPU友好
c.定期过期:隔100ms随机抽取一定数据,进行检查是否过期,过期删除。其他数据采用惰性过期方式
2. 内存淘汰(当Redis内存不足时)
a. volate-lru LRU清除算法 清除 设置了过期时间的key
b. allKeys-lru LRU清除算法 清除 所有key
c. volate-lfu LUF清除算法 清除 设过期key
d. allKeys-lfu LFU清除算法 清除 所有key
e. volate-Random 随机 清除 设置了过期时间key
f. allkeys-Random 随机 清除 所有key
g. volate-ttl 越早过期 越先清除
h. noeviction 默认、内存不足抛出异常
2.2.6 Redis持久化
1.文件加载流程
a.redis启动
b.判断是否开启AOF?
(1)是:是否存在AOF ?(1.1)是:加载AOF并判断是否加载成功 ?(1.1.1)成功
(1.1.2)失败
(1.2)否:是否存在RDB?(1.2.1)否 启动完成
(1.2.2)是:加载RDB (1.2.2.1)成功
(1.2.2.2)失败
(2)否:是否存在RDB (2.1)否 启动完成
(2.2)是:加载RDB (2.2.1)成功
(2.2.2)失败
即,先判别AOF,再判别RDB
2.AOF
以日志方式记录Redis每个操作,默认不开启
优点:一致性,完整性
缺点:文件大,恢复慢
3.RDB
redis默认方式,将快照保存到磁盘,redis安装目录下自动生产dump.rdb文件
触发方式:a. 手动 save同步、bgsave异步
b. 自动 在m秒内执行n次操作,触发RDB自动写入
优点:适合大规模数据,集群化场景
确定:不能实时
2.2.7 Redis高可用(分布式)
1. 主从模式
主节点负责读写,从节点只读,主从复制机制由全量复制和增量复制实现
a. 全量复制(从节点第一次连接主节点时)
master slave
缓存RDB生产期间写命令 RDB-> 载入快照
缓存RDB同步期间写命令 同步缓存-> 执行缓存命令
b. 增量复制
通过replicationFeeddSlaves()函数,同步有数据更新的主节点redis操作
2. 哨兵模型
监控主节点,若主节点下线,从节点升级为主节点
故障切换过程:主节点宕机,哨兵1检测到,不会直接failover,当检测到此情况哨兵到一定数量,发起投票,执行failover,切换成功后通过发布订阅模式,通知从节点切换master
3. 集群模式
为避免每个节点存储相同数据造成浪费,Redis3.0加入分布式存储,对数据进行切片,每台节点存储不同内容,来解决在线扩容问题,且可以解决复制和故障转移问题。
节点间通过Gossip协议进行通信,常用Gossip消息如下:meet、ping、pong、fail
Cluster集群分布算法是Hash Slot插槽算法,也叫哈希槽算法,通过哈希映射CRC16算法计算出一个16位的值,对16384取模,放到数据库的16384个哈希槽中。
其中,高可用还是由主从实现,主管下线:某个节点人为另一个节点不可以。客观下线:多个节点共识结果。
集群部署
a.redis集群需要六个节点,三主三从
b.通过GCC(编译器) make 编译、安装 Redis
c. 分发安装好的Redis到每个节点,并改写Redis.conf文件,每个节点独立的ip,端口,和总线端口。
d.关闭防火墙
e.开启每个节点redis服务器 ./bin/redis-server redis.conf
f.开启集群
redis下载解压后的包->src
./redis-cli --cluster create ip:port ...... --cluster replicates1
g. 加入节点
客户端登录 redis/bin 目录下, ./reis-cli -h ip -p port
CLUSTER MEET ip port
h.redis集群创建完成,进入任意客户端,即可访问
IDE连接集群Redis
a. 开启集群,导入Jedis jar包
b. 创建集群信息set
set.add(new HostAndPort("IP","port"));
new JedisCluster(set);
c.通过JedisCluster set get方法 存、取
d.关闭 JedisCluster.close()
2.2.8 常见问题
1.redis多线程
redis在处理客户端请求时,如socket解析,执行,都是单线程,只有在网络IO使用多线程,处理数据读写和协议解析,这是因为redis性能瓶颈在于网络IO而非CPU,使用多线程提高IO效率,从而提高redis性能。
2.redis事务
redis事务本质是顺序性、一致性、排他性地执行一个队列的一系列命令,
流程 MULTI(开启事务)
命令队列
EXEC(执行事务)、DISCARD(撤销事务)
3.hash冲突
hash冲突:不同的值落在一个 hash表中,
解决:链式Hash
4.生产RDB期间可以同时写吗
可以,RDB手动触发时,dbsave是异步另起一个线程进行RDB。
5.Redis底层使用什么协议
RESP redis Serilzation Procotol 转为Redis设计的序列化实例,它有简单实现、解析速度快,可读性好等优点。