Redis学习笔记

Redis【实战篇】---- 分布式锁-redission 重入问题:重入问题是指 获得锁的线程可以再次进入到相同的锁的代码块中,可重入锁的意义在于防止死锁,比如HashTable这样的代码中,他的方法都是使用synchronized修饰的,假如他在一个方法内,调用另一个方法,那么此时如果是不可重入的,不就死锁了吗?所以可重入锁他的主要意义是防止死锁,我们的synchronized和Lock锁都是可重入的。不可重试:是指目前的分布式只能尝试一次,我们认为合理的情况是:当线程在获得锁失败后,他应该能再次尝试获得锁。 阅读详情

redis特性

  • 快
    1. 基于内存操作,操作不需要跟磁盘交互
    2. 本身就是k-v结构,类似与hashMap,所以查询速度接近O(1)。
    3. 同时redis自己底层数据结构支持,比如跳表、SDS
    4. 命令执行是单线程,同时通信采用多路复用
    5. lO多路复用,单个线程中通过记录跟踪每一个sock(I/O流) 的状态来
      管理多个I/O流 。
  • 更丰富的数据类型 ,虽然都是k、v结构, value可以存储很多的数据类
    型。String、List、Hash、Set、ZSet、BitMap等。
  • 完善的内存管理机制、保证数据一致性。持久化机制、过期策略。
  • 支持多种编程语言。
  • 高可用,集群、保证高可用。主从、哨兵、cluster。

Redis的数据类型以及使用场景

Redis的基本数据类型包括String、Hash、List、Set、SortSet、BitMap等。

String

基本指令

在这里插入图片描述在这里插入图片描述

在这里插入图片描述

应用场景

在这里插入图片描述

  • 缓存,需要设置过期时间,过期时间之后保持与数据库最终一致性。
  • incr命令计数相关场景、自增的分布式id、点赞数、评论数。因为单线程,是线程安全的。

Hash

基本指令

hset h1 f 6 :对象h1的f字段设置值为6
hset h1 e 5:对象h1的e字段设置值为5
hmset h1 a 1 b 2 c 3 d 4:批量设置h1的字段
hget h1 a:获取对象h1的a字段
hmget h1 a b c d:批量获取h1对象的a、b、c、d字段
hkeys h1:h1对象的所有字段名字
hvals h1:h1对象的所有value
hgetall h1:获取h1整个对象
hincrby h1 a 10 给某个字段添加值

hexists h1 y :查询h1中y字段是否存在
hdel h1 a :删除h1对象的a字段
hlen h1:h1对象有多杀个字段

应用场景

  • 缓存
  • 存储对象类数据
  • 多维度的统计

List

可重复的有序列表

基本命令

lpush queue a:从左边添加元素a
lpush queue b c:从左边添加元素b c
rpush queue d e :从右边添加元素d e
lpop queue:左边弹出一条数据
rpop queue:右边弹出一条数据
blpop queue 10:阻塞从左边弹出
brpop queue 10:阻塞从右边弹出
lindex queue 0:取左边第一个元素
lrange queue 0 -1:获取所有元素

应用场景

  • 双端可阻塞队列
  • 朋友圈

Set

无序、不可重复的集合。如果集合中的元素全是整型,则是有序的。

基本命令

sadd huihuiset a b c d e f g:添加一个或者多个元素。
smembers huihuiset:获取所有元素。
scard huihuiset:获取集合中元素的个数。
srandmember huihuiset:随机获取一个元素。
spop huihuiset:随机弹出一个元素。
srem huihuiset g a:弹出指定元素。
sismember huihuiset e:查看元素是否存在。
sdiff huihuiset huihuiset1:获取huihuiset集合中有的,huihuiset1集合中没有的。
sinter huihuiset huihuiset1:获取两个集合的交集。
sunion huihuiset huihuiset1:获取两个集合的并集。

应用场景

  • 抽奖。spop和srandmember随机弹出(不可重复抽奖)、获取一个元素(可重复抽奖)。
  • 点赞、签到。sadd
  • 交集、并集,共同关注的场景。

Sort Set(ZSet)

有序的set,每个元素都有个score排序,score相同则按照key的ASCII码排序。
在这里插入图片描述

基本命令

zadd z1 10 a 20 b 30 d 40 c :放入元素。
zrange z1 0 -1 withscores:根据分数从低到高排序。
zrevrange z1 0 -1 withscores:根据分数从高到低排序。
zrangebyscore z1 20 30:根据分数范围取值。
zrem z1 a:移除元素。
zcard z1:获取z1中元素的个数。
zincrby z1 20 b:给z1集合中的b元素加分。
zcount z1 50 60:获取分数范围内元素的个数。
zrank z1 d:返回指定元素的索引。
zscore z1 d:获取元素的分数。

应用场景

  • 排行榜(热搜榜、游戏评分榜)

BitMap

基本命令

setbit permission 5 1 //把位5设置为1
getbit permission 5 //得到位5的值
bitcount permission //获取位为1的总数
bitpos permission 1 //获取 permission位为1的第一个位置
bitop AND hbit bitkey permission //获取bitkey与permission的&运算 并且赋值给hbit

应用场景

  • 每个学员每天的签到统计
  • 用户权限
  • 布隆过滤器

Redis的原子性

redis事务

127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr myid
QUEUED
127.0.0.1:6379> incr testid
QUEUED
127.0.0.1:6379> DISCARD
OK

127.0.0.1:6379> exec

  1. (integer) 1
  2. (integer) 1

命令说明:

  • multi:开启事务
  • incr myid、 incr testid事务中执行的内容
  • exec:执行事务
  • discard:回滚事务。

事务中的错误处理:
1.可能排队就错误,比如语法的错误 会报错给用户 并且丢失这次事务。
2.执行指令的失败,比如你对string类型执行incr 这种事务里面的其他指令
会正常执行,并且不提供回滚。

事务的特点及场景:

  • 命令是原子的 在执行事务中的指令时,服务器阻塞,不能执行其他指令。
  • 不能拿到事务中间的指令的结果 来决定后面指令的逻辑。

Lua脚本

lua语言是一个轻量级的脚本语言,致力于很容易嵌入其他语言中使用的语
言。所以依赖于其他宿主语言,自己不会有大而全的功能,但是可以调用
宿主语言的功能。

redis中完美契合了lua脚本功能 redis可以调用lua脚本中的api,lua脚本也
可以调用redis中的指令。

Lua脚本的使用场景:

  • 需要原子性地执行多个命令
  • 需要中间值来组合后面的命令

pipelining管道技术

什么事pipelining?

redis的请求:
客户端发送一个请求给服务端----->客户端等待服务器响应—>服务器收到请
求并处理---->返回客户端
客户端到服务端是需要时间的,包括网络传输、建立连接,这个时间叫RTT时间(Round Trip Time)。为了避免多次的RTT时间,Redis有了管道技术。

使用场景

  • 在客户端下次写之前不需要获取读的场景的大数据量并发写入的场景。
  • 对性能有要求
  • 管道里的命令不具备原子性,只能保证某个客户端发送的指令是顺序执 行的,但是多客户端的命令会交叉执行
  • 不需要以上一个指令的返回结果来判断后续的逻辑

订阅与发布

订阅

subscribe指令
127.0.0.1:6379> subscribe huihui huihui1
Reading messages… (press Ctrl-C to quit)

  1. “subscribe”
  2. “huihui”
  3. (integer) 1
  4. “subscribe”
  5. “huihui1”
  6. (integer) 2

也可以模糊订阅 psubscribe
代表0个或者多个字符 ?代表1个字符
127.0.0.1:6379> psubscribe h
j*
Reading messages… (press Ctrl-C to quit)

  1. “psubscribe”
  2. “h*”
  3. (integer) 1
  4. “psubscribe”
  5. “j*”
  6. (integer) 2
  7. “pmessage”
  8. “h*”
  9. “huihui”
  10. “message”

发布

192.168.8.129:6379> publish huihui message
(integer) 2 //接收消息的客户端的数量

我们消费端得到消息
127.0.0.1:6379> subscribe huihui huihui1
Reading messages… (press Ctrl-C to quit)

  1. “subscribe”
  2. “huihui”
  3. (integer) 1
  4. “subscribe”
  5. “huihui1”
  6. (integer) 2
  7. “message”
  8. “huihui”
  9. “message”

Redis实现分布式锁

什么是分布式锁?

synchronize、Lock接口等都是单机锁,分布式系统中的分布式锁应该独立于我们的业务服务,如用redis中间件实现。
分布式锁的特性:

  • 只能有一个线程访问互斥资源
  • 其他线程要么等待要么报错

Redis实现分布式锁思路

exist+set+expire
判断key是否存在,存在则说明有人持锁,自旋等待。否则set锁的值,并加上过期时间,过期时间是给锁加个超时时间,避免死锁。释放锁的时候,把这个key删除掉。

上面的思路仍然有问题:

  • 几个命令不能保证原子性,因此需要lua脚本。
  • 如果锁30秒过期,但是业务未执行完,锁失效,其他线程进入,导致加锁失败。需要看门狗续过期时间。
  • 做成可重入锁,非重入锁如果遇到自己等自己释放,容易死锁。

Redission实现的分布式锁

Redission分布式锁的流程图

在这里插入图片描述

  • 分布式锁中存的是hash类型,根据key(大key)获取锁。
  • hash对象中有个字段UUID+线程ID,值是这个线程的重入次数。
  • waitTime是获取锁时的等待时间,超过这个时间则获取锁失败。
  • releaseTime是锁的释放时间。
  • 锁到时间了,但是但是业务没执行完了,需要看门狗机制,看门狗用的是时间轮。
  • 通过发布订阅,释放锁时,别人可以感应到。解锁时发布消息。
  • 时间轮:HahsedWheelTimer,异步延时执行任务的工具类。

Redis扩容机制

数据机构图

在这里插入图片描述
Redis发生Hash冲突为什么要头插?而HashMap为什么1.8之后要尾插?

  • 因为头插在并发情况下会形成死链 而Redis是单线程执行,不会存在并发
    问题,也不会形成死链表。
  • 而头插的性能比尾插的性能高很多,尾插必须找到链表的最后一个位置,
    而头插只需要加到数据下标,并且把next指向之前的第一个数据。

为什么需要扩容?
因为不扩容,查询速度就是接近链表的速度,是O(n)。链表过长,遍历性能差。

什么时候扩容?

  • 当没有fork子进程在进行RDB或者AOF持久化(内存的数据保存到磁盘防
    止丢失,后面详细讲解)时,ht[0]的used大于等于size时,触发扩容
  • 如果有子进程在进行RDB或者AOF时,ht[0]的used大于等于size的5倍的
    时候,会触发扩容 。

怎么扩容

  1. 当满足我扩容条件,触发扩容时,判断是否在扩容,如果在扩容,或者
    扩容的大小跟我现在的ht[0].size一样,这次扩容不做。
  2. new一个新的dictht,大小为ht[0].used * 2(但是必须向上2的幂,比
    如6 ,那么大小为8) ,并且ht[1]=新创建的dictht。
  3. 我们有个更大的table了,但是需要把数据迁移到ht[1].table ,所以将
    dict的rehashidx(数据迁移的偏移量)赋值为0 ,代表可以进行数据迁
    移了,也就是可以rehash了。
  4. 等待数据迁移完成,数据不会马上迁移,而是采用渐进式rehash,慢慢
    的把数据迁移到ht[1],等下我们讲
  5. 当数据迁移完成,ht[0].table=ht[1] ,ht[1] .table = NULL、ht[1] .size
    = 0、ht[1] .sizemask = 0、 ht[1] .used = 0;
  6. 把dict的rehashidex=-1

怎么进行数据迁移?

采用渐进式迁移
何时迁移:
1.每次进行key的crud操作都会进行一个hash桶的数据迁移
2.定时任务,进行部分数据迁移

Redis持久化

为什么需要持久化?

redis是基于内存的,数据存储在内存中。如果断电或者关机,数据就会丢失,因此需要持久化。

持久化的方式有哪些?

  • RDB:RDB是redis默认的持久化方案,RDB快照(Redis DataBase),当满足一定条件时,会把内存中的数据写入磁盘,生成一个快照文件dump.rdb(默认)。
  • AOF:由于RDB的数据可靠性低,所以redis又提供了另外一种持久化方案,Append Only File,简称AOF。AOF默认是关闭的,以追加文件的形式,每次更改的命令都会追加到AOF文件中。

RDB

RDB默认开启,默认生成的快照文件时dump.rdb,文件名字和路径可以通过下面形式配置。

# The filename where to dump the DB
dbfilename dump.rdb //dunmp.rdb文件名
dir ./ //文件路径

什么时候触发RDB呢?

自动触发
  1. 配置触发
save 900 1 900s检查一次,至少有1个key被修改就触发
save 300 10 300s检查一次,至少有10个key被修改就触发
save 60 10000 60s检查一次,至少有10000个key被修改
  1. shutdown正常关闭
    任何组件,再正常关闭的时候,都会去完成该完成的事情,比如Mysql
    中的Redolog持久化 正常关闭的时候也会去持久化。
  2. flushall指令触发
    数据清空指令会触发RDB操作,并且是触发一个空的RDB文件,所以,
    如果在没有开启其他的持久化的时候,flushall是可以删库跑路的,在
    生产环境慎用。
手动触发
  • save 主线程去进行备份,备份期间不会去处理其他的指令,其他指令
    必须等待
  • bgsave 子线程去进行备份,其他指令正常执行。

备份流程

  • 新起子线程,子线程会将当前Redis的数据写入一个临时文件。
  • 当临时文件写完成后,会替换旧的RDB文件。
  • 当Redis启动的时候,如果只开启了RDB持久化,会从RDB文件中加载数
    据。

RDB的优势与不足

优势(快)
  • 是个非常紧凑型的文件,非常适合备份与灾难恢复。
  • 最大限度的提升了性能,会fork一个子进程,父进程永远不会产于磁盘
    IO或者类似操作。
  • 更快的重启。
劣势
  • 数据安全性不是很高,因为是根据配置的时间来备份,假如每5分钟备份
    一次,也会有5分钟数据的丢失
  • 经常fork子进程,所以比较耗CPU,对CPU不是很友好。

AOF

由于RDB的数据可靠性非常低,所以Redis又提供了另外一种持久化方案:
Append Only File 简称:AOF

AOF默认是关闭的,你可以再配置文件中进行开启:

appendonly no //默认关闭,可以进行开启,yes 是开启
# The name of the append only file (default:
"appendonly.aof")
appendfilename "appendonly.aof" //AOF文件名

追加文件,即每次更改的命令都会附加到我的AOF文件中。

AOF同步机制(什么时候写AOF文件)

AOF,会记录每个写的操作,那么问题来了?我难道每次操作命令又得跟磁
盘交互呢?不跟mysql一样每次需要跟磁盘交互呢?

当然不行,所以,redis支持几种策略,由你们自己来决定要不要每次都跟
磁盘交互。

# appendfsync always 表示每次写入都执行fsync(刷新)函数 性能会
非常非常慢 但是非常安全
appendfsync everysec 每秒执行一次fsync函数 可能丢失1s的数据。(默认)
# appendfsync no 由操作系统保证数据同步到磁盘,速度最快 你的数
据只需要交给操作系统就行

AOF重写机制

由于AOF是追加的形式,所以文件会越来越大,越大的话,数据加载越慢。
所以我们需要对AOF文件进行重写。

何为重写

比如 我们的incr指令,假如我们incr了100次,现在数据是100,但是我们
的aof文件中会有100条incr指令,但是我们发现这个100条指令用处不大,
假如我们能把最新的内存里的数据保存下来的话。
所以,重写就是做了这么一件事情,把当前内存的数据重写下来,然后把
之前的追加的文件删除。

重写流程

在Redis7之前:

  1. Redis fork一个子进程,在一个临时文件中写入新的AOF (当前内存的
    数据生成的新的AOF)
  2. 那么在写入新的AOF的时候,主进程还会有指令进入,那么主进程会在
    内存缓存区中累计新的指令 (但是同时也会写在旧的AOF文件中,就算
    重写失败,也不会导致AOF损坏或者数据丢失)
  3. 如果子进程重写完成,父进程会收到完成信号,并且把内存缓存中的指
    令追加到新的AOF文件中
  4. 替换旧的AOF文件 ,并且将新的指令附加到重写好的AOF文件中。
何时重写

配置文件redis.conf

# 重写触发机制
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb 就算达到了第一个百分比的大小,也
必须大于 64M

举例说明上述配置的意义
在 aof 文件小于64mb的时候不进行重写,当到达64mb的时候,就重写一
次。重写后的 aof 文件可能是40mb。上面配置了auto-aof-rewritepercentag
为100,即 aof 文件到了80mb的时候,进行重写。

AOF的优势与不足

优势

1.安全性高,就算默认的持久化同步机制,也最多只会导致1s丢失。
2.AOF由于某些原因,比如磁盘满了等导致追加失败,也能通过redischeck-
aof 工具来修复
3.格式都是追加的日志,所以可读性更高

劣势
  1. 数据集一般比RDB大
  2. 持久化跟数据加载比RDB更慢
  3. 在7.0之前,重写的时候,因为重写的时候,新的指令会缓存在内存
    区,所以会导致大量的内存使用
  4. 并且重写期间,会跟磁盘进行2次IO,一个是写入老的AOF文件,一个
    是写入新的AOF文件

Redis集群

主从

为什么要有主从?

  1. 故障恢复 主挂了或者数据丢失了,我从还会有数据冗余
  2. 负载均衡,流量分发 我们可以主写,从库读,减少单实例的读写压力
  3. 高可用 我们等下讲的集群 等等,都是基于主从去实现的。

主从数据同步

info replication

我们发现,我们的信息中,有个slave_read_only,如果是1 代表只读,也
就是默认,当然也可以配置成可写,但是写的数据不会同步到主库,需要
自己去保证数据一致性,可能从库写的数据会被主库的数据操作覆盖。出
现在从库set一个值后,获取到的是主库覆盖的数据。

从库如何从主库同步数据的?

建立连接

当首次成为主节点的从节点时,执行replicaof ip port命令的时候就会保存
主服务器的IP与端口
并且与主服务器建立连接,接收主节点返回的命令
判断主节点是否有密码,如果有,进行权限校验
保证主从之间保存了各自的信息,并正常连接

slave发起同步master数据指令

在slave的serverCron方法调用replicationCron方法,里面会发起跟
master的数据同步。

全量同步
  1. master服务器收到slave的命令后(psync),判断slave传给我的
    master_replid 是否跟我的replid一致,如果不一致或者传的是个空
    的,那么就需要全量同步。
    备注:4.0之前,用的是runId,但是runId每次实例重启时都会改变,会导致主从切换或者重启的时候,都需要全量同步,所以4.0之后采用replid。
    replid有master_replid跟master_replid2,当主从切换的时候,我升级
    为master的slave会继承之前master的replid,所以不需要每次主从切
    换,都触发全量同步。同时slave会把master的master_replid持久化到磁盘。

  2. slave首次关联master,从主同步数据,slave肯定是没有主的replid,所以需要进行全量同步。

  3. 进行全量同步

    • master开始执行bgsave,生成一个RDB文件,并且把RDB文件传输
      给我们的slave,同时把master的replid以及offerset(master的数
      据进度,处理完命令后,都会写入自身的offerset)。
    • slave接收到rdb文件后,清空slave自己内存中的数据,然后用rdb
      来加载数据,这样保证了slave拿到的数据是master生成rdb时候的
      最新数据。
    • 由于master生成RDB文件是用的bgsave生成,所以,在生成文件的
      时候,是可以接收新的指令的。那么这些指令,我们需要找一个地
      方保存,等到slave加载完RDB文件以后要同步给slave。
      • 看在master生成rdb文件期间,会接收新的指令,这些新的指令会
        保存在一个内存区间,这个内存区间就是replication_buffer。
        我们可以通过以下方式设置replication_buffer的大小:
      • 这个空间不能太小,如果太小,为了数据安全,会关闭跟从库
        的网络连接。再次连接得重新全量同步,但是问题还在,会导
        致无限的在同步。
client-output-buffer-limit replica 256mb 64mb 60
256mb 硬性限制,大于256M断开连接
64mb 60 软限制 超过64M 并且超过了60s还没进行同步
内存数据就会断开连接
增量同步

我们刚才有说过,每个节点都会保存数据的偏移量(从0开始,随着数据的
添加递增)。那么就有可能出现slave跟master网络断开一小会,然后发起
数据同步的场景,如图:
在这里插入图片描述
slave1由于网络断开,偏移量跟master差了3。
当slave1重新与master连接上时,不需要全量同步,只需要增量同步即可。
所以当master收到slave的指令时:

  1. 判断slave1传给我的master_replid 是否跟master的replid一致,由于之前已经连接过保过了master的replid,满足条件。
  2. 所以我希望只同步断开连接后没有同步到的数据,slave1只差了3的数据。那么我需要找到这个3的数据。所以master中有个另外的积压缓存(replication_backlog_buffer)。我们可以设置replication_backlog_buffer的大小:
# The bigger the replication backlog, the longer the
time the replica can be 复制积压越大,复制副本的时间越长
# disconnected and later be able to perform a partial
resynchronization. 已断开连接,稍后可以执行部分重新同步。
#
# The backlog is only allocated once there is at least
a replica connected. 只有在至少连接了一个副本后,才会分配积压工
作。
#
# repl-backlog-size 1mb

我们也不可能无限制的往里面写数据, replication_backlog_buffer的数据是会覆盖的。
3. 所以,我们slave1跟master相差的3条数据可能会被覆盖,如果覆盖了,触发全量,如果没有覆盖,即能找到相差的3条数据。增量即可。

指令同步

master写入的指令,异步同步至slave,如果有slave,写入
replication_backlog_buffer
在这里插入图片描述

哨兵

主从解决了负载、数据备份的问题,但是主节点挂掉后,从节点不能自动升级为主节点,必须手动升级。哨兵就能解决自动升级的问题。

哨兵提供了监测、通知、自动故障转移、配置提供等功能。

  • 监测:监测redis各个实例是否正常工作。
  • 通知:如果redis的实例出现问题,能够通知其他redis实例,以及sentinel。
  • 自动故障转移:当master宕机,slave可以自动升级为master。
  • 配置提供:sentinel可以提供redis的master地址,因此客户端只需要和sentinel连接即可。
    在这里插入图片描述

哨兵故障转移的流程

首先,我们要知道,sentinel与sentinel之间,以及sentinel与master/slave之间都会进行通信。

发现故障
  1. 当我们某个sentinel 跟master通信时(默认1s发送ping),发现我在一定时间内(down-after-milliseconds) 没有收到master的有效的回复。这个时候这个sentinel就会人为master是不可用,但是有多个sentinel,它现在只有1个人觉得宕机了,这个时候不会触发故障转移,只会标记一个状态,这个状态就是SDOWN(Subjectively Down
    condition ),也就是我们讲的主观下线。
  2. SDOWN时,不会触发故障转移,会去询问其他的sentinel,其他的sentinel是否能连上master,如果超过Quorum(法定人数)的sentinel都认为master不可用,都标记SDOWN状态,这个时候,master可能就真的是down了。那么就会将master标为ODOWN(Objectively Downcondition 客观下线)
进行故障转移(哪个sentinel做?)
  1. 当状态为ODWON的时候,我们就需要去触发故障转移,但是有这么多的sentinel,我们需要选一个sentinel去做故障转移这件事情,并且这个sentinel在做故障转移的时候,其他sentinel不能进行故障转移。
  2. 所以,我们需要选举一个sentinel来做这件事情:其中这个选举过程有2个因素。
    1. Quorum如果小于等于一半,那么必须超过半数的sentinel授权,你才能去做故障迁移,比如5台 sentinel,你配置的Quorum=2,那么选举的时候必须有3(5台的一半以上)人同意
    2. Quorum如果大于一半,那么必须Quorum的sentinel授权,故障迁移才能启动。
选举问题(哪个slave成为master?)
  1. 与master的断开连接时间
    如果slave与主服务器断开的连接时间超过主服务器配置的超时时间(down-after-milliseconds)的十倍,被认为不适合成为master。直接去除资格
  2. 优先级
    https://redis.io/docs/manual/sentinel/#replica-selection-and-priority
    配置 replica-priority,replica-priority越小,优先级越高,但是配置为0的时候,永远没有资格升为master
  3. 已复制的偏移量
    比较slave的赋值的数据偏移量,数据最新的优先升级为master
  4. Run ID (每个实例启动都会有个Run ID )
    通过info server可以查看。

sentinel导致的数据一致性问题

官方建议配置至少3个sentinel。且redis的实例个数建议是奇数,因为4个和3个是一样的。

脑裂问题

脑裂问题其实就是我会有2个master,client会从不同的master写数据,从而在master恢复的时候数据丢失。所以只要发生分区容错行,不管多少个节点都可能出现脑裂。

脑裂问题解决方案

在Redis.cfg文件中有2个配置:

min-replicas-to-write 1 至少有1个从节点同步到我主节点的数
据,但是由于是异步同步,所以是最终一致性 不会确保有数据写入
min-replicas-max-lag 10 判断上面1个的延迟时间必须小于等于10s

Cluster

sentinel提供了比如监控、自动故障转移、客户端配置等,高可用方案,但是没有分片功能。Cluster是比sentinel更高级的集群方案。

什么是分片?

把数据分配到不同节点,如果某些节点数据异常,其他节点可以正常工作。类似于微服务的思想。

Cluster的特点?

  • 多个节点之间的数据拆分,即数据分片。
  • 某个节点故障,其他节点还能提供服务。

虚拟槽(hash slot)

如何进行分片?

分片就是把不同的数据分配到对应的实例中,相当于分表。

如何将数据分配的对应的实例中呢,一般是按实例数进行取模。但是有缺点,实例需要扩容或者缩容,全部数据需要迁移,因此引入虚拟槽的概念,也就是虚拟节点。

redisCluster中有16384个虚拟槽。

key与虚拟槽的关系?

slot = CRC16(key) & 16383

key跟虚拟槽的关系是根据key算出来的,后序不变。

虚拟槽与真实节点间的关系?

我们的虚拟槽会跟我们的真实节点进行对应,这个关系是可以变更的。可以设置某个实例节点包含哪些虚拟槽,但是至少得有3个主实例节点,主节点可以有自己的从节点。
假如,我们现在有6台实例,三主三从。 主跟槽的对应关系如下
master1 0-5460虚拟槽
master2 5461-10922虚拟槽
master3 10923-16383虚拟槽

我们可以知道,k1 的虚拟槽是10001 ,所以放入master3,k2的虚拟槽是10 放入master1 ,k3的虚拟槽为666,放入master2。从节点的数据全部来源于主,所以k1放入master3的从,以此对应。

我们可以通过指令查看当前节点的虚拟槽信息

127.0.0.1:6380> cluster nodes 查看当前节点的虚拟槽信息

每次的节点的扩容与缩容,只需要改变节点跟虚拟槽的关系即可,不需要全部变动。

节点移动、宕机故障转移、扩容缩容

【Redis】分布式锁之 Redission 本文主要介绍了基于setnx实现的分布式锁存在的问题,包括重入问题、不可重试、超时释放和主从一致性问题。接着介绍了 Redission 的快速入门方法,包括引入依赖、配置客户端和使用分布式锁。然后详细阐述了 Redission 可重入锁原理、锁重试和 WatchDog 机制以及锁的 MutiLock 原理,为读者深入理解 Redission 分布式锁提供了全面的参考。 阅读详情

相关推荐

STM32 ADC精准采集12V电池电压:从分压电路到软件校准全解析

本文详细解析了STM32 ADC精准采集12V电池电压的全过程,涵盖分压电路设计、电阻选型、ADC配置优化及软件校准方法。针对电池电压监测中的噪声、温漂等挑战,提供了硬件滤波与软件过采样等实战技巧,确保测量精度达到1%以内,满足嵌入式设备对电源管理的严苛要求。

tech5的博客 1012

Redis之Redisson原理详解

Redisson顾名思义,Redis的儿子,本质上还是Redis加锁,不过是对Redis做了很多封装,它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。

上善若泪 6398

Claude Code vs Codex

Claude Code 提供了一个生产就绪(production-ready)的实现,包含良好的错误处理、优雅的关闭逻辑、详细注释和文档,以及内置测试。Claude Code 输出了一个可运行的 Next.js + TypeScript 前端,但错过了一些设计里的黄色主题元素;Codex 则生成自己的版本,没有导出设计中的图片,也没严格遵照设计主题。Codex 完成同样功能,但更简洁直接,文档和注释少一些但功能达标。任务都用同样的提示,使用 TypeScript 实现,并在一天内完成。

weixin_49869937的博客 2385

redis事务及类事务回滚机制

目录 前言 一、redis事务 二、通过redis-cli体验redis事务相关命令 1.开启事务 2.放弃事务 3.redis事务中的命令正确而数据类型错误、命令错误时的执行情况 (1)、第一种情况-Redis 事务遇到的命令正确而数据类型不符合 (2)、第二种情况-Redis 命令有错,事务中所有的命令都不会执行 三、总结 前言 今天记录一下对redis事务的探索过程,各位看到此博客的小伙伴,如有不对的地方请及时通过私信我或者评论此博客的方式指出,以免误人子弟。多谢! 首

FAIRYTAIL的博客 4349

Delta并联机械手-Codesys实现以及正解逆解研究

由于Codesys的Robotics模块有Delta并联机械手的运动模型,因此借助Codesys的机械手运动模型,研究自己的正解逆解算法。

weixin_42386991的博客 5561

深入解析路科验证V0实验lab1:SV接口与时钟块实战

本文深入解析了路科验证V0实验Lab1的核心内容,重点阐述了SystemVerilog接口与时钟块在验证环境搭建中的关键作用。通过拆解router_io接口设计、时钟块同步机制及程序块封装,详细讲解了如何构建稳定可靠的验证通信基础,并提供了复位时序分析与常见调试技巧,为后续复杂验证打下坚实基础。

peach的博客 430

Redis和Redission两种方式实现分布锁

在高并发请求下,使用分布式锁来保证系统可用性,防止数据库因请求过大而宕机。

weixin_45150104的博客 7607

2026年(新服务器默认密码)最新各大厂商默认凭证大全

本文整理了国内外主流服务器厂商的默认管理接口凭证信息,包括Dell、HPE、浪潮、华为等品牌的管理接口类型、默认用户名/密码和IP地址。特别强调国产服务器在信创环境下的安全风险,指出国内厂商部分型号仍保留固定默认密码(如浪潮admin/admin),而国际厂商多采用随机密码标签。文章提供了新机初始化安全流程建议:查找机箱标签、立即修改默认密码、配置网络隔离、更新固件等。最后提醒运维人员,服务器安全应从首次上电开始重视,管理接口暴露是重大风险点,必须严格执行安全规范。

你好,旧时光! 1696

Redis技术学习笔记

Redis 是一个高性能的key-value数据库。redis的出现,很大程度补偿了memcached这类keyvalue存储的不足,在部 分场合可以对起到很好的补充作用。它提供了Python,Ruby,Erlang,PHP,使用很方便。

qq_739988982的博客 1821

TMS320F280049C 学习笔记21 交叉开关 Crossbar (X-BAR)

简单介绍了X-BAR。

whyorwhnt的专栏 2万+

对工时评估的思考:当AI颠覆了coding效率

在AI时代,“人日”作为软件工时度量衡已然失效。开发的价值核心正从“编码实现”转向“深度思考”与“精准沟通”——即如何将人类的模糊需求精确地传达给AI。当最有价值的“思想工作”变得最难量化时,传统的项目管理范式随之动摇。我们必须超越对过程的算计,开始探索衡量思想、沟通与业务价值的新标尺。

架构师刘7的博客 1017

redis基础学习笔记

1. 单机MySQL的年代90年代,一个基本的网站访问量一般不会太大,单个数据库完全足够!那个时候,更多的去使用静态网页 Html~服务器根本没有太大的压力!思考一下,这种情况下 : 整个网站的瓶颈是什么?数据量如果太大,一个机器放不下数据的索引(B+ Tree),一个机器内存也放不下访问量(读写混合),一个服务器承受不住2. Mencached(缓存)+MySQL+垂直拆分(读写分离)站80%的情况都是在读,每次都要去查询数据库的话就十分的麻烦!

weixin_43977307的博客 1908

ZYNQ GP总线实现PS与PL交互

3,完成 ZYNQ7 Processing System 的配置更改后,回到 Diagram 界面中,可以看到新出现了名为 M_AXI_GP0_ACLK、M_AXI_GP0 和 FCLK_CLK0 的接口,下面我们要对这些接口进行连接或引出。此处的偏移量,AXI的相邻寄存器偏移量相差4个字节,默认slv_reg0的偏移量是0,可以推导出slv_reg1,slv_reg2的偏移量分别为4和8,这里只用到了slv_reg0,所以偏移量为0。当然了,窗口数量的增加,势必会使得单个窗口的采样深度变小。

wangjie36的博客 7094

redis学习笔记

redis学习笔记 #步骤 论坛 商城 app 小程序 mysql 关系型数据库 redis mongo es nosql(非关系型数据库) 关系:互补关系 特点:具体看应用场景 第一天--redis介绍 单节点 1.介绍 2.安装部署 3.配置文件介绍 4.redis基础命令 5.数据持久化 结构: 1.主从复制 2.哨兵 3.集群 运维 redis常用运维工具 故障...

三思博客 389

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

博客目录——Redis学习笔记

【Redis学习笔记】Redis笔记(一)——特点、基础命令和数据结构 【Redis学习笔记】Redis笔记(二)——Redis客户端

roguesir的博客 883

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

redis学习笔记-XMind

** redis学习笔记-XMind **

doubanjiangjiang的博客 481

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Redis学习笔记(基础篇)

SQLNoSQL数据结构结构化非结构化数据关联关联的无关联查询方式SQL查询非SQL事务特性ADIDBASE存储方式磁盘内存扩展性垂直水平使用场景1)数据结构固定 2)对一致性、安全性要求较高1)数据结构不稳定 2)相关业务对数据安全性、一致性要求不高 3)对性能有要求。

qq_63003916的博客 1278
上一篇: 设计模式之责任链模式
下一篇: Spring 三级缓存解决循环依赖源码分析
ludkjava
博客等级 码龄11年 173粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值