单机Redis、Redis持久化、Redis主从模式、Redis哨兵模式、Redis分片集群

news2024/11/20 11:36:19

一、单机Redis

数据库分类:

到目前为止,所有数据库分为两大类:

  • RDBMS:关系型数据库即传统数据库

                     像MySQLSQLServer、DB2、Sybase、SQLite、Oracle等等

                     以表的形式存储数据,表与表之间维护数据的关系

                     这一类数据库有非常严谨的事务,所以可以保证数据一致性和完整性

  • NoSQL:泛指一切非关系数据库

                       有非常非常多不同结构的数据库,数据模式非常灵活

                       例如:

                               Redis:key-value结构的数据库

                               Hbase列式存储数据库

                               MongoDB文档型数据库

                               Neo4J数据库,擅长表示拓扑关系

1. 问题说明

Redis:是一个key-value结构的NoSQL,为了进一步提升性能,Redis把数据存储到内存里。所以Redis有极高的读写速度。官方数据 读11万次/秒, 写8.1万次/秒

在实际开发中,Redis通常作为缓存使用

之前我们在使用Redis的时候,全部使用的是Redis的单机模式。因为单机模式Redis搭建简单、使用方便,利于学习入门。但是在实际使用中,单机Redis存在一些问题需要解决:

  • 持久化存储问题

    Redis为了提高性能,数据是在内存中存储的。而内存不能持久化存储数据,所以Redis提供了持久化机制

  • 并发能力问题

    单机Redis的并发能力有限,可以通过主从集群来实现读写分离,从而提高并发能力

  • 故障恢复问题

    在Redis集群中,一旦某个节点宕机,就必须要手动进行故障转换与恢复。Redis提供了哨兵模式来实现自动故障恢复

  • 存储能力问题

    无论是主从模式的集群,还是哨兵模式的集群,都没有解决存储能力的扩展问题。Redis提供了分片集群模式,可以很方便的动态扩容

2. 安装Redis

提示:虚拟机里,我们都以root帐号登录CentOS7

提示:虚拟机里,先关闭防火墙,再做后边的操作

  • 关闭防火墙:systemctl stop firewalld

  • 防火墙 取消开机自启:systemctl disable firewalld

2.1 解压安装Redis

把资料里的《redis-6.2.4.tar.gz》上传到Linux的/root目录下

执行命令安装redis:

#1. 安装Redis需要的依赖程序包
yum install -y gcc tcl

#2. 切换到root用户的家目录
cd ~
#3. 解压Redis程序包
tar -xvf redis-6.2.4.tar.gz
#4. 切换到Redis目录里
cd ~/redis-6.2.4/
#5. 编译并安装Redis。如果此命令不出错,通常就表示安装成功了
make && make install

2.2 配置Redis 

#1. 在root家目录里创建文件夹
mkdir ~/01standalone
#2. 把Redis配置文件拷贝进来
cp ~/redis-6.2.4/redis.conf ~/01standalone/
#3. 切换到~/01standalone/目录里
cd ~/01standalone/
#4. 使用vi编辑redis.conf
vi redis.conf

使用vi修改redis.conf的如下内容: n命令  搜索名

# 绑定地址,默认是127.0.0.1,只能在本机访问Redis服务。修改为0.0.0.0则可以在任意IP访问Redis服务
bind 0.0.0.0
# 数据库数量,设置为1
databases 1

2.3 启动Redis

所有单机问题,我们全在~/01standalone/目录里操作,使用这个目录里的配置文件

  • 首先:cd ~/01standalone/

  • 启动Redis服务:redis-server redis.conf

  • 使用Redis:redis-cli,然后就可以使用Redis的命令了

  • 关闭Redis服务:redis-cli shutdown

💡Redis服务安装好以后,可以同时启动多个实例,只要加载不同的配置文件,使用不同的端口即可

3. 小结

1. 请介绍一下Redis
    Redis是key-value结构的NoSQL,为了提升数据的读写速度,把数据存储到了内存中
    Redis在实际开发中,通常作为缓存来使用

2. 单机Redis有哪些问题
    数据持久化存储的问题:因为Redis的数据在内存中,当Redis服务关闭时要避免数据被清空释放掉
    单机Redis并发能力有限:可以搭建Redis主从集群,实现读写分离
    要解决故障恢复的问题:要能够实现主节点故障后自动恢复
    要解决存储容量的问题:可以搭建分片集群提升存储容量

二、Redis持久化

1. 持久化机制介绍

所谓持久化,指的是数据永久保存

Redis是一个内存数据库,它的所有数据都在内存中,所以有极高的读写性能,

但是内存中的数据全部是临时的,所以一旦Redis进程结束所有数据就会清空了。

为了防止这样的问题,Redis提供了持久化机制:

  • RDB模式:快照模式

  • AOF模式:日志模式

注意:在后续的所有演示中,只要修改了配置文件,就必须要重启redis服务

2. RDB模式

RDB,Redis Database Backup file,称为Redis数据快照

当执行RDB持久化时,会把Redis内存中的数据全部都保存磁盘文件上;

RDB恢复数据时,会读取磁盘文件,把文件里所有的数据恢复到内存中

快照文件,也称为RDB文件,默认保存在当前运行目录

                        (在哪个目录里启动Redis服务,就保存在哪个目录)

1 RDB执行时机

在以下情况下,会执行RDB快照持久化:

  • 执行了save命令

  • 执行了bgsave命令

  • Redis服务关闭

  • 触发自动RDB的条件时

        1 save命令

                        说明

                        当执行save命令时,Redis会执行一次RDB持久化

                        但是save命令是一个阻塞式命令:

  • 它由Redis主进程执行RDB持久化,在持久化过程中Redis将不能处理客户端的操作,直到RDB执行完毕

  • 如果Redis中数据非常多,持久化将会花费比较长的时间,Redis也将会阻塞比较长的时间

  • 目前,save命令已经很少使用了,通常使用bgsave代替它

    示例:

            使用redis-cli连接Redis服务之后,执行命令:save,就会执行一次RDB持久化

  • [root@ithma ~]# redis-cli
    127.0.0.1:6379> save
    OK
    127.0.0.1:6379> 

    退出redis-cli,查看一下有没有RDB文件:

  • 127.0.0.1:6379> exit
    [root@itma 01standalone]# ls
    dump.rdb  redis.conf

     2 bgsave命令

                             说明

                             bgsave,指background save。

                             当执行bgsave命令时,将会执行一次RDB持久化

                             而bgsave是非阻塞的、

      异步式的:

  • Redis会fork一个子进程,由子进程负责RDB持久化

  • 而主进程仍然可以处理客户端的操作,使用体验更好

        示例

                使用redis-cli连接Redis服务之后,执行命令bgsave,就会执行一次RDB持久化

127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379> 

                退出redis-cli,查看一下有没有RDB文件:    

127.0.0.1:6379> exit
[root@ithiema 01standalone]# ls
dump.rdb  redis.conf

        3 Redis服务关闭

当结束Redis服务时,Redis会先执行一次save命令,把内存中的数据进行RDB持久化。

关闭Redis服务的方式有很多,可以:

* 在redis-server服务进程中,按`ctrl + c`,立即结束redis服务
* 在redis-cli客户端中,执行命令`shutdown`,关闭redis服务
* 或者直接执行Linux命令`redis-cli shutdown`命令

         4 RDB自动触发

                Redis的RDB模式提供了默认的自动触发机制,

                相关的配置参数在配置文件redis.conf中。

默认值如下:

  • 如果3600秒内有1次数据变更,就执行一次RDB

  • 如果300秒内有100次数据变更,就执行一次RDB

  • 如果60秒内有10000次数据变更,就执行一次RDB

  • save 3600 1;save 300 100;save 60 10000

  • 提示:如果写成 save "",表示禁用RDB

2 RDB的其它参数

在Redis的配置文件redis.conf中,还有一些RDB相关的参数,我们可以了解一下

rdbcompression yes
dbfilename dump.rdb
dir ./
  • rdbcompression:是否开启RDB文件压缩

    如果参数值为yes,Redis将会对rdb文件进行压缩,最终rdb文件会更小

    占用磁盘空间更小,但是压缩与解压时会消耗CPU

  • dbfilename:RDB文件名称

    自定义RDB文件名称

  • dir:工作路径

    RDB文件保存的路径,默认是./

3 RDB执行原理

默认情况下,Redis服务只有一个进程,由这个进程负责处理客户端的一切操作请求

当执行bgsave命令时,Redis会fork一个子进程出来,实现异步RDB

  • 子进程负责执行RDB,

  • 主进程继续负责处理客户端的操作请求。

虽然子进程执行RDB持久化的过程中,并不会对主进程造成影响,所以主进程不会阻塞,

可以继续处理客户端的操作请求。

但是还有一些新问题需要考虑:

  • fork子进程,也需要一定的时间。但这个时间相对于RDB持久化而言,就非常短暂了,只需要几十毫秒多则1秒钟的时间

  • 如果子进程执行RDB的过程中,客户端有新的操作改变了数据,为了避免这些新改变的数据对RDB过程造成影响,Redis采用了copy-on-write技术:

    • 主进程执行读操作时,访问共享内存;

    • 主进程执行写操作时,则会拷贝一份数据,执行写操作。

3. AOF模式

AOF,Append Only File。

执行AOF持久化时,会把执行的每个数据变更的命令追加保存到磁盘文件里。

AOF恢复数据时,会读取磁盘文件,按顺序依次执行所有的命令恢复数据

1 开启AOF

Redis的AOF默认是关闭状态的,如果要开启AOF模式,

则需要

           修改redis.conf配置文件

appendonly yes
# AOF文件的名称
appendfilename "appendonly.aof"
  • appendonlyAOF模式的开关。如果值是yes,表示开启;如果是no,表示关闭

  • appendfilenameAOF文件的名称。默认是appendonly.aof,可以自定义文件名

           重启Redis服务

                                    先关闭Redis服务,执行命令:redis-cli shutdown

                                    再重启Redis服务,执行命令:redis-server redis.conf

2 AOF执行时机

开启AOF模式之后,在redis.conf中配置有的AOF持久化执行时机,

可通过appendfsync参数进行配置

#appendfsync always 
appendfsync everysec 
#appendfsync no
  • 如果值为always:每次的写数据的命令,就立即追加到aof文件中

  • 如果值为everysec:每次的写命令先放到AOF缓冲区

                                          然后以每秒一次的频率,把缓冲区里的命令保存到aof文件

  • 如果值为no:每次的写命令先放到AOF缓冲区

                             然后完全由操作系统决定何时把缓冲区里命令保存到aof文件

三种时机的对比:

配置项刷新时机优点缺点
always同步刷盘可靠性高,几乎不丢数据·对性能影响大
everysec每秒刷盘性能适中最多丢失1秒的数据
no由操作系统控制性能最好可靠性较差可能丢失大量数据
注意:只要修改了配置文件,就必须要重启redis服务

3 AOF文件重写

1.AOF冗余记录

因为AOF保存的是写命令,类似于日志文件,

所以通常情况下AOF日志文件都比RDB文件大

且随着使用时间的推移,AOF文件通常会越来越大,

从而导致:

  • 磁盘空间的占用越来越大

  • 恢复数据的速度越来越慢

主要原因在于,AOF忠实的记录每次写操作的命令,就可能有大量重复的命令;

比如对同一key有多次修改操作,每次修改操作都会记录到AOF文件里,

而实际上只有最后一次操作命令才有效。

假如先后执行以下命令set num 1; set num 10; set num 100 ;set num 1

        那么AOF文件里会保存4条命令,实际上只需要最后一条命令就可以了

2.bgrewriteaof重写

手动执行AOF重写

通过在redis-cli中执行bgrewriteaof命令,可以让AOF文件执行重写:

删除无效的命令。例如:set a A, set a B, del a三个命令,其实全部都可以删除掉

合并多余的命令。例如:

 

自动触发AOF重写

Redis也会在触发阈值时自动去重写AOF文件,阈值的配置在redis.conf文件中

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

auto-aof-rewrite-min-sizeAOF文件必须大于这个值,才可能触发AOF重写

auto-aof-rewrite-percentageAOF文件上次重写后的文件对比,超过这个百分比后,会触发AOF重写

4. RDB和AOF对比

RDB和AOF两种持久化模式各有各的优缺点。在实际开发中往往是两者结合使用

对比项RDBAOF
持久化方式定时整个内存数据做快照记录每次执行写命令
数据完整性两次备份之间数据可能丢失丢失数据的可能性较小,取决于刷盘策略
文件大小相对较小,且有RDB压缩记录命令文件相对较大
恢复速度很快
恢复时优先级
系统资源占用高,大量CPU和内存消耗低,主要是磁盘IO较高 但AOF重写时会占用较高的CPU和内存
使用场景可能容忍数分钟内的数据丢失, 追求更快的启动速度对数据安全性要求较高时使用

5. 小结

1. Redis是如何解决持久化问题的,介绍一下Redis的两种持久化模式
    Redis提供了两种持久化机制,分别是RDB和AOF
    RDB:叫快照模式。Redis会把内存里的数据,保存到磁盘文件上。

               当重启Redis的时候,加载文件恢复数据到内存
    AOF:叫日志模式。

2. Redis什么时候会执行RDB
    手动执行save命令:用的不多,因为是阻塞式的命令。

                                     在RDB过程中,Redis不能处理客户端的操作请求
    手动执行bgsave命令:用的较多,因为是非阻塞式的命令。会开启一个子进程,

                                         由子进程负责RDB;主进程处理客户端的操作请求
    关闭Redis服务的时候:redis会自动RDB之后,才会退出
    RDB的自动触发:在配置文件里有触发的时机

3. 说一下RDB的原理 面试
    当执行bgsave命令的时候,

Redis做了:
                fork一个子进程,把主进程的页表复制到子进程里,

                会把物理内存的数据设置为read-only只读
                子进程:根据页表访问物理内存里的数据,把这些数据保存到磁盘文件上
                主进程:可以继续处理客户端的请求
                               如果客户端要改数据:会把数据复制一个副本,修改这个副本数据
                               如果客户端要读数据:让它读取副本的新数据


4. AOF的文件过大,Redis是怎么解决的
    重写AOF文件,有两种实现方式
    手动重写AOF文件:执行命令bgrewriteaof
    自动重写AOF文件:在redis.conf里有配置阈值 aof文件超过64M,并且比上次重写时文件大小翻一倍,就重写
5. RDB和AOF对比,各有什么优缺点
    丢数据的可能性:RDB丢数据的可能性更高
    数据的可靠安全:AOF更安全
    使用的时候:如果追求更快的速度,并且能够容忍一些数据的丢失,就选择RDB;否则就使用AOF

三、Redis主从模式

1. 介绍

单节点Redis服务支持并发是有限的:

                                                              所有客户端的请求全部冲击到仅有的一台服务器上,

                                                              服务器可能因为压力过大而阻塞不能及时响应。

这时候可以采用主从架构

做到读写分离

                        多个Redis节点共同提供服务,所有写数据操作请求主服务器

                        所有读数据操作请求从服务器读写分离提升并发能力

 2. 搭建Redis主从架构【备用】

1 架构说明

我们搭建的Redis主从集群结构,共包含三个节点。其中一个主节点两个从节点

我们将会在同一个虚拟机里开启三个Redis实例,模拟主从集群,信息如下:


角色ip端口
角色ip端口
master192.168.126.1206380
slave192.168.126.1206381
slave192.168.126.1206382
如图所示:
 我们创建三个文件夹

#1. 准备一个文件夹02master,把主从集群所有相关的配置全放到这个文件夹里
mkdir ~/02master
#2. 在02master里准备三个文件夹,作为三个redis实例的工作目录
cd ~/02master/
mkdir 6380 6381 6382

#3. 把Redis的配置文件,分别拷贝到6380,6381,6382三个文件夹里。
echo 6380 6381 6382 | xargs -t -n 1 cp ~/redis-6.2.4/redis.conf

#4. 分别修改6380、6381、6382三个文件夹里的配置文件
#	把端口分别修改为6380、6381、6382
#	把配置文件里的dir,全部修改为各自的工作目录
cd ~/02master
sed -i -e 's/6379/6380/g' -e 's/dir .\//dir \/root\/02master\/6380\//g' -e 's/bind 127.0.0.1 -::1/bind 0.0.0.0/g' 6380/redis.conf
sed -i -e 's/6379/6381/g' -e 's/dir .\//dir \/root\/02master\/6381\//g' -e 's/bind 127.0.0.1 -::1/bind 0.0.0.0/g' 6381/redis.conf
sed -i -e 's/6379/6382/g' -e 's/dir .\//dir \/root\/02master\/6382\//g' -e 's/bind 127.0.0.1 -::1/bind 0.0.0.0/g' 6382/redis.conf

#5. 修改每个Redis实例的ip
#	虚拟机本身有多个虚拟网卡,有多个ip地址。为了防止地址混乱,我们直接在配置文件里指定要绑定的ip地址
#	6380、6381、6382三个文件夹里的配置文件都要修改,执行以下命令
cd ~/02master
printf '%s\n' 6380 6381 6382 | xargs -I{} -t sed -i '1a replica-announce-ip 192.168.200.136' {}/redis.conf

3 启动集群

为了方便查看每个Redis实例的日志,我们开启三个ssh容器,分别启动3个redis实例。

命令如下:

# 第一个Redis实例
redis-server ~/02master/6380/redis.conf
# 第二个Redis实例
redis-server ~/02master/6381/redis.conf
# 第三个Redis实例
redis-server ~/02master/6382/redis.conf

 

 

 附加:如果想要一键停止所有Redis实例,可以执行以下命令:

printf '%s\n' 6380 6381 6382 | xargs -I{} -t redis-cli -p {} shutdown

4 开启主从关系

到目前为止,三个Redis实例之间还没有任何关系。

配置主从关系,可以使用Redis提供的replicaof命令(Redis5.0开始)或者slaveof命令(Redis5.0以前),两个命令效果一致。

主从关系配置临时配置永久配置两种

永久生效修改配置文件,然后重启所有Redis服务

                 在redis.conf中增加一行配置:slaveof masterIp masterPort

临时生效:使用redis-cli连接Redis服务,执行slaveof命令(Redis实例重启后失效)

                  slaveof masterIp masterPort

这里为了方便演示,我们使用方式二临时生效将6380节点设置为master:

 

  

设置从节点:连接6381,执行命令

#连接6381实例
redis-cli -p 6381
#设置为6380的从节点
slaveof 192.168.200.123 380

设置从节点:连接6382,执行命令         

#连接6382实例
redis-cli -p 6382
#设置为6380的从节点
slaveof 192.168.200.123 6380

连接主节点6380,查看集群状态

#连接6380实例
redis-cli -p 6380
#查看集群状态
info replication

 

5 测试

按顺序执行以下操作:

  • 使用redis-cli连接6380,执行 set sum 100

  • 使用redis-cli连接6381,执行get num, 然后再执行set num 101

  • 使用redis-cli连接6382,执行get num,然后再执行set num 102

结果发现:

  • 只有6380这个节点上可以进行写操作

  • 6381和6382两个节点上只能进行读操作

3. 主从数据同步原理

1 全量同步

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

但是这里有一个问题:Master如何判断 slave是否第一次连接呢?

我们需要先了解一个概念:

  • Replication Id:简称replid,由40位十六进制字符组成。每个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是否一致

 

完整流程描述:

  • slave节点请求增量同步

  • master节点判断replid,发现不一致,拒绝增量同步

  • master将完整内存数据生成RDB,发送RDB到slave

  • slave清空本地数据,加载master的RDB

  • master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave

  • slave执行接收到的命令,保持与master之间的同步

 

2 增量同步

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

什么是增量同步?就是只更新slave与master存在差异的部分数据。如图:

 

3 repl_backlog原理

那么master怎么知道slave与自己的数据差异在哪里呢?

这就需要理解全量同步时的repl_backlog文件

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

repl_backlog中会记录Redis处理过的命令日志offset,包括master当前的offset,和slave已经拷贝到的offset:

 

slave与master的offset之间的差异,就是salve需要增量拷贝的数据了。

随着不断有数据写入,master的offset逐渐变大,slave也不断的拷贝,追赶master的offset:

直到数组被填满:

 

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

但是,如果slave出现网络阻塞,导致master的offset远远超过了slave的offset:

 

如果master继续写入新数据,其offset就会覆盖旧的数据,直到将slave现在的offset也覆盖:  

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

注意:repl_backlog大小有上限,写满后会覆盖最早的数据。如果slave断开时间过长,导致尚未备份的数据被覆盖,则无法基于log做增量同步,只能再次进行全量同步

 

 

 

 

 

4. 主从同步优化

主从同步可以保证主从数据的一致性,非常重要。

可以从以下几个方面来优化Redis主从就集群:

  • 在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘IO。

  • Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO

  • 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步

  • 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力

主从从架构图:

 

5. 小结

1. 怎么解决Redis的并发问题
    搭建Redis的主从集群
        主节点:可以读、写
        从节点:只能读
    在实际使用中:
        通常是写数据,找主节点
        通常是读数据,找从节点

2. 主从节点之间数据是如何同步的
    有两种同步方式:全量同步,增量同步
    全量同步:master把自己的所有数据,全部发送给slave节点。同步速度慢
        slave向master请求同步数据时,会带自己的replid
        
master判断:replid和自己的是否相同
            如果不同:说明是第一次同步,要进行全量同步,会把master自己的

                              replid发给slave存储起来
            如果相同:说明之前同步过,要进行增量同步
    增量同步:master把自己的新的数据(命令),发送给slave节点,slave节点执行命令,

                     增量同步数据
                     slave向master发请求同步数据时,会带自己的replid
                     master判断:和自己的replid相同
                                        master会把 上次同步之后,新的数据变更的命令,发送给slave;

                                        slave执行命令,实现增量同步

3. repl_baklog原理
    数组在逻辑上以首尾相接的环形处理
    master把写命令 不断的添加到环形里。如果添加了一圈了,就会把最旧的命令覆盖掉
    slave不断从环形里获取落后的命令,同步到slave
    
    如果slave同步的速度足够快:可以正常进行同步
    如果slave因为网络原因或其它原因,导致长时间连接不上master,就会导致落后的过多,

    断开时间太长,会进行全量同步

4. 主从集群的优化
    配置无磁盘同步,减少磁盘的IO
    减少单个Redis节点的内存占用
    适当提高repl_backlog的大小,减少全量同步的机会 
    一个master不在关联过多slave,如果slave确实多,可以使用主-从-从链式结构,

    减少master的压力

四、Redis哨兵模式

1. 介绍

Redis的主从模式可以保证主从的数据一致性,并且可以实现读写分离,有效提升并发能力

但是主从集群有一个缺陷:Master宕机之后,需要人工干预进行故障恢复

这时候,可以引入哨兵模式,实现集群故障的自动恢复

2. 哨兵模式的架构原理

哨兵模式的架构

 

哨兵的作用如下:

  • 监控:Sentinel 会不断检查您的master和slave是否按预期工作

  • 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主

  • 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端

集群监控原理

Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:

  • 主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线

  • 客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。

  •  

     

集群故障恢复原理

        选举原则

一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:

  • 首先会判断slave节点与master节点断开时间长短

                           如果超过指定值(down-after-milliseconds * 10 )则会排除该slave节点

  • 然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举

  • 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高

  • 最后是判断slave节点的replid大小,越小优先级越高。

        切换Master

当选出一个新的master后,该如何实现切换呢?

流程如下:

  • sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master

  • sentinel给所有其它slave发送slaveof 命令,让这些slave成为新master的从节点,开始从新的master上同步数据。

  • 最后,sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点

3. 搭建哨兵集群

架构说明

这里我们搭建一个三节点形成的Sentinel集群,来监管之前的Redis主从集群。如图

三个Sentinel实例信息如下:

节点ip端口
s1192.168.126.12316380
s2192.168.126.12316381
s3192.168.126.12316382

准备实例和配置

准备文件夹

要在同一台虚拟机开启3个实例,必须准备三份不同的配置文件和目录,配置文件所在目录也就是工作目录。

先创建文件夹~/03sentinel文件夹,然后在~/03sentinel里创建三个文件夹,名字分别叫s1、s2、s3:

mkdir 03sentinel
cd 03sentinel/
mkdir s1 s2 s3

准备sentinel配置文件

准备s1实例的配置

切换到s1文件夹里:cd ~/03sentinel/s1

使用创建文件sentinel.confvi sentinel.conf,添加如下内容:

port 16380
sentinel announce-ip 192.168.126.123
sentinel monitor mymaster 192.168.126.123 6380 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
dir "/root/03sentinel/s1"

说明:

  • port 16380: 当前Sentinel实例的端口号

  • sentinel monitor mymaster 192.168.126.129 6380 2:指定主节点master的信息

    • mymaster:主节点名称,任意写

    • 192.168.126.129 6380:主节点的ip和端口

    • 2:选举时的quorum

准备s2和s3实例的配置

#将`~/03sentinel/s1/sentinel.conf`拷贝到s2和s3两个目录中
cp ~/03sentinel/s1/sentinel.conf  ~/03sentinel/s2
cp ~/03sentinel/s1/sentinel.conf  ~/03sentinel/s3

#修改s2和s3的配置文件,将其端口分别修改为16381、16382
sed -i -e 's/16380/16381/g' -e 's/s1/s2/g' ~/03sentinel/s2/sentinel.conf
sed -i -e 's/16380/16382/g' -e 's/s1/s3/g' ~/03sentinel/s3/sentinel.conf

启动

要使用Sentinel,我们必须保证刚才的Redis主从集群是启动运行状态,并且要保证6380是Master节点

如果Redis主从集群未启动,就执行以下命令:

  1. 启动三个Redis实例

redis-server ~/02master/6380/redis.conf
redis-server ~/02master/6381/redis.conf
redis-server ~/02master/6382/redis.conf
  1. 设置主从关系:把6380设置为master节点

    • redis-cli -p 6381,然后执行命令 slaveof 192.168.126.129 6380

    • redis-cli -p 6382,然后执行命令 slaveof 192.168.126.129 6380

    • redis-cli -p 6380,然后执行命令查看集群状态 info replication

确定6380是master节点,6381和6382是slave节点

为了方便查看日志,我们打开3个ssh客户端,分别启动3个redis实例,启动命令:

# 第1个
redis-sentinel ~/03sentinel/s1/sentinel.conf
# 第2个
redis-sentinel ~/03sentinel/s2/sentinel.conf
# 第3个
redis-sentinel ~/03sentinel/s3/sentinel.conf

测试

尝试让master节点6380宕机: redis-cli -p 6380 shutdown

查看sentinel日志。发现已经有了新的master节点:6382

4. RestTemplate访问哨兵集群

在Sentinel集群监管下的Redis主从集群,其节点会因为自动故障转移而发生变化,Redis的客户端必须感知这种变化,及时更新连接信息。Spring的RedisTemplate底层利用lettuce实现了节点的感知和自动切换。

导入资料里的《redis-cluster》工程,然后:

添加依赖坐标

添加spring-data-redis起步依赖

最终依赖如下:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.9.RELEASE</version>
    <relativePath/>
</parent>

<properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
    <!--Redis起步依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

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

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

准备配置文件

在引导类或者配置类里,添加以下代码,配置Redis集群的读写策略:

spring:
  redis:
    sentinel:
      master: mymaster  #主节点的名称。在创建Sentinel集群时指定的
      nodes: #Sentinel哨兵的地址
        - 192.168.126.129:16380
        - 192.168.126.129:16381
        - 192.168.126.129:16382

配置读写策略

/**
     * 配置Redis的Sentinel集群读写策略
     *      ReadFrom.MASTER: 仅从master节点读数据
     *      ReadForm.REPLICA:仅从slave节点读数据
     *      ReadForm.MASTER_PREFERRED:优先从Master节点读数据
     *      ReadFrom.REPLICA_PREFERRED:优先从Slave节点读数据
     */
@Bean
public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){
    return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}

测试

创建测试类,读写数据

@SpringBootTest
public class RedisSentinelTest {
    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Test
    public void test(){
        // redisTemplate.opsForValue().set("key::sentinel", "hello, sentinel");
        String s = redisTemplate.opsForValue().get("key::sentinel");
        System.out.println("s = " + s);
    }
}

5. 小结

1. Redis主从集群的故障转移问题怎么解决
	给主从集群进行增强,增加哨兵,使用哨兵模式

2. 哨兵模式中哨兵起了什么作用
	监控:监控集群中所有节点的状态。靠心跳监控
		主观下线:一个哨兵,在规定时间内一直ping不能某个节点,就认为它主观下线
		客观下线:如果过半哨兵都认为这个节点主观下线,就标记成为客观下线
	切换Master:哨兵会在Master失联之后,自动挑选一个slave提升成为Master
		选举原则:
			如果某些slave与master之间失联的时间超过配置的参数,排除这个节点,不参与选举
			再根据节点的slave-priority优先级,值越小,优先级越高
			再根据节点的offset值,值越大,说明它的数据同步的越完整,优先级越高
			最后根据replid判断,越小,优先级越高
		切换Master:当确定了某个节点要提升成为master之后
			哨兵先向这个节点发出一个命令 slaveof no one,这个节点变成master
			哨兵再向其它所有节点发出命令 slaveof 新的master节点
			当旧的master重启之后,就只能成为slave了
	通知:哨兵可以向客户端(Java程序)推送集群的地址

3. 哨兵模式中怎样进行集群监控的

4. 哨兵模式中如何进行故障恢复的

5. RedisTemplate如何访问Redis哨兵模式集群

五、Redis分片集群

1. 介绍

主从和哨兵可以解决高可用高并发读的问题。但是依然有两个问题没有解决:

  • 海量数据存储问题

  • 高并发写的问题

使用分片集群可以解决上述问题

2. 分片集群的架构

分片集群特征:

  • 集群中有多个master,每个master保存不同数据

  • 每个master都可以有多个slave节点

  • master之间通过ping监测彼此健康状态

  • 客户端请求可以访问集群任意节点,最终都会被转发到正确节点

3. 搭建分片集群

架构说明

分片集群需要的节点数量较多,这里我们搭建一个最小的分片集群,包含3个master节点,每个master包含一个slave节点,结构如下:

这里我们会在同一台虚拟机中开启6个redis实例,模拟分片集群,信息如下:

ip端口角色
192.168.126.1217380master
192.168.126.1217381master
192.168.126.1217382master
192.168.126.1218380slave
192.168.126.1218381slave
192.168.126.1218382slave

 

 

准备实例和配置

准备文件夹

创建04cluster文件夹,并在文件夹里准备7380 7381 7382 8380 8381 8382六个文件夹

mkdir ~/04cluster
cd ~/04cluster/
mkdir 7380 7381 7382 8380 8381 8382


准备配置文件

准备7380的配置

  • 切换到7380目录:cd ~/04cluster/7380

  • 使用vi编辑文件:vi redis.conf, 内容如下

port 7380
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file /root/04cluster/7380/nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir /root/04cluster/7380
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 192.168.126.121
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile /root/04cluster/7380/run.log


准备其它实例的配置 

#修改每个目录下的redis.conf,修改其端口:
cd ~/04cluster
# 执行修改
printf '%s\n' 7381 7382 8380 8381 8382 | xargs -I{} -t sed -i 's/7380/{}/g' {}/redis.conf


​
#修改每个目录下的redis.conf,修改其端口:
cd ~/04cluster
# 执行修改
printf '%s\n' 7381 7382 8380 8381 8382 | xargs -I{} -t sed -i 's/7380/{}/g' {}/redis.conf

​

启动

#因为已经配置了Redis后台运行,所以可以直接启动,不需要开多个shell端口。执行以下命令:
cd ~/04cluster
#启动7380 7381 7382 8380 8381 8382 六个Redis服务
printf '%s\n' 7380 7381 7382 8380 8381 8382 | xargs -I{} -t redis-server {}/redis.conf


#查看是否成功启动,执行命令:`ps -ef | grep redis`。如果看到以下结果,说明6个redis实例都启动成功

如果要关闭所有进程,可以执行命令:

  • 方式一:ps -ef | grep redis | awk '{print $2}' | xargs kill

  • 方式二:printf '%s\n' 7380 7381 7382 8380 8381 8382 | xargs -I{} -t redis-cli -p {} shutdown

创建集群

虽然服务已经成功启动,但目前6个Redis实例还是独立的,它们之间没有任何关系。

我们需要执行命令来创建集群。在Redis5.0之前创建集群比较麻烦,5.0之后集群管理命令都集成到了redis-cli中

命令说明

redis5.0之前

Redis5.0之前集群命令都是用redis安装包下的src/redis-trib.rb来实现的。因为redis-trib.rb是有ruby语言编写的所以需要安装ruby环境:

 # 安装依赖
 yum -y install zlib ruby rubygems
 gem install redis

 然后通过命令管理集群:

# 进入redis的src目录
cd ~/redis-6.2.4/src
# 创建集群
./redis-trib.rb create --replicas 1 192.168.126.121:7380 192.168.126.121:7381 192.168.126.121:7382 192.168.126.121:8380 192.168.126.121:8381 192.168.126.129:8381

redis5.0开始

我们使用的是Redis6.2.4版本,集群管理以及集成到了redis-cli中,格式如下:

redis-cli --cluster create --cluster-replicas 1 192.168.126.129:7380 192.168.126.121:7381 192.168.126.121:7382 192.168.126.121:8380 192.168.126.129:8381 192.168.126.121:8382

 

命令说明:

  • redis-cli --cluster或者./redis-trib.rb:表示要操作redis集群

  • create:表示要创建集群

  • --cluster-replicas 1或者--replicas:指令集群中每个master的副本个数为1。这样:

    master节点的数量:节点总数 / (replicas + 1),得到的就是master节点的数量

    节点列表中前n个就是master节点,其它是slave节点。这些slave随机分配给不同的master

创建集群

如果在执行下面的命令创建集群时报错:[ERR] Node 192.168.126.129:7380 is not empty. Either the node already knows other nodes

主要原因可能是:该节点默认生成的配置与历史存储的数据不一致导致的

解决的方法是:

  1. 关闭所有redis实例:

printf '%s\n' 7380 7381 7382 8380 8381 8382|xargs -I{} -t redis-cli -p {} shutdown
  1. 清除对应节点的dump.rdb、nodes.conf等文件

find / -name nodes.conf | xargs rm -rf
find / -name dump.rdb | xargs rm -rf
  1. 然后重启redis实例,再执行创建集群的命令

cd ~/04cluster
#启动7380 7381 7382 8380 8381 8382 六个Redis服务
printf '%s\n' 7380 7381 7382 8380 8381 8382 | xargs -I{} -t redis-server {}/redis.conf

执行以下的命令,创建集群

redis-cli --cluster create --cluster-replicas 1 192.168.126.121:7380 192.168.126.121:7381 192.168.126.121:7382 192.168.126.121:8380 192.168.126.121:8381 192.168.126.121:8382

需要我们确证一下,输入“yes“,就开始创建集群了:

 

开始创建集群  

查看集群状态: redis-cli -p 7380 cluster nodes

测试

使用命令连接7380节点:redis-cli -c -p 7380,做如下操作:

  1. 存储数据:set num 10

  2. 获取数据:get num

  3. 再次存储:set a 1

在使用redis-cli连接分片集群时,必须加上参数-c,否则操作时可能会出错。示例:

尝试连接7380节点:redis-cli -p 7380,做如下操作:

  1. 存储数据:set num 10

  2. 获取数据:get num

  3. 再次存储:set a 1

发现报错了:

4. 散列插槽

查看插槽命令:cluster nodes 

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

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

  • key中包含"{}",且“{}”中至少包含1个字符,“{}”中的部分是有效部分

  • key中不包含“{}”,整个key都是有效部分

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

提问:如何将一批key固定的保存在同一个Redis实例上呢?

答案:可以给这些数据的key,增加相同的{标识}。例如这些key都以{typeId}为前缀

5. 集群伸缩

因为Redis的分片集群,数据并没有与Redis节点直接进行绑定,而是:数据与插槽绑定,插槽与Redis节点绑定。这样就可以很方便的进行集群的伸缩,增加或减少Redis节点。

我们通过下面例子,演示一下给集群增加节点,需要如何实现。要求:向集群中添加一个新的master节点,并向其中存储num = 10

  1. 启动一个新的Redis实例,端口为7383

  2. 把7383节点添加到之前的集群,并作为一个master节点

  3. 给7383节点分配插槽,使得这个num可以存储到7383实例

这需要有两大步:

  1. 添加一个节点到集群中

  2. 转移插槽

创建7383节点

#创建7383文件夹
mkdir ~/04cluster/7383
#把配置文件拷贝到7383文件夹里
cp ~/04cluster/7380/redis.conf ~/04cluster/7383
#修改配置文件
sed -i s/7380/7383/g ~/04cluster/7383/redis.conf
#启动7383实例
redis-server ~/04cluster/7383/redis.conf

添加到集群

查看redis集群操作帮助: redis-cli --cluster help

执行命令:

#把7383节点添加到集群
redis-cli --cluster add-node  192.168.126.121:7383 192.168.126.121:7380
#查看集群状态
redis-cli -p 7380 cluster nodes

转移插槽

查看num的插槽

我们要将num存储到7383节点,因此需要先看看num的插槽是多少:

  1. 连接任意一个Redis节点:redis-cli -c -p 7382

  2. 查询num的数据: get num,发现num的插槽是2765,在7380节点上

  3.  我们可以将0~3000插槽,从7380节点移动到7383节点上

转移插槽

转换插槽的命令,操作如下:

  1. 建立连接:redis-cli --cluster reshard 192.168.126.121:7380

     

    输入要移动的插槽数量,我们输入 3000  

    输入目标节点的id(哪个节点要接收这些插槽,就输入哪个节点的id)

    我们从刚刚的输出结果中,找到7383节点的id设置过来

     

     

    从哪个节点里转移出插槽?

  2. 输入all,表示全部。即从现有每个master节点中各转移一部分出来

    输入节点id,表示从指定节点中转移出来

    输入done,表示输入完毕了

    我们这里从7380节点转移出来一部分,要输入7380节点的id

     

    输入yes,确认转移  

    确认结果

     执行命令:redis-cli -p 7380 cluster nodes,可以看到7383节点拥有0~2999插槽,说明转移插槽成功了

  3.  

     

     

     

6. 故障转移

当master宕机时,Redis的分片集群同样具备故障转移的能力。

接下来给大家演示一下分片集群的故障转换,先确认一下集群的初始状态:

  • 7380是master节点,8382是其slave节点

  • 7381是master节点,8380是其slave节点

  • 7382是master节点,8381是其slave节点

  • 7383是master节点,没有slave节点

自动故障转移

当master宕机时,分片集群会自动将其slave节点提升为master。

我们直接将7381节点关闭:redis-cli -p 7381 shutdown

然后查看集群状态 redis-cli -p 7380 cluster nodes,发现7381是fail状态,8380已经提升成为master

再次启动7381节点:redis-server 7381/redis.conf

再次查看集群状态:redis-cli -p 7380 cluster nodes,发现7381节点成为了slave

手动故障转移

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

这种failover命令可以指定三种模式:

  • 缺省:默认的流程,如图1~6歩

  • force:省略了对offset的一致性校验

  • takeover:直接执行第5歩,忽略数据一致性、忽略master状态和其它master的意见

其流程如下:

我们以7381这个slave节点为例,演示如何手动进行故障转移,让7381重新夺回master:

  1. 利用redis-cli连接7381这个节点:redis-cli -p 7381

  2. 在7381节点上执行cluster failover命令

  3. 重新查看集群状态:cluster nodes

  4.  

7. RedisTemplate访问分片集群

RedisTemplate底层同样基于lettuce实现了分片集群的支持,而使用的步骤与哨兵模式基本一致:

1)引入redis的starter依赖

2)配置分片集群地址

3)配置读写分离

与哨兵模式相比,其中只有分片集群的配置方式略有差异,如下:

spring:
  redis:
    cluster:
      nodes:
        - 192.168.126.129:7380
        - 192.168.126.129:7381
        - 192.168.126.129:7382
        - 192.168.126.129:8380
        - 192.168.126.129:8381
        - 192.168.126.129:8382

8. 小结

1. Redis分片集群解决了什么问题
    海量数据存储的问题。有多个Master都可以存储数据
    高并发写的问题。有多个Master都可以提供写数据的服务

    连接分片集群,使用命令:redis-cli -c -p 任意Master节点的端口

2. 分片集群中的插槽是什么
    在存取每个key时,Redis会根据key通过CRC16算法做hash计算得到hash值,再拿hash值对16384求余数,是slot插槽值
    分片集群里,每个master节点都会负责一部分插槽的管理
    当存取数据时,Redis会根据key的slot插槽的值,判断这个key归哪个节点管理,就重定向到该节点上,执行存取

3. 分片集群伸缩的步骤

4. 分片集群如何实现故障转移

5. 用RedisTemplate如何访问分片集群

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

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

相关文章

为什么投稿 SCI 被审稿人通过,又被编辑拒收?

有些作者在投稿过程中会遇到各种坑&#xff0c;不过有一种坑却最让作者痛心疾首&#xff0c;不知道大家有没有遇到过这样的状况&#xff1a; 审稿人建议接收&#xff0c;编辑却拒稿了&#xff1b; 或者审稿人建议拒稿&#xff0c;编辑却让自己改改再投&#xff1f; 有国外学者…

微服务: Seata AT springCloud整合分布式事务以配置方式(中篇)

目录 上篇: 安装seata 并启动成功的传送门 1. 前言: 2. springCloud 使用seata at 的步骤如下 第一步 查看springCloud版本 第二步添加maven依赖 第三步 添加yml配置 第四步: 配置数据源(druid) 第五步 修复一个警告 第六步: 启动后 看看日志是否成功 上篇: 安装seat…

边缘计算盒子功能介绍,为什么要用边缘计算盒子?

边缘计算盒子&#xff08;Edge Computing Box&#xff09;是一种用于边缘计算设备。边缘计算是一种分布式计算模型&#xff0c;它将计算和数据处理能力从传统的集中式云计算数据中心延伸到网络边缘的设备上&#xff0c;以便更快地响应实时数据处理需求和减少对云服务的依赖。 边…

HardenedVault 推出 Linux 安全加固版

导读HardenedVault 于 AWS 云平台上推出 Linux 安全加固版&#xff0c;该产品可以通过实施CIS和STIG基准来帮助您实现合规要求&#xff08;PCI-DSS和GDPR&#xff09;。 Shawn the R0ck 写道&#xff1a;HardenedVault自从 2022 年 7 月在 Amazon Web Services (AWS)推出了 Har…

Vscode运行Html的插件以及快速编写Html框架

然后我们点击创建文件&#xff0c;记住要以.html结尾 输入英文感叹号回车就行&#xff08;记住要英文&#xff09; 好了&#xff0c;希望小伙伴能快速入手VsCode&#xff0c;很好用的一款开源免费软件

基于Android的校园外卖系统app

一、项目介绍 Android客户端功能描述&#xff1a; 1&#xff1a;登录注册&#xff1a;用户可以通过自己的信息进行账号的注册 2&#xff1a;商家查看&#xff1a;查看发布的外卖商家信息 3&#xff1a;商家详情&#xff1a;用户点击某一个商家之后可以查看商家的地址和联系方…

AI人工智能在Python中构建回归器的原理、优缺点、应用场景和实现方法

回归器&#xff08;Regressor&#xff09;是一种常用的机器学习算法&#xff0c;可以用于预测数值型变量的值。在人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;领域中&#xff0c;回归器是一种高效的算法&#xff0c;可以用于许多应用领域&#…

6.4.4最短路径问题-Floyd算法

原来在邻接矩阵种v2使无法到达v1的 但如果我们把v0作为中转站 不断增加中转点&#xff08;1个中转点&#xff09; 这里的path的值是中转点 v1到v2之间是没有中转点的。 这只是以一个中转点&#xff0c;more 路走得越多&#xff0c;会越来越小 广度优先遍历算法是遍历顶点和边…

(二)ArcGIS空间数据的转换与处理——矢量数据变换

ArcGIS空间数据的转换与处理——矢量数据变换 目录 ArcGIS空间数据的转换与处理——矢量数据变换 1.空间校正2.边匹配 数据变换是指对数据进行诸如放大、缩小、翻转、移动、扭曲等几何位置、形状和方位的改变等操作。对 矢量数据的相应操作可以通过 ArcMap 中空间较正 (Spatia…

录制屏幕怎么设置?怎么录制高画质的视频?

在今天的数字时代&#xff0c;屏幕录制已经成为了日常工作中不可或缺的一部分。许多人需要在电脑上录制屏幕来制作教程视频、演示文稿或者是游戏录像。本文将介绍如何在电脑上录制屏幕并获得高画质的视频。 屏幕录制软件的选择 要在电脑上录制高画质的视频&#xff0c;首先需要…

【1】机器学习

目录 1 机器学习概述 1.1 定义 1.2 基本方法 1.3 基本概念 1.4 有监督学习 1.5 无监督学习 1.6 过度拟合问题 模型过于复杂(例如参数过多) 正则化 1.7 模型选择 交叉验证 K折交叉验证 2 机器学习常用工具 3 Scikit-learn 3.1 基本流程 3.2 Scikit-learn常用函数 3.…

csdn Markdown编辑器

文章目录 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个注脚注释也是…

云视如何实现流量转化

云视如何实现流量转化 大家好我是小鱼 小伙伴很好奇 云视除了直播带货 打赏&#xff0c;广告 还有哪些方式 可以实现流量转化 今天我和大家分享一下这个话题 接下来我们要讲讲 我们要用的工具 优惠券 适用于刺激消费回流&#xff0c;构建闭环消费圈。 课程赠送 趣味推广营销&am…

平台使用篇 | 批处理(bat)脚本使用教程(三)

导读 本讲针对RflySim平台的一些特点简要介绍了平台使用批处理技术的原因&#xff0c;并根据CopterSim中仿真功能区的参数设置阐述了批处理技术在平台中的具体运用。 平台使用篇 | 批处理(bat)脚本使用教程(三&#xff09; RflySim平台使用批处理技术的原因 ①调用多个软件Rf…

吲哚菁绿ICG-Amine/NH2荧光标记和成像1686147-55-6

ICG-Amine是一种荧光染料&#xff0c;ICG-Amine具有良好的荧光性能&#xff0c;可用于生物医学研究中的荧光标记和成像。ICG-Amine的物理性质如下&#xff1a;化学式&#xff1a;C47H56N4O4S&#xff0c;分子量为773.04&#xff0c;外观&#xff1a;深绿色粉末溶解性&#xff1…

代码随想录算法训练营第四十八天 | 树形dp

198.打家劫舍 文档讲解&#xff1a;代码随想录 (programmercarl.com) 状态&#xff1a;看了“决定dp[i]的因素才做出来"。 思路 当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷了。 所以这里就更感觉到&#xff0c;当前状态和前面状态会有一种依赖关系&#xf…

点云重建总结

几何处理和三维视觉 几何处理&#xff1a;是一种计算的方法研究世界中的物理对象&#xff0c;通过硬件扫描生成物理对象的三维模型然后做各种处理和分析。 三维视觉&#xff1a;传统的3D视觉是指从图像中恢复底层的三维结构。 1 几何重建 1.1几何重建的基本流程 扫描&…

宝塔PHP7.1版本37个扩展作用介绍

PATH_INFO&#xff1a;这个扩展可以让PHP获取到URL中的PATH_INFO信息&#xff0c;方便处理URL路由。 bt_safe&#xff1a;这个扩展可以帮助PHP防止一些常见的安全漏洞&#xff0c;比如SQL注入、XSS攻击等。 ionCube&#xff1a;这个扩展可以对PHP代码进行加密&#xff0c;保护…

Linux——线程7|线程池

线程池 线程池以空间换时间,预先申请一批线程,当有任务到来,直接指派线程。 由于这是类的成员函数,因此传参的时候会有一个this指针,我们如果想在传参的时候不传这个this指针,我们只需加上static。 这里只传一个参数,是因为我们的routine是这种类型的

苹果笔不用原装可以吗?apple pencil二代平替笔推荐

随着网络技术的飞速发展&#xff0c;移动电话、平板电脑、笔记本等移动设备正在逐渐走进人们的生活。就好比如我们现在用的是电容笔。我认为&#xff0c;如果我们可以运用它来学习记笔记&#xff0c;做笔记&#xff0c;或其他一些很简单的事情&#xff0c;我们将不必为一支原装…