Redis 是 C 语言开发的一个开源的高性能键值对(key-value)的内存数据库,可以用作数据库、缓存、消息中间件等。它是一种 NoSQL的数据库。
性能优秀,数据在内存中,读写速度非常快,支持并发 10W QPS。
单进程单线程,是线程安全的,采用 IO 多路复用机制。
丰富的数据类型,支持字符串、散列、列表、集合、有序集合等。
支持数据持久化。可以将内存中数据保存在磁盘中,重启时加载。
主从复制,哨兵,高可用。
可以用作分布式锁。
可以作为消息中间件使用,支持发布订阅。
redis有以下几种常用的基本类型。
string:常用命令:set,get,setnx 功能:缓存。
list:常用命令:lpush(压入元素),linsert(指定元素前后插入元素),lset 功能:是一个双向链表,可以通过 lpush 和 rpop 写入和读取消息,做简单的消息队列。
hash:常用命令:hset,hget 功能:单点登录,存储用户信息。
set:常用命令:sadd(添加元素),scard()获取成员的数量 功能:全局去重功能,可以实现交集、并集等操作,从而实现共同好友等功能。
sorted Set(和set类似但是可以排序):常用命令:zadd,zcard 功能:有序性操作,可以对数据进行排序,可应用于排行榜等。
Bitmap:位图,Redis的位图是一种特殊的字符串数据类型,它可以存储一系列二进制位。位图可以进行位操作,如设置、获取和计数位的操作。它适用于一些特定的应用场景,如统计用户在线状态、记录用户活跃度等。
缓存雪崩:
什么是雪崩:缓存一般都是定时任务去刷新,假如redis的数据在同一时刻全部失效,这个时候正好有大量用户涌入,造成数据库崩溃。
如何避免雪崩:在批量往redis中存数据的时候,把每个key的失效时间都加一个随机值。
如果是集群,将数据均匀的分布到不同的redis库也可避免。
或者是设置热点数据永不过期。
缓存穿透:当查询的数据在redis和数据库中都不存在的时候-----解决:将空值设置到缓存,并设置较短的过期时间或者是在业务前进行验证脏数据。
缓存击穿:频繁的去查询访问一个热点数据,当这个数据失效的时候,会有一大批请求访问数据库,造成数据库挂机----解决:可以设置热点数据永不过期,或者是加互斥锁。
哨兵:通过发送命令,让redis服务器返回监控及运行状态,包括主服务器和从服务器。当哨兵检测到master宕机,会自动将从切换成主,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让他们切换主机。
(1)完全基于内存,数据存在内存中,绝大部分请求是纯粹的内存操作,非常快速,跟传统的磁盘文件数据存储相比,避免了通过磁盘IO读取到内存这部分的开销。
(2)数据结构简单,对数据操作也简单。Redis中的数据结构是专门进行设计的,每种数据结构都有一种或多种数据结构来支持。Redis正是依赖这些灵活的数据结构,来提升读取和写入的性能。
(3)采用单线程,省去了很多上下文切换的时间以及CPU消耗,不存在竞争条件,不用去考虑各种锁的问题,不存在加锁释放锁操作,也不会出现死锁而导致的性能消耗。
(4)使用基于IO多路复用机制的线程模型,可以处理并发的链接。
redis的持久化有两种方式:
RDB(快照)方式持久化(默认)
AOF持久化
RDB的持久化是将某个时间点的所有数据都放到磁盘上,他的缺点是:如果系统发生故障,将会丢失最后一次创建快照之后的数据。如果数据量很大,保存快照的时间会很长。
快照方式在redis的配置如下:
#在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 900 1
#在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 300 10
#在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 60 10000
创建快照的方式有以下几种:
BGSAVE命令 :客户端向Redis发送 BGSAVE命令 来创建一个快照。对于支持BGSAVE命令的平台来说(基本上所有平台支持,除了Windows平台),Redis会调用fork来创建一个子进程,然后子进程负责将快照写入硬盘,而父进程则继续处理命令请求。
SAVE命令 :客户端还可以向Redis发送 SAVE命令 来创建一个快照,接到SAVE命令的Redis服务器在快照创建完毕之前不会再响应任何其他命令。SAVE命令不常用,我们通常只会在没有足够内存去执行BGSAVE命令的情况下,又或者即使等待持久化操作执行完毕也无所谓的情况下,才会使用这个命令。
save选项 :如果用户设置了save选项(一般会默认设置),比如 save 60 10000,那么从Redis最近一次创建快照之后开始算起,当“60秒之内有10000次写入”这个条件被满足时,Redis就会自动触发BGSAVE命令。
SHUTDOWN命令 :当Redis通过SHUTDOWN命令接收到关闭服务器的请求时,或者接收到标准TERM信号时,会执行一个SAVE命令,阻塞所有客户端,不再执行客户端发送的任何命令,并在SAVE命令执行完毕之后关闭服务器。
一个Redis服务器连接到另一个Redis服务器:当一个Redis服务器连接到另一个Redis服务器,并向对方发送SYNC命令来开始一次复制操作的时候,如果主服务器目前没有执行BGSAVE操作,或者主服务器并非刚刚执行完BGSAVE操作,那么主服务器就会执行BGSAVE命令。
AOF持久化是将写命令添加到AOF文件的末尾。
与快照持久化相比,AOF持久化 的实时性更好,因此已成为主流的持久化方案。默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:
appendonly yes
开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof
一般来说, 如果想达到足以媲美PostgreSQL的数据安全性,应该同时使用两种持久化功能。在这种情况下,当 Redis 重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。
如果非常关心数据, 但仍然可以承受数分钟以内的数据丢失,那么可以只使用RDB持久化。
有很多用户都只使用AOF持久化,但并不推荐这种方式,因为定时生成RDB快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比AOF恢复的速度要快,除此之外,使用RDB还可以避免AOF程序的bug。
如果只希望数据在服务器运行的时候存在,也可以不使用任何持久化方式。
立即删除:立即删除能保证内存中数据的最大新鲜度,因为它保证过期键值会在过期后马上被删除,其所占用的内存也会随之释放。但是立即删除对cpu是最不友好的。因为删除操作会占用cpu的时间,如果刚好碰上了cpu很忙的时候,比如正在做交集或排序等计算的时候,就会给cpu造成额外的压力。
而且目前redis事件处理器对时间事件的处理方式–无序链表,查找一个key的时间复杂度为O(n),所以并不适合用来处理大量的时间事件。
惰性删除:惰性删除是指,某个键值过期后,此键值不会马上被删除,而是等到下次被使用的时候,才会被检查到过期,此时才能得到删除。所以惰性删除的缺点很明显:浪费内存。dict字典和expires字典都要保存这个键值的信息。
举个例子,对于一些按时间点来更新的数据,比如log日志,过期后在很长的一段时间内可能都得不到访问,这样在这段时间内就要拜拜浪费这么多内存来存log。这对于性能非常依赖于内存大小的redis来说,是比较致命的。
定时删除:从上面分析来看,立即删除会短时间内占用大量cpu,惰性删除会在一段时间内浪费内存,所以定时删除是一个折中的办法。定时删除是:每隔一段时间执行一次删除操作,并通过限制删除操作执行的时长和频率,来减少删除操作对cpu的影响。另一方面定时删除也有效的减少了因惰性删除带来的内存浪费。