谈谈你对Redis的了解?
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
Redis使用场景?
1、缓存:减轻MySQL的查询压力,提升系统性能
2、排行榜:利用Redis的SoreSet(有序集合)实现
3、计算器/限速器:利用Redis中原子性的自增操作,我们可以统计类似用户点赞数、用户访问数等。这类操作如果使用MySQL,频繁的读写会带来相当大的压力;限速型比较经典的使用场景是限制某个用户访问某个API的频率,常用的抢购时,防止用户疯狂点击带来不必要的压力。
4、好友关系:利用集合的一些命令,比如求交集、并集、差集等。可以方便解决一些共同好友、共同爱好之类的功能
5、消息队列:除了Redis自身的发布/订阅模式,我们也可以利用List来实现一个队列机制。比如:到货通知、邮件发送之类的需求,不需要可靠,但是会带来非常大的DB压力,完全可以使用异步操作来完成解耦。
6、Session共享:Session是保存在服务区的文件中,如果是集群服务,同一个用户过来可能会落在不同的集群上,这就会导致用户频繁登录;采用Redis保存Session后,无论用户落在哪台机器上都能够获取到对应的Session信息
Redis有哪些常见的功能?
1、数据缓存功能
2、分布式锁的功能
3、支持数据持久化
4、支持事务
5、支持消息队列
Redis为什么这么快?
1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速;
2、数据结构简单,对数据操作也简单
3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现的死锁而导致性能消耗
4、使用多路I/O复用模型,非阻塞IO
什么是缓存穿透?怎么解决?
缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。
解决办法:
缓存空对象:如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然将这个空结果进行缓存,但它的过期时间会很短,最长不超过5分钟。
缓存空对象带来的问题:
1、空值做了缓存,意味着缓存中存了更多的键,需要更多的内存空间,比较有效的办法是针对这类数据设置一个较短的过期时间,让其自动剔除。
2、缓存和存储的数据会有一段时间窗口不一致,可能会对业务有一定影响
2、布隆过滤器:将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap给拦截掉,从而避免了对底层存储系统的查询压力。
什么是缓存雪崩?该如何解决?
如果缓存集中在一段时间内失效,发送大量的内存穿透,所有的查询都会落在数据库上,造成了缓存雪崩
解决办法:
1、加锁排队:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量
2、数据预热:可以通过缓存reload机制,预先去更新缓存,在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀
3、做二级缓存,或者双缓存策略:Cache1为原始缓存,Cache2为拷贝缓存,Cache1失效时间,可以访问Cache2,Cache1缓存失效时间设置为短期,Cache2设置为长期
4、在缓存的时候给过期时间加上一个随机值,这样就会大幅度的减少缓存在同一时间过期
Redis持久化有哪几种方式?
持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。Redis提供了两种持久化方式:RDB(默认)和AOF
RDB
RDB是Redis Database的缩写。按照一定的时间周期策略把内存的数据以快照的形式保存到硬盘的二进制文件。即Sanpshot快照存储,对应产生的数据文件为dump.rdb,通过配置文件中的save参数来定义快照的周期。核心函数:rdbSave(生成RDB文件)和rdbLoad(从文件加载内存)两个函数。
AOF
AOF是Append-only file的缩写。Redis会将每一个收到的写命令都通过write函数追加到文件最后,类似于MySQL的binlog。当Redis重启是会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。每当执行服务器(定时)任务或者函数时,flushAppendOnlyFile函数会被调用,这个函数执行一下两个工作:
WRITE:根据条件,将aof_buf中的缓存写入到AOF文件;
SAVE:根据条件,调用fsync或fdatasync函数,将AOF文件保存到磁盘中
RDB和AOF的区别:
1、AOF文件比RDB更新频率高,优先使用AOF还原数据;
2、AOF比RDB更安全也更大
3、RDB性能比AOF好
4、如果两个都配了优先加载AOF
Redis怎么实现分布式锁?
Redis为单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系。
Redis中可以使用SETNX命令实现分布式锁。一般使用setnx指令,只允许被一个程序占用,使用完调用del释放锁。
Redis复制与集群
复制
为提高高可用性,排除单点故障,redis支持主从复制功能,其整体结构是一个有向无环图
同步方式
分为两种:
全同步
全同步是第一次从机连主机是进行的同步,主机会生成一个RDB文件给从机,然后从机加载该文件。
部分同步
当主机收到修改命令之后会把命令发给从机进行部分同步。这里会有一个缓存区,主要是用来,如果有从机掉线,再次连接的时候会优先使用缓存区中的数据进行同步,实在不行才使用全同步
问题:
单主单从的情况下,读写分离很好,但是如果万一主挂了,这样就无法写了。或者单主多从时,如果主挂了,也无法进行同步了。这样就需要选举出一个新的主来作为主机。
主从切换
使用Sentinel,其包含如下功能:
监控:监控服务器节点
提醒:当监控的节点出现问题时,可以通过api通知其他应用等
故障转移:当主挂时会选举新的从服务器为主服务器,代替原来主服务器的地位
集群
主从为了提高可用性,防止单点故障。集群则是为了伸缩性。
集群行为
当集群收到请求之后:
一个节点接收到了请求,会检查是否自己的槽,不是则返回MOVED,告诉客户端去哪个槽
重新分片是由客户端去做的,把一个槽的所有键值转到另外的槽
如果正在进行转移,客户请求没有命中,则会返回ask消息,让客户端去另外的节点去找
集群中如果有主从,那么从节点复制主节点,主节点下线之后,从节点升级代替主节点
redis的淘汰策略有哪些?
volatile-lru->根据LRU算法删除带有过期时间的key
allkeys-lru->根据LRU算法删除任何key
volatile-random->根据过期设置来随机删除key,具备过期时间的key
allkeys->random->无差别随机删除任何一个key
volatile-ttl->根据最近过期时间来删除(辅以TTL),这是对于有过期时间的key
noeviction->谁也不删,直接在写操作时返回错误
redis集群基础
所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和宽带
节点的fail是通过集群中超过半数的master节点检测失效时才生效
客户端与redis节点直连,不需要中间proxy层。客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
redis-cluster把所有的物理节点映射到slot上,cluster负责维护node<->slot<->key
如果存入一个值,按照redis cluster哈西槽点算法。那么就会把这个key的存储分配到对应的master上
redis Cluster主从模式
如果集群超过半数以上的master挂掉,无论是否有slave,集群进入fail状态,所以集群中至少有奇数个节点,所以至少有三个节点,每个节点至少有一个备份节点
redis cluster为了保证数据的高可用性,加入了主从模式,一个主节点对应一个或多个从节点,主节点提供数据存取,从节点则从主节点拉取数据备份,当这个主节点挂掉,就会有这个从节点选取一个来充当主节点,从而保证集群不会挂掉。