什么是Redis?

news2024/11/24 11:38:00

什么是Redis

  • 什么是Redis
    • 一、特性
      • 1. 支持多种数据结构
      • 2. 读/写速度快,性能高。
      • 3. 支持持久化。
      • 4. 实现高可用主从复制,主节点做数据副本。
      • 5. 实现分布式集群和高可用。
  • 二、基本数据类型
    • string(字符串)
    • list(双向链表)
    • set(集合)
    • zset(排序set)
    • Hash(hash表)
  • 三、特殊数据类型
    • geospatial(地理位置)
    • Hyperloglog(基数)
    • Bitmaps(位存储)
  • 四、击穿
    • 出现原因
    • 解决方案
  • 五、雪崩
    • 出现原因
    • 解决方案
  • 六、穿透
    • 出现原因
    • 解决方案
  • 七、集群同步
    • 1. 主从复制
    • 2. 哨兵(sentinel)
    • 3. 集群(Cluster)
  • 八、持久化
    • RDB(快照)
      • 何时触发
        • 自动触发
          • 1. save
          • 2. stop-writes-on-bgsave-error
          • 3. rdbcompression
          • 4. rdbchecksum
          • 5. dbfilename
          • 6. dir
        • 手动触发
          • 1. save
          • 2. bgsave
        • a. shutdown正常关闭
        • b. flushall指令触发
        • 恢复数据
        • 停止 RDB 持久化
      • 优势
      • 劣势
    • AOF
      • 优势
      • 劣势
      • 触发
    • RDB与AOF混合持久化

什么是Redis

Redis是一个高性能的key-value数据库,是由 Salvatore Sanfilippo 用C语言开发的一款开源的、高性能的键值对存储数据库,它采用 BSD 协议,为了适应不同场景下的存储需求,提供了多种键值数据类型。
支持的键值数据类型有字符串、列表、有序集合、散列及集合等。正是因为它有如此丰富的数据类型的支持,才会有庞大的用户群体。
内置复制、Lua 脚本、LRU 收回、事务及不同级别磁盘持久化功能,同时通过 Redis Sentinel 实现高可用,通过 Redis Cluster 提供自动分区等相关功能。

一、特性

Redis 是一款功能强大、支持多语言多种数据类型的数据库,它具有许多优秀的特性,可以实现消息订阅发布、Lua 脚本、数据库事务、Pipeline(管道,即当指令达到一定数量后,客户端才会执行)。同时 Redis 是单线程的,它不依赖外部库,它的所有操作都是原子性的,使用简单,
具体如下:

1. 支持多种数据结构

哈希、集合、位图(多用于活跃用户数等的统计)、HyperLogLog(超小内存唯一值计数,由于只有 12KB,因而是有一定误差范围的)、GEO(地理信息定位)。

2. 读/写速度快,性能高。

官方给出的数据是,Redis 能读的速度是 110 000次/s,写的速度是 81 000次/s。之所以有这么快的读/写速度,是因为这些数据都存储在内存中。

3. 支持持久化。

Redis 的持久化也就是备份数据,它每隔一段时间就将内存中的数据保存在磁盘中,在重启的时候会再次加载到内存中,从而实现数据持久化。Redis 的持久化方式是 RDB 和 AOF。

通常来看,数据放在内存中是不安全,一旦发生断电或者故障,重要的数据可能会丢失。因此Redis提供了两种持久化方式:RDB和AOF,这两种方式可以将数据保存到硬盘中,这样就保证了数据的持久化。

4. 实现高可用主从复制,主节点做数据副本。

Redis提供了复制功能,实现多个相同数据的Redis副本。
复制功能是分布式Redis的基础。

5. 实现分布式集群和高可用。

2.8版本正式提供了高可用实现Redis Sentinel ,它能保证Redis节点的故障发现和故障自动转移。
3.0版本正式提供了分布式实现Redis Cluster ,它是是Redis真正的分布式实现,提供了高可用,读写和容量的扩展性。

二、基本数据类型

string(字符串)

它师最基本的类型,可以理解为Memcached一模一样的类型,一个key对应一个value
常用命令:set、get、decr、incr、mget等
一个键最大能存储 512MB

// 批量设置
> mset key1 value1 key2 value2
// 批量获取
> mget key1 key2
// 获取长度
> strlen key  
//  字符串追加内容
> append key xxx
// 获取指定区间的字符
> getrange key 0 5
// 整数值递增 (递增指定的值)
> incr intkey (incrby intkey 10)
// 当key 存在时将覆盖
> SETEX key seconds value
// 将 key 的值设为 value ,当且仅当 key 不存在。
> SETNX key value

list(双向链表)

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
常用命令:lpush、rpush、lpop、rpop、lrange等
列表最多可存储 232 - 1 元素 (4294967295, 每个列表可存储40多亿)

// 将一个或多个值 value 插入到列表 key 的表头
> LPUSH key value [value ...]
// 将一个或多个值 value 插入到列表 key 的表尾(最右边)。
> RPUSH key value [value ...]
// 移除并返回列表 key 的头元素。
> LPOP key
// 移除并返回列表 key 的尾元素。
> RPOP key
// BLPOP 是列表的阻塞式(blocking)弹出原语。
> BLPOP key [key ...] timeout
// BRPOP 是列表的阻塞式(blocking)弹出原语。
> BRPOP key [key ...] timeout
// 获取指点位置元素
> LINDEX key index

set(集合)

Redis 的 Set 是 string 类型的无序集合
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)
常用命令:sadd、spop、smembers、sunion等
Set可包含的最大元素数量是4294967295

// 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
> SADD key member [member ...]
// 返回集合 key 中的所有成员。
> SMEMBERS key
// 返回集合 key 的基数(集合中元素的数量)。
> SCARD key
// 如果命令执行时,只提供了 key 参数,那么返回集合中的一个随机元素。
> SRANDMEMBER key [count]
// 移除并返回集合中的一个随机元素。
> SPOP key
// 移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。
> SREM key member [member ...]
// 判断 member 元素是否集合 key 的成员。
> SISMEMBER key member
// 获取前一个集合有而后面1个集合没有的
> sdiff huihuiset huihuiset1
// 获取交集
> sinter huihuiset huihuiset1
// 获取并集
> sunion huihuiset huihuiset1

zset(排序set)

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序
常用命令:zadd、zrange、zrem、zcard等
zset的成员是唯一的,但分数(score)却可以重复

//将一个或多个 member 元素及其 score 值加入到有序集 key 当中。
> ZADD key score member [[score member] [score member] ...]
// 返回有序集 key 中,指定区间内的成员。其中成员的位置按 score 值递增(从小到大)来排序
> ZRANGE key start stop [WITHSCORES]
// 返回有序集 key 中,指定区间内的成员。其中成员的位置按 score 值递减(从大到小)来排列。
> ZREVRANGE key start stop [WITHSCORES]
// 返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。
>  ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
// 移除有序集 key 中的一个或多个成员,不存在的成员将被忽略。
> ZREM key member [member ...]
// 返回有序集 key 的基数。
> ZCARD key
// 为有序集 key 的成员 member 的 score 值加上增量 increment 。
> ZINCRBY key increment member
// 返回有序集 key 中, score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量。
> ZCOUNT key min max
// 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列。
> ZRANK key member

Hash(hash表)

Redis hash 是一个键名对集合
Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象
常用命令:hget、hset、hgetall等
每个 hash 可以存储 232 -1 键值对(40多亿)

// 将哈希表 key 中的域 field 的值设为 value 。
> HSET key field value
// 返回哈希表 key 中给定域 field 的值。
>  HGET key field
// 返回哈希表 key 中的所有域。
> HKEYS key
// 返回哈希表 key 中所有域的值。
>  HVALS key
// 为哈希表 key 中的域 field 的值加上增量 increment 。
> HINCRBY key field increment
// 查看哈希表 key 中,给定域 field 是否存在。
> HEXISTS key field

三、特殊数据类型

geospatial(地理位置)

1.geospatial将指定的地理空间位置(纬度、经度、名称)添加到指定的key中。
这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。
2.sorted set使用一种称为Geohash的技术进行填充。经度和纬度的位是交错的,以形成一个独特的52位整数。
sorted set的double score可以代表一个52位的整数,而不会失去精度。(有兴趣的同学可以学习一下Geohash技术,使用二分法构建唯一的二进制串)
3.有效的经度是-180度到180度
有效的纬度是-85.05112878度到85.05112878度

命令功能描述
geoadd添加地理位置往key中添加地理位置的坐标(经度、纬度、位置名称)
geopos查询经纬度返回指定成员的经纬度参数
geodist查询距离返回指定2个成员之间的直线距离(默认单位:米)
georadius附近的人指定经纬度为中心,返回该中心指定半径内的成员
georadiusbymember附近的人等同georadius,上述是指定经纬度,这个是指定成员附近的人
geohash地理位置坐标返回Redis GEO 的地理位置的坐标

m 表示单位为米[默认值]
km 表示单位为千米
mi 表示单位为英里
ft 表示单位为英尺

  1. geoadd 向key中添加指定的地理位置:经度、纬度、位置名称 (添加位置)

geoadd key longitude latitude member [longitude …]
geoadd {key} {longitude} {latitude} {member} [longitude latitude member…]

// 添加北京(经纬度)、上海(经纬度)的位置到名为mycity的key中
127.0.0.1:6379> geoadd mycity 116.40 39.9 beijing 121.47 31.23 shanghai
(integer) 2
 
// 底层是zset存储方式,可以直接用zrange查询索引区间的所有成员
127.0.0.1:6379> zrange mycity 0 -1
1) "beijing"
2) "tianjin"
  1. geopos 返回指定成员的经纬度参数 (查询位置)

geopos key member1 member2…
geopos {key} {member} [member…]

// 底层是zset存储方式,可以直接用zrange查询索引区间的所有成员
127.0.0.1:6379> zrange mycity 0 -1
1) "beijing"
2) "shanghai"
 
// 查询上海、北京、成都的经度纬度
127.0.0.1:6379> geopos mycity beijing shanghai tianjin
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
2) 1) "121.47000163793563843"
   2) "31.22999903975783553"
3) (nil)  # 不存在mycity中的城市位置,则返回nil
  1. geodist 返回指定2个成员之间的距离 (查询位置)

geodist key member1 member2… [m|km|ft|mi 单位可选]
geodist {key} {member1} {member2} [m|km|ft|mi ]

// 指定单位的参数 unit 必须是以下单位的其中一个
// 返回上海到北京的直线距离,单位为:km千米
127.0.0.1:6379> geodist mycity beijing shanghai km
"1067.3788" 
 
// 返回北京到天津的直线距离,成都在mycity中不存在,返回nil
127.0.0.1:6379> geodist mycity beijing tianjin
(nil)
  1. georadius 以给定的经纬度为中心,返回指定半径内的成员 (查询附近的人)

georadius key longitude latitude radius [m|km|ft|mi 单位可选]
georadius {key} {longitude} {latitude} radius m|km|ft|mi

# 返回经度120,纬度30 的周边500千米内的成员
127.0.0.1:6379> georadius mycity 120 30 500 km
1) "nanchang"
2) "hangzhou"
3) "shanghai"
4) "nanjing"
 
# 100千米内的成员
127.0.0.1:6379> georadius mycity 120 30 100 km
1) "hangzhou"
 
# 200千米内的成员
127.0.0.1:6379> georadius mycity 120 30 200 km
1) "hangzhou"
2) "shanghai"
 
# 200千米内的成员名称、12030与该成员位置的直线距离数、经纬度参数
127.0.0.1:6379> georadius mycity 120 30 200 km withdist withcoord
1) 1) "hangzhou"
   2) "30.8146"  # 直线距离
   3) 1) "120.1600000262260437"  
      2) "30.2400003229490224"
2) 1) "shanghai"
   2) "196.2512"
   3) 1) "121.47000163793563843"
      2) "31.22999903975783553"
 
# 返回1200千米内的成员名称 (count num 指定显示num个)
127.0.0.1:6379> georadius mycity 120 30 200 km count 1
1) "hangzhou"
  1. georadiusbymember 指定某成员为中心,返回指定半径内的成员 (查询附近的人)

georadiusbymember key longitude latitude radius [m|km|ft|mi]

# 返回上海的周边300千米内的成员名称
127.0.0.1:6379> georadiusbymember mycity shanghai 300 km
1) "hangzhou"
2) "shanghai"
3) "nanjing"
 
# 200千米内的成员名称
127.0.0.1:6379> georadiusbymember mycity shanghai 200 km
1) "hangzhou"
2) "shanghai"
 
# 返回上海的周边200千米内的成员名称、经纬度参数
127.0.0.1:6379> georadiusbymember mycity shanghai 200 km withcoord
1) 1) "hangzhou"
   2) 1) "120.1600000262260437"
      2) "30.2400003229490224"
2) 1) "shanghai"
   2) 1) "121.47000163793563843"
      2) "31.22999903975783553"
  1. geohash 获取一个或多个地理位置的hash值 (返回坐标hash值)

geohash key member1 member2…

# 返回上海、北京、杭州的坐标hash
127.0.0.1:6379> geohash mycity shanghai beijing hangzhou
1) "wtw3sj5zbj0"
2) "wx4fbxxfke0"
3) "wtmkn31bfb0"

Hyperloglog(基数)

hyperloglog 是用来做基数统计的,其优点是:输入的提及无论多么大,hyperloglog使用的空间总是固定的12KB ,利用12KB,它可以计算2^64个不同元素的基数!非常节省空间!但缺点是估算的值,可能存在误差
这个结构可以非常省内存的去统计各种计数,比如注册 IP 数、每日访问 IP 数的页面实时UV、在线用户数,共同好友数等。
Redis HyperLogLog 是一种基数算法,可以用于估计一个集合中的元素数量。Redis HyperLog 的特点如:
Redis HyperLogLog 是一种基数算法,可以用于估计一个集合中的元素数量。
Redis HyperLogLog 的误差率很小,通常在 0.81% 左右。
Redis HyperLogLog 的空间占用很小,通常只需要几 KB 的空间。

# 添加指定元素到 HyperLogLog 中
# PFADD key [element [element ...]]
127.0.0.1:6379> PFADD mykey1 a b c d e f g h i j
(integer) 1

# 返回给定 HyperLogLog 的基数估算值。
# PFCOUNT key [key ...]
127.0.0.1:6379> PFCOUNT mykey1
(integer) 10

# 将多个 HyperLogLog 合并为一个 HyperLogLog
# PFMERGE destkey sourcekey [sourcekey ...]
127.0.0.1:6379> PFADD mykey2 i j z x c v b n m
(integer) 1
127.0.0.1:6379> PFCOUNT mykey2
(integer) 9
127.0.0.1:6379> PFMERGE mykey3 mykey1 mykey2
OK
127.0.0.1:6379> PFCOUNT mykey3
(integer) 15

Bitmaps(位存储)

Redis提供的Bitmaps这个“数据结构”可以实现对位的操作。Bitmaps本身不是一种数据结构,实际上就是字符串,但是它可以对字符串的位进行操作。
Bitmap 即位图数据结构,都是操作二进制位来进行记录,只有0 和 1 两个状态。
比如:统计用户信息,活跃,不活跃! 登录,未登录! 打卡,不打卡! 两个状态的,都可以使用
可以把Bitmaps想象成一个以位为单位数组,数组中的每个单元只能存0或者1,数组的下标在bitmaps中叫做偏移量。单个bitmaps的最大长度是512MB,即2^32个比特位。

1.设置Bitmaps中某个偏移量的值(0或1)

setbit key offset value

2.获取Bitmaps中某个偏移量的值

getbit key offset

3.统计字符串从start字节到end字节比特值为1的数量

bitcount key [start end]

4.对多个Bitmaps的and(交集)、or(并集)、not(非)、xor(异或)操作并将结果保存在destkey中

bitop and(or/not/xor) destkey [key1 key2 ...]
127.0.0.1:6379> SETBIT sign:Bob:202201 1 1 # 设置 这里的 1|0 是二进制
(integer) 0
127.0.0.1:6379> SETBIT sign:Bob:202201 2 1
(integer) 0
127.0.0.1:6379> SETBIT sign:Bob:202201 3 0
(integer) 0
127.0.0.1:6379> SETBIT sign:Bob:202201 4 1
(integer) 0
127.0.0.1:6379> SETBIT sign:Bob:202201 5 1
(integer) 0
127.0.0.1:6379> SETBIT sign:Bob:202201 6 1
(integer) 0
127.0.0.1:6379> SETBIT sign:Bob:202201 7 1
(integer) 0
127.0.0.1:6379> GETBIT sign:Bob:202201 2 # 获取某天状态
(integer) 1
127.0.0.1:6379> BITCOUNT sign:Bob:202201 # 统计 位 1 的数量
(integer) 6

对指定key按位进行交、并、非、异或操作,并把结果保存到destKey中

127.0.0.1:6379> SETBIT sign:Bob:202201 1 1 # 设置 这里的 1|0 是二进制
(integer) 0
127.0.0.1:6379> SETBIT sign:Bob:202201 2 1
(integer) 0
127.0.0.1:6379> SETBIT sign:Bob:202201 3 0
(integer) 0
127.0.0.1:6379> SETBIT sign:Bob:202201 4 1
(integer) 0
127.0.0.1:6379> SETBIT sign:Bob:202201 5 1
(integer) 0
127.0.0.1:6379> SETBIT sign:Bob:202201 6 1
(integer) 0
127.0.0.1:6379> SETBIT sign:Bob:202201 7 1
(integer) 0
127.0.0.1:6379> GETBIT sign:Bob:202201 2 # 获取某天状态
(integer) 1
127.0.0.1:6379> BITCOUNT sign:Bob:202201 # 统计 位 1 的数量
(integer) 6

事务

// 1. multi命令开启事务,exec命令提交事务
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
// 2. 组队的过程中可以通过discard来放弃组队。
 127.0.0.1:6379> multi
OK
 127.0.0.1:6379(TX)> set k3 v3
QUEUED
 127.0.0.1:6379(TX)> set k4 v4
QUEUED
 127.0.0.1:6379(TX)> discard
OK

四、击穿

缓存已过期了,请求直奔数据库。

出现原因

  1. 热点Key过期

解决方案

查DB后同步Redis、Canal同步

  1. 设置热点key永不过期,但是非常占用空间对内存消耗也是极大。个人并不建议使用该方法,应该根据具体业务逻辑来操作。
  2. 加互斥锁:通过synchronized+双重检查机制 当发生reids穿透的时候,这时海量请求发送到数据库。保证了只有一个线程能够进行持久层数据查询,其它线程保持阻塞状态(可以让它们sleep几秒)。当这个进入数据库的线程查询出key对应的value时,我们再将其同步至redis的缓存当中,其它线程睡醒以后再重新去redis里边请求数据。
  3. 使用Timetask做一个定时任务 使用Timetask做定时,每隔一段时间对一些热点key进行数据库查询,将查询出的结果更新至redis中。前条件是不会给数据库过大的压力。

五、雪崩

大量的热点Key过期(Redis 宕机),请求全部打到DB,导致数据库极大压力飙升甚至宕机。

出现原因

  1. 大量Key同时失效
  2. Redis宕机

解决方案

过期时间添加随机值、接口限流

  1. 设置缓存时,随机初始化其失效时间
  2. 将不同的热点key放置到不同的节点上去
  3. 使用Timetask做一个定时任务,在失效之前重新刷redis缓存
  4. 时效设置成永不过期
  5. Redis高可用,搭建Redis集群(异地多活)
  6. 限流降级:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
  7. 数据预热,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀 。

六、穿透

查询不存在的数据(一般为恶意请求),请求直奔数据库,缓存系统形同虚设,对数据库产生很大压力从而影响正常服务。

出现原因

  1. 特殊请求在查询一个不存在的数据,即Redis不存在且数据库也不存在。

解决方案

布隆过滤器、设置缺省值

  1. 布隆过滤器,可以理解成一个白名单或者黑名单,它的作用就是判断一个元素是否存在于这个过滤器。
    白名单: 过滤器里有数据库中所有的合法的参数key,请求经过布隆过滤器,布隆过滤器判断这个请求的key在不在过滤器,在就放行让请求进入redis,不在就直接return空数据。
    在数据写入数据库的同时将这个 ID 同步到到布隆过滤器中,当请求的 id 不存在布隆过滤器中则说明该请求查询的数据一定没有在数据库中保存,就不要去数据库查询了。
  2. DB即使空值也讲其在Redis设置一个缺省值(比如:None)并设置一个过期时间,再访问这个数据将会从Redis中访问,保护了持久层的数据库
    a. 很多多余的空值
    b. 缓存与DB不一致,请求Redis导致查询结果不正确(不是真实DB数据)
  3. 拉黑其IP
  4. 对请求的参数进行合法性校验,在判断其不合法的前提下直接return跳出

七、集群同步

1. 主从复制

主从复制是高可用Redis的基础,哨兵和cluster都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。

优势:

  1. 读写分离:如果只有一台服务器,读和写操作都在一台服务器上进行,这台服务器的压力就会很大。而使用主从复制可以达到读写分离效果,写操作都在master主服务器进行,写操作进行完成之后,把内容复制到它的从服务器去;读操作都在slave从服务器进行。
  2. 容灾快速恢复:如果主服务器中进行写操作之后,复制到了从服务器(从服务器一般有多台),如果第一台从服务器在读的过程中突然挂掉,就会切换到另外一台从服务器进行读操作,此即为容灾快速恢复。

缺陷:故障恢复无法自动化,写操作无法负载均衡,存储能力受到单机的限制。

主从复制模式就是,部署多台redis节点,其中只有一台节点是主节点(master),其他的节点都是从节点(slave),也叫备份节点(replica)。只有master节点提供数据的事务性操作(增删改),slave节点只提供读操作。所有slave节点的数据都是从master节点同步过来的。

2. 哨兵(sentinel)

哨兵模式即为反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。

缺陷:故障恢复无法自动化,写操作无法负载均衡,存储能力受到单机的限制。

  1. 集群监控:负责监控 Redis master 和 slave 进程是否正常工作
  2. 消息通知:如果某个 Redis 实例出现故障,那么哨兵负责发送消息作为报警通知给管理员
  3. 故障转移:如果 master node 挂掉了,会自动转移到 slave node 上
  4. 配置中心:如果故障转移发生了,通知 client 客户端习新的 master 地址

3. 集群(Cluster)

通过集群,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案

主节点负责读写请求和集群信息的维护,从节点只进行主节点数据和状态信息的复制

  1. 数据分区

数据分区(或称数据分片)是集群最核心的功能(分布式)

集群将数据分散到多个节点,一方面突破了 Redis 单机内存大小的限制,存储容量大大增加,另一方面每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力

Redis 单机内存大小受限问题,例如,如果单机内存太大,bgsave 和 bgrewriteaof 的 fork 操作可能导致主进程阻塞,主从环境下主机切换时可能导致从节点长时间无法提供服务,全量复制阶段主节点的复制缓冲区可能溢出

  1. 高可用

集群支持主从复制(模式)和主节点的自动故障转移(与哨兵类似),当任意节点发送故障时,集群仍然可以对外提供服务

  1. 数据分片

Redis 集群引入了哈希槽的概念,有 16384 个哈希槽(编号 0~16383)

集群的每个节点负责一部分哈希槽,每个 Key 通过 CRC16 校验后对 16384 取余来决定放置哪个哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作

八、持久化

Redis是一种内存型数据库,一旦服务器进程退出,数据库的数据就会丢失,为了解决这个问题Redis供了两种持久化的方案,将内存中的数据保存到磁盘中,避免数据的丢失
两种持久化方式:快照(RDB文件)和追加式文件(AOF文件),下面分别为大家介绍两种方式的原理。

RDB(快照)

Redis中的RDB持久化方式,采用了写时复制技术(copy on write)和fork子进程。

RDB是Redis用来进行持久化的一种方式,是把当前内存中的数据集快照写入磁盘,也就是 Snapshot 快照(数据库中所有键值对数据),它可以手动执行,也可以在redis.conf配置文件中配置,定时执行,恢复时是将快照文件直接读到内存里。

Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,在用这个临时文件替换上次持久化好的文件.

整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能

如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效.

何时触发

自动触发

1. save

在这里插入图片描述
save:这里是用来配置触发 Redis的 RDB 持久化条件,也就是什么时候将内存中的数据保存到硬盘。比如“save m n”。表示m秒内数据集存在n次修改时,自动触发bgsave(这个命令下面会介绍,手动触发RDB持久化的命令)

当然如果你只是用Redis的缓存功能,不需要持久化,那么你可以注释掉所有的 save 行来停用保存功能。可以直接一个空字符串来实现停用:save “”

save 900 1 900s检查一次,至少有1个key被修改就触发
save 300 10 300s检查一次,至少有10个key被修改就触发
save 60 10000 60s检查一次,至少有10000个key被修改
2. stop-writes-on-bgsave-error

默认值为yes。当启用了RDB且最后一次后台保存数据失败,Redis是否停止接收数据。这会让用户意识到数据没有正确持久化到磁盘上,否则没有人会注意到灾难(disaster)发生了。如果Redis重启了,那么又可以重新开始接收数据了

3. rdbcompression

默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能,但是存储在磁盘上的快照会比较大。

4. rdbchecksum

默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。

5. dbfilename

设置快照的文件名,默认是 dump.rdb

6. dir

设置快照文件的存放路径,这个配置项一定是个目录,而不能是文件名。默认是和当前配置文件保存在同一目录。

也就是说通过在配置文件中配置的 save 方式,当实际操作满足该配置形式时就会进行 RDB 持久化,将当前的内存快照保存在 dir 配置的目录中,文件名由配置的 dbfilename 决定。

手动触发

1. save

该命令会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止。

显然该命令对于内存比较大的实例会造成长时间阻塞,这是致命的缺陷,为了解决此问题,Redis提供了第二种方式。

2. bgsave

执行该命令时,Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。具体操作是Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短。

基本上 Redis 内部所有的RDB操作都是采用 bgsave 命令。

ps:执行执行 flushall 命令,也会产生dump.rdb文件,但里面是空的,无意义

a. shutdown正常关闭

任何组件在正常关闭的时候,都会去完成应该完成的事。比如Mysql 中的Redolog持久化,正常关闭的时候也会去持久化。

b. flushall指令触发

数据清空指令会触发RDB操作,并且是触发一个空的RDB文件,所以, 如果在没有开启其他的持久化的时候,flushall是可以删库跑路的,在生产环境慎用。

恢复数据

将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可,redis就会自动加载文件数据至内存了。Redis 服务器在载入 RDB 文件期间,会一直处于阻塞状态,直到载入工作完成为止。

获取 redis 的安装目录可以使用 config get dir 命令
  在这里插入图片描述

停止 RDB 持久化

有些情况下,我们只想利用Redis的缓存功能,并不像使用 Redis 的持久化功能,那么这时候我们最好停掉 RDB 持久化。可以通过上面讲的在配置文件 redis.conf 中,可以注释掉所有的 save 行来停用保存功能或者直接一个空字符串来实现停用:save “”

也可以通过命令:

redis-cli config set save " "

优势

1.RDB是一个非常紧凑(compact)的文件,它保存了redis 在某个时间点上的数据集。这种文件非常适合用于进行备份和灾难恢复。
2.生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。
3.RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

劣势

  1. 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为数据完整性和一致性不高,因为RDB可能在最后一次备份时宕机,此前没有来得及写入磁盘的数据都将丢失,可能会丢失最后一次快照后的修改
  2. fork的时候,内存中数据被克隆了一份,需要考虑内存的使用,fork过程比较耗时,可能响应客户端的时间不能达到毫秒级,经常fork子进程,所以比较耗CPU,对CPU不是很友好
  3. 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。
  4. DB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建子进程,属于重量级操作(内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑),频繁执行成本过高(影响性能)
  5. RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式的RDB版本,存在老版本Redis服务无法兼容新版RDB格式的问题(版本不兼容)

AOF

以日志的形式来记录每个写的操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
Everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。

配置项写回时机优点缺点
Always同步写回可靠性高,数据基本不会丢失每个写命令都要落盘,性能影响较大
Everysec每秒写回性能适中宕机时丢失1秒内的数据
No操作系统控制的写回性能好宕机时丢失数据较多

base:表示基础AOF,一般由子进程重写产生,该文件最多只有一个。
incr:表示增量AOF,一般会在AOFRW开始执行时被创建,该文件可有多个。
history:表示历史AOF,由base和incr变化而来,每次AOFRW成功完成时,本次AOFRW之前对应的base和incr都会变成history,history类型的AOF会被redis自动删除

优势

AOF相对RDB更加安全,一般不会有数据的丢失或者很少,官方推荐同时开启AOF和RDB。

如果系统是愿意牺牲一些性能,换取更高的缓存一致性(AOF)
或者是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(RDB)。
Redis允许同时开启AOF和RDB,既保证了数据安全又使得进行备份等操作十分容易。此时重新启动Redis后Redis会使用AOF文件来恢复数据,因为AOF方式的持久化可能丢失的数据更少。

  1. 更好的保护数据不丢失:使用默认每秒写回策略也最多只会丢失一秒钟的写入
  2. 性能高:AOF仅是一个附加日志,不会出现寻道问题,也不会在断电时出现损坏问题,并且多数问题redis-check-aof工具能轻松修复它
  3. 可做紧急恢复:例如最后一条命令是flushall,只需要打开增量文件把flushall删除,再重启服务,数据就恢复到flushall之前了

劣势

  1. AOF文件通常比相同数据集的等效RDB文件大
  2. AOF运行效率要慢于RDB,每秒同步策略效率较好,不同步效率和RDB相同

触发

AOF也有不同的触发方案,这里简要描述以下三种触发方案:

always:每次发生数据修改就会立即记录到磁盘文件中,这种方案的完整性好但是IO开销很大,性能较差;
everysec:在每一秒中进行同步,速度有所提升。但是如果在一秒内宕机的话可能失去这一秒内的数据;
no:默认配置,即不使用 AOF 持久化方案。
可以在redis.config中进行配置,appendonly no改换为yes,再通过注释或解注释appendfsync配置需要的方案

RDB与AOF混合持久化

  1. 数据恢复顺序和加载流程:
    在这里插入图片描述
  2. 混合持久化中RDB持久化的必要性
    在混合持久化情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。
    RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。但是RDB更适合用于备份数据库(AOF在不断变化不好备份),留着rdb作为一个万一的手段。
  3. 混合持久化结合了RDB和AOF的优点,既能快速加载又能避免丢失过多的数据
    RDB镜像做全量持久化,AOF做增量持久化。
    先使用RDB进行快照存储,然后使用AOF持久化记录所有的写操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的RDB记录。这样的话,重启服务的时候会从RDB和AOF两部分恢复数据,既保证了数据完整性,又提高了恢复数据的性能。
    简单来说:混合持久化方式产生的文件一部分是RDB格式,一部分是AOF格式。----> AOF包括了RDB头部+AOF混写

应用场景:做纯粹的高并发高性能缓存服务器时
关闭RDB:save “”
关闭AOF:appendonly no
同时关闭RDB+AOF,但在RDB+AOF都禁用的情况下,仍然可以使用save/bgsave命令生成rdb文件,仍可以使用bgrewriteaof命令生成aof文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/781315.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

22matlab数据分析 拉格朗日插值(matlab程序)

1.简述 第一部分:问题分析 (1)实验题目:拉格朗日插值算法 具体实验要求:要求学生运用拉格朗日插值算法通过给定的平面上的n个数据点,计算拉格朗日多项式Pn(x)的值,并将其作为实际函数f(x)的估…

文心千帆为你而来

1. 前言 3月16号百度率先发布了国内第一个人工智能大语言模型—文心一言。文心一言的发布在业界引起了不小的震动。而文心一言的企业服务则由文心千帆大模型平台提供。文心千帆大模型平台是百度智能云打造出来的一站式大模型开发与应用平台,提供包括文心一言在内的…

文件被识别为病毒,被删除,如何解决

我们的文件有时候有用,但是电脑却识别为病毒,直接给我删除掉了,这让人是真的很XX,那该怎么办呐。 我最近用了这个方法很多次,蛮好用,分享给大家! 1、先找到安全中心 2、找不到排除项 3、点击添…

工程矩阵理论复习线路推荐

文章目录 写在前面复习线路推荐前期中期后期其他资料 写在前面 本篇博客仅适用于东南大学研究生 工程矩阵理论科目复习 对不少人来说,研究生的课程成绩相较于本科成绩不是那么重要了。但是由于工程矩阵还是比较有难度的,又很长时间没接触过数学&#x…

7-22练习

题目1 链接5071 不难发现通过A的范围可以缩小B的范围进而减少循环次数 通过B可以消除A的循环 这个是一个很巧妙的地方。这个题还有一个比较容易引起歧义的地方就是i:n每一次循环都要符合条件 这样我们不难构造出一个函数 f(B+x) = 1000*A+x 试验1 运行超时-- 需要减少复杂度…

时钟分频器

文章目录 一、8分频二、n倍时钟分频器 一、8分频 8倍时钟分频器是一种电路或设备,用于将输入时钟信号的频率分成原来的1/8。它可以在数字电子系统中用于将高频时钟信号降低到较低的频率,以满足特定的系统需求。 在这个电路中,CLK是输入的时钟…

【晓风残月】byte,short,int,long——八种基本类型

文章目录 前言废话不多说,总结下今天的成果以及踩的坑 一、第一个坑【数据丢失】二、第二个坑【byte集合无法转换byte数组】三、第三个坑【Byte[]转byte[]】四、第四个坑【16进制转byte】总结快一年没写博客了,貌似都不记得过去的自己了向前看&#xff1…

Camtasia2023电脑录屏视频自动生成字幕软件

制作视频通常需要添加字幕,添加字幕比较麻烦的是让字幕和声音同步,使用好的软件可以大大提高剪辑效率,让视频更快制作完成。本文将给大家介绍录制视频自动生成字幕的软件设置字幕语音同步教程。 一、录屏视频自动生成字幕的软件 Camtasia是…

查询优化之“查询分离”

什么业务场景需要使用查询分离 当数据在任何时候都可能被修改和查询的场景下,就不适合采用冷热分离来解决问题。而读写分离方案得到的工单查询速度提升是有限的,它主要还是用在数据库高并发的场景中。查询分离可以有效提升数据的查询效率,即…

【Ajax】笔记-JQuery发送请求与通用方法

Get请求 语法格式: $.get(url, [data], [callback], [type]) url:请求的 URL 地址。data:请求携带的参数。callback:载入成功时回调函数。type:设置返回内容格式,xml, html, script, json, text, _default。 准备三个按钮分别测试Get 、Post、通用型方…

PHP8知识详解:PHP8的应用领域

PHP 8 是一个通用的编程语言,可以用于开发各种类型的应用程序,包括 web 应用程序、移动应用程序、服务器端应用程序等等。由于 PHP 8 具有许多新的特性和改进,因此它可以更好地满足现代 Web 开发的需求,例如更快的执行速度、更好的…

关于我组件家庭服务器,挑选硬件设备的经历

目录 起因 升级——玩客云 原因 折腾日记 又升级——d2550工控主机 原因 折腾日记 又双升级——itx主机 原因 折腾日记 又双叒升级(目前再用的机器)——i9级x99平台e5v3主机 原因 折腾日记 心得 起因 起因大概在今年三月底四月初的时候&…

Linux磁盘分区、逻辑卷、交换分区管理

一.分区 1.MBR分区 2.GPT分区 二.磁盘分区管理 1.查看磁盘信息 2.添加磁盘 3.管理分区 (1)fdisk,默认划分为MBR的格式 (2)gdisk,默认默认划分为GPT的格式 (3)parted&#xf…

哈希:探索快速的数据存储和搜索方法

哈希:探索快速的数据存储和搜索方法 哈希表作为一种高效的数据存储结构,可以使数据的存储位置与关键码之间建立一一映射的关系,从而加快元素的搜索速度。然而,哈希方法也面临着哈希冲突的问题,即不同的关键字通过相同…

K8s中的核心概念

1.Pod (1)最小部署单元(2)一组容器的集合(3)共享网络(4)生命周期是短暂的 2.Controller (1)确保预期pod副本数量 (2)无状态应用部署 (3) 有状态应用部署 确保所有的node运…

Cmake笔记记录

工作后开发内容都是在Linux系统下完成,cmake使用比较频繁,找到一篇很不错的CMake笔记。 记录下来方便自己查阅。 目录 1.CMake介绍2.示例一:编译单个文件CMAKE_BUILD_TYPE 3.示例二:编译同个目录下多个文件aux_source_directory()…

Kubernetes_核心组件_kubelet_kubelet服务全解析(二)

文章目录 前言kubelet 架构kubelet 职责Node管理(节点管理)Pod管理 kubelet管理Podkubelet如何管理当前节点上所有Podkubelet三个端口kubelet获取Pod清单kubelet通过CRI接口管理Pod以及里面的容器 PodWorker的工作细节PodWorker的工作细节PLEG组件PLEG报错 kubelet创建并启动Po…

uni-app 使用安卓模拟器 mumu教程

第一步 去官网下载 这个直接下载就行 第二步 去uni-app 里面配置 在这里设置adb路径和模拟器端口 进去安装目录找到adb.exe 相关的就行我的是 D:/moniqi/MuMuPlayer-12.0/shell/adb.exe 端口设置的是 16385 但是不起作用 第三步 .\adb connect 127.0.0.1:7555 .\adb devi…

可证明安全初步(Provable Security Basics)

Speecher: Bingsheng Zhang 这一系列的课程,为了介绍一些基础,弥补一些上密码学课和看论文的Gap。 历史上的密码学是art,就像鲁班锁,看着很精妙,但是没有证明。 1970s以来,逐渐发展成Science。 定义和模…

【未来趋势】无屏幕笔记本

近日,来自以色列的科技公司Sightful推出了号称全球首台增强现实(AR)笔记本电脑——Spacetop。通过AR技术,用户可以拥有一块100英寸的虚拟屏幕,并且可以无视环境在任何地点办公,如咖啡店、公园、飞机上等等&…