记录一下对redis的理解~
Redis
基础信息
Redis是一个开源的,基于内存的数据结构存储,可用作于数据库、缓存、消息中间件。实现语言是c语言。单线程。
Redis可以保存多种数据结构,它的存储基于内存,可以key-Value的形式保存;其保存格式类似于Map
为什么不用Map而使用Redis呢?
- Map是本地存储,无法保证多台机器的缓存一致性,而redis是分布式缓存,多台服务器共享
- Map存储的东西过多,Jvm容易挂掉,所以一般只用于做临时存储,它的有效性会随着jvm的销毁而结束,并且也必须需要手动去编写过期时间
- Redis可以将缓存数据写在硬盘里,不需要被程序的启动和关闭而影响,并且它提供了多样的数据结构和过期机制
为什么要使用缓存机制?
假设请求量和并发量特别大的时候,所有的信息都需要去数据库查询,这样就很容易让数据库挂掉,从而有性能问题(访问反应慢,无法获取数据等),因为数据库的读写都是要经过磁盘,然而磁盘的访问速度没有内存快;
Redis的数据结构
Redis是以key-value的形式存储,Key一定是字符串,则Vlaue可以是String,list,hash,set,sortset等数据结构
Redis并没有直接使用这些数据结构实现key-value的数据库,而是基于这些数据结构创建了一个对象系统,也就是说,Redis使用对象来表示key和value,新建一个键值对的时候则生成两个对象,key对象和value对象
对象都有type(类型)、encoding(编码)、ptr(指向底层数据结构的指针)来表示
Redis的基础信息
Redis的默认端口是6379,默认数据库数量为16,且不同数据库之间是具有隔离性的
过期时间
Redis是基于内存, 内存是有限的,所以我们会去掉一些不常用的数据,所以需要我们设置一下键的过期时间
- 设置键的生存时间可以通过EXPIRE或者PEXPIRE命令。
- 设置键的过期时间可以通过EXPIREAT或者PEXPIREAT命令
- PERSIST(移除过期时间)
- TTL(Time To Live)返回剩余生存时间,以秒为单位
- PTTL以毫秒为单位返回键的剩余生存时间
- 过期时间是保存在RedisDB中的一个叫做 expires的hash表中
过期策略
由于过期时间是保存在表中的,那么到了过期时间是否会直接执行删除呢?它会遵守什么样的过期策略呢?
过期策略分为如下三种1.定时删除(类似定时器的定时)2.惰性删除(取键的时候判断时候过期)3.定期删除(类似定时器的每隔多久)
Redis采用的是惰性删除和定期删除。所以不一定会及时删除的
持久化
因为redis基于内存,如果服务器重启/断电导致了redis的重启,内存数据将会丢失
所以redis有两种持久化的策略:
-
RDB:
它所生成的 RDB 文件是一个压缩的二进制文件,基于快照的方式,通过该文件可以还原生成 RDB 文件时的数据库状态
创建方法:
有两个命令可以生成 RDB 文件,一个是 SAVE(阻塞Redis服务器进程)、另一个是 BGSAVE(fork一个子进程,父进程继续处理,写完数据库后新的RDB文件会替换旧)
文件载入:
没有开启AOF持久化,RDB 文件的载入是在服务器启动时自动执行的,所以没有用于载入的命令,期间阻塞主进程。 -
AOF:Append-only-file的简写,当redis执行命令时候,将命令写入AOF文件中
实现步骤:
命令追加、文件写入、文件同步
过期键的处理方式
- RDB:创建的时候,过期键不会保存;载入的时候,过期键不会载入
- AOF:如果键过期,但是并未被删除,AOF会保留但是没有实际影响,因为如果过期键被删除,会追加一条DEL命令去记录,在重写AOF文件的时候,程序会对键进行检查,如果过期则会被删除
Redis是单线程的
Redis服务器主要处理文件事件(基于socket通信,I/O多路复用)和时间事件(基于serverCron)
Redis单线程快:1.纯内存操作2.核心是非阻塞I/O 3.单线程就避免了多线程的上下文切换的问题
Redis主从复制(master/replica)
如果访问请求过多,为了提高服务的高可用性,我们可以增加Redis服务器进行主从管理
主服务器负责写请求,从服务器负责读请求
好处:
- 读写分离
- 高可用 :如果某台服务器挂了,其他服务器还能接受请求
- 处理高并发量
复制功能
在Redis中,用户可以通过执行SALVEOF命令或者设置salveof选项,让一个服务器去复制(replicate)另一个服务器,我们称呼被复制的服务器为主服务器(master),而对主服务器进行复制的服务器则被称为从服务器(salve)
具体体现形式:
- 同步(sync):将从服务器的数据库状态更新至主服务器的数据库状态
- 命令传播(command propagate):主服务器的数据库状态被修改,导致主从服务器的数据库状态不一致,让主从服务器的数据库状态重新回到一致状态。
复制步骤
-
从服务器设置主服务器的IP和端口
-
建立与主服务器的Socket连接
-
发送PING命令(检测Socket读写是否正常与主服务器的通信状况)
-
身份验证(看有没有设置对应的验证配置)
-
从服务器给主服务器发送端口的信息,主服务器记录监听的端口
Redis机制
如果主服务器挂了,Redis提供了哨兵机制去将一台从服务器提升成主服务器,等到主服务器恢复好则变成从服务器
哨兵(Sentinel)模式的原理及功能
- 不停地监控主从服务器是否正常工作(两秒也刺激)
- 如果有故障,哨兵发送信息通知管理员
- 如果主服务器挂了,会主动提升从服务器成主服务器,且配置文件修改
- 哨兵可以作为配置中心,提供当前主服务器的信息
Redis故障
缓存雪崩
可能情况
Redis挂掉了,请求直接访问数据库或者是键都设置同一过期时间,同时失效
解决方案
-
在缓存设置过期时间的时候加上随机值,这样会避免同时过期造成的雪崩
-
可以设置主从复制+哨兵,有效避免redis服务器挂掉造成的影响,提高可用性
缓存穿透
无限制的去请求一个不可能存在的数据(比如说id为负数),由于缓存无法集中,所以造成大量的访问数据库。
解决方案
- java中的过滤器(filter)拦截
- 将请求数据库找不到的数据以空的形式放入缓存,设置较短的过期时间
Redis数据和数据库数据一致性
执行更新操作有两种选择(必须遵守原子性:一起成功一起失败):
- 先操作数据库,在更新缓存(默认删除缓存在插入)
- 先更新(同上)缓存在更新数据库
解决方案
更新数据库–>删除缓存
高并发的情况几率小:由于读操作会比写操作简单,并且写操作会在写的时候锁表,所以读操作必须要在写操作之前进入,又要晚于写操作更新缓存
删除缓存–>更新数据库
1.放入队列,实行串行化