当前位置: 首页 > article >正文

Linux——redis

非关系型数据库 -- redis

基本特性:

  1. redis一共有16个库
  2. redis使用键值对完成数据存储
  3. 每一个库当中可以保存固定数量的键值对
  4. redis 的默认端口是6379
  5. redis支持的值的类型非常丰富,支持目前最为流行的json 也支持自定义数据类型
  6. redis数据的读写都直接的发生在内存中
  7. redis支持AOF 和 RDB 两种方式持久化,将内存中的数据写入指定文件以实现持久化
  8. redis 支持哨兵模式,对于redis 进程进行监控,一旦出现问题可以尝试恢复redis服务进程
  9. redis自带集群模式,自动形成redis集群,自动划分每一个库维护的键值对数量
  10. 丰富的开发语言支持

差别点

mysql

redis

数据存储

  1. mysql 关系型数据库在写入数据时,一般以直接将数据写入磁盘
  2. 关系型数据库一般以数据表(二维表)形式存储,
  3. 存储值的类型区别较大,mysql 主要处理的值的类型可以分为字符型、数值型、时间日期、二进制型

1、 数据优先写入到内存中,再通过某些方式同步到数据文件中

2、redis 可以通过两种方式将内存中数据写入系统文件

3、 redis 在进行数据存储以键值对形式存储数据,不论哪种类型的数据,redis都是通过键来完成数据处理

4、 redis 支持字符串、列表、集合等,对于编程支持较好的语言。

数据存储限制

mysql 数据以数据表的格式进行存储,数据存储几乎没有上限

redis 数据一共有16个库,每一个库独立进行数据存储,每一个库以一个数据槽对应一组键值对的方式进行数据存储,而对于单个redis实例或者整个redis集群,数据槽(slot)的数量是固定。

扩展功能

关系型数据库集群的水平扩展或者集群管理,一般需要结合额外的数据库管理服务实现。比如:mha、

redis 自带集群管理和监控功能,可以实现自动failover 故障转移

数据备份和恢复

可以按照备份的方式分为:

冷备份 热备份

逻辑备份  物理备份

全量备份  增量备份等

对于redis 而言,数据的备份就是以数据持久化来实现。

适用场景:

  1. 数据缓存
  2. 数据复制
  3. sessions 管理
  4. 快速数据处理

使用行业:

金融服务

游戏

医保

零售

一、安装

[root@bogon ~]# dnf module list redis 
Last metadata expiration check: 2:42:31 ago on Fri 30 Aug 2024 12:35:20 PM CST.
CentOS Stream 9 - AppStream
Name                           Stream                          Profiles                            Summary                                                    
redis                          7                               common [d]                          Redis persistent key-value database                        

Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled
[root@bogon ~]# dnf -y install redis 
Last metadata expiration check: 2:43:18 ago on Fri 30 Aug 2024 12:35:20 PM CST.
Dependencies resolved.
==============================================================================================================================================================
 Package                            Architecture                        Version                                  Repository                              Size
==============================================================================================================================================================
Installing:
 redis                              x86_64                              6.2.7-1.el9                              appstream                              1.3 M

Transaction Summary
==============================================================================================================================================================
Install  1 Package

Total download size: 1.3 M
Installed size: 4.7 M
Downloading Packages:
redis-6.2.7-1.el9.x86_64.rpm                                                                                                  2.1 MB/s | 1.3 MB     00:00    
--------------------------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                                         822 kB/s | 1.3 MB     00:01     
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                                                                                                      1/1 
  Running scriptlet: redis-6.2.7-1.el9.x86_64                                                                                                             1/1 
  Installing       : redis-6.2.7-1.el9.x86_64                                                                                                             1/1 
  Running scriptlet: redis-6.2.7-1.el9.x86_64                                                                                                             1/1 
  Verifying        : redis-6.2.7-1.el9.x86_64                                                                                                             1/1 

Installed:
  redis-6.2.7-1.el9.x86_64                                                                                                                                    

Complete!
[root@bogon ~]# systemctl enable --now redis
redis-sentinel.service  redis.service           
[root@bogon ~]# systemctl enable --now redis.service 
Created symlink /etc/systemd/system/multi-user.target.wants/redis.service → /usr/lib/systemd/system/redis.service.
[root@bogon ~]# ss -anput | grep redis
tcp   LISTEN    0      511                 127.0.0.1:6379          0.0.0.0:*    users:(("redis-server",pid=3551,fd=6))                                            
tcp   LISTEN    0      511                     [::1]:6379             [::]:*    users:(("redis-server",pid=3551,fd=7))                                            
[root@bogon ~]# redis-cli ping
PONG

redis 一般可以作为a、 关系型数据的缓存加速服务部署  b、 作为应用数据库

而redis所有的数据以键值对的形式存储,下面简单了解redis数据操作语句。

redis-cli指令一般默认连接 127.0.0.1 的 6379 端口, 通过 -h  和 -p 选项可以连接其他ip和端口的redis服务端

二、指令

1.ping  不属于数据操作语句   验证数据库是否运行  

root@bogon ~]# ss -anput | grep redis
tcp   LISTEN 0      511                 127.0.0.1:6379          0.0.0.0:*    users:(("redis-server",pid=3551,fd=6))                                            
tcp   LISTEN 0      511                     [::1]:6379             [::]:*    users:(("redis-server",pid=3551,fd=7))                                            
[root@bogon ~]# redis-cli ping
PONG
[root@bogon ~]# systemctl stop redis
[root@bogon ~]# redis-cli ping
Could not connect to Redis at 127.0.0.1:6379: Connection refused

2.keys  列出键

[root@bogon ~]# systemctl start redis
[root@bogon ~]# redis-cli 
127.0.0.1:6379> ping 
PONG
127.0.0.1:6379> keys  *
(empty array)

3.del   删除键

基于不同数据类型,对应的语句

redis社区版支持一下数据类型,企业版数据支持更加丰富

String  -  字符串

Hash  -  哈希值

List  -  列表

Set  -  集合

Sorted set  -  有序集合

Stream  - 数据流    一个特殊形式的字符串,只能在字符串的末尾新增,类似于日志文件

Bitmap  -  位映射   一种比较特殊的字符串 ,可以对字符串进行位运算

Bitfield  -     可以从bit位进行字符串数据的批量操作

Geospatial  -  地理   基于经纬度实现定位

字符串,  最大不超过512m

4.set key value 键值对的生存时间

127.0.0.1:6379> set bike diamon
OK
127.0.0.1:6379> keys * 
1) "bike"
127.0.0.1:6379> set bike1 value1 ex 10				// 设定键的生存时间
OK
127.0.0.1:6379> keys * 
1) "bike"
2) "bike1"
127.0.0.1:6379> get bike1
"value1"
127.0.0.1:6379> keys * 
1) "bike"
127.0.0.1:6379> set bike1 value1 nx		// 如果键不存在,则创建新的键值对,
// 如果存在的话,不做任何事退出
OK
127.0.0.1:6379> get bike1
"value1"
127.0.0.1:6379> set bike1 value1 nx
(nil)
127.0.0.1:6379> set bike1 value2 nx
(nil)
127.0.0.1:6379> get bike1
"value1"
127.0.0.1:6379> set bike2 value2 nx
OK
127.0.0.1:6379> set bike1 value3 xx		// 如果键存在,则更新值
// 如果键不存在,不会创建新的键
OK
127.0.0.1:6379> get bike1
"value3"
127.0.0.1:6379> keys *
1) "bike"
2) "bike2"
3) "bike1"
127.0.0.1:6379> set bike3 aab xx 
(nil)
127.0.0.1:6379> keys *
1) "bike"
2) "bike2"
3) "bike1"

5.mset 一次性设置多个键值对  为键值对可以调整的参数与单个键值对创建的参数一致

127.0.0.1:6379>  mset bike:1 "Deimos" bike:2 "Ares" bike:3 "Vanth"
OK
127.0.0.1:6379> keys *
1) "bike"
2) "bike1"
3) "bike2"
4) "bike:1"
5) "bike:3"
6) "bike:2"

6.INCR  INCRBY 自增,注意此时字符串的字符一般为数字字符

127.0.0.1:6379> set counter 0
OK
127.0.0.1:6379> get counter
"0"
127.0.0.1:6379> incr counter
(integer) 1
127.0.0.1:6379> get counter
"1"
127.0.0.1:6379> incrby counter 5
(integer) 6
127.0.0.1:6379> get counter
"6"

三、列表处理

redis每一个列表最多保存 2^32 - 1 (4,294,967,295)

添加元素:lpush rpush

移除元素: rpop  lpop

获取列表长度: llen

移动列表元素到新列表: lmove

获取列表元素:lrange

控制列表元素数量:ltrim

127.0.0.1:6379> LPUSH queue1 user1
(integer) 1
127.0.0.1:6379> LPUSH queue1 user2
(integer) 2
127.0.0.1:6379> LPUSH queue1 user3
(integer) 3
127.0.0.1:6379> RPOP queue1
"user1"
127.0.0.1:6379> RPOP queue1
"user2"
127.0.0.1:6379> RPOP queue1
"user3"
127.0.0.1:6379> keys queue1
(empty array)
127.0.0.1:6379> keys *
1) "bike:1"
2) "bike1"
3) "bike2"
4) "bike:2"
5) "bike:3"
6) "counter"
7) "bike"
127.0.0.1:6379> RPUSH queue2 user1
(integer) 1
127.0.0.1:6379> RPUSH queue2 user2
(integer) 2
127.0.0.1:6379> RPUSH queue2 user3
(integer) 3
127.0.0.1:6379> rpop queue2 
"user3"
127.0.0.1:6379> RPUSH queue2 user3
(integer) 3
127.0.0.1:6379> lpop queue2
"user1"
127.0.0.1:6379> lpop queue2
"user2"
127.0.0.1:6379> llen queue2
(integer) 1
127.0.0.1:6379> LRANGE queue2 0 -1
1) "user3"
127.0.0.1:6379> LRANGE queue2 0 -1
1) "user3"
127.0.0.1:6379> lpush queue2 user2
(integer) 2
127.0.0.1:6379> lpush queue2 user1
(integer) 3
127.0.0.1:6379> LRANGE queue2 0 -1
1) "user1"
2) "user2"
3) "user3"
127.0.0.1:6379> del queue
(integer) 1
127.0.0.1:6379> lmove queue2 newqueue left left 
"user1"
127.0.0.1:6379> lrange queue2 0 -1
1) "user2"
2) "user3"
127.0.0.1:6379> lrange newqueue 0 -1
1) "user1"
127.0.0.1:6379> lpush queue2 user1
(integer) 3
127.0.0.1:6379> lrange newqueue 0 -1
1) "user1"
127.0.0.1:6379> rpush queue2 user4
(integer) 4
127.0.0.1:6379> rpush queue2 user5
(integer) 5
127.0.0.1:6379> rpush queue2 user6
(integer) 6
127.0.0.1:6379> LRANGE queue2 0 -1
1) "user1"
2) "user2"
3) "user3"
4) "user4"
5) "user5"
6) "user6"
127.0.0.1:6379> LRANGE queue2 0 3
1) "user1"
2) "user2"
3) "user3"
4) "user4"
127.0.0.1:6379> LTRIM queue2 0 3
OK
127.0.0.1:6379> LRANGE queue2 0 -1
1) "user1"
2) "user2"
3) "user3"
4) "user4"

四、集合

集合(不包括重复元素的列表,但是集合本身是无序的【集合内元素的顺序不重要】)

127.0.0.1:6379> SADD set1 mem1 mem2 mem3 		//设置集合
(integer) 3
127.0.0.1:6379> SRANDMEMBER set1 3		// 显示集合内所有元素
1) "mem3"
2) "mem2"
3) "mem1"
127.0.0.1:6379> SRANDMEMBER set1 5      // 长度大于集合本身大小 不会报错
1) "mem3"
2) "mem2"
3) "mem1"
127.0.0.1:6379> SCARD set1					// 获取集合长度
(integer) 3
127.0.0.1:6379> SRANDMEMBER set1 3		// 获取集合长度后,再查看集合内所有元素
1) "mem3"
2) "mem2"
3) "mem1"
127.0.0.1:6379> SREM set1 mem1				// 从集合中移除一个元素
(integer) 1
127.0.0.1:6379> SRANDMEMBER set1 3
1) "mem3"
2) "mem2"
127.0.0.1:6379> SISMEMBER set1 mem1     // 判断元素是否属于集合
(integer) 0
127.0.0.1:6379> SISMEMBER set1 mem3
(integer) 1
127.0.0.1:6379> SADD set2 mem3 mem1 mem6 			
(integer) 3
127.0.0.1:6379> SRANDMEMBER set1 3
1) "mem3"
2) "mem2"
127.0.0.1:6379> SRANDMEMBER set2 3
1) "mem3"
2) "mem6"
3) "mem1"
127.0.0.1:6379> SINTER set1 set2			// 两个集合相同元素
1) "mem3"
127.0.0.1:6379> SADD set2 mem3 mem2 	// 重复添加相同元素时,集合内元素数量不增加
(integer) 1
127.0.0.1:6379> SRANDMEMBER set2 4		
1) "mem3"
2) "mem2"
3) "mem6"
4) "mem1"
127.0.0.1:6379> SRANDMEMBER set1 4
1) "mem3"
2) "mem2"
127.0.0.1:6379> SDIFF set1 set2			// set1 对 set 2 求差集 结果为0
(empty array)
127.0.0.1:6379> SDIFF set2 set1			//set2 对 set1 求差集 有两个元素 
1) "mem6"
2) "mem1"

有序集合

可以根据集合元素的分数设置排序的集合,注意集合内元素的顺序根据分数排序,只有分数相同的情况下,才会基于值的字典顺序排序。

适用于:

  1. 线上游戏,基于分数排名
  2. 速率限制,基于请求次数排序,限制异常高频访问
127.0.0.1:6379> ZADD sset1 60 tom 70 amy 32 ss 
(integer) 3
127.0.0.1:6379> ZRANDMEMBER sset1 3
1) "amy"
2) "tom"
3) "ss"
127.0.0.1:6379> ZRANDMEMBER sset1 3 withscores
1) "amy"
2) "70"
3) "tom"
4) "60"
5) "ss"
6) "32"
127.0.0.1:6379> ZADD sset1 67 amy 60 john			// 更新amy分数 同时john的分数
// 与tom相同,按照字典排序
(integer) 1
127.0.0.1:6379> ZRANDMEMBER sset1 5
1) "amy"
2) "tom"
3) "john"
4) "ss"
127.0.0.1:6379> ZRANDMEMBER sset1 5 withscores
1) "amy"
2) "67"
3) "tom"
4) "60"
5) "john"
6) "60"
7) "ss"
8) "32"
127.0.0.1:6379> ZRANGE sset1  0 -1 withscores		// 升序列出所有
1) "ss"
2) "32"
3) "john"
4) "60"
5) "tom"
6) "60"
7) "amy"
8) "67"
127.0.0.1:6379> ZREVRANGE sset1 0 -1 withscores	// 降序列出所有
1) "amy"
2) "67"
3) "tom"
4) "60"
5) "john"
6) "60"
7) "ss"
8) "32"
127.0.0.1:6379> ZRANGEBYSCORE sset1 30 60 withscores		//分数在30-60 的元素
1) "ss"
2) "32"
3) "john"
4) "60"
5) "tom"
6) "60"
127.0.0.1:6379> ZRANGEBYSCORE sset1 50 60 withscores		// 分数在50-60的元素
1) "john"
2) "60"
3) "tom"
4) "60"
127.0.0.1:6379> ZRANK sset1 amy							// 指定元素 升序排名
(integer) 3
127.0.0.1:6379> ZREVRANK sset1 amy						// 指定元素 降序排名
(integer) 0											// 排名从零开始
127.0.0.1:6379> ZINCRBY sset1 30 ss			// zadd直接调整现有分数ZINCRBY 在现有分数上做加法
"62"
127.0.0.1:6379> ZRANGE sset1 0 -1
1) "john"
2) "tom"
3) "ss"
4) "amy"
127.0.0.1:6379> ZRANGE sset1 0 -1 withscores
1) "john"
2) "60"
3) "tom"
4) "60"
5) "ss"
6) "62"
7) "amy"
8) "67"

四、数据流

类似于只能新增的日志,redis会给数据流的每一个单独的信息设置唯一的ID,基于id对数据流信息进行处理,

使用场景:

  1. 事件追踪:用户操作比如说鼠标点击
  2. 传感器监控:读取设备信息
  3. 用户提醒:不同用户的提示信息,可以保存到不同的数据流中

XADD 新增数据流信息

XREAD 读取数据流信息

XRANGE 两个信息ID之间一共有多少个消息

XLEN 数据流的完整长度

每一个消息ID默认基于时间生成,所有ID值不同是正常的

127.0.0.1:6379> XADD game_event * player player1 speed  150km/h  rank 1
"1725247886395-0"					// 第一条消息ID
127.0.0.1:6379> XADD game_event * player player2 speed  100km/h  rank 2
"1725247898840-0"
127.0.0.1:6379> XADD game_event * player player3 speed  99km/h  rank 3
"1725247913980-0"
127.0.0.1:6379> XADD game_event * player player4 speed  94km/h  rank 4
"1725247923881-0"
127.0.0.1:6379> XRANGE game_event 1725247886395-0 + 	//从第一条信息输出所有
1) 1) "1725247886395-0"
   2) 1) "player"
      2) "player1"
      3) "speed"
      4) "150km/h"
      5) "rank"
      6) "1"
2) 1) "1725247898840-0"
   2) 1) "player"
      2) "player2"
      3) "speed"
      4) "100km/h"
      5) "rank"
      6) "2"
3) 1) "1725247913980-0"
   2) 1) "player"
      2) "player3"
      3) "speed"
      4) "99km/h"
      5) "rank"
      6) "3"
4) 1) "1725247923881-0"
   2) 1) "player"
      2) "player4"
      3) "speed"
      4) "94km/h"
      5) "rank"
      6) "4"
127.0.0.1:6379> XLEN game_event		//查看game_event 存储多少条记录
(integer) 4

127.0.0.1:6379> XRANGE game_event 1725247886395-0 + COUNT 2		// 从第一条消息开始,只显示两条
1) 1) "1725247886395-0"
   2) 1) "player"
      2) "player1"
      3) "speed"
      4) "150km/h"
      5) "rank"
      6) "1"
2) 1) "1725247898840-0"
   2) 1) "player"
      2) "player2"
      3) "speed"
      4) "100km/h"
      5) "rank"
      6) "2"

127.0.0.1:6379> XREAD count 10 BLOCK 300 STREAMS game_event $     // 从game_event 中读取10次,如果没有新的写入,则阻塞300ms, $ 可以替换为消息ID $ 代表的是指定数据流的最后一个信息
// 将上一条指令的$替换为player2的消息ID ,则从player2 下一条消息开始输出
127.0.0.1:6379> XREAD count 100 BLOCK 300 STREAMS game_event 1725247898840-0
1) 1) "game_event"
   2) 1) 1) "1725247913980-0"
         2) 1) "player"
            2) "player3"
            3) "speed"
            4) "99km/h"
            5) "rank"
            6) "3"
      2) 1) "1725247923881-0"
         2) 1) "player"
            2) "player4"
            3) "speed"
            4) "94km/h"
            5) "rank"
            6) "4"

五、地理空间

使用经纬度表示地理位置,先写经度(-180~180) 再写维度(-90~90)。

东经为正 西经为负   北纬为正  南纬为负

127.0.0.1:6379> GEOADD site1 -122.27652 37.805186 station:1			//site1 坐标1
(integer) 1
127.0.0.1:6379> GEOADD site1 -122.2674626 37.8062344 station:2			//site1 坐标2
(integer) 1
127.0.0.1:6379> GEOADD site1 -122.2469854 37.8104049 station:3			//site1 坐标3
(integer) 1
127.0.0.1:6379> GEOSEARCH site1 FROMLONLAT -122.2612767 37.7936847 BYRADIUS 5 km WITHDIST    //site1 距离给定坐标5千米的点位,同时返回每个点位距离给定坐标的具体距离
1) 1) "station:1"
   2) "1.8523"
2) 1) "station:2"
   2) "1.4979"
3) 1) "station:3"
   2) "2.2441"

六、redis 中数据的持久化配置

  1. rdb   redis db file        类似于mysqldump的所导出的文件,实际上可以理解为某一个时刻对于redis中所保存数据的快照

rdb持久化配置 一般需要关注到时间参数的设定  redis库中的数据变化频繁、数据变更速度较快,rdb持久化持久化的策略,一般需要在10分钟左右、1个小时、3个小时、5个小时:

1、10分钟内发生数据变更

  1. 一个小时之内发生10次数据变更

rdb 持久化策略一般保存在redis配置文件中。

### 查看redis 配置文件,redis配置文件管理非常灵活,为了避免管理员操作失误,一般rpm包的配置文件是/etc/redis/redis.conf,但是实际上确认redis的配置文件需要结合redis服务端进程的启动参数,使用ps 命令抓取redis-server 服务端程序的运行参数,配置文件通过-C 参数指定

rdb 默认配置选项

rdbcompression yes // rdb文件是否启用压缩功能,节省磁盘空间

rdbchecksum yes // 启用rdb文件校验

dbfilename dump.rdb // rdb 文件名,注释此配置项,rdb持久化被禁用

rdb-del-sync-files no  // 数据删除操作是否配置独立的文件

dir /var/lib/redis // rdb文件的保存目录

 save  秒数  数据变更的次数

# save 3600 1 // 3600s= 1h 一个小时内发生一次数据变更则更新rdb快照

# save 300 100 // 300s=5m  5分钟内,发生100次数据变更

# save 60 10000 // 60s=1m 1分钟内,发生10000次数据变更

如果说发生数据变更但是没有触发rdb策略,则有可能导致数据丢失的情况出现

 展示rdb的数据持久化效果

127.0.0.1:6379> keys *    // 数据版本1
 1) "bike1"
 2) "set1"
 3) "newqueue"
 4) "bike:3"
 5) "set2"
 6) "bike"
 7) "bike:1"
 8) "bike2"
 9) "queue2"
10) "bike:2"
11) "game_event"
12) "counter"
13) "site1"
14) "sset1"

打开另一个终端。配置rdb文件,并重启redis服务
[root@bogon ~]# ls /var/lib/redis/
dump.rdb
[root@bogon ~]# mv /var/lib/redis/dump.rdb  /root/  //版本一快照文件
[root@bogon ~]# ls /var/lib/redis/
[root@bogon ~]# systemctl restart redis
[root@bogon ~]# ls /var/lib/redis/
dump.rdb
[root@bogon ~]# ll /var/lib/redis/dump.rdb 
-rw-r--r--. 1 redis redis 630 Sep  2 17:12 /var/lib/redis/dump.rdb

切换到redis-cli的交互输入终端
127.0.0.1:6379> keys *			// 因为连接终端,出现一次报错
Error: Broken pipe
127.0.0.1:6379> keys *			// 停止redis服务前,redis先进行一次数据快照
// 所以 重启时从快照文件读数据 数据不会丢失
 1) "bike"
 2) "newqueue"
 3) "bike1"
 4) "bike:3"
 5) "counter"
 6) "sset1"
 7) "bike:1"
 8) "site1"
 9) "bike:2"
10) "set2"
11) "queue2"
12) "game_event"
13) "set1"
14) "bike2"
127.0.0.1:6379> FLUSHALL			// 清楚所有键值
OK
127.0.0.1:6379> keys *			
(empty array)
在另一个终端:
[root@bogon ~]# systemctl restart redis
[root@bogon ~]# ll -h /var/lib/redis/dump.rdb 
-rw-r--r--. 1 redis redis 92 Sep  2 17:14 /var/lib/redis/dump.rdb
切换到redis-cli
127.0.0.1:6379> keys *
Error: Server closed the connection
127.0.0.1:6379> keys *				// 重启时,是一个空库,所以重启后快照也是空的
(empty array)
127.0.0.1:6379> keys *
(empty array)

127.0.0.1:6379> set test adbsd
OK
127.0.0.1:6379> mset a v e c s v d g e d g s
OK
127.0.0.1:6379> get keys*
(nil)
127.0.0.1:6379> keys *   //版本二数据库
1) "test"
2) "e"
3) "d"
4) "a"
5) "g"
6) "s"

[root@bogon ~]# systemctl stop redis.service 
[root@bogon ~]# ll -h /var/lib/redis/dump.rdb 
-rw-r--r--. 1 redis redis 134 Sep  2 17:19 /var/lib/redis/dump.rdb	//版本二数据库快照文件
[root@bogon ~]# systemctl start redis.service 
127.0.0.1:6379> keys *
Error: Server closed the connection
127.0.0.1:6379> keys *
1) "g"
2) "test"
3) "a"
4) "d"
5) "e"
6) "s"
127.0.0.1:6379> FLUSHALL		// 清空数据库
OK
127.0.0.1:6379> keys *
(empty array)
[root@bogon ~]# systemctl stop redis.service 
[root@bogon ~]# cp /root/dump.rdb  /var/lib/redis/dump.rdb   //将版本一文件复制到快照文件夹下,重启时从此文件恢复数据
cp: overwrite '/var/lib/redis/dump.rdb'? y
[root@bogon ~]# systemctl start redis.service 
[root@bogon ~]# redis-cli 
127.0.0.1:6379> keys *			
 1) "game_event"
 2) "counter"
 3) "bike:3"
 4) "set1"
 5) "set2"
 6) "site1"
 7) "bike2"
 8) "bike:1"
 9) "sset1"
10) "queue2"
11) "bike"
12) "bike:2"
13) "newqueue"
14) "bike1"
127.0.0.1:6379> exit
[root@bogon ~]# vim /etc/redis/redis.conf 

[root@bogon ~]# systemctl stop redis.service 
[root@bogon ~]# systemctl start redis.service 
[root@bogon ~]# redis-cli 		//禁用了rdb快照,所以重启后是一个空的数据库
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> exit
[root@bogon ~]# vim /etc/redis/redis.conf 

[root@bogon ~]# systemctl stop redis.service 
[root@bogon ~]# ll /var/lib/redis/dump.rdb 
-rw-r--r--. 1 redis redis 630 Sep  2 17:25 /var/lib/redis/dump.rdb
[root@bogon ~]# systemctl start redis.service 
[root@bogon ~]# redis-cli 	// 使用版本1快照文件启动redis
127.0.0.1:6379> keys *
 1) "bike:2"
 2) "set2"
 3) "newqueue"
 4) "queue2"
 5) "bike2"
 6) "bike1"
 7) "set1"
 8) "bike"
 9) "site1"
10) "sset1"
11) "bike:1"
12) "bike:3"
13) "game_event"
14) "counter"

redis-cli 原生客户端指令

save   // 立刻执行一次redis快照

config get 配置选项 // 查看某一个配置指令的值

config set 配置选项 值 // 修改目前redis服务端配置

127.0.0.1:6379> CONFIG get save
1) "save"
2) "3600 1 300 100 60 10000"
127.0.0.1:6379> config set save "600 20"
OK
127.0.0.1:6379> CONFIG get save
1) "save"
2) "600 20"
127.0.0.1:6379> config set dbfilename "redis1.rdb"
OK
127.0.0.1:6379> exit
[root@bogon ~]# ll /var/lib/redis/
total 4
-rw-r--r--. 1 redis redis 630 Sep  3 08:43 dump.rdb
[root@bogon ~]# redis-cli  save 
OK
[root@bogon ~]# ll /var/lib/redis/
total 8
-rw-r--r--. 1 redis redis 630 Sep  3 08:43 dump.rdb
-rw-r--r--. 1 redis redis 630 Sep  3 08:49 redis1.rdb

rdb 可能失效的场景:

  1. 服务器意外断电,那么redis进程意外中断,不更新快照文件,比较容易发生数据丢失
  2. rdb 是一个redis数据快照,因此,实际不能通过rdb倒推redis库中可能发生的数据变更

七、aof

    1. aof   // append only file 仅支持追加内容的文件
    2. aof本质是一个redis数据变更的日志文件
    3. aof持久化文件的优先级高于rdb快照文件 也是如果有aof 就不使用rdb快照
    4. 默认不启用aof 持久化,下面介绍aof 持久化的配置选项

appendonly no // 是否启用aof 持久化,值为no代表禁用 值为yes代表启用

appendfilename "appendonly.aof" // aof持久化文件名,在未写明目录的情况下,默认保存到/var/lib/redis,也是dir的默认值

appendfsync everysec //AOF 持久化调用fsync() 函数完成持久化,这个配置选项fsync的函数调用的时机,简单点说就是指aof追加数据的时机, 值是

no  代表系统默认,时间间隔较久 执行速度 但是不能保证数据不会丢失

always  // 每一个指令都写入AOF文件 最安全 数据丢失可能性最小

everysec // 每秒记录一次数据写入指令 没有就不执行 效率和安全性之间平衡

no-appendfsync-on-rewrite no // 在执行数据同步命令时,不会调用fsync

aof-use-rdb-preamble yes // rdb + aof结合,在AOF持久化文件中留下标记,标记将指向一个rdb文件,在基于AOF恢复redis数据时,先加载rdb文件,然后从标记的位置开始从aof文件中恢复数据

auto-aof-rewrite-percentage 100 // aof文件大小比起上次重写时的大小,增长100%(配置可以大于100%)时,触发重写

auto-aof-rewrite-min-size 64mb // aof文件大小超过64MB*2时,触发重写,为何要乘以2,因为auto-aof-rewrite-percentage 100 是翻倍即100%,达到翻倍时才重写

127.0.0.1:6379> mset key1 a key2 b key3 c key4 d 
OK
127.0.0.1:6379> keys *
 1) "key4"
 2) "key2"
 3) "counter"
 4) "game_event"
 5) "sset1"
 6) "key3"
 7) "bike"
 8) "bike:3"
 9) "bike:1"
10) "set1"
11) "bike1"
12) "newqueue"
13) "bike2"
14) "key1"
15) "set2"
16) "queue2"
17) "site1"
18) "bike:2"
127.0.0.1:6379> save
OK
127.0.0.1:6379> exit

[root@bogon ~]# vim /etc/redis/redis.conf 		// 仅修改截图中的内容

[root@bogon ~]# systemctl restart redis
[root@bogon ~]# ls /var/lib/redis/
appendonly.aof  dump.rdb  redis1.rdb
[root@bogon ~]# ll  /var/lib/redis/
total 8
-rw-r--r--. 1 redis redis   0 Sep  3 09:23 appendonly.aof		// 一个空的aof文件

// 其实此时如果需要保存之前的数据,只需要在重启前手动执行一个bgrewriteaof指令,就可以,因为aof和rdb 混合模式下,实际还是从aof文件中恢复,之前重写AOF文件指令会基于rdb格式生成数据快照在AOF文件开头,所以恢复时先读aof文件的前面的rdb快照数据,再读取aof记录的指令,完成数据恢复,因为没有提前执行bgrewriteaof指令,所以只恢复了aof中记录的数据,而rdb中指令则未加载

// 在redis运行一段时间后启用AOF 持久化的正常指令顺序为先执行bgrewriteaof ,修改redis配置文件,启用AOF ,然后重启redis服务。

-rw-r--r--. 1 redis redis 630 Sep  3 08:43 dump.rdb
-rw-r--r--. 1 redis redis 662 Sep  3 09:23 redis1.rdb
[root@bogon ~]# redis-cli  
127.0.0.1:6379> mset aaa vvv bbb xxx ccc xxx 
OK
127.0.0.1:6379> keys *
1) "ccc"
2) "bbb"
3) "aaa"
127.0.0.1:6379> exit
[root@bogon ~]# ll  /var/lib/redis/
total 12
-rw-r--r--. 1 redis redis  91 Sep  3 09:24 appendonly.aof
-rw-r--r--. 1 redis redis 630 Sep  3 08:43 dump.rdb
-rw-r--r--. 1 redis redis 662 Sep  3 09:23 redis1.rdb
[root@bogon ~]# systemctl restart redis
[root@bogon ~]# redis-cli  
127.0.0.1:6379> keys *
1) "bbb"
2) "aaa"
3) "ccc"
127.0.0.1:6379> save
OK
127.0.0.1:6379> exit

aof文件中内容如下:

实际上AOF文件就是一个记录了数据写入修改指令的文件,在重启redis期间,读写这些指令并执行。

如果发生了演示中的错误,可以尝试将rdb文件的内容导入到aof文件开头

 八、AOF+RDB 混合模式

先启用了rdb redis数据库中保存部分数据的情况下,再启用aof,可能因为操作失误导致部分数据丢失,正确的操作顺序如下:

实验重点为:

  1. 在启用aof之前一定要生成对应的aof持久化文件,如果没有生成的话可能导致数据丢失;
  2. aof文件本身支持rdb格式,所以如果没有通过指令生成aof文件,可以直接使用rdb文件内容来手动生成AOF文件
[root@bogon ~]# redis-cli 
127.0.0.1:6379> keys *		//此时未启用aof持久化。redis中保存数据
 1) "sset1"
 2) "key3"
 3) "set1"
 4) "bike1"
 5) "set2"
 6) "bike2"
 7) "site1"
 8) "bike:2"
 9) "counter"
10) "newqueue"
11) "bike"
12) "bike:3"
13) "queue2"
14) "game_event"
15) "key1"
16) "key2"
17) "bike:1"
18) "key4"
127.0.0.1:6379> BGREWRITEAOF		// 先生成 一个aof文件
Background append only file rewriting started
127.0.0.1:6379> exit
[root@bogon ~]# ls /var/lib/redis/ -l
total 12
-rw-r--r--. 1 redis redis 662 Sep  3 10:12 appendonly.aof		// 生成的aof文件
-rw-r--r--. 1 redis redis 662 Sep  3 10:12 dump.rdb			// rdb快照文件
-rw-r--r--. 1 redis redis 662 Sep  3 09:23 redis1.rdb			// 之前实验演示遗留 和本实验无关
[root@bogon ~]# vim /etc/redis/redis.conf 
appendonly yes			//配置文件中启用aof 
[root@bogon ~]# systemctl restart redis
[root@bogon ~]# redis-cli 
127.0.0.1:6379> keys *		// 原来数据还在,依然是18个键
 1) "bike:3"
 2) "site1"
 3) "key1"
 4) "key4"
 5) "set2"
 6) "bike1"
 7) "set1"
 8) "newqueue"
 9) "sset1"
10) "queue2"
11) "bike"
12) "bike:1"
13) "key2"
14) "key3"
15) "counter"
16) "bike2"
17) "bike:2"
18) "game_event"
127.0.0.1:6379> mset a 1111 b 2222 c 3333		// 写入新的数据
OK
127.0.0.1:6379> keys *
 1) "bike:3"
 2) "site1"
 3) "a"
 4) "key1"
 5) "key4"
 6) "set2"
 7) "bike1"
 8) "set1"
 9) "newqueue"
10) "sset1"
11) "c"
12) "queue2"
13) "bike"
14) "bike:1"
15) "key2"
16) "key3"
17) "b"
18) "counter"
19) "bike2"
20) "bike:2"
21) "game_event"
127.0.0.1:6379> exit
[root@bogon ~]# ls /var/lib/redis/ -l
total 12
-rw-r--r--. 1 redis redis 750 Sep  3 10:13 appendonly.aof		// aof文件变大,说明新的写入同步到aof文件
-rw-r--r--. 1 redis redis 662 Sep  3 10:13 dump.rdb
-rw-r--r--. 1 redis redis 662 Sep  3 09:23 redis1.rdb
[root@bogon ~]# systemctl restart redis
[root@bogon ~]# ls /var/lib/redis/ -l
total 12
-rw-r--r--. 1 redis redis 750 Sep  3 10:13 appendonly.aof		
-rw-r--r--. 1 redis redis 680 Sep  3 10:19 dump.rdb	// rdb快照因为重启更新一次
-rw-r--r--. 1 redis redis 662 Sep  3 09:23 redis1.rdb
[root@bogon ~]# redis-cli 
127.0.0.1:6379> keys *	//21个键 在原本的18个基础上新增a b c 三个键
 1) "key3"
 2) "bike:3"
 3) "game_event"
 4) "queue2"
 5) "key1"
 6) "bike1"
 7) "set1"
 8) "bike:1"
 9) "b"  	// 在初始数据库的基础上新增的
10) "bike2"
11) "newqueue"
12) "counter"
13) "site1"
14) "set2"
15) "c"	// 在初始数据库的基础上新增的
16) "a"	// 在初始数据库的基础上新增的
17) "key2"
18) "key4"
19) "bike:2"
20) "sset1"
21) "bike"

如果在启用aof之前忘记通过生成aof文件可以通过rdb快照导入aof文件的方式来恢复。

比如说下面通过指令模拟忘记提前生成aof文件的情况。

127.0.0.1:6379> mset d 4444 e 5555		// 此时aof启用所以键的在新增和删除都在aof文件中记录
OK
127.0.0.1:6379> del d
(integer) 1
127.0.0.1:6379> del e
(integer) 1
127.0.0.1:6379> config set appendonly no 			//从这里开始禁用aof 观察aof文件则不会写入后面新增的键  ddd eee 
OK
127.0.0.1:6379> mset ddd 4444 eee 5555
OK
127.0.0.1:6379> exit

此时配置文件中是启用aof的,所以重启时,依旧从aof中恢复数据,aof文件中中仅记录21个键, rdb中记录23个键,因为只从aof文件中恢复数据那么重启后,redis库中仅有2个键。
[root@bogon ~]# systemctl restart redis
[root@bogon ~]# ls /var/lib/redis/ -l
total 12
-rw-r--r--. 1 redis redis 861 Sep  3 10:24 appendonly.aof
-rw-r--r--. 1 redis redis 696 Sep  3 10:28 dump.rdb
+
-rw-r--r--. 1 redis redis 662 Sep  3 09:23 redis1.rdb
[root@bogon ~]# redis-cli 
127.0.0.1:6379> keys *
 1) "set2"
 2) "bike2"
 3) "key3"
 4) "c"
 5) "sset1"
 6) "bike:2"
 7) "newqueue"
 8) "set1"
 9) "queue2"
10) "game_event"
11) "b"
12) "key2"
13) "bike1"
14) "bike:1"
15) "counter"
16) "key1"
17) "bike:3"
18) "a"
19) "key4"
20) "bike"
21) "site1"

那么此时如果想恢复手动禁用aof后创建的ddd 和 eee 就可以尝试将rdb文件的内容直接复制到aof文件中,因为aof 和rdb文件格式略有不同,最好的方式不是cp指令,而是通过重定向将rdb文件内容导入aof文件,然后启动redis服务。

通过aof文件检查命令,目前aof文件中包括21个键

rdb文件检查命令显示rdb文件中23个键

将rdb文件内容导入aof文件

[root@bogon ~]# cat /var/lib/redis/dump.rdb > /var/lib/redis/appendonly.aof 
[root@bogon ~]# redis-check-aof /var/lib/redis/appendonly.aof 		// 检查AOF文件
The AOF appears to start with an RDB preamble.
Checking the RDB preamble to start:
[offset 0] Checking RDB file /var/lib/redis/appendonly.aof
[offset 26] AUX FIELD redis-ver = '6.2.7'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1725331033'
[offset 67] AUX FIELD used-mem = '876616'
[offset 83] AUX FIELD aof-preamble = '0'
[offset 85] Selecting DB ID 0
[offset 696] Checksum OK
[offset 696] \o/ RDB looks OK! \o/
[info] 23 keys read				// 23 个键
[info] 0 expires
[info] 0 already expired
RDB preamble is OK, proceeding with AOF tail...
AOF analyzed: size=696, ok_up_to=696, ok_up_to_line=1, diff=0
AOF is valid
AOF is valid

启动redis服务,查看有23个键
[root@bogon ~]# systemctl restart redis
[root@bogon ~]# redis-cli 
127.0.0.1:6379> keys *
 1) "bike:3"
 2) "set1"
 3) "ddd"
 4) "eee"
 5) "bike2"
 6) "set2"
 7) "site1"
 8) "key1"
 9) "b"
10) "bike:2"
11) "a"
12) "bike1"
13) "sset1"
14) "newqueue"
15) "key4"
16) "bike"
17) "queue2"
18) "key3"
19) "c"
20) "game_event"
21) "bike:1"
22) "key2"
23) "counter"


redis aof 目前配置如下:
appendonly  yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb		// 以上几个配置含义见 9月3日 第一篇文档
aof-load-truncated yes				// 允许加载缩减后的aof文件,用于aof文件出现格式问题无法加载,通过相同指令恢复aof文件时生效
aof-use-rdb-preamble yes			// 启用aof + rdb 混合,就是支持aof文件中由rdb格式+aof组成 rdb在前 aof在后 顺序不能反

在aof和rdb混合使用的情况下,为了保证数据的完整性,启用aof 以aof文件为准,同时,每隔一定时间更新rdb快照,作为数据备份。

# 手动更新rdb快照,从bash命令行执行

redis-cli save

结合crontab 周期任务,每隔一定时间自动执行更新rdb快照的命令。

aof从理论上说,是比rdb更加稳定的数据持久化策略,

演示:删除aof文件,使用rdb文件恢复aof文件

[root@bogon ~]# redis-cli 
127.0.0.1:6379> keys *
 1) "bike:3"
 2) "set1"
 3) "ddd"
 4) "eee"
 5) "bike2"
 6) "set2"
 7) "site1"
 8) "key1"
 9) "b"
10) "bike:2"
11) "a"
12) "bike1"
13) "sset1"
14) "newqueue"
15) "key4"
16) "bike"
17) "queue2"
18) "key3"
19) "c"
20) "game_event"
21) "bike:1"
22) "key2"
23) "counter"
127.0.0.1:6379> exit
[root@bogon ~]# systemctl stop redis.service 
[root@bogon ~]# rm -f /var/lib/redis/appendonly.aof 
[root@bogon ~]# redis-check-rdb /var/lib/redis/dump.rdb 
[offset 0] Checking RDB file /var/lib/redis/dump.rdb
[offset 26] AUX FIELD redis-ver = '6.2.7'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1725332814'
[offset 67] AUX FIELD used-mem = '876616'
[offset 83] AUX FIELD aof-preamble = '0'
[offset 85] Selecting DB ID 0
[offset 696] Checksum OK
[offset 696] \o/ RDB looks OK! \o/
[info] 23 keys read
[info] 0 expires
[info] 0 already expired
[root@bogon ~]# cat /var/lib/redis/dump.rdb  > /var/lib/redis/appendonly.aof 
[root@bogon ~]# redis-check-aof /var/lib/redis/appendonly.aof 
The AOF appears to start with an RDB preamble.
Checking the RDB preamble to start:
[offset 0] Checking RDB file /var/lib/redis/appendonly.aof
[offset 26] AUX FIELD redis-ver = '6.2.7'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1725332814'
[offset 67] AUX FIELD used-mem = '876616'
[offset 83] AUX FIELD aof-preamble = '0'
[offset 85] Selecting DB ID 0
[offset 696] Checksum OK
[offset 696] \o/ RDB looks OK! \o/
[info] 23 keys read
[info] 0 expires
[info] 0 already expired
RDB preamble is OK, proceeding with AOF tail...
AOF analyzed: size=696, ok_up_to=696, ok_up_to_line=1, diff=0
AOF is valid
[root@bogon ~]# systemctl start redis
Job for redis.service failed because the control process exited with error code.
See "systemctl status redis.service" and "journalctl -xeu redis.service" for details.
[root@bogon ~]# chown redis.redis /var/lib/redis/appendonly.aof 
[root@bogon ~]# systemctl start redis
[root@bogon ~]# redis-cli 
127.0.0.1:6379> keys *
 1) "game_event"
 2) "bike1"
 3) "key4"
 4) "key1"
 5) "bike:3"
 6) "queue2"
 7) "eee"
 8) "ddd"
 9) "bike:2"
10) "counter"
11) "bike"
12) "bike2"
13) "bike:1"
14) "newqueue"
15) "set1"
16) "a"
17) "key2"
18) "site1"
19) "key3"
20) "set2"
21) "c"
22) "sset1"
23) "b"


http://www.kler.cn/a/294144.html

相关文章:

  • 深度解析:Android APP集成与拉起微信小程序开发全攻略
  • 表的数据结构和常见操作
  • debian 系统更新升级
  • 离线 快速搭建 docker docker-compose k8s 环境
  • 【项目组件】第三方库——websocketpp
  • 简易入手《SOM神经网络》的本质与原理
  • day47——面向对象特征之继承
  • 【AI】Pytorch_模型构建
  • Form 表单的 resetFields() 失效原因
  • 站在 AI 与 Web3 的交汇路口,EraAI 如何带领投资者进入智能化决策时代?
  • C++中匿名命名空间的主要使用方法
  • OpenCV直方图计算
  • neon指令
  • 【Moveit2官方教程】使用 MoveIt Task Constructor (MTC) 框架来定义和执行一个机器人任务
  • 奇异递归模板模式(Curiously Recurring Template Pattern)
  • 未雨绸缪:环保专包二级资质续期工程师招聘时间策略
  • Python和MATLAB(Java)及Arduino和Raspberry Pi(树莓派)点扩展函数导图
  • TYPE-C USB设计
  • [数据集][目标检测]轮胎检测数据集VOC+YOLO格式4629张1类别
  • 等保测评:如何构建安全的远程工作环境
  • 工作:GX WORKS标签的分类
  • Seata环境搭建
  • Unity TMP (TextMeshPro) 更新中文字符集
  • IDEA取消自动选择光标所在行
  • go面试:说一下 GMP 模型的原理
  • 关于IDEA的快捷键不能使用的原因