Redis

Redis

windows版Redis启动方式

在这里插入图片描述

然后输入redis-server redis.windows.conf 启动成功后如下图所示

在这里插入图片描述

ctrl+c取消连接

redis.conf文件

绑定主机地址 bind IP 默认是本机,只能本机访问(远程访问连接为0.0.0.0)

在这里插入图片描述

设置服务器端口号 port 默认6379

在这里插入图片描述

如果端口号为默认端口号6379,再打开一个终端,输入redis-cli 然后输入ping 它会出现PONG说明连接成功

如果不是默认端口,需要输入redis-cli -p 端口号

在这里插入图片描述

设置服务器文件保存地址 dir path

maxclients 设置最大连接数

在这里插入图片描述

在这里插入图片描述

把maxclients设置为1

然后,ctrl+c取消连接,再重新输入redis-server redis.windows.conf 启动,然后再另一个终端输入ping ,然后输入info clients

查看当前的连接数量为1

在这里插入图片描述

然后再重新打开一个终端

在这里插入图片描述

超过了最大连接数

Redis基本操作

redis中以key——value的形式存储

在这里插入图片描述

Redis数据类型(常用的4种)

string 、hash、list、set

在学习sting这个数据形式之前,我们先要明白sting到底是修饰什么的。我们知道redis 自身是一个 Map,其中所有的数据都是采用 key-value 的形式存储。对于这种结构来说,我们用来存储数据一定是一个值前面对应一个名称,我们通过名称来访问后面的值,按照这种形势,我们可以对出来我们的存储格式。前面这一部分我们称为key。后面的一部分称为value,而我们的数据类型,他一定是修饰value的

数据类型指的是存储的数据的类型,也就是 value 部分的类型,key 部分永远都是字符串。

string数据类型

添加/修改数据 set key value
获取数据 get key
删除数据del key
在这里插入图片描述

判定性添加数据 setnx key value(仅在键不存在时才设置该键。SETNX是 “Set if Not Exists”(如果不存在则设置)的缩写)

在这里插入图片描述

添加/修改多个数据 mset key1 value1 key2 value2.
获取多个数据mget key1 key2
获取数据字符个数(字符串长度)strenkey
追加信息到原始信息后部(如果原始信息存在就追加,否则新建)append key value

在这里插入图片描述

string类型数据的扩展操作

string在redis内部存储默认就是一个字符串,当遇到增减类操作incr,decr时会转成数值型进行计算

数字进行操作:

incr key (是要进行自增操作的键名,每次执行 INCR 命令,键的值都会增加1,并返回自增后的值。)

在这里插入图片描述

incrby key increment (自定义自增 Incrby 命令将 key 中储存的数字加上指定的增量值,如果 key 不存在,那么 key 的值会先被初始化为0 ,然后再执行INCRBY 命令)

在这里插入图片描述

incrbyfloat key increment(指定浮点数进行自增)

在这里插入图片描述

设置数值数据减少指定范围的值 decr key
decrby key increment(Decrby 命令将 key 所储存的值减去指定的减量值。如果key不存在,那么key 的值会先被初始化为0然后再执行DECRBY 操作)

在这里插入图片描述

设置数据具有指定的生命周期
setex key seconds value(设置key对应字符串value,并且设置key在给定的seconds时间之后超时过期)

psetex key miliseconds value(设置key对应的value,并设置key的过期时间为miliseconds 毫秒之后)

在这里插入图片描述

注意事项

(1)数据操作不成功的反馈与数据正常操作之间的差异
表示运行结果是否成功
(integer) 0 ==》false 失败
(integer) 1 ==》 true 成功
表示运行结果值
(integer)3 ==》3 3个
(integer)1 == 》1 1个
(2)数据未获取到时,对应的数据为(nil),等同于nul
(3)数据最大存储量:512MB
(4)string在redis内部存储默认就是一个字符串,当遇到增减类操作incr,decr时会转成数值型进行计算
(5)按数值进行操作的数据,如果原始数据不能转成数值,或超越了redis数值上限范围,将报错9223372036854775807(iava中long型数据最大值,Long.MAX VALUE)
(6)redis所有的操作都是原子性的,采用单线程处理所有业务,命令是一个一个执行的,因此无需考虑并发带来的数据影响

string应用场景与key命名约定
应用场景

它的应用场景在于:主页高频访问信息显示控制,例如新浪微博大V主页显示粉丝数与微博数量。
我们来思考一下:这些信息是不是你进入大V的页面儿以后就要读取这写信息的啊,那这种信息一定要存储到我们的redis中,因为他的访问量太高了!那这种数据应该怎么存呢?我们来一块儿看一下方案!

解决方案

(1)在redis中为大V用户设定用户信息,以用户主键和属性值作为key,后台设定定时刷新策略即可。
eg: user: id: 506728370 fans–> 12210947
eg: user: id: 3506728370 blogs -->6164
eg: user: id: 3506728370 focuses–> 83
(2)也可以使用json格式保存数据
eg: user: id:3506728370 --> {"fans”:12210947,“blogs”:6164,"focuses ":83 }
(3)key 的设置约定
数据库中的热点数据key命名惯例

表名主键名主键值字段名
eg1orderid2433535name
eg2equipid2424455type
eg3newsid3234656title
hash类型

新的存储需求:对一系列存储的数据进行编组,方便管理,典型应用存储对象信息

需要的存储结构:一个存储空间保存多个键值对数据

hash类型:底层使用哈希表结构实现数据存储

左边一个key,对右边一个存储空间。这里要明确一点,右边这块儿存储空间叫hash,也就是说hash指的是一个数据类型,他指的不是一个数据,是这里边的一堆数据,那么它底层呢,是用hash表的结构来实现的。
值得注意的是:
如果field数量较少,存储结构优化为类数组结构
如果field数量较多,存储结构使用HashMap结构

hash的基本操作

添加/修改数据
hset key field value

在这里插入图片描述

获取数据
hget key field

hgetall key

在这里插入图片描述

删除数据

hdel key field1 [field2]

在这里插入图片描述

设置field的值,如果该field存在则不做任何操作
hsetnx key field value

在这里插入图片描述

添加/修改多个数据

hmset key field1 value1 field2 value2

在这里插入图片描述

获取多个数据
hmget key field1 field2

在这里插入图片描述

获取哈希表中字段的数量
hlen key

获取哈希表中是否存在指定的字段
hexists key field

在这里插入图片描述

hash 类型数据扩展操作

获取哈希表中所有的字段名或字段值
hkeys key
hvals key
设置指定字段的数值数据增加指定范围的值
hincrby key field increment

hincrbyfloat key field increment

在这里插入图片描述

hash类型数据操作的注意事项

(1)hash类型中value只能存储字符串,不允许存储其他数据类型,不存在嵌套现象。如果数据未获取到,对应的值为(nil)。2,第个在强人星对复篇:2?2的,?出用,严深。心在对象的教播方,并且可以灵活添加删除对象属性。但hash设计初衷
(3)hgeta 操作可以获取全部属性,如果内部field过多,遍历整体数据效率就很会低,有可能成为数据访问瓶颈。

hash应用场景

双11活动日,销售手机充值卡的商家对移动、联通、电信的30元、50元、100元商品推出抢购活动,每种商品抢购上限1000 张。

也就是商家有了,商品有了,数量有了。最终我们的用户买东西就是在改变这个数量。那你说这个结构应该怎么存呢?对应的商家的ID作为key,然后这些充值卡的ID作为feld,最后这些数量作为value。而我们所谓的操作是其实就是increa这个操作,只不过你传负值就行了。看一看对应的解决方案:

解决方案
以商家id作为key
将参与抢购的商品id作为field
将参与抢购的商品数量作为对应的value
抢购时使用降值的方式控制产品数量

list类型

前面我们存数据的时候呢,单个数据也能存,多个数据也能存,但是这里面有一个问题,我们存多个数据用hash的时候它是没有顺序的,。我们平时操作,实际上数据很多情况下都是有顺序的,那有没有一种能够用来存储带有顺序的这种数据模型呢,list就专门来干这事儿。

数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分需要的

存储结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序

list类型:保存多个数据,底层使用双向链表存储结构实现

list类型数据基本操作

添加/修改数据
lpush key value1 [value2]…(注意lpush第一位为小写的L)左边添加
rpush key value1 [value2]… 右边添加

获取数据(注意lrange第一位为小写的L)
lrange key start stop(返回存储在 key 的列表里指定范围内的元素。start 和 end 偏移量都是基于0的下标,即list的第一个元素下标是0(list的表头),第二个元素下标是1,以此类推,偏移量也可以是负数,表示偏移量是从list尾部开始计数。 例如,-1表示列表的最后一个元素,-2 是倒数第二个,以此类推)
lindex key index(返回列表 key 中,下标为 index 的元素。)
llen key(返回当前列表key的长度。当key不存在时返回0)
获取并移除数据
Ipop key(移除并返回表头(左侧)的元素。当key不存在时,返回nil)

在这里插入图片描述

list扩展操作

移除指定数据
lrem key count value
注意:Lrem 根据参数 COUNT 的值,移除列表中与参数 VALUE 相等的元素。COUNT 的值可以是以下几种:
count>0:从表头开始向表尾搜索,移除与 VALUE 值相同的元素,移除数量为 COUNT
count <0:从表尾开始向表头搜索,移除与 VALUE 值相同的元素,移除数量为 COUNT 的绝对值。
count=0:移除表中所有与 VALUE 值相同的元素。

在这里插入图片描述

规定时间内获取并移除数据
blpop key1[key2]timeout (移出并获取列表的第一个元素,如果列表没有元素会阻塞列表直超时或发现可弹出元素为止)参数说明:
。key1 [key2 … keyN]: 至少一个列表类型的键名,如果多个键名,BLPOP按照key1,key2,…keyN的顺序查找非空列表进行弹出操作。
timeout: 超时时间,单位为秒。如果timeout为0,即阻塞时间为0,则BLPOP命令将会一直阻塞,直到有非空列表能够弹出,否则当前连接一直阻塞。

在这里插入图片描述

此时会阻塞,然后我们再打开一个终端,

在这里插入图片描述

然后发现上一个移除完成
在这里插入图片描述

brpop key1 [key2] timeout 右移除,基本操作同上

brpoplpush source destination timeout(命令从列表中取出最后一个元素,并插入到另外一个列表的头部; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止)

在这里插入图片描述

会阻塞(上图为阻塞消失后的最终结果),打开另一个终端

在这里插入图片描述

前面的阻塞会消失,如上图

set类型

set类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值是不允许重复

set类型基本操作

添加数据:sadd key member1 [member2]

获取全部数据:smembers key

删除数据: srem key member1 [member2]

获取集合数据总量:scard key

判断集合中是否包含指定数据:sismember key member

在这里插入图片描述

随机获取集合中指定数量的数据: srandmember key [count]

随机获取集合中某个数据并将该数据移除集合:spop key [count]

在这里插入图片描述

set类型数据扩展操作

求两个集合的交 并 差集

sinter key1 [key2…] 交集

sunion key1[key2…] 合集

sdiff key1 [key2…] 差集(在前面的为参照)

在这里插入图片描述

求两个集合的交、并、差集并存储到指定集合中
sinterstore destination key1 [key2 …]
(将key1 与key2的合集放入destination destination可以更改为其他名字)

sunionstore destination key1 [key2 …]

sdiffstore destination key1 [key2 …]

将指定数据从原始集合中移动到目标集合中
smove source destination member

在这里插入图片描述

set类型数据操作的注意事项

set 类型不允许数据重复,如果添加的数据在 set 中已经存在,将只保留一份

set 虽然与hash的存储结构相同,但是无法启用hash中存储值的空间

常用指令
key基本操作

删除指定的key del key

获取key是否存在 exists key

获取key的类型 type key

排序 sort key:返回值从小到大排序的结果

​ sort key desc:返回键值从小到大的排序结果

改名 rename key newkey(如果newkey已经存在,那么该命令将会用oldkey的值覆盖newkey的值)

​ renamenx key newkey(命令用于在新的key不存在时修改key的名称)

在这里插入图片描述

key扩展操作(时效性控制)

为指定key设置有效期
expire key seconds(设置过期时间为多少秒)
pexpire key milliseconds(设置过期时间为多少毫秒)

expireat key timestamp (用于将键key的过期时间设置为timestamp所指定的秒数时间戳。)

pexpireat key miiseconds-timestamp (用于将键key的过期时间设置为timestamp所指定的毫秒数时间戳。)

在这里插入图片描述

ttl key 获取key的有效时间
如果key不存在或者已过期,返回-2
如果key存在并且没有设置过期时间(永久有效),返回-1。

pttl key 用于获取一个键的剩余过期时间,以毫秒为单位。

如果键不存在或已过期,则返回-2.
如果键没有关联到过期时间,则返回-1

persist key 切换key从时效性转换为永久性exists

在这里插入图片描述

key 扩展操作(查询模式)

查询key
keys pattern查询模式规则

匹配任意数量的任意符号 *
配合一个任意符号 ?

匹配一个指定符号 [ ]

keys * 查询所有
keys it* 查询所有以it开头
keys *buka 查询所有以buka结尾
keys ??buka 查询所有前面两个字符任意,后面以buka结尾
keys user:? 查询所有以user:开头,最后一个字符任意
keys u[st]er:1 查询所有以u开头,以er:1结尾,中间包含一个字母,s或t

数据库指令
key重复问题

在这个地方我们来讲一下数据库的常用指令,在讲这个东西之前,我们先思考一个问题:假如说你们十个人同时操作redis,会不会出现key名字命名冲突的问题。
一定会,为什么?因为你的key是由程序而定义的。你想写什么写什么,那在使用的过程中大家都在不停的加,早晚有一天他会冲突的,。
redis在使用过程中,伴随着操作数据量的增加,会出现大量的数据以及对应的key。
那这个问题我们要不要解决?要!怎么解决呢?我们最好把数据进行一个分类,除了命名规范我们做统一以外,如果还能把它分开,这样是不是冲突的机率就会小一些了

redis为每个服务提供有16个数据库,编号从0到15
每个数据库之间的数据相互独立

在对应的数据库中划出一块区域,说他就是几,你就用几那块,同时,其他的这些都可以进行定义,一共是16个,这里边需要注意一点他们这16个共用redis的内存。没有说谁大谁小,也就是说数字只是代表了一块儿区域,区域具体多大未知。这是数据库的一个分区的一个策略!

在这里插入图片描述

数据库基本操作

切换数据库 select index

在这里插入图片描述

数据移动 move key db
将当前数据库的 key 移动到给定的数据库 db 当中。

数据总量 dbsize

数据清除 flushdb(清空当前库的数据)

在这里插入图片描述

实时监控指令MONITOR

MONITOR是一个Redis的内置命令,用于实时监控Redis服务器上执行的所有命令和活动。当我们执行这个命令时,Redis会立即返回个实时的事件流,显示所有传入的命令以及它们的执行时间

在这里插入图片描述

注意事项:
性能影响:MONITOR命令会消耗一定的CPU和内存资源。在生产环境中使用时,需要谨慎考虑其对性能的影响。

数据安全:因为MONITOR会输出所有执行的命令,包括可能包含敏感信息的命令(如AUTH),所以在使用时需要特别注意数据安全。

单一职责:当redis-cli进入MONITOR模式后,它不能执行其他Redis命令。

Jedis

我们要使用Java来操作Redis

什么是Jedis?是Redis官方推荐的Java连接开发工具!使用Java操作Redis中间件!

1、导入对应依赖
<dependency>
     <groupId>redis.clients</groupId>
     <artifactId>jedis</artifactId>
     <version>2.9.0</version>
</dependency>
2、编码测试
  • 连接数据库

  • 操作命令

  • 断开连接

    package com.buka;
    
    import redis.clients.jedis.Jedis;
    
    public class TestPing {
        public static void main(String[] args) {
            //1、 new Jedis对象
            Jedis jedis = new Jedis("127.0.0.1",6379);
            //jedis 所有的命令就是我们之前学习的说有指令
            System.out.println(jedis.ping());
        }
    }
    

    输出 PONG

SpringBoot集成redis

引入依赖

  <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.3.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.3.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

    </dependencies>

配置application.yml

server:
  port: 8080

spring:
  redis:
    host: localhost
    port: 6379
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RedisController {
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @RequestMapping("/get/{key}")
    public String test(@PathVariable("key") String key){
        return stringRedisTemplate.opsForValue().get(key);
    }
}

package com.buka.redisspringboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RedisSpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisSpringBootApplication.class,args);
    }
}

SpringBoot实现共享Session

在使用SpringBoot做负载均衡的时候,多个app之间的session要保持一致,这样负载到不同的app时候,在一个app登录之后,而访问到另外一台服务器的时候,session丢失,在开发Springboot app的时候可以借助spring session和redis来存储session的状态,保证多个app之间可以实现session的共享

创建两个应用,并且引入相关的依赖

创建SpringBootStudy和SpringBoot1应用,并导入相关的依赖

<!--配置spring session data redis的依赖-->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
    <version>2.0.2.RELEASE</version>
</dependency>

编写相应代码和配置

创建配置文件,开启共享session的功能,在主类添加@EnableRedisHttpSession

在yaml中编写相关配置

spring:
  redis:
    port: 6379
    host: localhost
  session:
    redis:
      namespace: spring:session  #保存session的名称空间
    store-type: redis   #存储的介质为redis

编写测试代码

在一个SpringBoot项目中向session中设置值

package com.buka.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

@RestController
public class SessionController {
    @RequestMapping("/getSession")
    public String getSession(HttpSession httpSession){
       return String.valueOf(httpSession.getAttribute("user"));
    }
}

在另一个SpringBoot项目中从session中获取值(注意这个项目也要开启RedisSession共享)

package com.buka.redisspringboot.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

@RestController
public class SessionController {
    @RequestMapping("/setSession")
    public String setSession(HttpSession httpSession){
        httpSession.setAttribute("user","zhangsan");
        return "ok";
    }
}
启动项目并且测试

发送请求设置值:

在这里插入图片描述

查看redis数据库:

在这里插入图片描述

可以看到session有关的信息都已经保存进redis中

发送获取session值的请求:

在这里插入图片描述

可以获取到对应的session的值

持久化

什么是持久化

(1)什么是持久化
利用永久性存储介质将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化
持久化用于防止数据的意外丢失,确保数据安全性。

(2)持久化过程保存什么?
我们知道一点,计算机中的数据全部都是二进制,如果现在我要你给我保存一组数据的话,你有什么样的方式呢,其实最简单的就是现在长什么样,我就记下来就行了,那么这种是记录纯粹的数据,也叫做快照存储,也就是它保存的是某一时刻的教据状态。
还有一种形式,它不记录你的数据,它记录你所有的操作过程,比如说大家用idea的时候,有没有遇到过写错了ctl+z撤销,然后ctlty还能恢复,这个地方它也是在记录,但是记录的是你所有的操作过程,那我想问一下,操作过程,我都给你留下来了,你说数据还会丢吗?肯定不会丢,因为你所有的操作过程我都保存了。这种保存操作过程的存储,用专业术语来说可以说是日志,这是两种不同的保存数据的形式啊。

总结一下:
第一种:将当前数据状态进行保存,快照形式,存储数据结果,存储格式简单,关注点在数据

第二种:将数据的操作过程进行保存,日志形式,存储操作过程,存储格式复杂,关注点在数据的操作过程。

save配置自动执行

设置自动持久化的条件,满足限定时间范围内key的变化数量达到指定数量即进行持久化
second changessave
参数
second:监控时间范围
changes:监控key的变化量范例:
save 3600 1
save 300 10
save 60 10000
其他相关配置:
dbfilename filename
dir path
rdbcompression yes|no
rdbchecksum yes|no
stop-writes-on-bgsave-error yes|no

RDB两种启动方式对比

方式save指令bgsave指令
读写同步异步
阻塞客户端指令
额外内存消耗
启动新线程
RDB特殊启动形式

服务器运行过程中重启
debug reload
关闭服务器时指定保存数据
shutdown save全量复制(在主从复制中详细讲解)

RDB优点:

RDB是一个紧凑压缩的二进制文件,存储效率较高

RDB内部存储的是redis在某个时间点的数据快照,非常适合用于数据备份,全量复制等场景

RDB恢复数据的速度要比AOF快很多

应用:服务器中每X小时执行bgsave备份,并将RDB文件拷贝到远程机器中,用于灾难恢复。

RDB缺点:

RDB方式无论是执行指令还是利用配置,无法做到实时持久化,具有较大的可能性丢失数据。

bgsave指令每次运行要执行fork操作创建子进程,要牺牲掉一些性能

Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象.

AOF

为什么要有AOF,这得从RDB的存储的弊端说起:
存储数据量较大,效率较低,基于快照思想,每次读写都是全部数据,当数据量巨大时,效率非常低.
大数据量下的IO性能较低
基于fork创建子进程,内存产生额外消耗。
岩机带来的数据丢失风险

那解决的思路是什么呢?

不写全数据,仅记录部分数据降低区分数据是否改变的难度,改记录数据为记录操作过程.
对所有操作均进行记录,排除丢失数据的风险

AOF概念

AOF(append ony e)持久化:以独立只志的方式记录每次写命令,重启时再重新执行AOF文件中命令 达到恢复数据的目的。与RDB根比可以简单理解为由记录数据改为记录数据产生的变化
AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式

启动AOF相关配置

开启AOF持久化功能,默认no,即不开启状态
appendonly yes|no
AOF持久化文件名,默认文件名为appendonly.aof,建议配置为appendonly-端口号.aof

appendfilename filename
AOF持久化文件保存路径,与RDB持久化文件保持一致即可

dir

AOF写数据策略,默认为everysec
appendfsync always|everysec|no

AOF执行策略

AOF写数据三种策略(appendfsync)
always(每次):每次写入操作均同步到AOF文件中数据零误差,性能较低,不建议使用。

everysec(每秒):每秒将缓冲区中的指令同步到AOF文件中,在系统突然宕机的情况下丢失1秒内的数据 数据准确性较高,性能较高,建议使用,也是默认配置
no(系统控制):由操作系统控制每次同步到AOF文件的周期,整体过程不可控

AOF重写
什么叫AOF重写?

随着命令不断写入AOF,文件会越来越大,为了解决这个问题,Redis引入了AOF重写机制压缩文件体积。AOF文件重写是将Redis进程内的数据转化为写命令同步到新AOF文件的过程。简单说就是将对同一个数据的若干个条命令执行结果转化成最终结果数据对应的指令进行记录。

AOF重写作用

降低磁盘占用量,提高磁盘利用率
提高持久化效率,降低持久化写时间,提高IO性能.
降低数据恢复用时,提高数据恢复效率

AOF重写规则

进程内具有时效性的数据,并且数据已超时将不再写入文件

非写入类的无效指令将被忽略,只保留最终数据的写入命令.
如del key1、hdel key2、srem key3、set key4 111、set key5 222等

如select指令虽然不更改数据,但是更改了数据的存储位置,此类命令同样需要记录
对同一数据的多条写命令合并为一条命令
如lpush list1 a、lpush list1 b、lpush list1 c可以转化为:lpush list1 a b c。

为防止数据量过大造成客户端缓冲区溢出,对list、set、hash、zset等类型,每条指令最多写入64个元素

AOF重写方式

手动重写 bgrewriteaof

自动重写

auto-aof-rewrite-min-size size

指定了触发AOF重写的最小AOF文件大小,当当前AOF文件大小超过这个值时,Redis会自动触发AOF重写操作。该参数的默认值为64MB,如果不希望Redis自动触发AOF重写操作,可以将该值设置为0.

auto-aof-rewrite-percentage percentage

配置了当 aof 文件相较于上一版本的 aof 文件大小的百分比达到多少时触发 AOF 重写

自动重写触发条件设置

auto-aof-rewrite-min-size size
auto-aof-rewrite-percentage percent

自动重写触发比对参数

aof_current_size
aof_base_size

自动触发与AOF重写配置几个参数有关
1)auto-aof-rewrite-min-size:AOF文件重写需要的最小的大小。就是说当AOF文件至少多大体积的时候在开始进行重写,默认64M。

2)auto-aof-rewrite-percentage:AOF文件增长率,当进行过了一次重写,下一次进行重写的时候看这个AOF文件的增长率,默认100。

3)aof current size:当前AOF文件的大小(单位:字节)。
4)aof base size:上一次操作或者重写后的AOF文件大小(单位:字节)。

RDB与AOF对比(优缺点)

持久化方式RDBAOF
占用存储空间小(数据级:压缩)大(指令级:重写)
存储速度
恢复速度
数据安全性会丢失数据依据策略决定
资源消耗高/重量级低/轻量级
启动优先级
RDB与AOF应用场景
RDB与AOF的选择之惑

对数据非常敏感,建议使用默认的AOF持久化方案
AOF持久化策略使用evervsecond,每秒钟fsvnc一次。该策略redis仍可以保持很好的处理性能,当出 现问题时,最多丢失0-1秒内的数据。

注意:由于AOF文件存储体积较大,且恢复速度较慢
数据呈现阶段有效性,建议使用RDB持久化方案
数据可以良好的做到阶段内无丢失(该阶段是开发者或运维人员手工维护的),且恢复速度较快,阶段点数据恢复通常采用RDB方案注意:利用RDB实现紧凑的数据持久化会使Redis降的很低,慎重

总结
综合比对

RDB与AOF的选择实际上是在做一种权衡,每种都有利有弊

如不能承受数分钟以内的数据丢失,对业务数据非常敏感,选用AOF.

如能承受数分钟以内的数据丢失,且追求大数据集的恢复速度,选用RDB.

灾难恢复选用RDB

双保险策略,同时开启 RDB和 AOF,重启后,Redis优先使用 AOF 来恢复数据,降低丢失数据的量.

  • 19
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值