Redis
基本数据结构
- String
- List
- Hash
- Set
- Sorted Set
- Geospatial (地理空间)
- Hyperloglog(基数统计)
- Bitmap (位图,存储标记,记录一个数据的俩种状态,一个月登录了几天)
String和Hash的对比
key | value
user1:name | jay string
user1:age | 18 string
user:1 | name jay Hash
| age 18
内部数据结构
每种数据结构都有自己的编码
-
String
-
int (默认缓存一万个整型值,长度不能超过20)
-
embstr (长度小于44字节)(只读)
- redisObject和SDS保存数据(分配一次内存空间)
- 坏处:增加字符串长度重新分配内存的时候,redisObject和SDS都需要重新分配空间
-
raw (长度大于44字节)
- redisObject和SDS保存数据(分配俩次内存空间)
-
-
List
- linkedlist
- ziplist
-
Sorted Set
- ziplist
- skiplist
-
Hash
- ziplist
- hashtable
-
Set
- hashtable
- inset
简单动态字符串(SDS)
- SDS(simple dynamic string)
数据结构
struct xx{
//记录buf数组中已使用字节的数量
//等于SDS所保存字符串长度
int len;
//记录buf数组中未使用字节的数量
int free;
//字节数组,用于保存字符串
char[] buf;
}
//TODO完善
为什么Redis这么快
总结
- redis是基于内存存储实现的数据库,相比于数据存在磁盘的mysql,可以省去磁盘io的消耗。
- redis支持多种数据类型和数据结构,合理的数据结构使得程序执行速度快
- 实现了I/O多路复用:一个线程可以监视多个文件句柄;一旦某个文件句柄就绪,就能够通知应用程序进行相应的读写操作;而没有文件句柄就绪时,就会阻塞应用程序,交出cpu
- redis实单线程模型,避免了CPU不必要的上下文切换和竞争锁的消耗。
- redis构建了虚拟内存机制,即把冷数据从内存交换到磁盘中,腾出内存空间用于热数据,节约系统调用时间
存储位置
- 内存型数据库
- 服务器宕机或者断电,内存数据丢失=》RDB和AOF
键值对的数据结构
-
全局哈希表
- 哈希表是一个数组,存储的是哈希桶(entry)
- 每当存储一个键值对时,会根据key进行hash计算,获取它在全局哈希表的位置,生成一个entry存入其中。
- entry有一个*key(键值对的key)和 *value(指向值的指针)(指针指向的是内存的指针还是磁盘数据库呢?)
-
哈希冲突和rehash
-
数据的增加,出现“哈希冲突”会导致redis查询数据越来越慢
-
出现情况
- 俩个key的哈希值计算后相等导致落在同一个哈希桶中,Redis解决哈希冲突的方式:链式哈希
-
-
rehash
-
全局哈希表1和表2
- 默认使用哈希表1
- 1.需要扩容时,给哈希表2分配更大的空间
- 2.将哈希表1的数据重新映射并拷贝到哈希表2中
- 3.释放哈希表1
-
扩容时第二步涉及大量数据拷贝,(单线程?)一次性把哈希表中的数据迁移完,会造成Redis线程阻塞,无法服务其他请求。
- 渐进式rehash:每处理一次请求,从哈希表1的第一个索引,顺带的将哈希表1的第一个索引位置开始,会将其哈希链上的所有entires拷贝到哈希表2中,等处理下一次请求的时候,再顺带拷贝哈希表1中的下一个索引位置的entries。
- 渐进式rehash:巧妙地把一次性大量拷贝的开销,分摊到了多次处理请求的过程中,避免了好事操作,保证了数据的快速访问
-
AOF重写机制
AOF日志内容
-
记录Redis执行命令行的日志文件
-
它是写后日志,是在Redis数据存入内存后再将这些操作命令记录到数据库中的。
-
优点:
- 操作命令存入redis之后证明其语句是正确的,省去了操作命令校验。
-
缺点:
- 记录日志和存储数据采用主线程,不可避免的导致主线程的阻塞,影响redis的性能
- 存储数据后,记录日志的服务器宕机,会导致存储数据丢失
-
三种写回策略
-
Always :同步写回
- 每个命令执行完,立马同步写回磁盘
-
Everysec:每秒写回
- 每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
-
No:操作系统控制的写回
- 每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
-
-
AOF重写机制
- Redis运行越久,文件日志越大,对主线程阻塞会越来越严重
- 多变一功能:旧日志的多条命令,重写后的新日志中,编程一条命令(一个键值被反复修改,记录多条命令,重写后只需要一条命令记录就可以了)。
-
RDB重写机制
概要
- 在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上
缓存穿透、缓存击穿、缓存雪崩
缓存雪崩
Redis中的缓存数据是有过期时间的,当在同一时间大量的缓存同时失效时,由于大量请求无法在redis缓存中处理,就会发送到数据库,导致数据库压力激增,可能会导致数据库崩溃,从而导致整个系统崩溃。 解决缓存雪崩的关键:避免Redis的缓存在短时间内大量的过期 解决方案:
- 根据业务需要来合理的设置过期的时间
- 使用redis分布式锁:让一时间只有一个相同请求落到MySql上,反正都是查询同一个信息,之后的其他请求就可以去Redis中找了
- 使用锁或队列:用加锁或者队列的方式来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上,该方法不适用高并发情况。
缓存穿透:
在Redis缓存和数据库中都找不到相关的数据。也就是说这是个非法的查询,假设客户端发出了大量非法的查询 比如id是负的 ,每次这个查询都需要去Redis和数据库中查询,可能会导致数据库崩溃 解决缓存穿透的要点,不让非法数据到数据库中查询 解决方案:
- 过滤非法查询:在后台服务中过滤非法查询,直接不让他落到Redis服务上。比如id<=0就直接断言。
- 缓存空对象:如果他的查询数据是合法的,但是确实Redis和MySql中都没有,那么我们就在Redis中储存一个空对象,这样下次客户端继续查询的时候就能在Redis中返回了。但是,如果客户端一直发送这种恶意查询,就会导致Redis中有很多这种空对象,浪费很多空间
- 采用布隆过滤器:它实际上是一个很长的二进制向量 (位图) 和一系列随机映射函数(哈希函数)。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难
缓存击穿
缓存击穿和缓存雪崩类似,也是因为Redis中key过期导致的。只不过缓存击穿是某一个热点的key过期导致的。当有一个热点数据突然过期时,就会导致突然有大量的请求直接落到数据库上,导致数据库崩溃。 解决缓存击穿的要点,不让热点key突然过期 解决方案:
- 预先设置热门数据:在 redis 高峰访问之前,把一些热门数据提前存入到 redis 里面,加大这些热门数据 key 的时长。
- 实时调整:现场监控哪些数据热门,实时调整 key 的过期时长。
- 使用redis分布式锁:让一时间只有一个相同请求落到MySql上,反正都是查询同一个信息,之后的其他请求就可以去Redis中找了。
redis的集群方案(3种)
哪三种
- 主从复制
- 哨兵模式
- Cluster模式
主从复制
1、模式: 主从复制模式包含一个主数据库,一个或多个从数据库。客户端可以对主数据库进行读写操作,对从数据库只能进行读操作,主数据库写入的数据会实时自动同步给从数据库。 2、具体步骤:
- slave启动后,向master发送同步命令,master接收到同步命令后通过bgsave命令保存快照,并使用缓冲区记录保存快照这段时间内执行的写命令。
- master将保存的快照文件发送给slave,并继续记录执行的写命令。
- slave接收到快照文件后,加载快照文件,载入数据。
- master快照发送完后开始向slave发送缓冲区的写命令,slave接收命令并执行,完成复制初始化。
- 此后master每次执行一个写命令都会同步发送给slave,保持master与slave之间数据的一致性
3、优点:
- master能自动将数据同步到slave,并且读写分离,可以分担master的读的压力。
- master和slave之间的同步是以非阻塞的方式进行的,同步期间,客户端仍然可以处理客户端请求。
4、缺点:
- 不具备自动容错与恢复功能,master或slave的宕机都可能导致客户端请求失败,需要等待机器重启或手动切换客户端IP才能恢复。
- master宕机,如果宕机前数据没有同步完,则切换IP后会存在数据不一致的问题。
哨兵模式
1、模式: 哨兵模式基于主从复制模式,只是引入了哨兵来监控与自动处理故障,当一个 master 宕机后,会从从服务器中选一个作为主机。如果只有一个哨兵进程对Redis服务器进行监控,当这个哨兵宕机后,就没办法对主服务器进行监控了,因此,我们一般使用多个哨兵进行监控。各个哨兵之间还会相互监控,这样就形成了多哨兵模式。 2、具体步骤:
- 假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover[故障转移]过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。
- 当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票。
- 投票的结果由一个哨兵发起,进行failover[故障转移]操作。
- 切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线
3、优点:
- 哨兵集群,基于主从复制模式,所有的主从配置优点,它全有。
- 主从可以切换,故障可以转移,系统的可用性就会更好。
- 哨兵模式就是主从模式的升级,手动到自动,更加健壮。
4、缺点:
- 难以支持在线扩容,Redis的容量受限于单机配置。
- 实现哨兵模式的配置很复杂,并且需要额外的资源来启动哨兵进程。
Cluster模式:
1、模式:
- Cluster模式实现了Redis的分布式存储,即每台节点存储不同的内容,来解决在线扩容的问题
- 所有的redis节点相互连接,内部使用二进制协议优化传输速度和带宽。
- 客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。(当Redis节点收到自己不负责的Slot的请求时,会将负责请求Key所在Slot的Redis节点地址返回给客户端,客户端收到后自动将原请求重新发往这个地址)
2、描述:
- 一个 Redis 集群包含16384个插槽,数据库中的每个键都属于这 16384 个插槽的其中一个,Redis的每个节点,都负责维护一部分插槽。
- 当我们存取key的时候,Redis会根据CRC16的算法得出一个结果,然后把结果对16384求余数,这样每个key都会对应一个编号在0-16383之间的哈希槽,通过这个编号,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
- Cluster模式也引入了主从复制模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。当其它主节点ping一个主节点A时,如果半数以上的主节点与A通信超时,那么认为主节点A宕机了。如果主节点A和它的从节点都宕机了,那么该集群就无法再提供服务了。
- Cluster模式集群节点最小配置6个节点(3主3从,因为需要半数以上),其中主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用。
3、优点:
- 可线性扩展到1000多个节点,节点可动态添加或删除。
- 能够实现自动故障转移。
4、缺点:
- 数据通过异步复制,不保证数据的强一致性。
- slave只是备用,不能缓解“读操作”的压力。
- 不支持多数据库空间,单机redis可以支持16个db,集群模式下只能使用一个,即db0
- 对于像批量操作、事务操作等的支持性不够好。
关于面试题目