Redis的数据类型
Redis支持五中常用数据类型,string hash list set zset
Redis的持久化机制是什么
Redis提供两种持久化机制,RDB和AOF机制
RDB持久化机制,是指数据集快照的方式半持久化模式记录Redis数据库的所有键值对,在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次的持久化文件,达到数据恢复.
优点:
- 只有一个文件dump.rdb,方便持久化.
- 容错性好,一个文件可以保存到安全的磁盘.
- 性能最大化,fork子进程来完成写操作,让主进程继续处理命令,所以是IO最大化,使用单独的子进程进行持久化,主进程不会进行任何的IO操作,保证了Redis的高性能.
- 相对于数据集大时,比AOF的启动效率更高.
缺点:数据安全性较低,RDB是间隔一段时间进行持久化,如果持久化之间Redis发生故障,会发生数据丢失.所以这种方式更适合数据要求不严谨的时候.
AOF持久化机制:是指所有的命令行记录以Redis命令请求协议的格式完全持久化存储保存为aof文件.
优点:
- 数据安全,aof持久化可以配置appendsync属性,有always,每进行一次命令操作就记录到aof文件中一次.
- 通过append模式写文件,及时中途服务器宕机,可以通过redis-check-aof工具解决数据一致性问题.
- AOF机制的rewrite模式,aof文件没有被rewrite之前,可以删除其中的某些命令
缺点:
- aof文件比rdb文件大,且恢复速度慢.
- 数据集大时,比RDB启动效率低
Redis过期策略,淘汰机制
过期策略
1.定时删除,当对一个key设置了过期时间,当该时间到期之后,立即执行对该key的删除,优点是对内存友好,保证key一旦过期就能立即从内存中删除.缺点:对CPU不友好,在过期的键数量较多的时候,删除过期的键需要占用一定的CPU时间,对服务器的响应时间和吞吐量造成影响.
2.惰性删除,当一个key过期之后,并不会立即从内存中删除,而是在调用key的时候去检查其是否过期,如果过期,将其从内存中删除.优点是对CPU友好,只有在使用的时候才会检查.对于没有用到的key不会浪费时间进行过期检查.缺点:对内存不友好,key过期之后如果一直没有使用,就会一直占用这部分内存.如果Redis中存在很多过期键没有被使用,就永远不会删除,内存不会被释放,从而造成内存泄漏.
3.定期删除,每隔一段时间,就随机抽取一些设置了过期时间的key进行检查,将其中过期的键删除掉,默认是1s执行10次定期删除,每次抽取5个.优点可以通过限制删除操作执行的时长和频率来减少删除的操作对CPU的影响.另外定期删除,也能有效释放过期键占用的内存.缺点:单一确定删除操作执行的时长和频率,如果执行的太频繁,定期删除策略变得和定时删除一样,对CPU不友好.如果执行频率太低,就和惰性删除一样,过期键占用的内存不会及时得到释放.而且,如果在获取某个键时,如果某个键的过期时间到了,但是还没执行定期删除,那么就会返回这个键的值,这是业务不能忍受的错误.
淘汰策略.
- no-eviction 当内存不足以容纳新数写入的数据时,新写入操作会报错.无法写入新数据,一般不操作.
- allkeys-lru 当内存不足以容纳新写入的数据时,移除最近最少使用的key,这个是最常用的.
- allkeys-random 当内存不足以容纳新写入的数据时,随机移除key
- allkeys-lfu 当内存不足以容纳新写入的数据时,移除最少使用的key
- volatile-lru 当内存不足以容纳新写入的数据时,在设置了过期时间的key中,移除最近最少使用的key
- volatile-random 内存不足以容纳新写入新写入的数据时,在设置了过期的key中,随机删除一个.
- volatile-lfu 当内存不足以容纳新写入的数据时,在设置了过期时间key中,移除最少使用的key
- volatile-ttl 当内存不足以容纳新写入的数据时,在设置了过期时间的key中,优先移除剩余存货时间最短的.
Redis的事务
Redis的事务不保证原子性,在Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚.事务中任意命令执行失败,其余的命令仍会被执行.
Redis没有隔离级别的概念,批量操作在发送exec命令前被放入队列缓存,并不会被实际执行,也就不存在事务内的查询要看到的事务里的更新,所以事务外的查询是查不到的.
优点:一次性按照顺序执行多个Redis命令,不受其他客户端命令请求影响,事务中的命令要么都执行,要么都不执行.
缺点:事务执行时,不能保证原子性,命令入队每次都需要和服务器进行交互,增加带宽.
注意:当事务中命令的语法使用错误时,最终会导致事务执行不成功,即事务中所有命令都不执行.当时事务中命令知识逻辑错误,就比如给字符串做加减乘除操作,只能在执行过程中发现错误,这种事务执行中失败的命令不影响其他命令的执行.
Redis集群,哨兵,主从复制模式
主从复制模式
主从复制,是只将一台Redis服务器的数据复制到其他Redis服务器,前者成为主节点,master,后者成为从节点slave,数据的复制只能是从主节点到从节点.master节点可以增删改查数据,slave只能查询数据
主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式.当主节点出现问题之后,可以有从节点提供服务,实现快速的故障恢复.在主从复制的基础上,配合读写分离,可以右主节点提供写服务,由从节点提供读服务,尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量.除此之外,主从模式还是集群和哨兵能够实施的基础.
哨兵模式
哨兵是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的Master并将所有的Slave连接到新的Master.所以整个运行哨兵集群的数量不能少于3个节点.
哨兵会不断检查主节点和从节点是否运作正常.当主节点不能正常工作时,哨兵会开始自动故障转移操作.它会将失效主节点的其中一个从节点升级为新的主节点.并让其他从节点改为复制新的主节点.
哨兵结构由哨兵节点和数据节点组成,在整个哨兵系统中,会同时存在一个或多个哨兵节点组成,哨兵节点的特殊的Redis节点,不存储数据.主节点和从节点都是数据节点.
集群
数据分区是集群最核心的功能.集群将数据分散到多个节点,一方面突破了Redis单机内存大小的限制,存储容量大大增加,另一方面,每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力.
集群支持主从复制模式和主节点的自动故障转移,当任意节点发送故障时,集群仍然可以对外提供服务.
Redis如果hash冲突,怎么解决
当一个新的键值对要添加到字典中时,程序需要现根据键值对的键算出哈希值和索引值,然后再根据索引值,将包含新键值对的哈希表节点放到哈希表数组对应的指定索引上面.
Redis中的hash冲突是指,两个key的哈希值和哈希桶计算对应关系时,正好落在了一个哈希桶中.
Redis的哈希表是采用链地址法解决键冲突的,每个哈希表节点上都有一个next指针,多个哈希表节点可以用next指针构成一个单向链表,被分配到同一个索引上的多个节点可以用这个单向链表连接起来,这样就解决了键冲突的问题.
Redis实现分布式锁
在分布式场景中,我们传统的synchronized和lock都失效了,所以此时需要一种全新的锁.redis提供的了一个命令--setnx,当我们使用这个命令去存储数据,如果当前的key已经存在,就不会进行任何操作,同时返回0,如果不存在,就会成功存储数据,返回1.
根据这个机制,我们可以访问一个程序时,先存入一个约定好的key,value可以是我们当前的时间戳,如果存入成功,那我们就视为当前线程获取到了锁,如果存入失败了.我们就视为锁已被其他线程占有,当前线程没有获取到线程锁.在需要释放线程锁的时候,我们将这个key从redis中删除即可.
同时,为了避免死锁,我们需要再setnx时对key 添加过期时间.
在获取锁时,我们可以通过循环去不断尝试获取锁,如果获取到了就开始执行,如果没有获取到就一直获取.当然,我们也可以为这个循环添加一个超时时间.类似于自旋锁的自旋机制.
缓存穿透问题
指查询一个不存在的数据,我们的机制是先去从缓存中读取,如果缓存中不存在的话会去数据库中查询,并且将查询到的结果存入缓存中.那如果数据库中也没有该数据,就不会放入缓存中,所以这种情况下就会去穿过缓存去访问数据库,这样就可能会导致数据库同时处理大量请求,可能导致数据库崩溃.
解决方法
- 如果是非法参数,我们可以在api层做参数校验,在接受到请求之后就去处理非法参数.
- 如果是正确请求,但是数据库中不存在,那我们在缓存中针对该数据添加一个key,value设为null,给他一个过期时间,这样首次请求会到达数据库,但是其他请求都会被缓存拦截.
- 采用布隆过滤器判断数据是否存在,如果存在就继续往下查.
缓存击穿
缓存击穿是指如果大量请求访问某个数据的时候这个数据失效了,就会穿过缓存访问数据库,这样对数据库造成大量压力,导致数据库崩溃
我们可以通过设置热点数据永不过期去解决,但是这样可能会浪费资源,所以我们可以使用分布式锁进行对数据库的访问拦截,同一时间该类请求中只能有一个线程访问数据库.这样就会大大降低数据库的压力.
缓存雪崩
缓存雪崩是指同时间大量热点数据同时失效,大量请求同时涌入数据库,导致数据库崩溃.
解决方式
首先最暴力的解决方式就是设置热点数据永不过期.
其次就是对热点数据设置随机的过期时间,不让大量热点同时过期.
布隆过滤器
布隆过滤器是有一个初始值为0的位图数组和n个哈希值组成的.当我们存储数据时,针对一个key通过多个hash算法取多个值,在位图数组中对这多个值对应的位置值改为1
在查询的时候,还是先针对这个key做hash计算取多个值,如果这几个值对应的位置都是1,则代表这个key可能存在.如果其中有一个以上的0,则说明这个key一定不存在.
例如:我们现在存储两条数据,其key分别为zhang和li,如果我们经过hash计算之后zhang得到了3个值,分别是1 3 5,那我们将位图中第 1 3 5位对应值分别改为1.li经过hash计算之后得到了 7 8 9,那我们将位图中第7 8 9对应的值分别改为1.至此,布隆过滤器中第 1 3 5 7 8 9位的值为1,,其余为0.文章来源:https://www.toymoban.com/news/detail-485676.html
我们现在开始查询key为wang和zhao 的两条数据,加入wang通过hash计算之后得到的3个值,分别是1 5 8,我们在位图数组上发现这三个位置对应的值都是1,所以布隆过滤器会认为这个值是可能存在的.zhao经过hash 计算之后得到的数据分别是 2 3 5,在位图数组上我们可以看到 3 5两个位置对应的值是1,但是2对应的值还是0,所以认为和这个key绝对不存在,就会被拦截.文章来源地址https://www.toymoban.com/news/detail-485676.html
到了这里,关于Java常见面试题之Redis的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!