❝本文主要介绍
Redis相关内容如有需要,可以参考 如有帮助,不忘点赞 ❥创作不易,白嫖无义! ❞

完全基于内存,绝大部分请求是纯粹的内存操作数据结构简单,对数据操作也简单,Redis中的数据结构是专门为各种场景设计的采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗使用多路 I/O 复用模型,非阻塞 IO「优点:」
「缺点:」
简介: 二进制安全可以存储的值: 字符串,整数或者浮点数,还有jpg图片或者序列化对象操作: 对整个字符串或者字符串的其中一部分执行操作,对整数和浮点数执行自增或者自减操作应用场景: 做简单的键值对缓存实际使用: > set test cbuc
ok
----------------------------
> get test
"cbuc"
----------------------------
> del test
(integer) 1
----------------------------
>get test
(nil)
简介: 链表(双向链表)可以存储的值: 列表操作: 从两端压入或者弹出元素,对单个或者多个元素进行修改,只保留一个范围内的元素应用场景: 最新消息排行;消息队列实际使用: > rpush test c1
(integer) 1
> rpush test c2
(integer) 2
> rpush test c2
(integer) 3
> lrange test 0 -1
1) "c1"
2) "c2"
3) "c3"
> lindex test 1
"c2"
> lpop test
"c1"
> lrange test 0 -1
"c2"
"c2"
简介: 键值对集合,即编程语言中的map类型可以存储的值: 适合存储对象,并且可以像数据库中的update一样,只修改某一项的属性值操作: 添加、获取、移除单个键值对,获取所有键值对,检查某个键是否存在应用场景: 存储、读取、修改用户属性实际使用: > hset test name cbuc
(integer) 1
> hset test age 23
(integer) 1
> hgetall test
1)"name"
2)"cbuc"
3)"age"
4)"23"
> hdel test age
(integer) 1
> hget test name
"cbuc"
> hgetall test
1)"name"
2)"cbuc"
简介: hash表实现,元素不重复可以存储的值: 无序集合操作: 添加、获取、移除单个元素,检查一个元素是否已经存在于集合中,计算交集、并集、差集从集合里面随机获取元素应用场景: 共同好友;利用唯一性,统计访问网站的所有IP实际使用: > sadd test c1
(integer) 1
> sadd test c2
(integer) 1
> sadd test c1
(integer) 0
>smembers test
1)"c1"
2)"c2"
> sismember test c3
(integer) 0
> sismember test c1
(integer) 1
> srem test c1
(integer) 1
> smembers test
1)"c2"
简介: 将 set 中的元素增加一个权重参数score,元素按score有序排列可以存储的值: 有序集合操作: 添加、获取、删除元素,根据分值范围或者成员来获取元素,计算一个键的排名应用场景: 排行榜;带权重的消息队列实际使用: > zadd test 92 math
(integer) 1
> zadd test 88 english
(integer) 1
> zadd test 92 score
(integer) 1
> zrange test 0 -1 withscores
1)"english"
2)"88"
3)"math"
4)"92"
> zrangebyscore test 80 90 withscores
1)"english"
2)"88"
> zrem test english
(integer) 1
> zrange test 0 -1 withscores
3)"math"
4)"92"
「高级用法:」
BitMap位图是支持按 bit 位来存储信息,可以用来实现 布隆过滤器(BloomFilter)HyperLogLog供不精确的去重计数功能,比较适合用来做大规模数据的去重统计,例如统计 UVGeospatial可以用来保存地理位置,并作位置距离计算或者根据半径计算位置等。可以用来实现附近的人,或者计算最优地图路径持久化就是把内存中的数据写到磁盘中去,防止服务宕机了内存数据丢失。
Redis提供两种持久化机制:RDB快照(默认)和AOF(机制)
「RDB」
❝RDB(Redis DataBase)是Redis中默认的持久化方式。按照一定的时间将内存的数据以快照的形式保存到磁盘中,会产生
dump.rdb数据文件,可以通过配置文件中的save参数来定义快照的周期。 ❞

「原理:」 fork和cow。fork 是指 redis间隔一段时间会 「fork」 一个子进程,子线程将数据写到磁盘上一个临时RDB文件中,当子进程写完临时文件后,将原来的RDB替换掉,这样的好处是可以 「cow(copy-on-wirte)」「优点:」
方便持久化,只有一个文件 dump.rdb容灾性好,一个文件可以保存到安全的磁盘中性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是IO最大化。使用单独子进程来进行持久化,主进程不会进行任何IO操作,保证 redis 的高性能「缺点:」
数据安全性低,RDB是间隔一段时间来进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失,所以这种方式更适合数据要求不严谨的时候用保存时间长,如果数据量很大,保存快照的时间会很长「AOF」
❝AOF(Append-Only-File),是将 Redis 执行的每次写命令记录到单独的日志文件中,当重启 Redis 会重新将持久化的日志中文件恢复数据 ❞

「原理:」 将写命令添加到 AOF 文件(Append Only File)的末尾。使用AOF持久化需要设置同步选项,从而确保写命令同步到磁盘文件上的时机。这是因为对文件进行写入并不会马上将内容同步到磁盘上,而是先存储到缓冲区,然后由操作系统决定什么时候同步到磁盘。「同步选项:」
选项 | 同步频率 |
|---|---|
no | 让操作系统决定何时同步 |
always | 每个写命令都同步 |
everysec | 每秒同步一次 |
no: 并不能给服务器性能带来多大的提升,而且也会增加系统奔溃时数据丢失的数量always: 严重减低服务器性能everysec: 这个选项比较合适,可以保证系统奔溃时只会丢失一秒左右的数据,并且 Redis 每秒执行一次同步对服务器性能几乎没有任何影响随着服务器写请求的增多,AOF文件会越来越大。Redis提供了一种将AOF重写的特性「auto-aof-rewrite」,能够去除AOF文件中的冗余写命令
「优点:」
数据安全,AOF 持久化可以配置 appendfsync 属性中的always,没进行一次写命令操作就记录到 AOF 文件中一次、一致性,通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题「缺点:」
两者比较
一般来说两者都会配置。如果单独用 「RDB」 的话你会丢失很多数据,单独用 「AOF」,你数据恢复没有 「RDB」 来的快,如果系统出现问题的时候我们可以先用 「RDB」 恢复,然后用 「AOF」 补全数据。冷热备份一起用,才能保证高健壮性的系统。
定时删除每个设置过期时间的 key 都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源来处理过期的数据,从而影响缓存的响应时间和吞吐量惰性删除只有当访问一个 key 时,才会判断该 key 是否已过期,是则删除。该策略可以最大化节省CPU资源,却对内存非常不友好。极端情况下可能出现大量的过期 key 没有再次被访问,从而不会被清除,占用大量内存定期删除每隔一定时间,会扫描一定数量的 expires 字典中的 key,并清除其中已过期的 key。该策略是前两者的一个折中方法。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。Redis 一般同时使用 惰性过期 和 定期过期 两种过期策略
「设置过期时间的键空间选择性移除」
volatile-lru:尝试回收最少使用的键使得新添加的数据有空间存放。volatile-random:回收随机的键使得新添加的数据有空间存放volatile-ttl:优先回收存活时间较短的键使得新添加的数据有空间存放「全局的键空间选择性移除」
allkeys-lru:尝试回收最少使用的键使得新添加的数据有空间存放。allkeys-random:回收随机的键使得新添加的数据有空间存放noeviction:当内存达到限制并且客户端尝试执行,会返回错误Redis 事务的本质是通过 「MULTI」、「EXEC」、「WATCH」、「DISCARD」四个原语实现的。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。总结:Redis 事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。
四个原语EXPIRE 和 PERSIST 命令
缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉解决方法:
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大解决方法:
缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉解决方法:
单机的 Redis,能够承载的 QPS 大概在上万到几万不等,对于缓存来说,一般都是用来支撑「读高并发」的。如果一台机器读写合一的那会很容易发生问题。因此会采用主从架构,让 master 去处理写操作,然后把数据同步到 slave 上,slave 负责读操作。这样就会分发掉大量的请求,而且在扩容的时候还可以轻松实现水平扩容。

当启动一台 slave 的时候,它会发送一个 psync 命令到 master ,如果是第一次同步,主节点会做一次「bgsave」,并同时将后续修改操作记录到内存「buffer」,待完成后将「RDB」文件全量同步到复制节点,复制节点接收完成后将「RDB」镜像加载到内存然后写入本地磁盘。处理完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。后续的增量数据通过「AOF」日志同步即可,类似于数据库的「binlog」。
简单来说就是先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放SETNX 是【SET if Not eXists】(如果不存在,则 SET)的简写。当且仅当 key 不存在,将 key 的值设为 value。若给定的 key 已经存在,则 SETNX 不做任何动作。返回值:设置成功,返回 1 。设置失败,返回 0 。
Redis可以使用主从同步,从从同步。第一次同步时,主节点会做一次「bgsave」,并同时将后续修改操作记录到内存「buffer」,待完成后将「RDB」文件全量同步到复制节点,复制节点接收完成后将「RDB」镜像加载到内存然后写入本地磁盘。处理完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。后续的增量数据通过「AOF」日志同步即可,类似于数据库的「binlog」。
Redis Sentinel(哨兵)着眼于高可用,在master 宕机时会自动将slave提升为master,继续提供服务。Redis Cluster(集群)着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。「选主策略:」

哨兵必须用三个实例去保证自己的健壮性,哨兵 + 主从 「并不能保证数据不丢失」 ,但是可以保证集群的高可用。工作原理:
何为脑裂:
❝Redis 的集群脑裂是指因为网络问题,导致 redis master 节点跟 redis slave 节点和 sentinel 集群处于不用的网络分区,此时因为 sentinel 集群无法感知到 master 的存在,所以将 slave 节点提升为 master 节点。此时存在两个不同的 master 节点,就像是一个大脑分裂成了两个。这时如果客户端还在基于原来的 master 节点继续写入数据,那么新的 master 节点将无法同步这些数据,当网络问题解决之后,sentinel集群就会将原先的 master 节点降为 slave 节点,此时再从新的 master 中同步数据,将会造成大量的数据丢失 ❞

解决:
min-replicas-to-write 3 # 表示连接到 master 的最少slave数量
min-replicas-max-lag 10 # 表示 slave 连接到 master 的最大延迟时间
按照上面配置,要求至少3个slave节点,且数据复制和同步的延迟不能超过10秒,否则的话 master 就会拒绝写请求,配置了这两个参数之后,如果发生集群脑裂,原先的 master 节点接收到客户端的写入请求会拒绝,就可以减少数据同步之后的数据丢失

看完不赞,都是坏蛋
❝今天的你多努力一点,明天的你就能少说一句求人的话!
很久很久之前,有个传说,据说:「看完不赞,都是坏蛋」 ❞