1、什么是Redis(Remote Dictionary Server)
Redis本质上是一个key-value类型的内存数据库,整个数据库加载在内存中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过10万次读写操作,是已知性能最快的key-value DB。
Redis支持多种数据结构:String、List、Hash、Set、 Sorted Set,单个value的最大限制是1GB。使用Redis可以用List来做FIFO双向链表,实现一个轻量级的高性能消息队列服务;用Set做高性能的tag系统。Redis还可以对存入的key-value设置expire时间。
Redis由于数据库容量受到物理内存的限制,不能用作海量数据的高性能读写(可以用MongoDB或者ElasticSearch),因此它的适用场景主要是在较小数据量的高性能操作和运算上。(可以做中间件)
2、Redis的数据淘汰策略
- noeviction:不删除策略,达到最大内存限制时,如果需要更多内存,直接返回错误的信息;
- allkeys-lru:所有key通用,优先删除最近最少使用的key(least recently used,LRU);
- allkeys-random:所有key通用,随机删除一部分key;
- volatile-lru:只限于设置了expire的部分,尝试回收最少使用的键;
- volatile-random:只限于设置了expire的部分,随机删除一部分expire的key;
- volatile-ttl:只限于设置了expire的部分,优先删除剩余时间端的key(time to time , ttl)
3、Redis为什么要把数据放到内存中
Redis为了达到最快的读写速度将数据都读到内存中,并通过内存的方式将数据写入磁盘。所以Redis具有快速和数据持久化的特征;如果不将数据放在内存中,磁盘I/O速度将严重影响Redis的性能。
4、Redis事务
事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发来的命令请求所打断。
事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
相关的命令有:MULTI、EXEC、DISCARD、WATCH ##28。
5、Redis管道
- 客户端向服务端发送一个查询请求,并监听socket返回,通常是以阻塞模式,等待服务端响应;
- 服务端处理命令,并将结果返回给客户端;
Redis管道技术可以在服务端未响应时,客户端可以继续想服务器端发送请求,并最终一次性读取所有服务端的响应。
6、Redis为什么要做分区
分区可以让Redis管理更大的内存,Redis可以使用所有机器的内存。
如果没有分区,Redis最多使用一台机器的内存。
分区使得Redis的计算能力通过简单地增加计算机的数量得到成倍提升;Redis的网络带宽也会随着计算机和网卡的增加而成倍增长。
7、Redis分区方案
- 客户端分区:在客户端决定数据会被存储到哪个Redis节点,或者从哪个Redis节点读取。大多数客户端已经实现了客户端分区。
- 代理分区:客户端将请求发送给代理,由代理决定去哪个节点写数据或者读数据。代理根据分区规则决定请求哪些Redis实例,然后根据Redis的响应结果返回给客户端。Redis和memcached的一种代理实现就是Twemproxy。
- 查询路由(Query routing):客户端随机地请求任意一个Redis实例,由Redis将请求转发给正确的Redis节点。
- Redis Cluster:实现了一种混合形式的查询路由,但并不是直接将请求从一个Redis节点转发到另一个Redis节点,而是在客户端的帮助下直接redireced到正确的Redis节点。
8、Redis缓存穿透
缓存穿透是指查询一个一定不存在的数据,由于缓存不命中,接着查询数据库也无法查询出结果,因此也不会写入到缓存中,这将会导致每个查询都会去请求数据库,造成缓存穿透。
解决方案:
- 布隆过滤器:对所有可查询的参数以hash形式存储,在控制层先进性校验,不符合规则丢弃,从而避免了对底层存储系统的查询压力。
- 缓存空对象:当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源。但是这种方法存在两个问题:1)如果空值能被存储起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多空值的键;2)即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
这两种方法的比较:
解决缓存穿透 | 适用场景 | 维护成本 |
布隆过滤 | 1、 数据命中不高 2、数据频繁变化,实时性高 |
1、代码维护复杂 2、缓存空间占用少 |
缓存空对象 | 1、数据命中不高 2、数据频繁变化,实时性高 |
1、代码维护简单 2、需要过多的缓存空间 3、数据不一致问题 |
9、Redis缓存雪崩
缓存雪崩是指,由于缓存层承载着大量请求,有效的保护了存储层,但是如果缓存层由于某些原因整体不能提供服务,于是所有的请求都会到达存储层,存储层的调用量会暴增,造成存储层也会挂掉(如缓存层大量的key在同一时间过期,这样大量key的请求就会直接访问存储层)
解决方案:
- 保证缓存层高可用性:即使个别节点、个别机器、甚至是机房宕掉,依然可以提供服务,比如Redis Sentinel和Redis Cluster都实现了高可用;
- 依赖隔离组件为后端限流并降级:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待;
- 数据预热:可以通过缓存reload机制,预先去更新缓存,在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。