3万字聊聊什么是Redis(八)完结了

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
日志服务 SLS,月写入数据量 50GB 1个月
简介: 继上篇Redis技术总结七,我们继续聊聊Redis的相关技术!这篇主要是介绍一下Redis事务机制ACID的实现,Redis主从同步的实战细节问题,

Redis如何实现事务ACID


什么是ACID

Redis能否实现事务ACID属性呢?

我们可以先来解释一下什么是ACID

  • A原子性:要不全部成功,要不全部失败
  • C一致性:事务执行前后是一致的,不能因为事务A执行时看到的字段A是1,准备提交时,字段A已经被事务B改成了2。这样是不行的。
  • I隔离性:执行事务时,其他操作无法存取到正在执行事务访问的数据。
  • D持久性:数据库执行事务后,数据的修改要被持久化保存下来。当数据库重启后,数据的值需要是被修改后的值。

Redis如何实现事务

事务执行的过程我们可以分为三步走

  1. 客户端要下达一个命令表示一个事务的开启 MULTI
  2. 客户端把本身要执行的操作和指令发给服务器端,这些也就是读写命令。服务器接收读写命令把他暂存在命令队列中 业务代码 set get incr 等
  3. 客户端向服务器端发起一个提交事务的命令让Redis去消化刚刚命令队列里的命令。 EXEC


事务机制的ACID的分析

原子性

对于Redis的原子性操作,主要分两种情况 执行报错入队报错

执行报错:  执行报错的话,说明入队的时候是不报错的。执行过程中必然会有正确的指令,Redis在执行过程中正确的会正常执行,报错的指令会返回报错。原子性就无法保证了

入队报错:  入队报错的话,Redis就不会执行这段指令,所以直接返回错误,可以保证原子性!

扩展一下MySQL,MySQL事务中报错的话会有回滚机制,Redis中是不存在回滚机制的。一旦使用过程中Redis发生了这种情况,我们可以使用Redis提供的 redis-check-aof 工具检查 AOF 日志文件,这个工具可以把未完成的事务操作从 AOF 文件中去除。这样一来,我们使用 AOF 恢复实例后,事务操作不会再被执行,从而保证了原子性。

如果AOF,RDB都不开启就不要谈数据安全性持久化这些概念了

一致性

事务的一致性保证会受到错误命令、实例故障的影响。所以,我们按照命令出错和实例故障的发生时机,分成三种情况来看。

  1. 入队就报错,Redis会放弃执行,同时也保证了数据库的一致性。
  2. 执行就报错,有错误的命令不会被执行,正确的命令可以正常执行,也不会改变数据库的一致性。
  3. 实例故障报错,实例故障重启后我们要根据用户是否开启了AOF和RDB进行分情况讨论。

如果我们使用了 RDB 快照,因为 RDB 快照不会在事务执行时执行,所以,事务命令操作的结果不会被保存到 RDB 快照中,使用 RDB 快照进行恢复时,数据库里的数据也是一致的。

如果我们使用了 AOF 日志,而事务操作还没有被记录到 AOF 日志时,实例就发生了故障,那么,使用 AOF 日志恢复的数据库数据是一致的。如果只有部分操作被记录到了 AOF 日志,我们可以使用 redis-check-aof 清除事务中已经完成的操作,数据库恢复后也是一致的。

Redis事务机制对一致性是有保证的

隔离性

事务的隔离性主要和并发有关。并发过程中我们还可以细分两个执行阶段。EXEC执行前EXEC执行后

执行前:  我们可以通过Redis提供的watch机制来实现隔离性

执行后:  无法保证

什么是watch机制?

在事务执行前,监控一个或多个键的值变化情况,当事务调用 EXEC 命令执行时,WATCH 机制会先检查监控的键是否被其它客户端修改了。如果修改了,就放弃事务执行,避免事务的隔离性被破坏。然后,客户端可以再次执行事务,此时,如果没有并发修改事务数据的操作了,事务就能正常执行,隔离性也得到了保证。

如果在执行前我们 没有使用watch机制,同时发生了并发请求,就会对数据进行读写,隔离性就没有得到保障

如果在EXEC执行后,虽然无法保证,但是Redis的单线程的。按照入队的先后顺序执行,所以后一个请求不会排的前面一个请求。于是 也不会破坏事务的隔离性

持久化

Redis 是内存数据库,所以,数据是否持久化保存完全取决于 Redis 的持久化配置模式。

  • 如果 Redis 没有使用 RDB 或 AOF,那么事务的持久化属性肯定得不到保证。
  • 如果 Redis 使用了 RDB 模式,那么,在一个事务执行后,而下一次的 RDB 快照还未执行前,如果发生了实例宕机,这种情况下,事务修改的数据也是不能保证持久化的。
  • 如果 Redis 采用了 AOF 模式,因为 AOF 模式的三种配置选项 no、everysec 和 always 都会存在数据丢失的情况,所以,事务的持久性属性也还是得不到保证。


Redis主从同步的那些问题


主从数据不一致

  1. 主从同步时,采用的是异步同步。所以无法保证主从库数据的实时一致性。
  2. 主从同步时,网络因素导致主从数据实时性的延迟
  3. 主从同步时,从库接收到了主库的命令。但是从库正在处理其他复杂度过高的命令而阻塞,从库只有处理完当前任务后才能处理主库的新命令。这就造成了主从延迟

解决方案

  1. 在硬件方面,我们要尽量保证主从库间的网络连接状况良好。例如,我们要避免把主从库部署在不同的机房,或者是避免把网络通信密集的应用和Redis 主从库部署在一起。
  2. 监控主从库间的复制差值,如果主从库差值过大我们就可以通过设置阈值的方式。干预解决主从同步的延迟问题

Redis 的 INFO replication 命令可以查看主库接收写命令的进度信息(master_repl_offset)和从库复制写命令的进度信息(slave_repl_offset),所以,我们就可以开发一个监控程序,先用 INFO replication 命令查到主、从库的进度,然后,我们用 master_repl_offset 减去 slave_repl_offset,这样就能得到从库和主库间的复制进度差值了

读到过期数据

平时应用中读到过期数据是比较常见的,我们分析一下为什么会读到过期数据。

假如一个key的过期时间是19:51:49,刚好有个请求访问了这个key,访问时间是19:51:50。

key过期了正等待被回收,但是还没有回收这段期间就被读取了。这主要是由Redis的过期策略引起的。

过期策略分 惰性删除定期删除

惰性删除。当一个数据的过期时间到了以后,并不会立即删除数据,而是等到再有请求来读写这个数据时,对数据进行检查,如果发现数据已经过期了,再删除这个数据。

这个策略的好处是尽量减少删除操作对 CPU 资源的使用,对于用不到的数据,就不再浪费时间进行检查和删除了。但是,这个策略会导致大量已经过期的数据留存在内存中,占用较多的内存资源。所以,Redis 在使用这个策略的同时,还使用了第二种策略:定期删除策略。

定期删除策略 是指Redis 每隔一段时间(默认 100ms),就会随机选出一定数量的数据,检查它们是否过期,并把其中过期的数据删除,这样就可以及时释放一些内存。

清楚了这两个删除策略,我们再来看看它们为什么会导致读取到过期数据。

首先,虽然定期删除策略可以释放一些内存,但是,Redis 为了避免过多删除操作对性能产生影响,每次随机检查数据的数量并不多。如果过期数据很多,并且一直没有再被访问的话,这些数据就会留存在 Redis 实例中。业务应用之所以会读到过期数据,这些留存数据就是一个重要因素。

其次,惰性删除策略实现后,数据只有被再次访问时,才会被实际删除。如果客户端从主库上读取留存的过期数据,主库会触发删除操作,此时,客户端并不会读到过期数据。但是,从库本身不会执行删除操作,如果客户端在从库中访问留存的过期数据,从库并不会触发数据删除。那么,从库会给客户端返回过期数据吗?这就和版本有关了!

版本问题

  • 3.2 之前的版本,从库在服务读请求时,并不会判断数据是否过期,而是会返回过期数据。
  • 3.2 版本后,如果读取的数据已经过期了,从库虽然不会删除,但是会返回空值,这就避免了客户端读到过期数据

除了版本的问题还有设置过期时间的命令有关,有些命令给数据设置的过期时间在从库上可能会被延后,导致应该过期的数据又在从库上被读取到了。

当主从库全量同步时,如果主库接收到了一条 EXPIRE 命令,那么,主库会直接执行这条命令。这条命令会在全量同步完成后,发给从库执行。而从库在执行时,就会在当前时间的基础上加上数据的存活时间,这样一来,从库上数据的过期时间就会比主库上延后了。

为了避免这种情况,我给你的建议是,在业务应用中使用 EXPIREAT/PEXPIREAT 命令,把数据的过期时间设置为具体的时间点,避免读到过期数据


结尾


大概总结了

  1. Redis在事务机制ACID的相关实现保证
  2. 分析了使用Redis时,Redis主从同步的那些问题

由主从同步问题展开了主从数据不一致的原因以及解决方案,过期数据的原因以及解决方案。

这篇文章大概算是Redis第二阶段的一个收尾吧。下面将从RocketMQ或者Mybatis进行技术的分享!


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
缓存 NoSQL Java
【Redis从头学-完结】Redis全景思维导图一览!耗时半个月专为Redis初学者打造!
【Redis从头学-完结】Redis全景思维导图一览!耗时半个月专为Redis初学者打造!
321 0
|
存储 缓存 监控
Redis学习笔记(五)完结
Redis的发布与订阅 Redis的主从复制 Redis的缓存穿透和雪崩
142 0
|
2月前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(一)
数据的存储--Redis缓存存储(一)
105 1
|
6天前
|
存储 缓存 NoSQL
解决Redis缓存数据类型丢失问题
解决Redis缓存数据类型丢失问题
124 85
|
2月前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(二)
数据的存储--Redis缓存存储(二)
53 2
数据的存储--Redis缓存存储(二)
|
2月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
84 6
|
4天前
|
缓存 监控 NoSQL
Redis经典问题:缓存穿透
本文详细探讨了分布式系统和缓存应用中的经典问题——缓存穿透。缓存穿透是指用户请求的数据在缓存和数据库中都不存在,导致大量请求直接落到数据库上,可能引发数据库崩溃或性能下降。文章介绍了几种有效的解决方案,包括接口层增加校验、缓存空值、使用布隆过滤器、优化数据库查询以及加强监控报警机制。通过这些方法,可以有效缓解缓存穿透对系统的影响,提升系统的稳定性和性能。
|
1月前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
1月前
|
存储 缓存 NoSQL
【赵渝强老师】基于Redis的旁路缓存架构
本文介绍了引入缓存后的系统架构,通过缓存可以提升访问性能、降低网络拥堵、减轻服务负载和增强可扩展性。文中提供了相关图片和视频讲解,并讨论了数据库读写分离、分库分表等方法来减轻数据库压力。同时,文章也指出了缓存可能带来的复杂度增加、成本提高和数据一致性问题。
【赵渝强老师】基于Redis的旁路缓存架构
|
1月前
|
缓存 NoSQL Redis
Redis 缓存使用的实践
《Redis缓存最佳实践指南》涵盖缓存更新策略、缓存击穿防护、大key处理和性能优化。包括Cache Aside Pattern、Write Through、分布式锁、大key拆分和批量操作等技术,帮助你在项目中高效使用Redis缓存。
275 22