Redis基础知识总结

Redis 介绍

NoSQL数据库

Redis 属于NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,泛指非关系型的数据库。 NoSQL 不依赖业务逻辑方式存储,而以简单的key-value模式存储。因此大大的增加了数据库的扩展能力。

  • 不遵循SQL标准。

  • 不支持ACID。

  • 远超于SQL的性能。

NoSQL 应用场景
  • 对数据高并发的读写

  • 海量数据的读写

  • 对数据高可扩展性的

Redis中的数据类型

常用五大数据类型
  1. String
    String是二进制安全的(以二进制形式存储),value最大值512MB

    底层结构:简单动态字符串(Simple DynamicString,缩写SDS),类似于Java的ArrayList,

    扩容:当字符串长度小于1M时,每次扩容增加一倍,大于1M时,每次扩容增加1M,最大为512MB

  2. List
    简单的字符串链表,按照插入顺序,可以从头或尾插入,底层结构为双链表

    底层结构:快速链表quickList+压缩列表zipList

    扩容:当列表元素较少时,分配一块连续内存,这个结构是zipList。当列表元素比较多时,使用双向指针将zipList连接起来成为quickList

  3. Set
    Set是string类型的无序集合。它底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)。

  4. Hash
    Hash是一个键值对集合,具体来说是一个string类型的 field 和 value 的映射表,比较适合用来存放对象,类似Java中的Map<String, Object>

    底层结构:Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。

  5. Zset
    Zset(sortedSet)有序集合,集合中的每个元素都关联了一个权重(score),这个权重被用来从升序的方式排序集合中的元素。集合中的元素是唯一的,但权重可以是重复的。

    底层结构:Zset底层使用了两个数据结构
    hash:用于关联元素 value 和权重 score,保障 value 的唯一性,可以通过元素 value 好到相应的 score 值
    跳跃表:用于给元素 value 排序,根据 score 的范围获取元素列表。

三大新数据类型
  1. Bitmaps
    Bitmaps本身不是一种数据类型, 实际上它就是字符串(key-value) , 但是它可以对字符串的位进行操作。
    Bitmaps单独提供了一套命令, 所以在Redis中使用Bitmaps和使用字符串的方法不太相同。 可以把Bitmaps想象成一个以位为单位的数组, 数组的每个单元只能存储0和1, 数组的下标在Bitmaps中叫做偏移量。

Bitmaps

  1. HyperLoglog
    HyperLogLog 是用来做基数统计(去重并计数)的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。

    在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
    但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

    什么是基数?
    比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。

  2. Geospatial
    Geospatial 就是元素的2维坐标,在地图上就是经纬度。redis基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度Hash等常见操作。

Redis持久化

RDB模式

RDB (Redis DataBase):在指定时间间隔内将内存中的数据集以快照的形式写入磁盘,恢复时将快照文件直接读入内存。

RDB持久化流程

Redis 会单独创建(fork)一个子进程来进行持久化。先将数据写入到一个临时文件中,待持久化过程结束后,用这个临时文件替换上一次持久化的rdb文件。整个过程中,Redis 主进程是不进行任何 IO 操作的,这就确保了 Redis 极高的性能。

RDB默认备份策略:1分钟内改了1万次,或5分钟内改了10次,或15分钟内改了1次时。

可以在 redis.conf 文件中 使用save [second] [times]进行修改。这种策略会导致丢失最后一次持久化的数据。如1分钟内修改了9000次,还没备份rdb文件快照,redis 主进程终止,将导致这9000次修改丢失。

系统默认开启 RDB 模式

RDB优势
  1. 适合大规模数据的恢复

  2. 更适合对数据完整性和一致性要求不高的场景

  3. 节省磁盘空间

  4. 恢复速度快

RDB劣势
  1. Fork时,内存中的数据被克隆了一份,大致2倍的膨胀性

  2. 虽然fork使用了写时复制(COW)技术,但当数据量较大时比较消耗性能

  3. 可能会丢失最后一次数据

AOF模式

AOF(Append Of File):以日志的形式来纪律每个写操作(增量保存,增删改保存,读不保存),redis 启动时会读取该日志文件以重新构建数据。换言之,redis 根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

系统默认不开启 AOF 模式,如需开启,在redis.conf文件中,将appendonly no修改成appendonly yes

若同时开启 AOF 与 RDB,系统默认读取 AOF 的数据,因为 AOF 模式下,数据不会丢失。

AOF持久化流程

客户端的增删改命令会被 append 追加到 AOF 缓冲区内;AOF缓冲区根据 AOF 缓冲策略[always, everysec, no]将操作同步到磁盘中的 appendonly.aof 文件(以下称为AOF文件)中;AOF 文件大小超过重写策略或手动重写时,会对 AOF 文件 rewrite 重写,压缩 AOF 文件容量;Redis 服务重启时,会重新加载 AOF 中的操作,达到数据恢复的目的。

AOF缓冲策略

always
始终同步,每次Redis的写入都会立刻记入日志;性能较差但数据完整性比较好
everysec
每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失。
no
redis不主动进行同步,把同步时机交给操作系统。

Rewrite重写

AOF采用文件追加的方式,每次增量操作都会记录在 AOF 文件中,这会导致 AOF 文件越来越大,为了避免 AOF 文件过大,新增了重写机制。当 AOF 文件大小超过阈值时,Redis 就会压缩 AOF 文件的内容。

重写原理:
当 AOF 文件持续增大,超过阈值时,会 fork 出一个新进程来将文件重写(同样是先写临时文件再改名覆盖)。Redis4.0 版本后的重写,是指吧RDB快照,以二进制的形式附在新的 AOF 头部,作为已有的历史数据, 替换掉原来的流水记录。

AOF的优势
  1. 备份机制更稳健,丢失数据概率更低。

  2. 可读的日志文本,通过操作AOF稳健,可以处理误操作。

AOF的劣势
  1. 比起RDB占用更多的磁盘空间。

  2. 恢复备份速度要慢。

  3. 每次读写都同步的话,有一定的性能压力。

  4. 存在个别Bug,造成恢复不能。

如何选择持久化模式

官方推荐两个都启用。
如果对数据不敏感,可以选单独用RDB。
不建议单独用 AOF,因为可能会出现Bug。
如果只是做纯内存缓存,可以都不用。

Redis主从复制

主从复制是什么?

主机数据更新后根据配置和策略, 自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主。这样的模式实现了读写分离,性能得以扩展,而且具备容灾快速恢复的功能。
通过slaveof <ip> <host>指令可以实现将当前服务器作为目标主机的从服务器

主从复制原理

slave 连接到 master 后,会发送一个 sync 命令;master 接收到命令后,启动后台的存盘进程,同时手机所有接收到的永固修改数据集的命令,在后台进程执行完毕后,master将传送整个数据文件到slave,以完成第一次同步;slave 接收到数据库文件数据后,将其存盘并加载到内存中(全量复制);master 继续将新的所有收集到的修改命令一次传给slave,完成同步(增量复制);slave 每次连接到 master 都会进行一次全量复制。

MasterSlaveReplication

常用的3种配置方式
  1. 一主二仆
    一个主服务器配备两个从服务器

  2. 薪火相传
    一个从服务器的主服务器,可以是另一个主服务器的从服务器。换句话说,就是一台主机 B 既可以当主机 A 的从服务器,也可以当主机 C 的主服务器。
    这种配置方式可以有效减轻主服务器的写压力,去中心化降低风险。但是当一台主机宕机后,其后面的主机都无法工作

  3. 反客为主
    当一个master宕机后,后面的slave可以立刻升为master,其后面的slave不用做任何修改。
    可以输入 slaveof no one 指令将从机变为主机。

哨兵模式

哨兵模式:反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库

投票数:当有一个哨兵监测到主服务器宕机,即视为投票。当投票数大于预先设定的阈值时,会自动将一个优先级高的从服务器设为主服务器。

在配置文件 redis.conf 中,可以通过添加slave-priority 10设置从服务器优先级,数字越低优先级越高,默认为100。

缓存穿透

问题描述:

用户访问key对应的数据,在Redis中无法找到,服务器便会访问MySQL,而MySQL中也不存在该数据,因此无法同步给Redis,下一次再访问该数据时仍然要访问MySQL,当这种访问不存在的请求变多,访问MySQL的次数增加,可能会导致MySQL崩溃,极有可能是收到黑客攻击。

解决方法:
对空值进行缓存:

若查询到不存在的数据,将这个数据的值设为空,并缓存到Redis,为了提高性能,可以设置较短的过期时间。

  • 使用布隆过滤器:

    布隆过滤器(Bloom Filter)是一个很长的二进制向量和一系列随即映射函数(哈希函数)。它可以用于检索一个元素是否在一个集合中。它的优点是时空效率远超一般算法,缺点是有一定的识别误差和删除困难。

    将所有可能存在的数据哈希到一个足够大的bitmaps中,一个一定不存在的数据会被 这个bitmaps拦截掉,从而避免了对底层存储系统的查询压力。

  • 在接口层做校验

    拦截一些非法请求,如ID为正数,当请求ID为负数时,对他进行拦截。

  • 进行实时监控

    当发现Redis命中率急速下降时,排查访问对象及数据,对异常IP进行封禁。

缓存击穿

问题描述:

用户访问的某个key数据在MySQL中存在,但是在Redis中过期,此时服务器便会访问MySQL并写回到Redis中,大并发请求这个key数据会导致数据库瞬时访问量激增,可能会导致MySQL崩溃。

解决方法:
  • 预先设置热门数据

    在redis高峰访问前,将一些热门数据提前存入redis中,并设置较长的保留时间

  • 实时调整

    现场监控热门数据,实时调整key的过期时间

  • 使用互斥锁

    当查询到数据过期时,设置互斥锁,使其余访问该数据的请求睡眠一段时间后再访问该数据,排他锁加锁成功后查询MySQL,同步缓存,并删除互斥锁

缓存雪崩

问题描述:

用户访问的某些key数据在MySQL中存在,但是在Redis中过期,此时服务器便会访问MySQL并写回到Redis中,大量访问过期key的请求会导致数据库瞬时访问量激增,可能会导致MySQL崩溃。

tips:缓存击穿与缓存雪崩的区别在于访问同一个过期key和访问多个过期key

解决方法:
  • 构建多级缓存架构

    nginx缓存 + redis缓存 + 其他缓存(如 ehcache等)

  • 使用锁或者队列

    用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。但不适用高并发情况

  • 将缓存失效时间分散开

    比如我们可以在原有的失效时间的基础上加一个随机值,这样每个缓存过期时间的重复率就会降低,就很难引发集体失效的事件。

Redis分布式锁

Redis 命令

  • SETEX key second value 设置键过期时间为 second 秒。该命令等同于 SET key value EX second

  • SETPX key value millisecond 设置键过期时间为 millisecond 毫秒。该命令等同于SET key value PX millisecond

  • SETNX key value当键 key 不存在时,才对键进行设置操作。该命令等同于SET key value NX

  • SETXX key value当键 key 存在时,才对键进行设置操作。该命令等同于 SET key value XX

Redis 实现加锁操作

通过 SETNX 实现加锁操作。

例如:我们规定,对共享资源 id 的操作需要对其加锁,对需要先进行SET idLock value NX 操作,只有成功执行这条语句,才可以视为获取到了 id 锁,否则无法对 id 进行操作。由于使用的是 SETNX 型指令,当有一个进程 SETNX 后,key 存在,便不能在对该 key 进行操作,只有当进程完成对 id 操作,并执行 del idLock删除这把锁,其他进程才能对这个资源上锁。需要注意的是对相同的共享资源,设置的 key 也要相同,value 的取值任意。

通过 SETEX 设置过期时间

可以发现的是,通过 SETNX 加锁好像和数据库乐观锁相似,体现不出 Redis 分布式锁的特点。因为 SETNX 会出现一个常见的问题,某进程对某共享资源上锁后被阻塞,一直无法释放锁。

通过 SETEX 优化,给锁设置一个过期时间,当进场占用该资源超过过期时间后,自动将该锁释放。该命令模板为

SET key value NX EX second
SET key value NX PX millisecond

另外,exprie 同样可以为设置过期时间

SET key value NX EX second

等同于{

SETNX key value
exprie key second

}

但不推荐使用 exprie,因为 exprie 缺乏原子性,可能会在 SETNX 和 exprie 之间出现异常。
以上为个人学习总结,如果疏漏、错误之处,欢迎指出。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值