Redis
Redis基础知识
简单介绍一下Redis,以及为什么要用Redis做缓存?为什么要用缓存?
Redis是一个使用C语言编写的非关系型数据库,与传统数据库不同的是,Redis的数据是存放在内存中的。由于数据存放在内存中,所以Redis对数据的读写非常的快。因此Redis被广泛应用于缓存方向,它每秒可以处理10万次的读写操作,是已知性能最快的Key-Value DB。另外Redis也经常被用来做分布式锁,甚至是消息队列。除此之外,Redis还提供了多种数据类型来支持不同的业务场景,并且它还支持事务,持久化,Lua脚本,多种集群方案。
使用Redis做缓存主要有以下两个方面的考虑:高性能、高并发。
高性能:用户第一次访问数据库中的某些数据,这个过程会比较慢,因为是从硬盘上读取的,如果将数据放入缓存,下一次要读取这些数据的时候,直接从缓存中读取即可,操作内存的速度比硬盘是更快的,因此我们通常将不经常改变的数据放入缓存,用户要读取这些数据的时候,直接从缓存中读取,当数据库中的数据改变之后,同步改变缓存中的相应数据即可,这样能大大提高系统性能。
高并发:在高并发场景下,往往会同时出现大量的请求打在数据库上,但是数据库能够承受的请求量是远远低于缓存的,因此可以考虑把数据库中的部分热点数据转移到缓存中去。
Redis和Memcached的区别和共同点
共同点:
1. 都是基于内存的数据库,一般都用来做缓存使用;
2. 都设置了过期策略;
3. 两者的性能都非常高。
区别:
1. 数据类型支持不同,与Memcached仅支持简单的key-value结构的数据记录不同,Redis支持的数据类型要丰富得多。最为常用的数据类型主要由五种:String、Hash、List、Set和Sorted Set。
2. 内存管理机制不同,在Redis中,并不是所有的数据都一直存储在内存中的。这是和Memcached相比一个最大的区别。当物理内存用完时,Redis可以将一些很久没用到的value交换到磁盘。
3. 数据持久化支持不同,Redis虽然是基于内存的存储系统,但是它本身是支持内存数据的持久化的,而且提供两种主要的持久化策略:RDB快照和AOF日志。而memcached是不支持数据持久化操作的。
4. 集群的管理不同,Memcached本身并不支持分布式,因此只能在客户端通过像一致性哈希这样的分布式算法来实现Memcached的分布式存储。相较于Memcached只能采用客户端实现分布式存储,Redis更偏向于在服务器端构建分布式存储。
缓存数据的处理流程?
Redis数据结构以及应用场景
String
1. 介绍: String数据结构是简单的key-value类型。
2. 常用指令:
set | get | strlen | exists | decr | incr | setx | setnx
3. 应用场景:一般用在需要计数的场景,比如用户的访问数量,热点文章的点赞和转发数据量等。
List
1. 介绍: list即链表,Redis的list的实现是一个双向链表。
2. 常用指令:
lpush | lpop | rpush | rpop | lrange | llen
消息队列: lpush 和 rpop 实现
栈: lpush 和 lpop 实现
3. 应用场景:一般用于发布和订阅(消息队列)和慢查询等。
Hash
1. 介绍: hash类似于hashmap,内部实现也差不多(数组+链表)。
2. 常用指令:
hset | hmset | hget | hgetall | hmset | hexists | hkeys | hvals等
3. 应用场景:一般用于系统中对象数据的存储。
Set
1. 介绍:Set表示集合,类似于HashSet,存储不重复的无序数据。
2. 常用指令:
sadd | spop | smemembers | sismember | scard | sinterstore | sunin 等
3. 应用场景:一般用于需要存放不重复数据的场景或者多个数据源求交集和并集的场景(微博和B站的共同关注、共同好友、相同爱好推荐)。
Sorted Set
1. 介绍:Sorted Set表示有序集合,相比于Set,Sorted Set增加了一个权重参数score,能够按照score进行有序排列。
2. 常用指令:
zadd | zcard | zscore | zrange | zrevrange | zrem等
3. 应用场景:一般用于需要对数据根据某个权重进行排序的场景,比如直播系统中,包含直播间的在线用户列表,各种礼物排行榜等
Geo
1. 介绍:Geospatial地理位置。
2. 常用指令:
geoadd | geodist | geohash | geopops | georadius | georadiusmember
3. 应用场景:一般用于推算两地间的距离,附近的人,朋友定位等
Hyperloglog
1. 介绍:基数(不重复的元素),可以接受统计误差时才能使用,比set更节约内存空间。
2. 常用指令:
3. 应用场景:一般用于网页的UV(访问人数,一个人访问一个网站多次,但是还是算作一个人)
BitMap
1. 介绍:位存储。
2. 常用指令:
setbit | getbit | bitcount
3. 应用场景:一般用于统计活跃、不活跃、登录、未登录、打卡、未打卡这种带两个状态的用户信息等
Redis单线程问题
为什么Redis选择单线程模型还那么快?
1. Redis完全基于内存,绝大部分请求为纯粹的内存操作;
2. 数据结构简单,对数据操作也简单;
3. 采用单线程更方便维护,避免了多线程带来的上下文切换和死锁等问题;
4. Redis服务器使用非阻塞的IO多路复用机制,并发处理来自客服端的多个连接,极大的减少系统开销;
5. Redis的性能瓶颈不在CPU,主要在内存和网络,所以多线程不能解决性能瓶颈问题。
Redis6.0之后为何又引入多线程?
1. Redis 6.0 引入多线程主要是为了提高网络IO读写性能,多线程只是在网络数据的读写这类耗时的操作上使用,执行命令仍然是单线程顺序执行。
2. 默认情况下,Redis6.0的多线程是被禁用的,只使用主线程。设置配置文件里面的: io-threads-do-reads为 yes 和 io-threads 为 4 来开启。
IO多路复用是什么?
Redis基于Reactor模式开发了自己的网络事件处理器,称之为文件事件处理器(File Event Hanlder)。文件事件处理器由Socket、IO多路复用程序、文件事件分派器(dispather),事件处理器(handler)四部分组成。
IO多路复用程序会同时监听多个socket,当被监听的socket准备好执行accept、read、write、close等操作时,与这些操作相对应的文件事件就会产生。IO多路复用程序会把所有产生事件的socket压入一个队列中,然后有序地每次仅一个socket的方式传送给文件事件分派器,文件事件分派器接收到socket之后会根据socket产生的事件类型调用对应的事件处理器进行处理。
文件事件处理器分为几种:
连接应答处理器:用于处理客户端的连接请求;
命令请求处理器:用于执行客户端传递过来的命令,比如常见的set、lpush等;
命令回复处理器:用于返回客户端命令的执行结果,比如set、get等命令的结果;
事件种类:
AE_READABLE:与两个事件处理器结合使用。当客户端连接服务器端时,服务器端会将连接应答处理器与socket的AE_READABLE事件关联起来;当客户端向服务端发送命令的时候,服务器端将命令请求处理器与AE_READABLE事件关联起来;
AE_WRITABLE:当服务端有数据需要回传给客户端时,服务端将命令回复处理器与socket的AE_WRITABLE事件关联起来。
Redis缓存过期和内存淘汰
Redis缓存设置过期时间有啥用?
一般情况下,我们保存的缓存数据都会设置一个过期时间,因为我们的内存是有限的,如果缓存中的数据一直保存的话,容易出现OutOfMemory错误。设置过期时间除了有助于缓解内存消耗,还适用于设置短信验证码和用户登录token等的有效时间。Redis除了字符串类型有自己独有设置过期时间的命令setex外,其他地方都需要依靠expire命令来设置过期时间。另外,persist命令可以移除一个键的过期时间。
Redis是如何判断缓存数据是否过期的?
Redis通过一个过期字典来保存数据过期的时间。过期字典的键指向Redis数据库中的某个键(key),过期字典的值是一个long long类型的整数,这个整数保存了key所指向数据库键的过期时间。
过期数据的删除策略了解么?
如果我们设置了一批key的过期时间为60s,那么60s之后,是怎样删除这批key的呢?常用的过期数据的删除策略主要有两个:
1. 惰性删除:只有取出key的时候才对数据进行过期检查。这样对CPU友好,但是可能会造成太多过期key没有被删除。
2. 定期删除: 每隔一段时间抽取一批key执行删除过期key操作,并且,Redis底层会通过限制删除操作执行的时长和频率来减少删除操作对CPU的影响。
3. 定期删除对内存友好,惰性删除对CPU友好,所以Redis采用的是定期+惰性/懒汉式删除。
Redis内存淘汰机制?
仅仅通过设置key的过期时间,可能存在定期删除和惰性删除漏掉了很多过期key的情况。这样可能会导致大量key堆积在内存中,造成Out of Memeory,要解决这个问题需要内存淘汰机制。比如: MySQL里有2000W条数据,Redis里只能存20W条数据,如何保证Redis中的数据都是热点数据?
1. volatile-lru:从设置过期时间的数据集中挑选最近最少使用的数据淘汰。
2. volatile-ttl: 从设置过期时间的数据集中挑选将要过期的数据淘汰。
3. volatile-random: 从设置过期时间的数据集中任意选择数据淘汰。
4. volatile-lfu: 从设置过期时间的数据集中挑选最不经常使用的数据淘汰。
5. allkeys-lru: 从所有键数据集中挑选最近最少使用的数据淘汰。
6. allkeys-random: 从所有键数据集中任意选择数据淘汰。
7. allkeys-lfu: 从所有键数据集中挑选最不经常使用的数据淘汰。
8. no-eviction: 禁止淘汰数据,内存不足时,新写入数据直接报错。
Redis持久化
什么是Redis持久化?
由于内存的有限容量和重启内存数据丢失等原因,我们需要将内存中的数据写入到硬盘中,以便之后重用数据,这就是持久化数据。Redis支持持久化,Memcached不支持持久化。
Redis持久化的实现方式?各自的优缺点是什么?
Redis持久化的实现方式主要有两种: RDB快照(默认)、AOF日志
1. RDB快照:在指定的时间间隔内将内存中的数据集快照写入磁盘。实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。,默认的文件名为dump.rdb。
触发方式:save、bgsave、自动触发三种方式。
2. AOF日志:AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。,默认文件名为appendonly.aof。
触发方式:always、everysec、no
Redis主从复制
什么是主从复制?
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制是单向的,只能由主节点到从节点。Master以写为主,Slave 以读为主。默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
主从复制的作用?
一主二从
Redis缓存存在的问题
缓存穿透?
缓存击穿?
缓存雪崩?