常用的五种数据类型:
String
String是最基本的数据类型,能够存储任何类型的字符串。单个字符串支持最大容量512M。
Hash
是有字符串类型的key/value组成的映射表,可以将它理解为包含多个键值对的集合。一般用来存储对象。
List
List中的元素是字符串类型,元素按照插入顺序进行排列,允许重复插入。
Set
Set的元素也是字符串类型,但是是无序集合。不允许重复插入。
Zset的元素也是字符串类型,是有序集合。集合中的元素具有唯一性,每一个元素还会关联一个double类型的分数(该分数允许重复)。根据该分数为集合中的成员排序。
外层依次往内:redisDb -> dict -> dictht -> dictEntry
redisDb默认16个。每一个redisDb包含一个dict。dict内部包含2个dictht的数组。dictht内部包含dictEntry数组。
String
Redis定义一个特殊结构SDS(Simple Dynamic String):简单动态字符串;这是一个可以修改的内部结构,类似Java的ArrayList。
SDS结构定义如下:
struct sdshdr{
//记录buf数组中已使用字符的数量,等于 SDS 保存字符串的长度
int len;
//记录 buf 数组中未使用的字符数量
int free;
//字符数组,用于保存字符串
char buf[];
在 C语言中,字符串类型的结尾以空字符串 ‘\0’来标识的。但在某些情况下,字符串可能会包含具有实际意义的“空字符”,此时 C语言就无法正确的存取这个字符了,而 Redis 通过 len 来标识字符串的总长度,从而保证了数据的二进制安全特性。
Hash
List
Set
两种存储结构相结合,intset和hashtable
Zset
又称快照(snapshot)模式,将数据库的快照保存在dump.rdb二进制文件中。
在Redis内部是一个定时器,定时判断数据改变是否达到触发持久化的条件。当满足触发条件时,通过操作系统调用fork()创建子进程,在子进程中遍历整个空间内存获取数据。
对Redis 中的数据执行周期性的持久化。
RDB更适合做冷备。
RDB持久化触发策略:
手动触发策略:通过SAVE、BGSAVE触发
自动触发策略:自动触发的条件包含在了 Redis 的配置文件中
#表示在 900 秒内,至少更新了 1 条数据,Redis 自动触发 BGSAVE 命令,将数据保存到硬盘。
save 900 1
#表示在 300 秒内,至少更新了 10 条数据,Redis 自动触 BGSAVE 命令,将数据保存到硬盘。
save 300 10
#表示 60 秒内,至少更新了 10000 条数据,Redis 自动触发 BGSAVE 命令,将数据保存到硬盘。
save 60 10000
AOF 被称为追加模式,或日志模式,是 Redis 提供的另一种持久化策略,它能够存储 Redis 服务器已经执行过的的命令,并且只记录对内存有过修改的命令,这种数据记录方法,被叫做“增量复制”,其默认存储文件为appendonly.aof。
对每条写入命令作为日志,以 append-only 的模式写入一个日志文件中,因为这个模式是只追加的方式,所以没有任何磁盘寻址的开销,所以很快,有点像Mysql中的binlog。
AOF更适合做热备。
Redis长期运行的过程中,aof文件会越来越长,可以通过BGREWRITEAOF进行aof文件重写,能够将aof进行一定的瘦身。
自动重写
#默认配置项 当 aof 文件的增量大于 100% 时才进行重写
auto-aof-rewrite-percentage 100
#表示触发AOF重写的最小文件体积,大于或等于64MB自动触发。
auto-aof-rewrite-min-size 64mb
AOF持久化策略配置:
appendfsync option
- Always:总是;每写入一个命令,就调用一次fsync(同步写入)函数。
- Everysec:每一秒(默认);每一秒调用一次fsync函数。
- No:不主动调用,由操作系统进行决定。不确定。
同4点
Redis 主机会一直将自己的数据复制给 Redis 从机,从而实现主从同步。
只有 master 主机可执行写命令,其他 salve 从机只能只能执行读命令,这种读写分离的模式可以大大减轻 Redis 主机的数据读取压力,从而提高了Redis 的效率,并同时提供了多个数据备份。主从模式是搭建 Redis Cluster 集群最简单的一种方式。
不足:
哨兵模式弥补了主从模式的不足。Sentinel 通过监控的方式获取主机的工作状态是否正常,当主机发生故障时, Sentinel 会自动进行 Failover(即故障转移),并将其监控的从机提升主服务器(master),从而保证了系统的高可用性。
原理:
哨兵是一个独立的进程,能够独立运行。
ping命令,通过Redis节点的回复来判断其运行状态。因为 Redis 是基于内存的操作,CPU不是 Redis的瓶颈。Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且 CPU 不会成为瓶颈,那就顺理成章地采用单线程的方案了。
指:当某个用户查询某个数据时,Redis不存在该数据,则会转向数据库进行查询,当数据库中也查询不到数据,则返回空对象。当该类请求过多时,会给数据库造成较大压力,甚至数据库奔溃。这就是缓存穿透。
集中在某个数据,缓存过期时,所有请求都直接请求到数据库中,倍增的压力会导致数据库阻塞。
解决方案:
1、布隆过滤器
对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃。还有最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。
2、缓存空对象
不论查询结果是否为空,都存入缓存中。但过期时间要设置短,避免影响占用。
缓存击穿是点的穿透,缓存雪崩是面的穿透。
同一时间内,大量缓存同时失效,导致数据库压力同一时间压力剧增。
解决方案:
1、加锁排队
在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
2、缓存时间增加随机值
不同失效时间,避免集体失效。
缓存降级对应用是有损的,对业务应用系统中不核心的缓存数据才能使用缓存降级。
当缓存系统挂掉后,会有大量的请求访问数据库,我们可以使用缓存降级不去访问数据库,直接返回默认值或者服务内的缓存数据。
通过几方面判断使用缓存的合理性:
是否热点数据:读取频率高的数据,有必要使用缓存。
是否频繁修改:频繁修改的数据,就没有必要使用缓存。