1、Redis是什么?
- NoSql数据库、内存数据库;key-value形式存储,存储在内存上;优点是结构简单速度快
2、Redis有哪几种数据类型?
- String:热点数据
- HashTable:热点数据、用户信息、视频信息
- LinkedList:微博时间轴
- Set:标签、点赞、收藏、关注
- ZSet:排行榜
3、利用redis的bitmap实现用户签到、统计活跃用户、用户在线状态
- Redis从
2.2.0
版本开始新增了setbit
,getbit
,bitcount
等几个bitmap相关命令。虽然是新命令,但是并没有新增新的数据类型,因为setbit
等命令只不过是在set上的扩展。
<?php
//计算offset
$offset = floor(($todayTime - $startTime) / 86400);
//签到:一年一个用户会占用多少空间呢?大约365/8=45.625个字节,好小,有木有被惊呆?
$redis->setBit($cacheKey, $offset, 1);
//查询签到情况
$bitStatus = $redis->getBit($cacheKey, $offset);
//计算总签到次数
echo $redis->bitCount($cacheKey) . PHP_EOL;
4、微信微博点赞、收藏、标签、关注(使用HashMap
数据结构)
- 用户某篇文章的点赞数:
HashMap
中的key
为articleId
,value
为Set
,Set
中的值为用户ID
,即HashMap<String, Set<String>>
- 用户总的点赞数:
HashMap
中的key
为userId
,value
为String
记录总的点赞数 - 用户点赞、收藏的文章:
HashMap
中的key
为userId
,value
为Set
,Set
中的值为文章ID
,即HashMap<String, Set<String>>
标签、关注功能
:HashMap
中的key
为userId
,value
为Set
,Set
中的值为标签,即HashMap<String, Set<String>>
5、Redis命令
- 用于查找所有符合给定模式 pattern 的 key:KEYS PATTERN(比如KEYS runoob*)
- 如果Redis有1亿个key,使用keys命令是否会影响线上服务?执行keys命令,redis会锁定,如果数据庞大的话可能需要几秒或更长,对于生产服务器上锁定几秒这绝对是灾难了
6、Redis缓存穿透和缓存雪崩是什么?
- 缓存穿透:redis中没有需要去查数据库;这个正常时候是没问题的,但是被黑客利用发送大量空请求会导致数据库宕机;解决方案是增加布隆过滤器或者缓存空对象
- 缓存雪崩:大量key同一时间点全部失效,同时又有大量请求打进来,导致流量直接打在DB上,造成DB不可用。
7、MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据?
- Redis有过期删除策略和内存淘汰机制(针对未设置过期时间的key)
8、过期删除策略
- 立即删除:过期立马删除,弊端是cpu繁忙给cpu增加了压力
- 惰性删除:下次使用时发现过期删除
- 定期删除:每个一段时间执行一次删除
9、内存淘汰管理机制
- no-enviction(驱逐):禁止驱逐数据
- volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
- volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
- volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
- allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
- allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
10、数据可靠性:持久化机制
- 为什么需要持久化:Redis数据存在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据
- 持久化方式:快照持久化RDB、追加日志持久化AOF文件
- RDB快照文件:save和bgsave命令打快照;优点是全量备份,缺点时持久化期间可能存在数据丢失
- AOF命令文件:保存每个命令;aof文件太大会进行瘦身;优点是可靠性高,缺点是aof文件太大,且启动aof会,qps会下降
11、数据一致性
- 数据库处理强一致性数据,redis不处理强一致性数据;
- 读写策略:读数据先读redis;写数据,高并发直接写rediscover,定期刷新到redis,非高并发的话先写数据库在刷新到redis
12、Redis集群策略
- 单机模式:
- 主从复制:一个master多个slave
- 哨兵模式:监听者机制(与zookeeper一样),master下线后自动进行故障转移、通知
- 集群模式:proxy型与直连型
13、redis是多线程还是单线程?
redis中io多路复用器模块是单线程执行,事件处理器也是单线程执行,两个线程不一样。所以实际redis应该是单进程多线程,只是不同的模块都用的单线程实现。(redis4.0以前所有模块是单线程的,4.0以后是异步删除模块和6.0的I/O读写是多线程的)两个维度来举例:
- 若是client发送命令到server的话,server处理命令是单线程逐条进行的。
- server内部可以是多线程的,比如aof持久化,假设策略每秒,那就是再单独开启一个线程去执行aof文件持久化操作,这就是多线程了。
14、Redis主线程既然是单线程,为什么还这么快?
基于内存操作、数据结构简单、多路复用和非阻塞IO、避免上下文切换
15、Redis6.0的多线程?
Redis4.0引入了多线程,但4.0的多线程只支持大数量的异步删除。6.0中引入的多线程用于提高IO的读写能力,主要实现思路是将主线程的IO读写任务拆分给一组独立的线程去执行,这样就可以使用多个socket的读写并行化了,但Redis的命令依然是主线程串行执行的
16、Redis的多路复用是什么?
socket的读写方法默认是阻塞的,Redis的非阻塞IO是指IO的读写流程不再是阻塞的,读写方法都是瞬间完成并且返回的,也就是它会采用能读多少就读多少、能写多少就写多少的策略来执行IO操作。非阻塞的IO也面临一个问题,那就是当执行读写操作时,有可能只读写了一部分数据,那么生效的数据何时写就成了一个问题。而IO的多路复用就是解决上面的这个问题的,使用IO多路复用最简单的方式就是使用select函数,此函数是操作系统提供给用户程序的API接口,用于监控多个文件描述符的可读和可写情况的,这样就可以监控到文件描述符的读写事件了。当监控到相应的时间之后就可以通知线程处理相应的业务了,这样就保证了Redis读写功能的正常执行。
【不过现在的操作系统已经基本上不适用select函数了,改为调用epoll函数(Linux)了,macOS则是使用Kqueue(继承与Unix),因为select函数在文件描述符非常多的时候性能非常差。】