目录
对Redis的了解
-
Redis是非关系型数据库,不依赖业务逻辑存储,以简单的key---value形式存储,基于内存存储
-
Redis采用单线程+多路IO复用技术
-
Redis采用单线程模式,无需进行线程切换,减少消耗一定的CPU时间和内存资源,处理请求更加高效
-
Redis主要是基于内存,单线程可以更好的利用CPU缓存。由于数据的访问和操作具有局部性,利用CPU缓存能提高内存访问速度
-
多路IO复用技术可以同时监听多个连接,当一个连接准备就绪时,就可以进行相应的操作
-
Redis在等待IO操作的过程中,将CPU资源用于执行其他任务 ,如数据处理和存储,充分利用资源
-
实现非阻塞IO ,当一个客户端的IO操作不可用时,Redis可以立即切换其他就绪的连接进行操作
-
Redis的数据类型
-
字符串(String)
- Redis最基本的数据类型,一个Key对应一个Value
-
列表(List)
-
单键多值,底层是一个双向链表
-
对两端的操作性能高,中间查询性能低
-
-
集合(Set)
-
与List相似,多一个自动排重的功能
-
是一个无序集合,存储不重复元素
-
-
哈希(Hash)
-
是一个string类型的field 和value的映射表
-
适合存储对象,类似Java里的Map<String,Object>
-
-
有序集合(Zset)
-
sorted ser 与set相似,是没有重复元素的字符串集合
-
每一个成员都关联了一个评分,评分用来排序
-
-
Bitmaps
-
本身是一个字符串类型,但是可以实现位操作
-
可以把Bitmaps当作一个数组,每个元素只能存储0和1 ,数组的下标称为偏移量
-
主要存储活跃用户,如某一时间段访问网址的用户,将用户id作为偏移量
-
-
HyperLogLog
-
用来做基数统计的数据结构,统计不重复元素
-
可以去重,添加时相同的元素,无法添加
-
-
Geospatital
- 提供经纬度设置、查询、范围查询、距离查询、经纬度Hash等
Redis的事务
-
Redis事务是一个单独的隔离操作,所有的命令被序列化,按顺序执行
-
事务主要分为两个部分
-
组队阶段
输入Milit命令开始组队阶段,将命令依次放入组队队列里面
-
执行阶段
输入Exec命令开始执行组队队列里面的代码
-
在组队结束后可以输入discard放弃组队
-
-
在组队阶段,如果命令出现错误,整个队列里面的命令全部都不会被执行
-
在执行阶段,命令出现错误,只有出现错误的命令不会执行,不影响其他命令执行
Redis的事务冲突
-
由于事务的单独隔离操作,当其他客户端发送请求后,会导致对同一个键值对进行操作,导致结果不同
-
这时采用锁机制进行预防
-
悲观锁
当一个客户端拿到数据后就会进行上锁,直到锁释放才会被其他客户端操作 效率较低
-
乐观锁
采用版本号机制,每次拿到数据后会进行判断,判断别的客户端是否修改过版本(是否为数据进行过修改)
- Redis中如果两个事务同时要对一个key进行操作,在组队阶段会先拿到键的版本号,当一个事务进入执行阶段执行后,另一个事务会在执行之前对键进行版本号校验,版本不同,事务就会被终止
Redis的持久化
- 将内存中的数据写入到磁盘,就是持久化
-
RDB
在一定的时间间隔内,将内存中的数据集快照写入磁盘
过程(写时复制技术)
-
先复制创建一个**子线程(Fork)**来进行持久化
-
将数据写入到一个临时文件中
-
等持久化的过程结束,将临时文件替换会持久化文件
-
由于直接创建持久化文件,当进程断开的时候,数据会丢失
-
缺点:最后一次持久化的数据可能会丢失
在durmp.rdb配置文件中,
save 20 3
意味着在20秒内当3个key发生变化时,进行持久化
-
-
-
AOF
AOF是以日志的形式记录写操作(增删改),将Redis执行过程中的指令记录下来,当Redis重启会重构数据
过程
-
客户端的命令会被append追加到AOF的缓存区
-
AOF缓存区会根据持久化策略(每次操作都立即写入日志、每隔一秒同步一次、不主动同步,由操作系统同步)将操作同步到磁盘中的appendonly.aof文件中
-
AOF根据文件大小执行重写策略(文件大于64M的100%---128M)的时候,用写时复制技术将文件的指令进行压缩
-
当Redis重启时,会加载文件重构数据
-
-
备份
先将.rdb和.aof配置文件复制下来,当Redis重启时会自动加载配置文件,以达到备份的功能
当RDB和AOF同时开启,默认读取的是AOF的数据
Redis主从复制
-
Redis主从复制是将一台Redis服务器的数据复制到其他Redis服务器
-
主服务器用来实现写的功能,从服务器实现读的功能,提高系统的并发性能
-
当主服务器故障时,从服务器可以升级为主服务器,不会操作系统停滞
原理
-
当从服务器连接上主服务器后,会主动发送数据同步的消息
-
主服务器收到消息后,进行数据持久化,并将RDB文件发送给从服务器
-
从服务器收到RDB文件后进行读取,实现数据同步
-
当主服务器写的时候,会主动的和从服务器进行数据同步
三大招式
-
一主两仆
-
当从服务器断开后,重写连接会变成单独的主服务器
-
当主服务器断开后,从服务器不会篡位
-
-
新火相传
-
从服务器可以组为主服务器(小组长),下面挂多个从服务器
-
当主服务器断开后,依旧遵循一主两仆,不会篡位
-
缺点:小组长从服务器断开后,下面的数据不会同步
-
-
反客为主
- 当主服务器断开后,从服务器会晋升为主服务器
哨兵模式
- 哨兵模式主要是检测Redis主从服务器的故障,当主服务器发送故障时,自动将从服务器升为主服务器,确保Redis服务的运行
-
配置sentinel.config文件,启动哨兵
-
哨兵会不断监控主从服务器的运行状态,包括时候在线、是否正常同步等
-
哨兵会定期的向主从服务器发送PING命令,如果主服务器在一定时间内没有响应,则认为出现故障
-
当检测主服务器故障时,会在从服务器中选择一个合适的服务器作为新的主服务器
-
哨兵会向其他服务器发送命令,让新的主服务器与其他服务器同步
-
最后将旧的主服务器重新配置为从服务器
-
选举规则
-
优先级靠前的
在redis.conf中默认配置:slave-priority 100 / replica-priority 100(值越小优先级越高)
-
偏移量大的
与主句数据同步值最高的
-
runid最小的从服务器
Redis启动后自动生成的40位的runid
-
集群
-
Redis集群就是对Redis的水平扩容,将数据分布存储在多个节点上
-
一个集群至少要有三个主节点
-
无中心化集群:任何一个节点都可以作为集群的入口,各个节点之间是相互连通的
-
客户端可以连接到集群的任意一个节点上
-
当执行命令时,会根据键的哈希值对 16384 取模计算出槽位
-
每个节点都负责自己范围的键的存储和查询操作
缓存问题
缓存穿透
- 主要是服务器被恶意攻击,大量的url访问服务器
解决方案
-
对空值缓存,如果查询数据库返回的时空值,对这个数据也存入缓存中,避免这个url一直访问服务器
-
设置白名单,利用Bitmaps类型作一个可访问名单,id作为偏移量,每次访问的时候与Bitmaps中的值进行比较(1表示用户访问过,无需在对服务器进行查询)
-
实时监控,当Redis命中率开始急速下降时,排查访问对象和访问数据,与运维人员配合处理
缓存击穿
-
主要是某个时间段内的热点新闻
-
在一点时间内,某一个key过期了,但是由大量返回去查询这个键,这是会去服务器中查询
-
数据库无法将数据存入缓存中,造成击穿
解决方案
-
预先设置热门数据,增加key的过期时间
-
实时调整,及时的监控热门数据,增加过期时间
-
使用锁机制
缓存雪崩
- 在某个时间内,大量的key过期,一直去数据库中查找,导致服务器奔溃
解决方案:
-
构建多级缓存架构
-
使用锁或队列,保证不会有大量的线程对数据库进行读写操作
缺点:不适合高并发
-
设置过期标志更新缓存,记录缓存数据是否过期,如果快过期就会触发通知,让其他线程进行更新
-
将缓存失效时间分散开,在失效时间设置随机数,保证不会有大量ket同时失效
分布式锁
-
对服务器加锁,加锁后,这个集群中的服务器都得加这个锁
-
锁的四个条件
-
互斥性,在任意时间,只有一个客户端持有锁
-
不会发送死锁
设置锁的过期时间,确保服务器断开后锁一直不被释放的问题
-
加锁和解锁必须是同一个客户端
设置uuid,避免a服务器在执行过程中锁过期自动释放后,a服务器执行完释放锁,造成正在使用这个锁的b服务器被释放
-
原子性
使用LUA脚本,确保在服务器执行操作的过程中别的客户端干扰