java面试之Redis

Redis
本质上是一个Key-Value类型的内存数据库,纯内存操作。
支持的数据类型
String,Hash,List,Set,ZSet(每个元素都会关联一个double类型的分数),HyperLogLog(用于估计一个Set中元素数量的概率性的数据结构)
Redis中有哪几种数据淘汰机制
1 allkeys-lru:尝试回收最少使用的键(LRU),使得新添加的数据有空间存放
2 volatile-lru:尝试回收最少使用的键,但仅限于在过期集合的键,使得新添加的数据有空间存放
3allkeys-random:回收随机的键使得新添加的数据有空间存放
4 volatile-random:回收随机的键使得新添加的数据有空间存放,但是仅限于在过期集合的键。
5 vilatile-ttl:回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存储。
6 no-eviction:禁止驱逐数据
Redis一个字符串类型的值能存储的最大容量
512M
Redis管道
在服务端未响应时,客户端可以继续向服务端发送请求,并最终一次性读取所有服务端的响应。
Redis key的过期时间和永久有效分别怎么设置
EXPIRE和PERSISI命令
Redis事务
事务是一个单独的隔离操作:事务中的所有命令都会序列化,按顺序的执行。事务在执行的过程中,不会被其他客户端发来的命令请求打断。服务器在执行万事务中所有的命令后,才会继续处理其他客户端的其他命令。
Redis如何实现分布式锁?以及zookeeper如何实现
1 线程A使用setnx方法(上锁的对象,超时时的时间戳t1),如果返回true,获得锁。
2 线程B使用get方法获取t1,与当前的时间戳比较,判断是否超时,没超时,获取失败,如果超时,执行下一步
3 计算新的超时时间 t2(自己的超时时间),使用getAndset命令返回t3,如果t1==t3。获得锁,如果不等于,说明锁被其他线程获取了。
4 获取锁后,处理完业务逻辑,再去判断锁是否超时。若如果没超时,删除锁,如果超时了,不用处理。
Zookeeper实现分布式锁
1 客户端对某个方法加锁时,在zk上的与该方法对应的指定节点的目录上,生成一个唯一的瞬时有序节点node1。
2客户端获取该路径下所有已经创建的子节点,如果发现自己创建的node1序号是最小的,就认为这个客户端获得了锁。
3 如果发现node1不是最小的,则监听比自己创建节点序号小的最大节点,进入等待。
4 获取锁,处理完逻辑后,删除自己创建的node1即可
Redis哨兵模式
哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是通过哨兵发送命令,等待Redis服务器响应。从而监控运行多个Redis实例。
哨兵的作用:
1 通过发送命令,让redis服务器返回信息从而监控其运行状态,包括主服务器和从服务器。
2 当哨兵检测到主节点宕机时,会自动将从节点切换为主节点,然后通过发布订阅模式通知其他从服务器,修改配置文件,让他们切换主键。
一个哨兵进程对Redis进行监控,可能会出现问题,因此可以使用多个哨兵进行监控,各个哨兵之间还会进行监控,这样就实现了多哨兵模式。
Redis实现秒杀功能
利用redis中的watch方法,使用watch监视一个或者多个key,跟踪key的value修改情况,如果有key的value值在事务exec执行之前被修改了,整个事务被取消。exec返回提示信息,表示事务已经失败。但是如果使用watch监视了一个带过期时间的键,那么即使这个键过期了,事务仍然可以正常执行。大多数情况下,不同的客户端会访问不同的键,相互同时竞争同一key的情况一般都很少,乐观锁能够以很好的性能解决数据冲突的问题。
watch方法何时释放监视的键:
1.watch命令可以被调用多次。对键的监视从watch执行之后开始生效,直到调用exec为止,不管事务是否成功执行,对所有键的监视都会被取消。
2.当客户端断开连接时,该客户端对键的监视也会被取消。
3.unwatch命令可以手动取消对所有键的监视。
Redis如何实现事务

Transaction transaction =jedis.multi();
transaction.exec();

String类型的底层实现
redis没有使用C语言传统的字符串表示(以‘\0’结尾的字符数组)而是构建了一种名为动态字符串(SDS)的抽象类型,并未redis的默认字符串表示,因为C字符串不能满足redis对字符串的安全性,效率以及功能方法的需求。
sds的定义:

struct sdshdr{
		int len;//记录sds所保存的字符串长度
		int free;//记录buf中未使用的数据
		char *buff;// 字符数组,用于保存字符串
}

Redis设置过期时间
EXPIRE :将键的生存时间设为ttl秒
PEXPIRE 将键的生存时间设为ttl毫秒
EXPIREAT将键的过期时间设定为timestamp所指定的秒数时间戳
PEXPIREAT将键的过期时间设定为timestamp所指定的毫秒数时间戳
怎么保证Redis和DB中的数据一致
如果不考虑并发的情况下,两种方法:
1先写MYSQL数据库,再删除Redis缓存2先删除缓存,再写MYSQL数据库
以上两种情况,在多线程的情况下,都有可能出现数据库不一致的情况。
在并发的情况下:
如果并发不高:
1 异步更新缓存(基于订阅binlog的同步机制)
MYSQL binlog增量订阅消费+消息队列——增量数据更新到redis
1 读Redis:热数据基本都在Redis
2写MYSQL:增删改操作都是操作MYSQL
3更新Redis数据:Mysql的数据操作binlog,来更新到Redis
Redis更新
1)数据操作主要分为两大块:
一个是全量(将全部数据一次写入到Redis)
一个是增量(实时更新)
这里的增量指的是mysql的update,insert,delete变更数据
2)读取binlog后分析,利用消息队列,推送到各个Redis缓存数据
这样一旦MYSQL中产生了新的写入,更新,删除等操作,就可以把binlog相关的消息推送到Redis,Redis再根据binlog中的记录,对redis进行更新。
类似于MYSQL的主从备份机制,主从一致也是通过binlog来实现数据的一致性。
可以使用canal(阿里的一款开源框架),通过该框架可以对MySQL进行订阅,而canal正是模仿了mysql的主从备份,使Redis的数据更新达到了相同的效果。
高并发下redis如何保证一致性
在高并发的情况下,可以采用队列的方法,首先,如果有数据更新请求,先把请求添加到队列中,当更新完成后再从队列中删除,如果在更新的过程中,有新的线程读数据,先去缓存查看是否有没有数据,如果没有,先去队列中查看是否有数据更新操作,如果有更新操作,就把查询的请求放到队列中,然后同步等待缓存更新完成,其他线程如果发现队列中有一个查询请求了,就不要放新的查询操作进去,用循环去查询缓存,查询大概200ms左右,如果缓存中还没有则直接取数据库中的数据,一般是可以取到的。
Redis是如何实现原子性的
与Redis的请求处理有关,Redis只用一个线程来处理客户端的请求,所有在执行命令的时候,没有其他客户端的请求在处理。只有一个线程处理请求处理的过来么?Redis的请求处理线程,是利用Select和事件循环进行处理的,由于是使用的select()来处理IO的,所以线程不会在一个Socket连接上阻塞,另一方面因为redis操作都在内存中,处理起来也很快,所以也不会出现响应时间太长的情况。
Incr和IncrBy
IncrBy:将key所储存的值加上增量interger,如果key不存在,那么key的值就初始化为0,然后再执行Incrby命令
incr:将key所存储的值加1,如果不存在,key的值初始化为0,然后加1
ThreadLocal介绍
通常情况下,我们创建的变量是可以被任何一个变量访问并修改的,如果向实现每一个线程都有自己的专属本地变量该如何解决呢?JDK中提供了ThreadLocal类解决了这样的问题。ThreadLocal类解决的就是让每个线程拥有自己绑定的值,如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的本地副本,可以通过ThreadLocal类的get()和set()方法,来获取默认值或者将值进行更改,从而避免了线程安全的问题。
缓存穿透与缓存雪崩
1缓存穿透:是指缓存和数据库中都没有数据,而用户不断发起请求,会去查询数据库,从而导致数据库压力过大。
解决方案:接口层增加校验。
2缓存雪崩:缓存中的数据大批量的过期,导致查询数据库的请求过多,引起数据库压力过大,甚至宕机。
解决方案:缓存数据的过期时间设置为随机值,防止同一时间大量数据过期现象发生。
如果缓存数据库是分布式部署的,将热点数据均匀分布在不同的缓存数据库中。
设置热点数据永不过期。
2缓存击穿:缓存击穿是指缓存中没有但数据库有的数据,这时由于并发用户特别多,同时去读数据库,导致数据库压力瞬间过大。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值