Redis学习笔记

Redis学习 记录

1、NoSQL 数据库

NoSQL,泛指非关系型的数据库。

  • 分类
    • 键值(Key-Value)存储数据库
    • 列存储数据库
    • 文档型数据库
分类 Examples举例 典型应用场景 数据模型 优点 缺点
键值(key-value) Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB 内容缓存,主要用于处理大量数据的高访问负载,也用于一些日志系统等等。 Key 指向 Value 的键值对,通常用hash table来实现 查找速度快 数据无结构化,通常只被当作字符串或者二进制数据
列存储数据库 Cassandra, HBase, Riak 分布式的文件系统 以列簇式存储,将同一列数据存在一起 查找速度快,可扩展性强,更容易进行分布式扩展 功能相对局限
文档型数据库 CouchDB, MongoDb Web应用(与Key-Value类似,Value是结构化的,不同的是数据库能够了解Value的内容) Key-Value对应的键值对,Value为结构化数据 数据结构要求不严格,表结构可变,不需要像关系型数据库一样需要预先定义表结构 查询性能不高,而且缺乏统一的查询语法。

2、Redis 事务

基本介绍

  • Redis 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 作用:串联多个命令防止别的命令插队。
执行流程(过程是原子性的)
  • multi(开启事务)
    • 从输入 multi 开始输入的命令都会依次进入命令队列中,但不会执行,直到输入 exec 命令后
  • 命令操作(set···)
  • exec/discard(执行/回滚)
    • 组队的过程中可以使用 discard 命令来放弃组队。
事务的错误处理
  • 情况一:在组队 multi 过程中有错误
    • 所有命令都不会执行
  • 情况二:在执行 exec 过程中发生错误
    • 谁有错谁不会执行,其他命令正常执行

事务和锁机制
在并发操作下,我们需要对部分数据加以控制,防止多线程环境下,造成数据不一致。比较常见的操作就是加锁。从加锁方式上主要分为两大类。

  • 悲观锁

    • 只允许该数据被单线程访问,在该数据被一个线程访问时,获取该数据的这把锁,其他线程只能排队等待。
    • MySQL中的行锁,表锁,读锁(S),写锁(X),以及 syncronized 实现的锁均为悲观锁。
    • Java中synchronized和ReentrantLock等独占锁本质上就是悲观锁。
  • 乐观锁

    • 不需要对操作的数据进行加锁,只有到数据提交的时候才通过一种机制来验证数据是否存在冲突。
    • 乐观锁通常是通过在表中增加一个版本(version)或时间戳(timestamp)来实现,其中,版本最为常用。
    • 最常见的乐观锁就是 Java 中 JUC 工具类就是基于操作系统底层 CAS 来实现的,CAS 操作就是乐观锁体现。
    • 用途
      • Redis 就是利用这种 set and check 机制来实现事务的。适用于读多写少的场景。
  • 乐观锁应用 ---- 监视器

    • watch key
      • 在执行multi之前,先执行 watch key1,key2···,如果事务咋执行之前这些 key 被其他客户端改动,那么事务将被打断(
      • 由于检查到乐观锁机制中的版本号不一致)

Redis 事务特性

  • 单独的隔离操作

    • 事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 没有隔离级别的概念

    • 队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被实际执行
  • 不保证原子性

    • 事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚

3、秒杀案例

超卖问题解决:使用事务加watch(乐观锁)解决,使用watch监视库存,然后放到事务中进行组队操作。

// 监视库存
// Redis Watch 命令用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断
jedis.watch(key);
// 组队执行
Transaction multi = jedis.multi();
multi.decr(key);
multi.sadd(userKey, userId);
List<Object> results = multi.exec();
// 对执行结果进行判断,执行失败结果集为空
if (results == null || results.size() == 0) {
    jedis.close();
    return false;
}
return true;

连接超时问题

  • 线程池解决

乐观锁造成库存遗留问题

通过 lua 脚本解决争抢问题,实际上是 Redis 利用其单线程的特性,用任务队列的方式解决多任务并发的问题。

4、Redis 持久化

Redis 提供了2种不同形式的持久化方式

  • RDB(Redis DataBase)
  • AOF(Append Of File)

4.1、Redis 持久化之 RDB

RDB(Redis DataBase)

  • 在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是 Snapshot 快照,它恢复时是将快照文件直接读到内存
  • 备份是如何执行的
    • Redis 会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何 IO 操作的,这就确保了极高的性能
    • 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那么 RDB 方式要比 AOF 方式更加的高效
  • 优缺点
    • 优点:
      • 适合大规模的数据恢复
      • 对数据完整性和一致性要求不高更适合使用
      • 节省磁盘空间
    • 缺点:
      • Fork 的时候,需要 2倍的空间
      • fork “写时拷贝” 消耗性能
      • 最后一次持久化前机器 down 掉,数据会丢失

Fork

  • Fork 的作用是赋值一个与当前进程一样的进程,创建一个子进程。
  • fork() 会产生一个和父进程完全相同的子进程,遵循 “读时共享,写时复制” 原则。
  • 一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容赋值一份给子进程。

4.2、Redis 持久化之 AOF

基本介绍

  • 以日志的形式来记录每个写操作(增量保存)
  • 将 Redis 执行过的所有写指令记录下来(读操作不记录)
  • 只许追加文件担保户可以改写文件
  • Redis 启动之初会读取该文件重新构建数据(根据日志文件将写指令从前到后执行一次完成数据的恢复)

AOF 持久化流程

  • 客户端的请求写命令会被 append 追加到 AOF 缓冲区内
  • AOF 缓冲区根据 AOF 持久化策略 [always,everysec,no] 将操作 sync 同步到磁盘的 AOF 文件中
    • 持久化同步频率设置
      • always: 每次的写入都会立刻记入日志;性能较差但数据完整性比较好
      • everysec:每秒同步,如果宕机,本秒的数据可能丢失
      • no:不主动进行同步,把同步时机交给操作系统
  • AOF 文件大小超过重写策略或手动重写时,会对 AOF 文件 rewrite 重写,压缩 AOF 文件容量
  • Redis 服务重启时,会重新 load 加载 AOF 文件中的写操作达到数据恢复的目的

AOF 默认不开启

  • 可以在 redis.conf 中配置文件名称,默认为 appendonly.aof
  • AOF 文件的保存路径同 RDB 的路径一直

AOF 和 RDB 同时开启,Redis 优先哪种?

  • 系统默认选择 AOF 的数据(数据不会存在丢失,安全至上,数据一致性、完整性优先)

恢复

  • 正常恢复

    • 重启 Redis 重新加载
  • 异常恢复

    • 修改默认的 appendonly no 改为 yes

优缺点

  • 优点:

- 备份机制更稳健,丢失数据概率更低
- 可读的日志文本,通过操作 AOF 文件,可以处理误操作
  • 缺点:

    • 比起 RDB 占用更多的磁盘空间
    • 恢复备份速度要慢
    • 每次读写同步的话,性能压力较大
    • 存在潜在 BUG,会造成不能恢复

------官方建议------:两种同时开启

5、Redis 主从复制

介绍

  • 只能一主一(多)从
  • 可以采用集群防止这一台主机挂掉导致服务瘫痪

用途作用

  • 读写分离,性能扩展
  • 容灾快速恢复

常用 3 招

  • 一主二仆

    • 当一台从服务器挂掉后,从服务器重启后不能继承上次的主从配置,需要重新配置从服务器,并且配置成功后会从头复制主库中的数据
      • slaveof [ip addr] [port]
    • 主服务器 down 掉后,不会抹除从服务器的配置,待主服务器重启后,主从关系照旧
  • 薪火相传

    • 主服务器A 负责其中一个从服务器B 的数据发送,其他的从服务器的数据来源由服务器B 来负责。
    • 优缺点:
      • 优点:性能提升,主服务器A 压力减小
      • 缺点:从服务器B 挂掉之后导致其他从服务器无法同步
  • 反客为主

    • 命令:slaveof no one
    • 主服务器A 挂掉后,A 的从服务器B 立马摇身一变成主服务器(前提是给从库配置好)

哨兵模式

  • 概念:反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转为主库。
  • 配置哨兵,填写内容
    • sentinel monitor mymaster 127.0.0.1 6379 1
    • 其中 mymaster 为监控对象起的服务器名称,1 为至少有多少个哨兵同一迁移的数量
    • 原主机重启后会变为从机
  • 故障恢复

主从复制原理

  1. 从服务器请求主服务器
  2. 主服务器接收到命令,主动向从服务器发送数据文件

两种复制方式

  • 全量复制:slave 服务在接收到数据库文件数据后,将其存盘并加载到内存种。
  • 增量复制:Master 继续将新的所有收集到的修改命令一次传给 slave,完成同步。

6、Redis 集群

问题引入

  • 容量不够,redis 如何进行扩容?
  • 并发写操作,redis 如何分摊?
  • 之前通过代理主机来解决(需要 8台 服务器),但是 redis3.0 中提供了解决方案。就是无中心化集群配置。

什么是集群?

Redis 集群实现了对 Redis 的水平扩容,即启动 N 个 redis 节点,将整个数据库分布存储在这 N 个节点中,每个节点存储总数据的 1/N。

Redis 集群通过分区(partition)来提供一定程度的可用性(availability):即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。

删除持久化数据

  • 将 rdb、aof 文件都删除掉。

集群配置

  • cluster-enabled yes 打开集群模式
  • cluster-config-file nodes-6379.conf 设置节点配置文件名
  • cluster-node-timeout 15000 设置节点失联时间,超过该时间(毫秒),集群自动进行主从切换4

redis cluster 如何分配这六个节点?

一个集群至少要有三个主节点

选项 --cluster-replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。

分配原则尽量保证每个主数据库运行在不同的 IP 地址,每个从库和主库不在一个 IP 地址上。

什么是 slots(插槽)

  • 一个 Redis 集群包括16384 个插槽,会将插槽分配到每个节点主机上,每个主机负责一个范围的插槽

  • 入值

    • set key ,key 是根据 hash 算法得出插槽编号,随机分配到插槽对应主机存储
    • 可以采用分组在一个 slot 中存储多个 key
      • 语法 :mset k1{groupname} v1 k2{groupname} v2 ···
  • 查值

    • 每个主机只能查询自己的对应的插槽范围内的值
  • 故障恢复

    • 主节点主机 down 掉,节点的从机上位。

Redis 集群优缺点

  • 优点

    • 实现扩容

    • 分摊压力

    • 无中心配置相对简单

  • 缺点

    • 多键操作是不被支持的
    • 多键的 Redis 事务是不被支持的。lua 脚本不被支持

7、Redis 应用问题解决

缓存穿透

  • 分析原因

    • 被黑客攻击

  • 解决方案

缓存击穿

  • 分析原因

    • 热点 key 过期
  • 解决方案

缓存雪崩

  • 问题分析

  • 解决方案

分布式锁

  • 问题描述

  • 解决方案

    • 优缺点:

      • image-20220806172603714
  • 具体实现

    • NX 条件:不存在

    • EX 条件:过期时间

  • 满足条件

posted @ 2022-09-24 22:31  lam要努力  阅读(44)  评论(0编辑  收藏  举报