写点什么

Redis 从入门到精通,至少要看看这篇,java 医疗管理系统技术描述

用户头像
极客good
关注
发布于: 刚刚
  • EX second:设置键的过期时间为 Second 秒。

  • PX millisecond:设置键的过期时间为 MilliSecond 毫秒。

  • NX:只在键不存在时,才对键进行设置操作。

  • XX:只在键已经存在时,才对键进行设置操作。


SET KEY value [EX seconds] [PX milliseconds] [NX|XX]


注:SET 操作成功完成时才会返回 OK,否则返回 nil。


有了 SET 我们就可以在程序中使用类似下面的代码实现分布式锁了:


RedisService redisService = SpringUtils.getBean(RedisService.class);


String result = redisService.set(lockKey,requestId,SET_IF_NOT_EXIST,SET_WITH_EXPIRE_TIME,expireTime);


if("OK.equals(result)"){


doOcuppiredWork();


}


如何实现异步队列


①使用 Redis 中的 List 作为队列


使用上文所说的 Redis 的数据结构中的 List 作为队列 Rpush 生产消息,LPOP 消费消息。



此时我们可以看到,该队列是使用 Rpush 生产队列,使用 LPOP 消费队列。


在这个生产者-消费者队列里,当 LPOP 没有消息时,证明该队列中没有元素,并且生产者还没有来得及生产新的数据。


缺点:LPOP 不会等待队列中有值之后再消费,而是直接进行消费。


弥补:可以通过在应用层引入 Sleep 机制去调用 LPOP 重试。


②使用 BLPOP key [key…] timeout


BLPOP key [key …] timeout:阻塞直到队列有消息或者超时。





缺点:按照此种方法,我们生产后的数据只能提供给各个单一消费者消费。能否实现生产一次就能让多个消费者消费呢?


③Pub/Sub:主题订阅者模式


发送者(Pub)发送消息,订阅者(Sub)接收消息。订阅者可以订阅任意数量的频道。



Pub/Sub 模式的缺点:消息的发布是无状态的,无法保证可达。对于发布者来说,消息是“即发即失”的。


此时如果某个消费者在生产者发布消息时下线,重新上线之后,是无法接收该消息的,要解决该问题需要使用专业的消息队列,如 Kafka…此处不再赘述。


Redis 持久化


什么是持久化


持久化,即将数据持久存储,而不因断电或其他各种复杂外部环境影响数据的完整性。


由于 Redis 将数据存储在内存而不是磁盘中,所以内存一旦断电,Redis 中存储的数据也随即消失,这往往是用户不期望的,所以 Redis 有持久化机制来保证数据的安全性。


Redis 如何做持久化


Redis 目前有两种持久化方式,即 RDB 和 AOF,RDB 是通过保存某个时间点的全量数据快照实现数据的持久化,当恢复数据时,直接通过 RDB 文件中的快照,将数据恢复。


RDB(快照)持久化


RDB 持久化会在某个特定的间隔保存那个时间点的全量数据的快照。


RDB 配置文件,redis.conf:


save 900 1 #在 900s 内如果有 1 条数据被写入,则产生一次快照。 save 300 10 #在 300s 内如果有 10 条数据被写入,则产生一次快照 save 60 10000 #在 60s 内如果有 10000 条数据被写入,则产生一次快照


stop-writes-on-bgsave-error yes #stop-writes-on-bgsave-error : 如果为 yes 则表示,当备份进程出错的时候, 主进程就停止进行接受新的写入操作,这样是为了保护持久化的数据一致性的问题。


①RDB 的创建与载入


SAVE:阻塞 Redis 的服务器进程,直到 RDB 文件被创建完毕。SAVE 命令很少被使用,因为其会阻塞主线程来保证快照的写入,由于 Redis 是使用一个主线程来接收所有客户端请求,这样会阻塞所有客户端请求。


BGSAVE:该指令会 Fork 出一个子进程来创建 RDB 文件,不阻塞服务器进程,子进程接收请求并创建 RDB 快照,父进程继续接收客户端的请求。


子进程在完成文件的创建时会向父进程发送信号,父进程在接收客户端请求的过程中,在一定的时间间隔通过轮询


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


来接收子进程的信号。


我们也可以通过使用 lastsave 指令来查看 BGSAVE 是否执行成功,lastsave 可以返回最后一次执行成功 BGSAVE 的时间。


②自动化触发 RDB 持久化的方式


自动化触发 RDB 持久化的方式如下:


  • 根据 redis.conf 配置里的 SAVE m n 定时触发(实际上使用的是 BGSAVE)。

  • 主从复制时,主节点自动触发。

  • 执行 Debug Reload。

  • 执行 Shutdown 且没有开启 AOF 持久化。


③BGSAVE 的原理



启动:


  • 检查是否存在子进程正在执行 AOF 或者 RDB 的持久化任务。如果有则返回 false。

  • 调用 Redis 源码中的 rdbSaveBackground 方法,方法中执行 fork() 产生子进程执行 RDB 操作。

  • 关于 fork() 中的 Copy-On-Write。


fork() 在 Linux 中创建子进程采用 Copy-On-Write(写时拷贝技术),即如果有多个调用者同时要求相同资源(如内存或磁盘上的数据存储)。


他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本给调用者,而其他调用者所见到的最初的资源仍然保持不变。


④RDB 持久化方式的缺点


RDB 持久化方式的缺点如下:


  • 内存数据全量同步,数据量大的状况下,会由于 I/O 而严重影响性能。

  • 可能会因为 Redis 宕机而丢失从当前至最近一次快照期间的数据。


AOF 持久化:保存写状态


AOF 持久化是通过保存 Redis 的写状态来记录数据库的。


相对 RDB 来说,RDB 持久化是通过备份数据库的状态来记录数据库,而 AOF 持久化是备份数据库接收到的指令:


  • AOF 记录除了查询以外的所有变更数据库状态的指令。

  • 以增量的形式追加保存到 AOF 文件中。


AOF 持久化:保存写状态


AOF 持久化是通过保存 Redis 的写状态来记录数据库的。


相对 RDB 来说,RDB 持久化是通过备份数据库的状态来记录数据库,而 AOF 持久化是备份数据库接收到的指令:


  • AOF 记录除了查询以外的所有变更数据库状态的指令。

  • 以增量的形式追加保存到 AOF 文件中。


开启 AOF 持久化


①打开 redis.conf 配置文件,将 appendonly 属性改为 yes。


②修改 appendfsync 属性,该属性可以接收三种参数,分别是 always,everysec,no。


always 表示总是即时将缓冲区内容写入 AOF 文件当中,everysec 表示每隔一秒将缓冲区内容写入 AOF 文件,no 表示将写入文件操作交由操作系统决定。


一般来说,操作系统考虑效率问题,会等待缓冲区被填满再将缓冲区数据写入 AOF 文件中。


appendonly yes


#appendsync always


appendfsync everysec

appendfsync no

日志重写解决 AOF 文件不断增大


随着写操作的不断增加,AOF 文件会越来越大。假设递增一个计数器 100 次,如果使用 RDB 持久化方式,我们只要保存最终结果 100 即可。


而 AOF 持久化方式需要记录下这 100 次递增操作的指令,而事实上要恢复这条记录,只需要执行一条命令就行,所以那一百条命令实际可以精简为一条。


Redis 支持这样的功能,在不中断前台服务的情况下,可以重写 AOF 文件,同样使用到了 COW(写时拷贝)。


重写过程如下:


  • 调用 fork(),创建一个子进程。

  • 子进程把新的 AOF 写到一个临时文件里,不依赖原来的 AOF 文件。

  • 主进程持续将新的变动同时写到内存和原来的 AOF 里。

  • 主进程获取子进程重写 AOF 的完成信号,往新 AOF 同步增量变动。

  • 使用新的 AOF 文件替换掉旧的 AOF 文件。


AOF 和 RDB 的优缺点


AOF 和 RDB 的优缺点如下:


  • RDB 优点:全量数据快照,文件小,恢复快。

  • RDB 缺点:无法保存最近一次快照之后的数据。

  • AOF 优点:可读性高,适合保存增量数据,数据不易丢失。

  • AOF 缺点:文件体积大,恢复时间长。


RDB-AOF 混合持久化方式


Redis 4.0 之后推出了此种持久化方式,RDB 作为全量备份,AOF 作为增量备份,并且将此种方式作为默认方式使用。


在上述两种方式中,RDB 方式是将全量数据写入 RDB 文件,这样写入的特点是文件小,恢复快,但无法保存最近一次快照之后的数据,AOF 则将 Redis 指令存入文件中,这样又会造成文件体积大,恢复时间长等弱点。


在 RDB-AOF 方式下,持久化策略首先将缓存中数据以 RDB 方式全量写入文件,再将写入后新增的数据以 AOF 的方式追加在 RDB 数据的后面,在下一次做 RDB 持久化的时候将 AOF 的数据重新以 RDB 的形式写入文件。


这种方式既可以提高读写和恢复效率,也可以减少文件大小,同时可以保证数据的完整性。


在此种策略的持久化过程中,子进程会通过管道从父进程读取增量数据,在以 RDB 格式保存全量数据时,也会通过管道读取数据,同时不会造成管道阻塞。


可以说,在此种方式下的持久化文件,前半段是 RDB 格式的全量数据,后半段是 AOF 格式的增量数据。此种方式是目前较为推荐的一种持久化方式。


Redis 数据的恢复


RDB 和 AOF 文件共存情况下的恢复流程如下图:



从图可知,Redis 启动时会先检查 AOF 是否存在,如果 AOF 存在则直接加载 AOF,如果不存在 AOF,则直接加载 RDB 文件。


Pineline


Pipeline 和 Linux 的管道类似,它可以让 Redis 批量执行指令。


Redis 基于请求/响应模型,单个请求处理需要一一应答。如果需要同时执行大量命令,则每条命令都需要等待上一条命令执行完毕后才能继续执行,这中间不仅仅多了 RTT,还多次使用了系统 IO。


Pipeline 由于可以批量执行指令,所以可以节省多次 IO 和请求响应往返的时间。但是如果指令之间存在依赖关系,则建议分批发送指令。


Redis 的同步机制


主从同步原理


Redis 一般是使用一个 Master 节点来进行写操作,而若干个 Slave 节点进行读操作,Master 和 Slave 分别代表了一个个不同的 Redis Server 实例。


另外定期的数据备份操作也是单独选择一个 Slave 去完成,这样可以最大程度发挥 Redis 的性能,为的是保证数据的弱一致性和最终一致性。


另外,Master 和 Slave 的数据不是一定要即时同步的,但是在一段时间后 Master 和 Slave 的数据是趋于同步的,这就是最终一致性。



全同步过程如下:


  • Slave 发送 Sync 命令到 Master。

  • Master 启动一个后台进程,将 Redis 中的数据快照保存到文件中。

  • Master 将保存数据快照期间接收到的写命令缓存起来。

  • Master 完成写文件操作后,将该文件发送给 Slave。

  • 使用新的 AOF 文件替换掉旧的 AOF 文件。

  • Master 将这期间收集的增量写命令发送给 Slave 端。


增量同步过程如下:


  • Master 接收到用户的操作指令,判断是否需要传播到 Slave。

  • 将操作记录追加到 AOF 文件。

  • 将操作传播到其他 Slave:对齐主从库;往响应缓存写入指令。

  • 将缓存中的数据发送给 Slave。


Redis Sentinel(哨兵)


主从模式弊端:当 Master 宕机后,Redis 集群将不能对外提供写入操作。Redis Sentinel 可解决这一问题。


解决主从同步 Master 宕机后的主从切换问题:


监控:检查主从服务器是否运行正常。


提醒:通过 API 向管理员或者其它应用程序发送故障通知。


自动故障迁移:主从切换(在 Master 宕机后,将其中一个 Slave 转为 Master,其他的 Slave 从该节点同步数据)。


Redis 集群


如何从海量数据里快速找到所需?


①分片


按照某种规则去划分数据,分散存储在多个节点上。通过将数据分到多个 Redis 服务器上,来减轻单个 Redis 服务器的压力。


②一致性 Hash 算法


既然要将数据进行分片,那么通常的做法就是获取节点的 Hash 值,然后根据节点数求模。


但这样的方法有明显的弊端,当 Redis 节点数需要动态增加或减少的时候,会造成大量的 Key 无法被命中。所以 Redis 中引入了一致性 Hash 算法。


该算法对 2^32 取模,将 Hash 值空间组成虚拟的圆环,整个圆环按顺时针方向组织,每个节点依次为 0、1、2…2^32-1。


之后将每个服务器进行 Hash 运算,确定服务器在这个 Hash 环上的地址,确定了服务器地址后,对数据使用同样的 Hash 算法,将数据定位到特定的 Redis 服务器上。


如果定位到的地方没有 Redis 服务器实例,则继续顺时针寻找,找到的第一台服务器即该数据最终的服务器位置。



③Hash 环的数据倾斜问题


Hash 环在服务器节点很少的时候,容易遇到服务器节点不均匀的问题,这会造成数据倾斜,数据倾斜指的是被缓存的对象大部分集中在 Redis 集群的其中一台或几台服务器上。



如上图,一致性 Hash 算法运算后的数据大部分被存放在 A 节点上,而 B 节点只存放了少量的数据,久而久之 A 节点将被撑爆。


针对这一问题,可以引入虚拟节点解决。简单地说,就是为每一个服务器节点计算多个 Hash,每个计算结果位置都放置一个此服务器节点,称为虚拟节点,可以在服务器 IP 或者主机名后放置一个编号实现。

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
Redis从入门到精通,至少要看看这篇,java医疗管理系统技术描述