热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java面试之Redis

Redis本质上是一个Key-Value类型的内存数据库,纯内存操作。支持的数据类型String,Hash,List,Set,ZSet(每个元素都会关联一个double类型的

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左右,如果缓存中还没有则直接取数据库中的数据,一般是可以取到的。


推荐阅读
author-avatar
nikechen
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有