Redis集群相关

news2025/1/18 10:45:19

目录

一、Redis主从集群

主从数据同步原理

全量同步

1)为什么是基本一致而不是完全一致呢?

2)上述过程还有一个问题,怎么判断是不是第一次同步?

增量同步

1)master节点怎么知道slave节点与自己的数据差异在哪里呢?

2)那么如何减少repl_baklog大小上限超出问题的出现呢?

全量同步和增量同步的区别

二、Redis哨兵

背景

哨兵工作原理

1)Sentinel怎么知道一个Redis节点是否宕机呢?

主观下线

客观下线

2)如何选举新的master?

3)如何实现故障转移?

三、Redis分片集群

背景

散列插槽

插槽原理

1)那为什么要做这个插槽呢?

2)那为什么数据key要与插槽绑定而不是与节点绑定?

3)Redis如何判断某个key应该在哪个实例?

4)如何将同一类数据固定的保存在同一个Redis实例?

集群伸缩

故障转移

手动转移


一、Redis主从集群

单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。

主从数据同步原理

全量同步

主从第一次建立连接时,会执行全量同步,将master节点的所有数据都拷贝给slave节点。

具体流程:判断是否是第一次同步,如果是,返回版本信息(replication id 和offset),将salve节点的版本信息变为master的,随后进行全量同步。全量同步,即为进行bgsave命令进行异步生成RDB快照并发送给salve节点,salve节点拿到RDB快照之后就等于拿到了master主节点的数据,接下来把salve节点自己本地的数据情清空,然后把RDB快照加载到内存中。此时就能确保主从节点上的数据基本一致。

1)为什么是基本一致而不是完全一致呢?

因为在生成RDB快照过程中,主进程还可能会去处理用户的请求,就意味着还可能在新的数据写入。这些写操作会进入repl_baklog缓冲区,repl_baklog缓冲区里记录的就是在这个RDB期间收到的一些新的写命令。最后把这些写命令也发送给slave节点,就完成了主从数据的一致。

2)上述过程还有一个问题,怎么判断是不是第一次同步?

判断依据:

  • Replication Id:简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid。
  • offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。

因此slave节点做数据同步,必须向master节点声明自己的replication id 和offset,master节点才可以判断到底需要同步哪些数据。

因为slave节点原本也是一个master节点,有自己的replid和offset,(宕机重启后)当第一次变成slave节点,与master节点建立连接时,发送的replid和offset是自己的replid和offset。master节点判断发现slave节点发送来的replid与自己的不一致,说明这是一个全新的slave节点,就知道要做全量同步了。master节点会将自己的replid和offset都发送给这个slave节点,slave节点保存这些信息。以后slave节点的replid就与master节点一致了。因此,master节点判断一个节点是否是第一次同步的依据就是看replid是否一致

因此,完整流程描述如下:

  1. slave节点请求增量同步。
  2. master节点判断replid,发现不一致,拒绝增量同步。
  3. master节点将完整内存数据生成RDB,发送RDB到slave节点。
  4. slave节点清空本地数据,加载master的RDB节点。
  5. master节点将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave节点。
  6. slave节点执行接收到的命令,保持与master节点之间的同步。

增量同步

全量同步需要先做RDB,然后将RDB文件通过网络传输给slave节点,成本太高了。因此除了第一次做全量同步,其它大多数时候slave节点与master节点都是做增量同步。

什么是增量同步?就是只更新slave节点与master节点存在差异的部分数据。即只用更新offset后的命令即可,offset之后的命令就是主从之间的数据差异,只更新这部分即可。

1)master节点怎么知道slave节点与自己的数据差异在哪里呢?

这就要说到全量同步时的repl_baklog文件了。这个repl_baklog文件是一个固定大小的数组,只不过数组是环形,也就是说角标到达数组末尾后,会再次从0开始读写,这样数组头部的数据就会被覆盖。

repl_baklog中会记录Redis处理过的命令日志及offset,包括master节点当前的offset、slave已经拷贝到的offset,即主从之间的offset差就是要同步到从节点的数据。

随着不断有数据写入,master节点的offset逐渐变大,记录的最新位置就是master节点当前的offset。同时slave节点也不会去做数据同步,同步的位置就是slave的offset,追赶master节点的offset。因此,slave节点与master节点的offset之间的差异,就是salve节点需要增量拷贝的数据了。

所以可以理解成,repl_baklog其实就是slave节点与master节点之间的数据差异的一个缓冲区。只要slave节点与master节点之间的数据差异不超过这个环的存储上限,那你永远都能够这个环里找到你所需要的数据,永远能实现增量同步。

但是如果slave节点与master节点之间的数据差异差太多,已经超过这个环的存储上限,那么这个时候就没办法做增量同步了。

我们继续分析,直到数组被填满,

此时,如果有新的数据写入,就会覆盖数组中的旧数据。不过,旧的数据只要是绿色的,说明是已经被同步到slave的数据,即便被覆盖了也没什么影响。因为未同步的仅仅是红色部分。

但是,如果slave出现网络阻塞,导致master的offset远远超过了slave的offset,马上就要超过这个个环的上限。如果master继续写入新数据,其offset就会覆盖旧的数据,直到将slave现在的offset也覆盖,注意此时master已经覆盖了从节点尚未同步过去的数据,这就出现了主从之间数据的不一致。

棕色框中的红色部分,就是尚未同步,但是却已经被覆盖的数据。此时如果slave恢复,需要同步,却发现自己的offset都没有了,无法完成增量同步了。只能做全量同步。  这就保证了主从数据的一致性。

总结一下,repl_baklog大小有上限,写满后会覆盖最早的数据。如果slave断开时间过久,导
致尚未备份的数据被覆盖,则无法基于log做增量同步,只能再次全量同步。

2)那么如何减少repl_baklog大小上限超出问题的出现呢?

主从同步可以保证主从数据的一致性,非常重要。 可以从以下几个方面来优化Redis主从就集群:

  • 在master中配置repl-diskless-sync yes启用无磁盘复制,直接通过网络传输,把数据发送给从节点,只适用于网络较快的设备,这样就能避免全量同步时的磁盘IO,提高全量同步的性能。
  • Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO,提高全量同步的性能。
  • 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步。
  • 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力。

全量同步和增量同步的区别

(1)全量同步:master将完整内存数据生成RDB,发送RDB到slave。后续命令则记录在repl_baklog,逐个发送给slave。

什么时候执行全量同步?

  • slave节点第一次连接master节点时。
  • slave节点断开时间太久,repl_baklog中的offset已经被覆盖时。

(2)增量同步:slave提交自己的offset到master,master获取repl_baklog中从offset之后的命令给slave

什么时候执行增量同步?

  • slave节点断开又恢复,并且在repl_baklog中能找到offset时。

 

二、Redis哨兵

背景

主从结构中,如果一个slave节点宕机,根本不用担心。因为只要这个slave节点重启,就能从master节点上完成数据同步恢复数据。

那如果宕机的不是slave节点而是master节点呢?如果说已经做了master节点的持久化,那master节点重启是可以解决这个问题的,数据也不会丢失。但是如果说在master节点宕机的这段时间内,还有在重启数据恢复的过程中,由于目前master节点是宕机状态,用户是无法执行写操作,也就意味着这个集群的可用性就下降了。

那么有什么办法能保证主从集群的高可用性呢?我们只需要去监控集群中的节点状态, 当发现master节点宕机的那一刻,立即选出一个新的slave节点作为新的master节点,因为这个slave节点本身一直在数据同步,有完整的数据,把它变成master节点很容易,这个时候我们整个集群依然是健康的,不仅可以进行读操作还可以写操作。至于那个宕机的master节点,将来等它启动之后变成slave节点就可以了。

这样就实现了主从切换,也就意味着这个集群的高可用性可以得到一个很好的保障。

但是这个监测和重启的动作谁来做呢?Redis主从模式当主服务器宕机后,需要手动把一台从服务器切换为主服务器,需要人工干预费事费力,为了解决这个问题出现了哨兵模式

哨兵工作原理

Redis提供了哨兵Sentinel)机制来监控主从集群监控状态,确保集群的高可用性。

哨兵的作用如下:

  • 状态监控:Sentinel 会不断检查您的master和slave是否按预期工作。
  • 故障恢复(failover):如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后会成为slave。
  • 状态通知:Sentinel充当Redis客户端的服务发现来源,当集群发生failover时,会将最新集群信息推送给Redis的客户端。

那么问题来了,

1)Sentinel怎么知道一个Redis节点是否宕机呢?

Sentinel基于心跳机制监测服务状态。每个Sentinel会每秒钟 一次的频率向它所知的主服务器、从服务器以及其他Sentinel实例发送一个PING命令,获取其拓扑结构和状态信息。然后通过实例的响应结果来做出判断,来确认这些节点是否可达,共同监控数据节点的运行状况。

  • 主观下线(sdown):如果某sentinel节点发现某Redis节点未在规定时间响应,则认为该节点主观下线。
  • 客观下线(odown):若超过指定数量(通过quorum设置)的sentinel都认为该节点主观下线,则该节点客观下线。quorum值最好超过Sentinel节点数量的一半,Sentinel节点数量至少3台。

主观下线

如果某个sentinel节点发现某实例未在规定的时间内(down-after-milliseconds)响应,则认为实例下线了。这种下线是主观下线。

哨兵每秒向所有与它创建命令连接的实例(包括主服务器、从服务器、其他sentine)发送PING命令,并通过实例返回的PING命令回复来判断是否在线。收到的有效回复为:+PONG、-LOADING、-MASTERDOWN命令。其余的都是无效回复(也包括没有回复的)。

如果在down-after-milliseconds毫秒以内,sentinel收到的都是无效回复,那么这个sentinel就会认为实例进入主观下线状态,同时修改实例结构中的flags属性,改为SRI_S_DOWN(主观下线)。

down-after-milliseconds毫秒不仅会成为sentinel判断master进入主观下线的标准,还会成为sentinel判断master属下所有从服务器,以及所有同样监视master的其他sentinel进入主观下线的依据。

客观下线

如果超出指定数量(quorum)的sentinel都认为该实例主观下线,则该实例就。quorum值最后超过sentinel实例数量的一半。

当sentinel将一个主服务器判断为主观下线后,为了确认这个主服务器是否真的下线了,它(当前这个sentinel)会向同样监视这一主服务器的其他sentinel进行询问,看看它们是否也认为当前主服务器已经进入了下线状态(无论是主观的还是客观的)。

根据其他sentinel回复的SENTINEL is-master-down-by-addr命令,sentinel将统计其他sentient是否同意主服务器已经下线的数量。当这个数量达到配知道你个判断客观所需要的数量时候,也就是当sentinel从其他sentinel那接收到足够数量的已下线判断之后,sentient会将主服务器实例结构flags属性的SRI_O_DOWN标识打开,标识主服务器已经进入客观下线状态,并对主服务器执行故障专业操作。

2)如何选举新的master?

一旦发现master故障,sentinel需要在salve中选择一个作为新的master。

选择依据是这样的:

首先会判断slave节点与master节点断开时间长短,如果断开时间超过down-after-milliseconds * 10,因为断开时间越长证明丢失的数据越多,则就会直接排除该slave节点,它就不具有选举权。这样就可以排除掉一部分数据是旧的slave节点。

然后判断slave节点的slave-priority值(默认都是1),这个slave-priority值越小优先级越高,如果是0则永不参与选举。

如果slave-prority一样,则判断slave节点的offset值,代表当前slave节点与master节点之间数据同步的进度,offset值越大证明这个当前slave节点与master节点之间的数据月接近,说明数据越新,优先级越高。因为我们要优先保证数据的完整性。

假设所有的slave节点的offset值都一样,那最后是判断slave节点的run_id大小,这个run_id(通过info server可以查看run_id)是在slave节点启动时的那一刻由Reids自动生成的一个id。这个run_id其实大小并不重要,此时我们就随便挑一个,run_id越小优先级越高。

那么,问题来了,当选出一个新的master后,该如何实现身份切换呢?

3)如何实现故障转移?

当选中了其中一个slave为新的master后(例如slavel),故障的转移的步骤如下:

假设现在的master宕机了,此时slave节点7002被选择作为新的master节点。

那么在做故障转移的时候,第一步sentinel会向salve节点发起一个请求,告诉salve节点去执行slaveof no one 命令,执行命令之后这个salve节点就会成为master节点。

第二步就是广播,sentinel给所有其他的slave节点发送slaveof xxx.xxx.xx.xx 端口。比如我们新master节点是192.168.1.11 7002,那么命令就是 slaveof 192.168.1.11 7002命令,让这些slave成为新master的从节点,开始从新master上同步数据。

最后,sentinel会强制修改故障节点的配置文件,在配置文件中设置slaveof 192.168.1.11 7002命令,也就是把它标记为slave。一旦配置文件修改了之后,当故障节点恢复后自动成为新master的slave节点。

此时,所有的slave就都成为了新master的从节点,整个主从切换就完成了。

三、Redis分片集群

背景

主从集群可以去应对Redis的高可用、高并发读的问题。但是Redis主从之间也会做同步,为了提高主从同步的性能,我们单节点的Redis的内存设置不能太高。如果内存占用过多,在RDB持久化的时候或者做全量同步的时候,会导致大量的IO,性能会下降。

那如果单节点的Redis的内存上限降低了,那如果有海量数据存储需要存储的时候怎么办?遇到了高并发写的问题该如何解决?

总结就是,但依然有两个问题没有解决:

  • 海量数据存储

  • 高并发写

要解决这两个问题就需要用到分片集群了。分片的意思就是把数据拆分存储到不同节点,这样整个集群的存储数据量就更大了。

分片集群特征:

  • 集群中有多个master,每个master保存不同分片数据 ,解决海量数据存储问题。同时每个master都可以写操作,并发写能力也得到提升。
  • 每个master都可以有多个slave节点 ,同时具备了主从集群的特性,确保高可用。
  • master之间通过ping监测彼此健康状态 ,类似哨兵作用。
  • 客户端请求可以访问集群任意节点,最终都会被转发到数据所在节点。

散列插槽

插槽原理

Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上,查看集群信息时就能看到,

1)那为什么要做这个插槽呢?

既然每个master都可以存储数据,那存储到哪一个里面,以后怎么取。插槽就是来解决这个问题的。

数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分两种情况:

  • key中包含"0",且“0”中至少包含1个字符,,“0!”中的部分是有效部分。
  • key中不包含“!”,整个key都是有效部分。

例如,key是num,那么就根据num计算,如果是{itcast}num,有效部分就是itcast,则根据itcast计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值。

2)那为什么数据key要与插槽绑定而不是与节点绑定?

正因为Redis的master节点是可能出现宕机情况的,或者是集群扩容增加了节点,或者是集群伸缩删除了节点。那如果一个节点删除或者宕机了,节点上面的数据也会跟着丢失。

而如果数据是与插槽绑定,那当节点删除或者宕机时,可以将这个节点对应的插槽转移到活着的节点。集群扩容时也可以将插槽进行转移。这样数据跟着插槽走就永远可以找到数据所在的位置。

3)Redis如何判断某个key应该在哪个实例?
  1. 将16384个插槽分配到不同的实例。
  2. 根据key的有效部分计算哈希值,对16384取余。
  3. 余数作为插槽,寻找插槽所在实例即可。

如图,在7001这个节点执行set a 1时,对a做hash运算,对16384取余得到的结果是15495,而15495槽是在7003这个节点上,因此此时会重定向到7003节点取值。在7003节点执行 get a就可以拿到a对应的value值1。在7003节点执行get num命令时,对num做hash运算,对16384取余,得到的结果是2765,因此会重定向到7001节点取值。

4)如何将同一类数据固定的保存在同一个Redis实例?

这一类数据使用相同的有效部分,例如key都以{typeld}为前缀。

集群伸缩

redis-cli --cluster提供了很多操作集群的命令,可以通过下面方式查看:

 比如,添加节点的命令:

故障转移

分片集群虽然没有哨兵机制,但是也具有故障转移的功能。

当集群中有一个master宕机会发生什么呢?

  1. 首先是该实例与其它实例失去连接。
  2. 然后是疑似宕机。
  3. 最后是确定下线,自动提升一个slave为新的master。

手动转移

利用cluster failover命令可以手动让集群中的某个master宕机,切换到执行cluster failover命令的这个slave节点,实现无感知的数据迁移。

大致的流程:在一个slave节点上执行cluster failover命令,那么这个slave节点对应的master节点会被替换掉,这个slave节点会成为新的主节点,而那个对应的master节点会成为从节点。

具体流程如下:

手动的Failover支持三种不同模式:

  • 缺省:默认的流程,如图1~6歩
  • force:省略了对offset的一致性校验
  • takeover:直接执行第5歩,忽略数据一致性、忽略master状态和其它master的意见

当在一个slave节点上执行cluster failover命令的时候,slave节点会向master节点发一个消息,告诉master节点我要替换你了。这个时候为了避免消息的丢失,master节点会拒绝客户端的一切请求,返回当前的offset值给slave节点,告诉slave节点我现在的数据已经最新到这个位置了。

此时,slave节点和master节点会检查当前的这个offset值是否一致。如果slave节点和master节点的数据不一致,slave节点会进行数据同步。数据同步完成之后,slave节点和master节点数据就会完全一致(因为此时已经不接收新的客户端请求了)。

数据完全一致之后,就可以进行故障转移了。完成之后,让slave把自己标记成一个master,广播通知集群中的每一个节点。当集群中的每一个节点收到消息之后,以后就和这个新的master节点做交互。并且原来的那个master节点接收到消息之后,就会知道与新的master节点之间的数据同步和转移已经结束了,会转为一个slave节点。

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

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

相关文章

关于Git Bash中如何定义alias

一、在一次临时Bash会话中使用alias 在Bash中直接输入alias xxdddd,xx为对应要执行的命令的缩写,dddd为要执行的命令,如alias ddcd /d,输入完成后,在Bash中输入dd,即可切换至D盘。 此种设置方式&#xff…

JavaSE——集合2:List(Iterator迭代器、增强for、普通for循环遍历集合)

目录 一、List (一)List接口基本介绍 二、List接口的常用方法 三、List集合的三种遍历方式 四、小练习——使用冒泡排序遍历集合 一、List (一)List接口基本介绍 List接口是Collection接口的子接口 public interface List<E> extends Collection<E> List集…

华大基因与NRL完成技转合作,为中东家庭提供更优质的产前筛查方案

今年年初&#xff0c;华大基因与中东地区最大的美国病理学家学会&#xff08;CAP&#xff09;认证实验室集团National Reference Laboratory&#xff08;NRL&#xff09;&#xff0c;顺利完成了无创产前基因检测技术&#xff08;NIPT&#xff09;技转合作&#xff0c;并向NRL实…

AI先行者工具撰写的烧脑短篇,你不可错过

以下文字是我用ai先行者所创造的文字。我就输入烧脑故事四个关键字 昨晚&#xff0c;我像往常一样刷着朋友圈&#xff0c;准备结束一天的工作前放松一下。突然间&#xff0c;我的好友小林发了一条状态&#xff1a;“如果有人发现我不见了&#xff0c;请不要报警。”这句话配上…

【JAVA毕业设计】基于Vue和SpringBoot的加油站管理系统

本文项目编号 T 003 &#xff0c;文末自助获取源码 \color{red}{T003&#xff0c;文末自助获取源码} T003&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

金蝶云星空与金蝶云星空对接集成采购订单查询连通采购订单新增(采购订单)

金蝶云星空与金蝶云星空对接集成采购订单查询连通采购订单新增(采购订单) 对接系统金蝶云星空 金蝶K/3Cloud在总结百万家客户管理最佳实践的基础上&#xff0c;提供了标准的管理模式&#xff1b;通过标准的业务架构&#xff1a;多会计准则、多币别、多地点、多组织、多税制应用…

Prometheus+Grafana 监控 Kubernetes

文章目录 一、Prometheus介绍二、Prometheus组件与监控三、Prometheus基本使用&#xff1a;怎么来监控四、Kubernetes监控指标五、Prometheus的基本使用&#xff1a;部署1.基于docker部署prometheusgrafana2. 查看prometheus配置文件3. 监控Linux服务器3.1找到自己相应的系统去…

php外卖霸王餐独立小程序 霸王餐源码 功能用户分销 会员系统 自用/推广私域运营

前言 外卖霸王餐小程序是一种结合了外卖点餐和优惠返利功能的微信小程序&#xff0c;旨在为用户提供一种便捷的点餐体验和优惠福利。 用户以5-10元吃到原价15-25元的外卖&#xff0c;底层逻辑是帮外卖商家做店铺推广&#xff0c;解决新店基础销量、老店增加单量、品牌打万单店…

Apache Kafka 使用示例

Kafka快速入门指南 微信公众号&#xff1a;阿俊的学习记录空间小红书&#xff1a;ArnoZhangwordpress&#xff1a;arnozhang1994博客园&#xff1a;arnozhangCSDN&#xff1a;ArnoZhang1994 第一步&#xff1a;获取Kafka 下载2.13-3.8.0版本的Kafka版本并解压&#xff1a; $…

2d实时数字人聊天语音对话使用案例,对接大模型

参看: https://github.com/wan-h/awesome-digital-human-live2d 电脑环境: ubuntu 1060ti 下载: git clone https://github.com/wan-h/awesome-digital-human-live2d.gitdocker部署; cd awesome-digital-human-live2d docker-compose -f docker-compose-quickStart.ya…

React 子组件调用父组件的方法,以及互相传递数据

<script type"text/babel" data-type"module"> import React, { StrictMode, useState } from react; import { createRoot } from react-dom/client;const ParentComponent () > {const [message, setMessage] useState("")//父组件…

代理模式、BigDecimal详解

代理模式 代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问&#xff0c;这样就可以在不修改原目标对象的前提下&#xff0c;提供额外的功能操作&#xff0c;扩展目标对象的功能 代理模式的主要作用是扩展目标对象的功…

kali(专业的渗透测试虚拟机)|kali下载链接地址 |kali安装 |kali部署指南

介绍 kali 是Debian开源linux系统体系下的子分支之一 Debian-kali 扩展&#xff1a;Ubuntu也是Debian开源linux系统体系下的子分支之一 Debian-ubuntu 安装kali 2023.03 稳定版 Index of /kali-images/kali-2023.1/ 安装可以参考他的教程&#xff0c; 写的很详细了…

编程练习5 转盘寿司

#include<iostream> #include<vector>using namespace std;//字符分割函数 //把字符串中的字符c剔除 同时将字符串中的其他内容以合适的类型保存 vector<int> split(string str_input, char c) {vector<int> result;while(str_input.find(c) ! -1){//…

阿拉伯语技术翻译的特点

将技术内容翻译成阿拉伯语具有独特的挑战和要求&#xff0c;这源于阿拉伯语复杂的结构、文化差异及其在全球科学技术领域中的地位。翻译人员需要具备深厚的语言专业知识&#xff0c;关注不断发展的科学技术术语&#xff0c;并了解阿拉伯语世界中的地区差异&#xff0c;以确保专…

安卓开发中实现可滑动区域触顶的提示

这篇博客记录在开发中使用 CoordinatorLayout、AppBarLayout 、CollapsingToolbarLayout实现监听滑动悬停的触顶提示&#xff0c;有不理解的小伙伴可移步之前的文章——安卓开发中上滑触顶悬停 上述三个控件的结构图如下&#xff0c;在滑动时需要触顶的部分需要在 AppBarLayo…

培训学校小程序开发

我是【码云数智】平台的黄导&#xff0c;今天分享&#xff1a;培训学校小程序开发 知识付费小程序能够实现线上音频课程、视频课程、直播课程以及专栏课程和图文课程&#xff0c;并且我们也针对营销端做了很多营销功能&#xff0c;可以精准触达目标用户&#xff0c;实现内容的…

软件设计之Redis(3)

软件设计之Redis(3) 路线图推荐&#xff1a; 【Java学习路线-极速版】【Java架构师技术图谱】 尚硅谷Redis零基础到进阶&#xff0c;最强redis7教程&#xff0c;阳哥亲自带练&#xff08;附redis面试题&#xff09; 资料可以去尚硅谷官网免费领取 感谢学习笔记提供&#xff1a…

探索OpenCV的人脸检测:用Haar特征分类器识别图片中的人脸

目录 简介 OpenCV和Haar特征分类器 实现人脸检测 1. 导入所需库 2. 加载图片和Haar特征分类器 3. 检测人脸 4. 标注人脸 5. 显示 6、结果展示 结论 简介 在计算机视觉和图像处理领域&#xff0c;人脸识别是一项重要的技术。它不仅应用于安全监控、人机交互&#xff0…

日期类的实现和取地址运算符重载

前面将类学的差不多&#xff0c;接下来我们就来实现一下日期类。这个日期类包含运算符重载和前面学 的C的语法知识。 首先我们先建立一个日期类的头文件和源文件&#xff1a; 一.日期类的头文件实现&#xff1a; 首先我们要知道我们有闰年&#xff0c;还有每个月的天数也不一样…