1.Redis的简介
- 高速内存数据库:Redis是一个存储在内存中的数据库,这意味着它的读写速度非常快,非常适合做缓存;
- 多种数据结构:字符串、哈希散列、列表、集合;
- 持久化选择:可以选择将数据定期存储到磁盘中,防止重启时数据丢失;
- 事务支持:可以将一组操作看成一个整体一起执行,确保了操作的完整性;
- 复制与集群:支持复制数据和集群部署,提高了数据的可用性和可扩展性;
- 发布/订阅:支持消息传递模式,适合用于构建实事应用;
- Lua脚本:支持编写Lua脚本,可在服务器上执行复杂操作;
- 自动检测恢复:具自动检测故障并恢复的能力,增强了系统的可靠性。
2.Redis和Mencache的共同点和区别?
共同点:
- 都是基于内存存储,都可作缓存;
- 都有过期策略
- 性能都高
区别:
- Redis支持数据类型丰富;Memcache只支持简单类型key,value的数据类型;
- Redis支持持久化;Memcache不支持
- Redis原生支持集群部署;Memcache不支持
- Redis支持发布/订阅,事务等;Memcache没有
3.为什么用Redis做Mysql?
由于Redis有高性能和高并发两个特性
高性能:
- 第一次访问mysql速度比较慢(硬盘读取)
- 将Rdeis的数据放入缓存,后续访问可直接从缓存中获取数据;
高并发:
- Redis的QPS(每秒处理完请求的次数)是Mysql的10倍;
- Redis单机可轻松突破10W,MySQL很难突破1W;
- Redis可轻松处理大量请输数据;从而减少数据库的压力
4.Redis支持的数据类型及应用场景
String:可对整体字符串或字符串的一部分并进行操作,对整数或浮点数进行自增或自减操作。 应用场景: 缓存对象、常规技术、分布式锁、共享session信息等。
List:可对链表的两端进行pop或push操作,读取单个或多个数据,根据值查找或删除数据。 应用场景:消息队列(两个问题:1.生产者需要实现全局唯一ID 2.不能以消费组的形式消费数据)
Hash:包含键值对无序哈希列表,包含数据的添加、获取、删除数据; 应用场景:缓存对象、购物车
Set集合:应用场景:聚合计算(交集、并集、差集),例如点赞、共同关注、抽奖活动等
Zset集合:zset是有序键值对,字符串成员与浮点数分数之间的有序映射,元素的排序与分数的大小有关,包含元素的添加,获取,删除操作以及与分值范围或成员获取数据; 应用场景:排序场景;例如:排行榜,姓名或电话排序等。
BitMap:二值状态键值, 应用场景:签到,用户登录状态,用户签到的总数等。
HyperLogLog: 应用于海量数据 应用场景:海量网页UV统计等。
GEO:获取地理位置信息 应用场景:滴滴打车
Stream:基于List的一些特性(自动生成全局唯一ID,支持消费组的形式消费数据)
5.五中常见redis数据类型
String 实现的底层原理:String的底层实质是SDS,SDS不仅可以保存文本文件,也可保存二进制文件;并对字符串长度的时间复杂度O(1)
List实现的底层原理:List基于链表结构和压缩列表
Hash实现的底层原理:Hash基于压缩列表和哈希表
Set实现的底层原理:Set基于哈希表和整数集合
ZSet实现的基层原理:Zset基于压缩列表和跳表
6.Redis6.0之前的单线程模式
客户端通过listen stocket连接到Redis;
Redis通过epoll多路复用机制多处理多客服端连接;
事件循环:
初始化时,创建一个epoll对象和监听套接字;
调用bind()绑定端口并调用listen()监听套接字;
将监听套接字加入epoll并注册接口事件处理函数;
时间处理流程:
接受连接请求:调用accept()获取已连接的套接字---->注册读时间处理函数。
读取数据:调用read()获取客户端发送的数据----->解析命令------>执行命令------->添加到发送队列------>写入缓存等待发送。
发送数据:遍历发送队列-------->调用write()发送数据------>如果未发送完,则继续注册事件处理函数,等待epoll_wait()发现可写后在处理。
7.Redis采用单线程为什么这么快?
Redis的吞吐量可达到每秒10万次请求。
原因如下:
- Redis的大部分操作都在内存中完成的,并采用高效的数据结构;
- 单线程模式避免多线程之间的竞争和开销;
- 使用I/O多路复用机制处理大量客户端Scoket请求
8.Redis6.0之前为什么使用单线程?
因为单线程程序是无利用服务器的多核CPU的 ;
CPU并不是制约Redis的瓶颈所在;
可以通过在同一台服务器上运行多个redis实例来充分利用多核CPU
使用了单线程后,可维护性高;多线程模式虽然在某些方面表现优异,但引入了程序执行顺序的不确定性,带来了并发读写的一系列问题,增加了系统复杂度、同时可能存在线程切换、甚至出现死锁、加锁、解锁
9.Redis6.0之后为什么引入多线程?
尽管Redis的主要工作一直是单线程来处理网络请求,,这是因为随着网络硬件的性能提升,Redis的性能瓶颈有时会出现在网络I/O的处理上;
为了提高网络I/O并行度,Redis6.0对于网络I/O采用多线程来处理;
Redis官方表示,Redis6.0版本引入的多线程I/O特性对性能提升至少是一倍以上;
默认情况下,I/O多线程只针对发送相应数据,并不会以多线程的方式处理请求。
10.Redis的持久化?
将当前数据进行保存,快照形式,存储数据结果,存储格式简单,关注点在数据(RDB);
将数据的操作过程进行保存,日志形式,存储操作过程,关注点在数据的操作过程(AOF)
缓存预热:系统启动时,将缓存相关的数据提前加载到缓存系统中;
解决方案(限流、线程隔离(仓壁模式)、降级熔断(断路器)、超时处理)
缓存雪崩:同一时段大量缓存key失效,Redis服务宕机,大量请求到数据库
解决方案(集群、降级限流、多级缓存)
缓存击穿:一个高并发访问且重建复杂的key失效,无数请求瞬间到达数据库,造成高负载
解决方案(互斥锁、逻辑过期)
缓存穿透:当客户端请求数据访问缓存和数据都没有时,导致每次请求都需查询数据库,从而给数据库带来不必要压力
解决方案(缓存空对象、使用布隆过滤器)
标签:面试题,缓存,单线程,Redis,场景,多线程,数据 From: https://blog.csdn.net/fada_da_da/article/details/142980643