赞
踩
Redis 是一种内存数据库,将数据保存在内存中,读写效率要比传统的将数据保存在磁盘上的数据库要快很多。但是一旦进程退出,Redis 的数据就会丢失。
为了解决这个问题,Redis 提供了 RDB 和 AOF 两种持久化方案,将内存中的数据保存到磁盘中,避免数据丢失。Redis的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为“半持久化模式”);也可以把每一次数据变化都写入到一个append only file(aof)里面(这称为“全持久化模式”)。
antirez 在《Redis 持久化解密》一文中说,一般来说有三种常见的策略来进行持久化操作,防止数据损坏:
RDB 就是第一种方法,它就是把当前 Redis 进程的数据生成时间点快照( point-in-time snapshot ) 保存到存储设备的过程。
RDB 触发机制分为使用指令手动触发和 redis.conf (linux)或redis.windows.conf (windows)配置自动触发。
手动触发 Redis 进行 RDB 持久化的指令的为:
自动触发 RDB 的默认配置如下所示:
- save 900 1 # 表示900 秒内如果至少有 1 个 key 的值变化,则触发RDB
- save 300 10 # 表示300 秒内如果至少有 10 个 key 的值变化,则触发RDB
- save 60 10000 # 表示60 秒内如果至少有 10000 个 key 的值变化,则触发RDB
如果不需要 Redis 进行持久化,那么可以注释掉所有的 save 行来停用保存功能,也可以直接一个空字符串来停用持久化:save “”。
Redis 服务器周期操作函数 serverCron 默认每个 100 毫秒就会执行一次,该函数用于正在运行的服务器进行维护,它的一项工作就是检查 save 选项所设置的条件是否有一项被满足,如果满足的话,就执行 bgsave 指令。
aof中的相关参数以及为什么这样是可以足够安全的。本文的描述主要参考redis的conf文件以及各项网络
appendonly
开启aof特性,这个控制是否启用aof.
appendfilename
写入文件的文件名。开启aof之后,每条命令(除读之外的命令),均会写入到文件中,这里即实际写入的文件.
appendfsync
写入策略,默认值everysec,每秒写一次(调用flush)。另外两个值,always | no,分别表示每次redis写命令之外就写文件,和由操作系统保证。always对硬盘压力大,everysec是一个平衡值,no对硬盘压力最小,但调度由系统控制,丢失数据风险最大.
no-appendfsync-on-rewrite
是否在后台写时同步单写,默认值no(表示需要同步).这里的后台写,表示后台正在重写文件(包括bgsave和bgrewriteaof.bgrewriteaof网上很多资料都没有涉及到。其实关掉bgsave之后,主要的即是aof重写文件了).no表示新的主进程的set操作会被阻塞掉,而yes表示新的主进程的set不会被阻塞,待整个后台写完成之后再将这部分set操作同步到aof文件中。但这可能会存在数据丢失的风险(机率很小),如果对性能有要求,可以设置为yes,仅在后台写时会异步处理命令.
auto-aof-rewrite-percentage
aof文件增长比例,指当前aof文件比上次重写的增长比例大小。aof重写即在aof文件在一定大小之后,重新将整个内存写到aof文件当中,以反映最新的状态(相当于bgsave)。这样就避免了,aof文件过大而实际内存数据小的问题(频繁修改数据问题).
auto-aof-rewrite-min-size
aof文件重写最小的文件大小,即最开始aof文件必须要达到这个文件时才触发,后面的每次重写就不会根据这个变量了(根据上一次重写完成之后的大小).此变量仅初始化启动redis有效.如果是redis恢复时,则lastSize等于初始aof文件大小.
aof-load-truncated
指redis在恢复时,会忽略最后一条可能存在问题的指令。默认值yes。即在aof写入时,可能存在指令写错的问题(突然断电,写了一半),这种情况下,yes会log并继续,而no会直接恢复失败.
注(rdb和aof可以同时开启,但是恢复数据时以aof来作为恢复,所以开启aof时没必要开启rdb,设置redis过期时间,如果挂掉时间超时过期时间,数据将丢失。)
RDB存在哪些优势呢?
RDB又存在哪些劣势呢?
AOF的优势有哪些呢?
AOF的劣势有哪些呢?
二者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(rdb)。rdb这个就更有些 eventually consistent的意思了。
利用redis中key自动过期机制,提交订单时将订单编号写入redis,并设置30分钟的过期时间,当订单过期后,取到过期的key然后做业务处理。
- K:keyspace事件,事件以__keyspace@<db>__为前缀进行发布;
- E:keyevent事件,事件以__keyevent@<db>__为前缀进行发布;
- g:一般性的,非特定类型的命令,比如del,expire,rename等;
- $:字符串特定命令;
- l:列表特定命令;
- s:集合特定命令;
- h:哈希特定命令;
- z:有序集合特定命令;
- x:过期事件,当某个键过期并删除时会产生该事件;
- e:驱逐事件,当某个键因maxmemore策略而被删除时,产生该事件;
- A:g$lshzxe的别名,因此”AKE”意味着所有事件
notify-keyspace-events Ex
开启过期事件监听,这样当redis持久化服务重启时,恢复数据才能够在过期时间内进行监听。
监听代码如下:
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.data.redis.connection.RedisConnectionFactory;
- import org.springframework.data.redis.listener.RedisMessageListenerContainer;
-
- /**
- * @Author linyuchi
- * @Date 2018/10/27 20:56
- */
- @Configuration
- public class RedisListenerConfig {
- @Bean
- RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
-
- RedisMessageListenerContainer container = new RedisMessageListenerContainer();
- container.setConnectionFactory(connectionFactory);
- return container;
- }
- }
- import com.plusesb.constant.ShSysConstant;
- import com.plusesb.service.ShOrderService;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.data.redis.connection.Message;
- import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
- import org.springframework.data.redis.listener.RedisMessageListenerContainer;
- import org.springframework.stereotype.Component;
-
-
- /**
- * 监听所有db的过期事件__keyevent@*__:expired"
- * @author linyuchi
- */
- @Component
- @Slf4j
- public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
-
- public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
- super(listenerContainer);
- }
- @Autowired
- ShOrderService shOrderService;
- /**
- * 针对redis数据失效事件,进行数据处理
- * @param message
- * @param pattern
- */
- @Override
- public void onMessage(Message message, byte[] pattern) {
- // 用户做自己的业务处理即可,注意message.toString()可以获取失效的key
- String expiredKey = message.toString();
- log.info("======================redis time out========================");
- if(expiredKey.startsWith(ShSysConstant.ORDER_PENDING)){
- //取到业务数据进行处理
- String orderNumber = expiredKey.substring(6);
- log.info("======================"+orderNumber+"======================");
- shOrderService.cancelOrderByRedis(orderNumber);
- }
- }
- }
参考资料:
https://blog.csdn.net/u012422440/article/details/94592513
https://www.cnblogs.com/AndyAo/p/8135980.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。