一、基础篇
1、什么是Redis
Redis(Remote Dictionary Server)是一个使用C语言编写的,开源的(BSD许可)高性能非关系型的键值对数据库。
1.1 Redis基本数据结构
Redis可以存储键和不同类型数据结构值之间的映射关系。键的类型只能是字符串,而值除了支持最基础的五种数据类型(String, List, Hash, Set, ZSet)外,还支持一些高级数据类型。
1.2 Redis小结
与传统数据库不同的是Redis的数据是存储在内存中的,所以读写速度非常快,因此Redis被广泛应用于缓存方向,每秒可以处理超过10万次读写操作,是已知性能最快的key-value数据库。另外Redis也经常用来做分布式锁。
除此之外,Redis支持事务、持久化、LUA脚本、LRU驱动事件、多种集群方案。
1.3 Redis的优缺点
优点
- 读写性能优异,Redis读的速度是110000次/秒,写的速度是81000次/秒。
- 支持数据持久化,支持AOF和RDB两种持久化方式
- 支持事务,Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性操作。
- 数据结构丰富,除了支持String类型的Value外还支持hash、set、zset、list等数据结构。
- 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
缺点
- 数据库容易受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小的数据量的高性能操作和运算上。
- Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
- 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还后引入数据不一致的问题,降低了系统的可用性。
- Redis较难支持在线扩容,在群集容量达到上限时在线扩容会变得很复杂,为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这此资源造成了很大的浪费。
1.4 为什么要用缓存?为什么使用Redis
提一下现在Web的现状
在日常的web应用对数据库的访问中,读操作的次数远超写操作,比例大概在1:9到3:7, 所以需要读的可能性比写的可能性大的多。当我们使用SQL语句去数据库进行读写操作时,数据库会去磁盘把对应数据索引取回来,这是一个相对较慢的过程。
使用Redis or 使用缓存带来的优势
如果我们把数据放在Redis中,也就是直接放在内存之中,让服务器直接去读取内存中的数据,那么这样速度明显就会快上不少(高性能),并且会极大减小数据库的压力(特别在高并发情况下)。
也要提一下使用缓存的考虑
但是使用内存进行数据存储的开销也是比较大的,限于成本的原因,我们一般只使用Redis存储一些常用和主要的数据,比如用户登录的信息等。
一般而言在使用Redis进行存储的时候,我们需要从以下几个方面来考虑:
- 业务数据常用吗?命中率如何?如果命中率很低,就没有必要写入缓存;
- 该业务数据是读操作多?还是写操作多?如果写操作多,频繁需要写入数据库,也没必要使用缓存;
- 业务数据大小如何?如果要存储几百zao字节的文件,会给缓存带来很大的压力,这样也没必要;
在考虑了这些问题之后,如果觉得有必要使用缓存,那么就使用它!
1.5 使用缓存会出现什么问题?
一般来说有如下几个问题,回答思路遵照 是什么->为什么->怎么解决:
1、缓存雪崩的问题
2、缓存穿透的总是
3、缓存和数据库双写一致性的问题
1.5.1 缓存雪崩问题
另外对于“Redis挂掉了,请求全部走数据库”这样的情况,我们还可以有如下思路:
- 事发前:实现Redis的高可用(主从架构+Sentinel或者Redis Cluster),尽量避免Redis挂掉这种情况发生。
- 事发中:万一Redis真挂掉了,我们可以设置本地缓存(ehcache)+限流(hystrix),尽量避免我们的数据库被干掉(起码能保证我们的服务还是能正常工作的)
- 事发后:Redis持久化,重启后自动从磁盘加载数据,快速恢复缓存数据。
1.5.2 缓存穿透问题
1.5.3 缓存与数据库双写一致问题
1.6 Redis为什么早期版本选择单线程?
官方解释
因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章的采用单线程的方案了。
简单总结一下
1、使用单线程模型能带来更好的可维护性,方便开发和调度;
2、使用单线程模型也能并发的管理客户端的请求;(I/O多路复用机制)
3、Redis服务中运行的绝大多数操作的性能瓶颈都不是CPU;
1.7 Redis为什么这么快?
1、纯内存操作:读取不需要进行磁盘I/O,所以比传统数据库要快上不少;(但不要有误区说磁盘就一定慢,例如Kafka就是使用磁盘顺序读取但仍然较快)
2、单线程,无锁竞争:这保证了没有线程的上下文切换,不会因为多线程的一些操作而降低性能;
3、多路I/O复用模型,非阻塞I/O:采用多路I/O复用技术可以让单个线程高效的处理多个网络连接请求(尽量减少网络IO的时间消耗)。
4、高效的数据结构,加上底层做了大量优化:Redis对于底层的数据结构和内存占用做了大量的优化,例如不同长度的字符串使用不同的结构体表示,HyperLogLog的密集型存储结构等等。
二 持久化篇
2.1 什么是持久化?
先简单谈一谈是什么
Redis的数据全部存储在内存中,如果,突然宕机,数据就会全部丢失,因此必须有一套机制来保证Redis的数据不会因为故障而丢失,这种机制就是Redis的持久化机制,它会将内存中的数据库状态保存到磁盘中。
2.2 Redis中的两种持久化方式?
方式一:快照 RDB
Redis快照是最简单的Redis持久性模式。当满足特定条件时,它将生成数据的时间点快照
方式二:AOF
AOF(append Only File-仅追加文件)它的工作方式非常简单:每次执行修改内存中数据集的写操作时,都会记录该操作。假如AOF日志记录了自Redis实例创建以来所有的修改性指令序列,那么就可以通过一个空的Redis实例顺序执行所有的指令,也就是重放,来恢复Redis当前实例的内存数据结构的状态。
三 集群篇
3.1 主从同步了解吗?
主从复制,是指将一台Redis服务器的数据,复制到其它Redis服务器。前者称为主节点(master),后者称为从节点(slave)。且数据的复制是单向的,只能由主节点到从节点. Redis主从复制支持主从同步和从从同步两种,后者是Redis后续新增的功能,以减少主节点的同步负担。
3.2 主从复制的主要作用
- 数据冗余:主从复制实现了数据的热备份,是持久外之外的一种数据冗余方式。
- 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复(实际上是一种服务的冗余)。
- 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载。尤其是在写少读多的场景下,通过多个节点分担读负担,可以大大提高Redis服务器的并发量。
- 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是高可用的基础。
实现原理
简化成三个阶段:准备阶段-数据同步阶段-命令传播阶段。
3.3 哨兵模式了解吗?
上图展示了一个典型的哨兵架构图,它由两部分组成,哨兵节点和数据节点:
- 哨兵节点:哨兵节点由一个或多个哨兵节点组成,哨兵节点是特殊的Redis节点,不存储数据。
- 数据节点:主节点和从节点都是数据节点;
在复制的基础上, 哨兵实现了自动化的故障恢复功能,下方是官方对于哨兵功能的描述:
- 监控(Monitoring): 哨兵会不断地检查主节点和从节点是否运作正常;
- 自动故障转移(Automatic failover): 当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其它从节点改为复制新的主节点。
- 配置提供者(Configuration provider): 客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址。
- 通知(Notification):哨兵可以将故障转移的结果发送给客户端。
其中,监控和自动转移功能,使得哨后可以及时发现主节点故障并完成转移。而配置功能和通知功能,则需要在与客户端交互中才能体现。
新的主服务是怎样被挑选出来的?
简单来说Sentinel使用以下规则来选择新的主服务器:
1、在失效主服务器属下的从服务器中,那些被标记为主观下线、已断线、或者最后一次回复PING命令的时间大于五秒的从服务器都会被淘汰。
2、在失效主服务器属下的从服务器中,那些与失效主服务器连接断开的时长超过down-after选项的指定时长十倍的从服务器都会被淘汰。
3、在经历以上两轮淘汰之后剩下的从服务器中,我们选出复制偏移量(replication offset)最大的那个从服务器作为新的主服务器;如果复制偏移量不可用,或者从服务器的复制偏移量相同,那么带有最小运行ID的那个从服务器成为新的主服务器。
3.4 Redis集群使用过吗?原理?
上图展示了Redis cluster典型的架构图,集成中的每一个Redis节点都互相两两连接,客户端任意直连到集群中的任意一台,就可以对其它Redis节点进行读写操作。
基本原理
Redis集群内置了16384个哈希cao。当客户端连接到Redis集群之后,会同时得到一份关于这个集群的配置信息,当客户端具体对某个key进行操作时,会计算出它的一个hash值
学习资料: