1、redis基本介绍
Redis 就是一个使用 C 语言开发的数据库,不过与传统数据库不同的是 Redis 的数据是存在内存中的 ,也就是它是内存数据库,所以读写速度非常快,因此 Redis 被广泛应用于缓存方向。
Redis是一个基于内存的高性能key-value数据库,是非关系型数据库,适用于存储缓存用的数据,也适合需要高速读/写的场合使用它快速读/写。
redis适用场景:会话缓存、全页缓存、队列、排行榜/计数器。
2、Redis的缺点
缓存穿透:是指查询一个数据库一定不存在的数据。程序在处理缓存时,一般是先从缓存查询,如果缓存没有这个key获取为null,则会从DB中查询,并设置到缓存中去。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
解决办法:
- 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
- BloomFilter。将可能出现的缓存key的组合方式的所有数值以hash形式存储在一个很大的bitmap中<布隆过滤器>。
- 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒。这样可以防止攻击用户反复用同一个id暴力攻击
缓存雪崩:缓存在同一时间大面积的失效,后面的请求都直接落到了数据库上,造成数据库短时间内承受大量请求。有一些被大量访问数据(热点缓存)在某一时刻大面积失效,导致对应的请求直接落到了数据库上。
解决方法:
- 采用 Redis 集群,避免单机出现问题整个缓存服务都没办法使用。
- 限流,避免同时处理大量的请求。
- 设置不同的失效时间比如随机设置缓存的失效时间。
- 缓存永不失效。
缓存击穿:指的是热点key在某个特殊的场景时间内恰好失效了,恰好有大量并发请求过来了,造成DB压力。
解决办法
- 用加锁或者队列的方式保证缓存的单线程(进程)写,在加锁方法内先从缓存中再获取一次,没有再查DB写入缓存。
- 设置热点数据永远不过期。
3、Redis和Mencached的区别和共同点
共同点 :
- 都是基于内存的数据库,一般都用来当做缓存使用。
- 都有过期策略。
- 两者的性能都非常高。
区别 :
- Redis 支持更丰富的数据类型(支持更复杂的应用场景)。
- Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而 Memcached 把数据全部存在内存之中。
- Redis 有灾难恢复机制。
- Memcached 没有原生的集群模式;但是 Redis 目前是原生支持 cluster 模式的。
- Memcached 是多线程,非阻塞 IO 复用的网络模型;Redis 使用单线程的多路 IO 复用模型。
- Memcached 过期数据的删除策略只用了惰性删除,而 Redis 同时使用了惰性删除与定期删除。
4、缓存数据的处理流程(更新)
- 如果用户请求的数据在缓存中就直接返回。
- 缓存中不存在的话就看数据库中是否存在。
- 数据库中存在的话就更新缓存中的数据。
- 数据库中不存在的话就返回空数据。
5、为什么要用Redis做缓存?
高性能:保证用户下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。不过,要保持数据库和缓存中的数据的一致性。 如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可!
高并发:一般像 MySQL 这类的数据库的 QPS (服务器每秒可以执行的查询次数)大概都在 1w 左右(4 核 8g) ,但是使用 Redis 缓存之后很容易达到 10w+,甚至最高能达到 30w+(就单机 redis 的情况,redis 集群的话会更高)。
6、Redis数据结构
5 种基础数据结构 :
- String 是最常用的一种数据类型,普通的kv存储都可以归为此类。
- hash 适合存储对象类型信息,例如个人信息、商品信息等。
- list 应用场景可以有微博的关注列表、粉丝列表、消息列表等。
- set表示存储的一个元素不重合的集合,适合做共同好友等功能
- zset 有序列表
3 种特殊数据结构 :HyperLogLogs(基数统计)、Bitmap (位存储)、Geospatial (地理位置)。
7、Redis线程模型
既然是单线程,那怎么监听大量的客户端连接呢?
Redis 通过IO 多路复用程序 来监听来自客户端的大量连接(或者说是监听多个 socket),它会将感兴趣的事件及类型(读、写)注册到内核中并监听每个事件是否发生。
这样的好处非常明显: I/O 多路复用技术的使用让 Redis 不需要额外创建多余的线程来监听客户端的大量连接,降低了资源的消耗(和 NIO 中的 Selector
组件很像)。
7.1 Redis6.0之前为什么不使用多线程?
- 单线程编程容易并且更容易维护;
- Redis 的性能瓶颈不在 CPU ,主要在内存和网络;
- 多线程就会存在死锁、线程上下文切换等问题,甚至会影响性能。
7.2 Redis6.0之后为什么又引入了多线程?
Redis6.0 引入多线程主要是为了提高网络 IO 读写性能,因为这个算是 Redis 中的一个性能瓶颈(Redis 的瓶颈主要受限于内存和网络)。
虽然,Redis6.0 引入了多线程,但是 Redis 的多线程只是在网络数据的读写这类耗时操作上使用了,执行命令仍然是单线程顺序执行。因此,你也不需要担心线程安全问题。
8、Redis内存管理
8.1 Redis给缓存数据设置过期时间有什么用?
- 因为内存是有限的,如果缓存中的所有数据都是一直保存的话,分分钟直接 Out of memory。
- 很多时候,我们的业务场景就是需要某个数据只在某一时间段内存在。如果使用传统的数据库来处理的话,一般都是自己判断过期,这样更麻烦并且性能要差很多。
8.2 Redis如何判断数据过期?
Redis 通过一个叫做过期字典(可以看作是 hash 表)来保存数据过期的时间。过期字典的键指向 Redis 数据库中的某个 key(键),过期字典的值是一个 long long 类型的整数,这个整数保存了 key 所指向的数据库键的过期时间(毫秒精度的 UNIX 时间戳)。
8.3 过期数据的删除策略
- 惰性删除 :只会在取出 key 的时候才对数据进行过期检查。这样对 CPU 最友好,但是可能会造成太多过期 key 没有被删除。
- 定期删除 : 每隔一段时间抽取一批 key 执行删除过期 key 操作。对内存友好。
仅通过给 key 设置过期时间还是有问题的。因为还是可能存在定期删除和惰性删除漏掉了很多过期 key 的情况。解决这个问题就是内存淘汰机制。
- volatile-lru 从已设置过期的数据集中挑选最近最少使用的淘汰
- volatile-ttl 从已设置过期的数据集中挑选将要过期的数据淘汰
- volatile-random 从已设置过期的数据集中任意挑选数据淘汰
- allkeys-lru 从数据集中挑选最近最少使用的数据淘汰
- allkeys-random 从数据集中任意挑选数据淘汰
- noenviction 禁止淘汰数据
9、Redis持久化机制
将内存中的数据异步写入硬盘中,两种方式:RDB(默认)和AOF。
RDB:
Redis 可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。Redis 创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis 主从结构,主要用来提高 Redis 性能),还可以将快照留在原地以便重启服务器的时候使用。
优点:Redis加载RDB恢复数据远远快于AOF的方式。
缺点:由于每次生成RDB开销较大,非实时持久化,有可能会丢失数据。
AOF:
以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。Redis通过rewrite的机制,让AOF文件不至于太庞大。就是大概是数据量多的时候,重写一个新的,把不需要的剔除。
优点:实时持久化。
缺点:所以AOF文件体积逐渐变大,需要定期执行重写操作来降低文件体积,加载慢。
10、Redis集群模式
10.1 主从复制
主从复制模式包含一个主数据库实例(master),一个或多个从数据库实例(slave)。
客户端可以对主数据库进行读写操作,对从数据库只能进行读操作,主数据库写入的数据会实时自动同步给从数据库。
master接收到SYNC命令后通过bgsave命令保存快照(RDB持久化),然后再同步给slava。
该模式分担master的读的压力。但是master宕机,如果宕机前数据没有同步完,则切换IP后会存在数据不一致的问题。
10.2 哨兵模式
使用一个或者多个哨兵(Sentinel)实例组成的系统,对redis节点进行监控,在主节点出现故障的情况下,能将从节点中的一个升级为主节点,进行故障转义,保证系统的可用性。
故障转义:当一个Master不能正常工作时,哨兵通过投票协议会开始一次自动故障迁移操作,它会将其他一个Slave升级为新的Master。
该模式主从可以切换,故障可以转移,系统的可用性就会更好。但是需要额外的资源来启动哨兵进程。
10.3 Redis-Cluster集群
(以上两种模式,存在难以在线扩容,Redis容量受限于单机配置的问题)
Cluster模式实现了Redis的分布式存储,即每台节点存储不同的内容,来解决在线扩容的问题。
但是数据通过异步复制,不保证数据的强一致性 。