Redis 安装部署[主从、哨兵、集群](linux版)

说明:如果打算将本文内容应用于生产环境,建议对相关参数进行适当调整,以确保系统的稳定性和性能优化。

背景

长期以来,我们一直在使用Redis,但始终未能形成一个高效的运维模式来快速搭建Redis环境。因此,我编写了这份文档,旨在作为一份备忘录,同时也希望能与团队分享,以便我们能够更高效地协作和提升工作效率。

为了便于大家理解,接下来我将展示如何通过编写Shell脚本快速搭建Redis环境。如果条件允许,也可以基于这些脚本逻辑,采用Docker容器化技术来构建Redis,以实现更加灵活和便捷的部署。

一、Redis 下载安装

  • 下载地址:https://download.redis.io/releases/
  • 选择版本:redis-7.4.0
  • 安装包名称:redis-7.4.0.tar.gz
  • 详细命令
# 进入安装目录
cd /home/middleware/redis# 下载
wget https://download.redis.io/releases/redis-7.4.0.tar.gz# 解压
tar -zxvf redis-7.4.0.tar.gz# 进入redis目录
cd redis-7.4.0# 下载相关依赖
yum -y install gcc gcc-c++ tcl automake autoconf libtool make# 安装编译redis(安装后,redis默认设置到环境变量中)
make && make install

二、Redis 主从复制 搭建

  • 主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。
  • 主从复制是高可用Redis的基础,哨兵和集群都是在主从复制基础上实现高可用的。
  • 缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。

1、创建配置目录

# 创建配置目录(下面的脚本都放到该目录,具体目录可自定义)
mkdir /home/middleware/redis/redis-master-slavecd /home/middleware/redis/redis-master-slave

2、创建模板配置文件 redis.conf.template

  • 创建配置文件
# 创建配置文件
vim redis.conf.template
  • 模板配置文件内容如下:
  • 模板配置文件中的占位符:
    • custom_port 自定义端口占位符
    • master_pwd 主节点密码
    • replicaof_master_ip_port 从节点同步主节点占位符
# 修改监听地址
bind 0.0.0.0# 关闭保护模式,默认yes,让redis支持远程连接
protected-mode no# redis监听端口,默认6379
port custom_port# 开启守护进程,以独立进程启动,默认no
daemonize yes# 设置pidfile,默认redis.pid
pidfile redis_custom_port.pid# 日志文件,默认redis.log
logfile "redis_custom_port.log"# 禁用save命令,同步执行有性能问题,推荐使用bgsave
save ""# 设置快照文件名称,默认dump.rdb
dbfilename dump_custom_port.rdb# 设置数据目录,默认./
dir ./# 连接主节点的密码,配置在从节点,默认12345
masterauth 'master_pwd'# 连接Redis服务的redis密码,配置在主节点,默认''
requirepass 'master_pwd' # 设置最大内存,单位kb/mb/gb
maxmemory 256mb# 设置内存淘汰策略,默认noeviction不淘汰数据
# volatile-lru 按照LRU算法逐出原有数据,但仅逐出设置了过期时间的数据
maxmemory-policy volatile-lru# 开启AOF持久化,默认no
appendonly yes# AOF持久化文件名称,默认appendonly.aof
appendfilename "appendonly_custom_port.aof"# 从节点配置 -----------------------------
# 指定要同步的Master节点IP和端口
# replicaof 127.0.0.1 6379
#replicaof_master_ip_port

3、创建控制脚本 redis-master-slave.sh

  • 创建脚本
# 创建脚本
vim redis-master-slave.sh# 授权
chmod 777 redis-master-slave.sh
  • 脚本内容如下:
  • 请根据自己需要,修改脚本中的属性
#!bin/bashPROG_NAME=$0
ACTION=$1# master ip和port
master_ip=172.18.31.17
master_port=6379
master_pwd=123456# 一台机器上启动的从节点的端口列表
slave_ports=(6380 6381)# 当前路径
curr_path=$(pwd)# redis模板配置文件
redis_conf_tempalte=redis.conf.template# redis模板配置文件中的占位符
old_char=custom_port
old_master_pwd=master_pwd# 针对从节点配置,做特殊处理
old_replicaof="#replicaof_master_ip_port"
new_replicaof="replicaof $master_ip $master_port"# 数组长度
slave_ports_len=${#slave_ports[@]}usage() {cat << EOF该脚本用于操作 Redis 主从节点.Usage: $PROG_NAME OptionsOptions:create_master_conf     批量生成主节点配置文件create_slave_conf      批量生成从节点配置文件start_master_node      批量启动主节点start_slave_node       批量启动从节点start_node             批量启动主节点和从节点stop_node              批量停止主节点和从节点restart_node           批量重启主节点和从节点
EOFexit 2
}# --------------------------------------------------------------
# 第一步:生成redis配置文件(基于模板配置文件redis.conf.template)
# 作用:无需手动修改redis配置文件中的内容,可简化操作
# --------------------------------------------------------------# 1、生成主节点redis配置文件
create_master_conf() {dest_filename=$master_port/redis-$master_port.confif [ ! -d "$master_port" ]; thenmkdir -p "$master_port"echo "Created directory: $master_port"fiif [ ! -e "$dest_filename" ]; thenecho "复制配置文件: $dest_filename"cp $redis_conf_tempalte $dest_filenameecho "替换配置文件中的占位符 $dest_filename"sed -i "s/$old_char/$master_port/g" $dest_filenamesed -i "s/$old_master_pwd/$master_pwd/g" $dest_filenameecho ""elseecho "配置文件已存在: $dest_filename"fi
}# 2、生成从节点redis配置文件
# 注意:每个从节点所在机器都需要执行一次
create_slave_conf() {for (( i=0; i<$slave_ports_len; i++ ))donew_char=${slave_ports[$i]}dest_filename=$new_char/redis-$new_char.confif [ ! -d "$new_char" ]; thenmkdir -p "$new_char"echo "Created directory: $new_char"fiif [ ! -e "$dest_filename" ]; thenecho "复制配置文件: $dest_filename"cp $redis_conf_tempalte $dest_filenameecho "替换配置文件中的占位符 $dest_filename"sed -i "s/$old_char/$new_char/g" $dest_filenamesed -i "s/$old_master_pwd/$master_pwd/g" $dest_filenamesed -i "s/$old_replicaof/$new_replicaof/g" $dest_filenameecho ""elseecho "配置文件已存在: $dest_filename"fidone
}# --------------------------------------------------------------
# 第二步:启动redis节点
# --------------------------------------------------------------# 1、启动redis主节点
start_master_node() {    echo "redis-$master_port start"cd $curr_path/$master_port# 异步执行nohup redis-server redis-$master_port.conf >/dev/null 2>&1 &echo "redis-$master_port end"echo ""
}# 2、批量启动redis从节点
# 注意:每个从节点所在机器都需要执行一次
start_slave_node() {for (( i=0; i<$slave_ports_len; i++ ))donew_char=${slave_ports[$i]}echo "redis-$new_char start"cd $curr_path/$new_char# 异步执行nohup redis-server redis-$new_char.conf >/dev/null 2>&1 &echo "redis-$new_char end"echo ""done
}# --------------------------------------------------------------
# 第三步:停止redis节点
# --------------------------------------------------------------
stop_node() {# 获取redis进程id列表,将ps awk 处理的信息转换为数组pids=(`ps -ef | grep 'redis-server' | grep -v grep |grep -v 'redis-master-slave.sh'| awk '{print$2}'`)if [ ${#pids[@]} -eq 0 ]; thenecho -e "\rno redis process"returnfiecho "stop redis process"times=60for e in $(seq 60)dosleep 1cost_time=$(($times - $e ))pids=(`ps -ef | grep 'redis-server' | grep -v grep |grep -v 'redis-master-slave.sh'| awk '{print$2}'`)if [ ${#pids[@]} -eq 0 ]; thenecho -e "\rredis process has exited"break;fifor pid in ${pids[*]}dokill -9 $pidecho -e "\r -- $pid stopping redis lasts `expr $cost_time` seconds."donedoneecho ""
}case "$ACTION" increate_master_conf)create_master_conf;;create_slave_conf)create_slave_conf;;start_master_node)start_master_node;;start_slave_node)start_slave_node;;start_node)start_master_nodestart_slave_node;;stop_node)stop_node;;restart_node)stop_nodestart_master_nodestart_slave_node;;*)usage;;
esac

4、执行控制脚本

  • 按顺序执行如下命令,搭建Redis 主从
# 主节点所在机器(172.18.31.17)# 1、生成主节点配置文件
sh redis-master-slave.sh create_master_conf# 2、生成从节点redis配置文件
sh redis-master-slave.sh create_slave_conf# 3、启动主从节点
sh redis-master-slave.sh start_node# 或者,分开启动主从节点
sh redis-master-slave.sh start_master_node
sh redis-master-slave.sh start_slave_node# 从节点所在机器(172.18.31.16)
# 1、生成从节点redis配置文件
sh redis-master-slave.sh create_slave_conf# 2、启动从节点
sh redis-master-slave.sh start_slave_node

5、测试命令

# 查看主从复制信息
redis-cli -h 127.0.0.1 -p 6379 -a 123456 info replication# 验证主从复制# 登录主节点
redis-cli -h 127.0.0.1 -p 6379 -a 123456keys *set name 123get name# 登录从节点
redis-cli -h 127.0.0.1 -p 6380 -a 123456keys *

三、Redis Sentinel 搭建

注意: 新版本redis自带哨兵,不需要单独安装

  • 在上面主从复制模式的基础上,新增sentinel哨兵的能力。
  • Redis Sentinel是Redis官方提供的高可用性解决方案,主要用于监控和管理Redis服务器,确保在主服务器发生故障时能够自动进行故障转移,从而保证服务的连续性和高可用性。
  • 主要功能
    • 主从监控:定期向主服务器和从服务器发送PING命令,检查它们是否在线
    • 故障转移:如果master 宕机,自动根据投票数将 slave 切换为新 master
    • 消息通知:哨兵可以将故障转移的结果发送给客户端
    • 配置中心:客户端通过连接哨兵来获得当前Redis服务的主节点地址
  • 缺陷:写操作无法负载均衡;存储能力受到单机的限制;哨兵无法对从节点进行自动故障转移,在读写分离场景下,从节点故障会导致读服务不可用,需要对从节点做额外的监控、切换操作。

1、创建配置目录

# 创建配置目录(下面的脚本都放到该目录,具体目录可自定义)
mkdir /home/middleware/redis/redis-sentinelcd /home/middleware/redis/redis-sentinel

2、创建模板配置文件 sentinel.conf.template

  • 创建配置文件
# 创建配置文件
vim sentinel.conf.template
  • 模板配置文件内容如下:
  • 模板配置文件中的占位符:custom_port 自定义端口占位符
# 关闭保护模式,让redis支持远程连接
protected-mode no# 端口,默认26379
port custom_port# 指定sentinel为后台启动
daemonize yes# 设置pidfile,默认redis-sentinel.pid
pidfile sentinel_custom_port.pid# 日志存放路径
logfile "sentinel_custom_port.log"# 指定数据存放路径
dir ./# 配置监听主服务器
# mymaster:自定义redis主节点名称,在一个sentinel网络中,一个redis主节点只能有一个名称
# 172.19.223.161:表示主节点ip
# 6379:表示主节点port
# 2:表示至少需要2个哨兵认为主节点不可⽤时,才会进⾏failover操作
sentinel monitor mymaster master_ip master_port 2# 配置服务密码
# mymaster:redis主节点名称(与上一致);
# 123456:redis主节点和从节点的密码
sentinel auth-pass mymaster master_pwd# 判定服务器down掉的时间周期,默认30000毫秒(30秒)
sentinel down-after-milliseconds mymaster 30000# 故障转移的最大超时时间为180000(180秒)
sentinel failover-timeout mymaster 180000

3、创建控制脚本 redis-sentinel.sh

  • 创建脚本
# 创建脚本
vim redis-sentinel.sh# 授权
chmod 777 redis-sentinel.sh
  • 脚本内容如下:
  • 请根据自己需要,修改脚本中的属性
#!bin/bashPROG_NAME=$0
ACTION=$1# master ip和port
master_ip=172.18.31.17
master_port=6379
master_pwd=123456# 一台机器上启动的sentinel的端口列表
sentinel_ports=(26379 26380 26381)# 当前路径
curr_path=$(pwd)# sentinel模板配置文件
sentinel_conf_tempalte=sentinel.conf.template# 模板配置文件中的占位符
old_char=custom_port# 主节点占位符
old_master_ip="master_ip"
old_master_port="master_port"
old_master_pwd="master_pwd"# 数组长度
sentinel_ports_len=${#sentinel_ports[@]}usage() {cat << EOF该脚本用于操作 Redis 主从节点.Usage: $PROG_NAME OptionsOptions:create_sentinel_conf   批量生成sentinel配置文件start_sentinel_node    批量启动sentinel节点stop_node              批量停止sentinel节点restart_node           批量重启sentinel节点
EOFexit 2
}# --------------------------------------------------------------
# 第一步:生成sentinel配置文件
# 注意:每个sentinel节点所在机器都需要执行一次
# --------------------------------------------------------------
create_sentinel_conf() {for (( i=0; i<$sentinel_ports_len; i++ ))donew_char=${sentinel_ports[$i]}dest_filename=$new_char/sentinel-$new_char.confif [ ! -d "$new_char" ]; thenmkdir -p "$new_char"echo "Created directory: $new_char"fiif [ ! -e "$dest_filename" ]; thenecho "复制配置文件: $dest_filename"cp $sentinel_conf_tempalte $dest_filenameecho "替换配置文件中的占位符 $dest_filename"sed -i "s/$old_char/$new_char/g" $dest_filenamesed -i "s/$old_master_ip/$master_ip/g" $dest_filenamesed -i "s/$old_master_port/$master_port/g" $dest_filenamesed -i "s/$old_master_pwd/$master_pwd/g" $dest_filenameecho ""elseecho "配置文件已存在: $dest_filename"fidone
}# --------------------------------------------------------------
# 第二步:启动sentinel节点
# 注意:每个sentinel节点所在机器都需要执行一次
# --------------------------------------------------------------
start_sentinel_node() {for (( i=0; i<$sentinel_ports_len; i++ ))donew_char=${sentinel_ports[$i]}echo "sentinel-$new_char start"cd $curr_path/$new_charnohup redis-sentinel sentinel-$new_char.conf >/dev/null 2>&1 &echo "sentinel-$new_char end"echo ""done
}# --------------------------------------------------------------
# 第三步:停止sentinel节点
# --------------------------------------------------------------
stop_node() {# 获取redis进程id列表,将ps awk 处理的信息转换为数组pids=(`ps -ef | grep 'redis-sentinel' | grep -v grep |grep -v 'redis-sentinel.sh'| awk '{print$2}'`)if [ ${#pids[@]} -eq 0 ]; thenecho -e "\rno redis process"returnfiecho "stop redis process"times=60for e in $(seq 60)dosleep 1cost_time=$(($times - $e ))pids=(`ps -ef | grep 'redis-sentinel' | grep -v grep |grep -v 'redis-sentinel.sh'| awk '{print$2}'`)if [ ${#pids[@]} -eq 0 ]; thenecho -e "\rredis process has exited"break;fifor pid in ${pids[*]}dokill -9 $pidecho -e "\r -- $pid stopping redis lasts `expr $cost_time` seconds."donedoneecho ""
}case "$ACTION" increate_sentinel_conf)create_sentinel_conf;;start_sentinel_node)start_sentinel_node;;stop_node)stop_node;;restart_node)stop_nodestart_sentinel_node;;*)usage;;
esac

4、执行控制脚本

  • 按顺序执行如下命令,搭建Redis Sentinel
# 1、生成sentinel配置文件
sh redis-sentinel.sh create_sentinel_conf# 2、启动sentinel节点
sh redis-sentinel.sh start_sentinel_node

5、测试命令

# 第一步:查看:sentinel 信息(主节点为6379)
[root@centos7 redis-sentinel]# redis-cli -h 127.0.0.1 -p 26379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.18.31.17:6379,slaves=2,sentinels=3# 第二步:模拟:kill 掉主节点 6379
[root@centos7 redis-master-slave]# ps -ef | grep redis
root       2518      1  0 11:23 ?        00:00:07 redis-server 0.0.0.0:6380
root       2519      1  0 11:23 ?        00:00:07 redis-server 0.0.0.0:6379
root       2520      1  0 11:23 ?        00:00:07 redis-server 0.0.0.0:6381
root       2656      1  1 11:37 ?        00:00:03 redis-sentinel *:26379 [sentinel]
root       2657      1  1 11:37 ?        00:00:03 redis-sentinel *:26380 [sentinel]
root       2658      1  1 11:37 ?        00:00:03 redis-sentinel *:26381 [sentinel]
root       2696   1952  0 11:42 pts/0    00:00:00 grep --color=auto redis[root@centos7 redis-master-slave]# kill -9 2519# 第三步:等待几秒,查看:sentinel 信息(主节点为6381,说明已自动切换主节点)
[root@centos7 redis-sentinel]# redis-cli -h 127.0.0.1 -p 26379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.18.31.17:6381,slaves=2,sentinels=3# 第四步:查看主从复制信息(6381变为主节点,且只有一个6380的从节点)
[root@centos7 redis-sentinel]# redis-cli -h 127.0.0.1 -p 6381 -a 123456 info replication
# Replication
role:master
connected_slaves:1
slave0:ip=172.18.31.17,port=6380,state=online,offset=16852,lag=0
master_failover_state:no-failover
master_replid:b763222247189ca9cd4f51b69f3cca41e1b42c7e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:16852
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:16852

四、Redis Cluster 搭建【推荐】

  • Redis Cluster模式解决了写操作无法负载均衡,以及单机存储限制的问题,实现了较为完善的高可用方案。
  • Redis Cluster模式中集群节点最小配置6个节点(3主3从),其中主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用。

1、创建配置目录

# 创建集群配置目录(下面的脚本都放到该目录,具体目录可自定义)
mkdir -p /home/middleware/redis/redis-clustercd /home/middleware/redis/redis-cluster

2、创建模板配置文件 redis.cluster.conf.template

  • 创建配置文件
# 创建配置文件
vim redis.cluster.conf.template
  • 模板配置文件内容如下:
  • 模板配置文件中的占位符:custom_port
  • 说明:
    • 若有参数需调整,可先修改该模板配置文件的内容,再执行后面的脚本。
    • 重点注意 requirepass 和 maxmemory的配置。
# 注释掉 bind 项,默认监听所有网卡
# bind 127.0.0.1
bind 0.0.0.0# 关闭保护模式,默认yes,让redis支持远程连接
protected-mode no# redis监听端口,默认6379
port custom_port# 开启守护进程,以独立进程启动,默认no
daemonize yes# 设置pidfile,默认redis.pid
pidfile redis_custom_port.pid# 日志文件,默认redis.log
logfile "redis_custom_port.log"# 禁用save命令,同步执行有性能问题,推荐使用bgsave
save ""# 默认yes【设置为no解决window11启动报错EXCEPTION_ACCESS_VIOLATION的问题】
stop-writes-on-bgsave-error no# 设置快照文件名称,默认dump.rdb
dbfilename dump_custom_port.rdb# 设置数据目录,默认./
dir ./# 从节点重新规划周期,默认10
repl-ping-slave-period 10# 连接主节点的密码,配置在从节点,默认12345
masterauth '123456'# 连接Redis服务的redis密码,配置在主节点,默认''
# 集群版建议将各个节点的masterauth和requirepass设置为相同的密码,因为从节点也可能升级为主节点
requirepass '123456'# 设置最大内存,单位kb/mb/gb
maxmemory 256mb# 设置内存淘汰策略,默认noeviction不淘汰数据
# volatile-lru 按照LRU算法逐出原有数据,但仅逐出设置了过期时间的数据
maxmemory-policy allkeys-lru# 开启AOF持久化,默认no
appendonly yes# AOF持久化文件名称,默认appendonly.aof
appendfilename "appendonly_custom_port.aof"# 开启群集功能,默认no
cluster-enabled yes# 群集节点名称文件设置,默认nodes-6379.conf
cluster-config-file nodes_custom_port.conf# 设置群集节点超时时间,默认15000
# 集群中每个节点都会定期向其他节点发送ping消息,接收节点回复pong消息作为响应。
# 如果在cluster-node-timeout时间内通信一直失败,则发送节点会认为接收节点存在故障,把接收节点标记为主观下线(pfail)状态。默认15000,即15s。
cluster-node-timeout 15000# 从节点有效因子,提高集群故障转移能力,默认10
# 每个从节点都要检查最后与主节点断线时间,判断其是否有资格替换故障的主节点。
# 如果从节点与主节点断线时间超过 (cluster-node-timeout * cluster-slave-validity-factor) + repl-ping-slave-period,则当前从节点不具备故障转移资格。
# 例如,如果节点超时时间为30秒,从节点有效因子为10,从节点重新规划周期为10秒,如果从节点与主节点断线时间超过310秒,则当前从节点不会尝试故障转移。
cluster-slave-validity-factor 10# 迁移屏障,提高集群抵抗故障的能力,默认1
# 迁移屏障为1,表示只有当主节点至少保留一个从节点时,从节点才会迁移
# 要禁用迁移,只需将其设置为一个非常大的值。
cluster-migration-barrier 1# 设置集群可用性,默认为yes
# yes 表示所有slot都正常工作,才能对外提供服务
# no  表示部分slot出现问题,其他正常的slot仍然可以继续提供服务
cluster-require-full-coverage yes

3、创建控制脚本 redis-cluster.sh

  • 创建脚本
# 创建脚本
vim redis-cluster.sh# 授权
chmod 777 redis-cluster.sh
  • 脚本内容如下:
  • 请根据自己的需要,修改脚本中的属性:hosts、ports、redis_pwd
#!bin/bashPROG_NAME=$0
ACTION=$1# 单机集群配置
# 举例:3主3从,1个ip,6个port,即一台机器6个节点
# hosts=("127.0.0.1")
# ports=(6001 6002 6003 6004 6005 6006)# 多机集群配置
# 举例:3主3从,3个ip,2个port,即一台机器2个节点,3主3
hosts=("172.18.31.15" "172.18.31.16" "172.18.31.17")
ports=(6001 6002)# redis密码,对应模板配置文件redis.cluster.conf.template中的密码
redis_pwd=123456# 数组长度
host_len=${#hosts[@]}
port_len=${#ports[@]}# 当前路径
curr_path=$(pwd)# redis模板配置文件
redis_conf_tempalte=redis.cluster.conf.template# redis模板配置文件中的占位符
old_char=custom_portusage() {cat << EOF该脚本用于操作 Redis Cluster.Usage: $PROG_NAME OptionsOptions:create_conf     批量生成redis配置文件start_node      批量启动redis集群节点stop_node       批量停止redis集群节点restart_node    批量重启redis集群节点create_cluster  创建redis集群
EOFexit 2
}# --------------------------------------------------------------
# 第一步:批量生成redis配置文件(基于模板配置文件redis.cluster.conf.template)
# 注意:每台机器都需要执行
# 作用:无需手动修改redis配置文件中的内容,可简化操作
# --------------------------------------------------------------
create_conf() {for (( i=0; i<$port_len; i++ ))donew_char=${ports[$i]}dest_filename=$new_char/redis-$new_char.confif [ ! -d "$new_char" ]; thenmkdir -p "$new_char"echo "Created directory: $new_char"fiif [ ! -e "$dest_filename" ]; thenecho "复制配置文件: $dest_filename"cp $redis_conf_tempalte $dest_filenameecho "替换配置文件中的占位符 $dest_filename"sed -i "s/$old_char/$new_char/g" $dest_filenameecho ""elseecho "配置文件已存在: $dest_filename"fidone
}# --------------------------------------------------------------
# 第二步:批量启动redis集群节点
# 注意:每台机器都需要执行
# --------------------------------------------------------------
start_node() {for (( i=0; i<$port_len; i++ ))donew_char=${ports[$i]}echo "redis-$new_char start"cd $curr_path/$new_char# 异步执行nohup redis-server redis-$new_char.conf >/dev/null 2>&1 &echo "redis-$new_char end"echo ""done
}# 批量停止redis集群节点
stop_node() {# 获取redis进程id列表,将ps awk 处理的信息转换为数组pids=(`ps -ef | grep 'redis-server' | grep -v grep |grep -v 'redis-cluster.sh'| awk '{print$2}'`)if [ ${#pids[@]} -eq 0 ]; thenecho -e "\rno redis process"returnfiecho "stop redis process"times=60for e in $(seq 60)dosleep 1cost_time=$(($times - $e ))pids=(`ps -ef | grep 'redis-server' | grep -v grep |grep -v 'redis-cluster.sh'| awk '{print$2}'`)if [ ${#pids[@]} -eq 0 ]; thenecho -e "\rredis process has exited"break;fifor pid in ${pids[*]}dokill -9 $pidecho -e "\r -- $pid stopping redis lasts `expr $cost_time` seconds."donedoneecho ""
}# --------------------------------------------------------------
# 第三步:创建redis集群
# 注意:在集群中任意一台机器上执行,且执行一次即可
# --------------------------------------------------------------
create_cluster() {# 生成 ip:port 格式串ip_port_list=""for (( i=0; i<$host_len; i++ ))dofor (( j=0; j<$port_len; j++ ))doip_port_list+=" ${hosts[$i]}:${ports[$j]}"donedoneecho "节点列表: $ip_port_list"# 执行创建集群命令# --cluster create 表示创建集群# --replicas 1 表示每个主节点有1个从节点,这里随机分配主从关系。如果需要定制,则可以不加该参数,使用add-node来定制。echo yes | redis-cli --cluster create $ip_port_list --cluster-replicas 1 -a $redis_pwd
}case "$ACTION" increate_conf)create_conf;;start_node)start_node;;stop_node)stop_node;;restart_node)stop_nodestart_node;;create_cluster)create_cluster;;*)usage;;
esac

4、执行控制脚本

  • 按顺序执行如下命令,搭建Redis Cluster
# 第一步:基于redis模板配置文件,一键批量生成redis集群中的节点配置文件
# 注意:每台机器都需要执行
sh redis-cluster.sh create_conf# 第二步:批量启动redis集群节点
# 注意:每台机器都需要执行
sh redis-cluster.sh start_node# 注意:集群所有节点都启动后,再执行下面步骤# 第三步:创建redis集群
# 注意:在集群中任意一台机器上执行即可
sh redis-cluster.sh create_cluster# 批量停止redis集群节点
# 注意:每台机器都需要执行
sh redis-cluster.sh stop_node# 批量重启redis集群节点
# 注意:每台机器都需要执行
sh redis-cluster.sh restart_node

5、测试命令

# 测试集群# -c 表示-c(cluster),连接集群时使用,可防止moved和ask异常
# -a 表示-a(auth),redis密码,无需手动auth命令
redis-cli -h 127.0.0.1 -p 6001 -c -a 123456# 查看节点的哈希槽编号范围
cluster slots# 设置name键的值
set name abcd
-> Redirected to slot [5798] located at 127.0.0.1:6002【说明:重定向到了6002】# 查看name键的槽编号(6002)
cluster keyslot name# 查看节点6002上name建是否存在(存在)
redis-cli -h 127.0.0.1 -p 6002 -c -a 123456
keys *# 查看节点6003上name建是否存在(不存在)
redis-cli -h 127.0.0.1 -p 6003 -c -a 123456
keys *# 在节点6003上获取name键的值
get name
-> Redirected to slot [5798] located at 127.0.0.1:6002【说明:重定向到了6002】
"abcd"# 手动关闭节点
redis-cli -h 127.0.0.1 -p 6001 -a 123456 shutdown# 查看redis节点信息
redis-cli -h 127.0.0.1 -p 6001 -a 123456 info# 每1秒打印一次info的过滤信息
# -r 表示将命令循环多少次
# -i 表示每隔几秒执行一次命令
redis-cli -h 127.0.0.1 -p 6001 -a 123456 -r 10 -i 1 info | grep used_memory_human

6、集群操作

查看集群命令帮助说明

# 
redis-cli --cluster help

查看集群节点id nodes

# 查看集群中的节点id
redis-cli -h 127.0.0.1 -p 6001  -a 123456 cluster nodes# 获取slot分配
redis-cli -c -p 127.0.0.1 -p 6001  -a 123456 cluster slots# 查看主从复制信息
redis-cli -h 127.0.0.1 -p 7003 -a 123456 -c info replication

查看集群 info

# 查看集群
redis-cli --cluster info 127.0.0.1:6001 -a 123456

检查集群 check

# 检查集群
redis-cli --cluster check 127.0.0.1:6001 -a 123456# 检查集群中是否有槽同时被分配给了多个节点,只有当所有的槽位正常时,集群状态才算OK
redis-cli --cluster check 127.0.0.1:6001 --cluster-search-multiple-owners -a 123456

迁移槽位 reshard

# 命令解释
# 迁移一个或者多个节点上的槽位至一个目标节点上
# --cluster-from <arg>   #槽位来源节点id,多个用,分割,all表示全部节点,值不为all的情况下,不能包含--cluster-to
# --cluster-to <arg>     #槽位目标节点id,只允一个
# --cluster-slots <arg>  #迁移的槽位数
# --cluster-yes          #是否默认同意集群内部的迁移计划(默认同意就可以)
# --cluster-timeout <arg>   #迁移命令(migrate)的超时时间
# --cluster-pipeline <arg>  #迁移key时,一次取出的key数量,默认10
# --cluster-replace         #是否直接replace到目标节点# 迁移槽位,迁移100个槽位,将100个槽位从6001,迁移到节点6002
redis-cli --cluster reshard 127.0.0.1:6001 --cluster-from 7e482eb54f131ef01f5050e600f12d1980ea7f1e --cluster-to 9db0701a7d10a3044763b7a17365933eeab47d08 --cluster-slots 100 --cluster-yes -a 123456

平衡集群 rebalance

# 命令解释
# rebalance host:port
# --cluster-weight <node1=w1...nodeN=wN> # 槽位权重(浮点型)比值,例如(这里使用端口号代替运行id): 7001=1 7002=1 7003=2 则表示,总权重为4, 7001和7002将分配到 (16384/4)*1  个槽位,7003则是(16384/4)*2个槽位。
# --cluster-use-empty-masters
# --cluster-timeout <arg>      # 迁移命令(migrate)的超时时间
# --cluster-simulate           # 模拟rebalance操作,不会真正执行迁移操作
# --cluster-pipeline <arg>     # 定义 getkeysinslot命令一次取出的key数量,默认值为10
# --cluster-threshold <arg>    # 平衡触发的阈值条件,默认为2.00%。例如上一步,7001和7002应该有4096个槽位,如果7001的槽位数不够4096个,且超过 (4096*0.02 约等于)82个及以上;或者7001的槽位数比4096少于82个及以上,则会触发自平衡。
# --cluster-replace            # 是否直接replace到目标节点# 重新分配集群各个节点负责的槽位,让各个节点负责的槽数量重新回到平均状态
redis-cli --cluster rebalance 127.0.0.1:6001 -a 123456# 平均分配所有的槽位:不手动指定槽位分配,自动将16384个槽位,分配给集群的每一个master
redis-cli --cluster rebalance 127.0.0.1:6001 --cluster-use-empty-masters --cluster-threshold 1 -a 123456# 按权重分配槽位:把node3上的槽位,平均分配到其他主节点上去
# 各个节点的权重都为1时,表示平均分配所有的槽位
redis-cli --cluster rebalance 127.0.0.1:6001 --cluster-weight node1=1 node2=1 node3=0 -a 123456# 按权重分配槽位:总权重为4,node1权重=1 node2权重=1 node3权重=2
redis-cli --cluster rebalance 127.0.0.1:6001 --cluster-weight 7e482eb54f131ef01f5050e600f12d1980ea7f1e=1 9db0701a7d10a3044763b7a17365933eeab47d08=1 7879e1312ab7d13267357bceb58f99a9ce15cd9e=2 -a 123456

集群扩容 add-node

  • 扩容,即向集群中添加主节点或从节点
  • 扩容后,迁移槽位时,如何保证不影响 redis 的使用?(待研究)
  • 在不影响集群对外服务的情况下,为集群添加节点进行扩容,也可以下线部分节点进行缩容
  • 扩容步骤:
    • 第一步:添加节点
    • 第二步:迁移槽位 or 槽位平衡
# 命令解释
# add-node 
# new_host:new_port            #新加入集群的ip和port
# existing_host:existing_port  #集群中任一节点的ip和port
# --cluster-slave              #新节点作为从节点,默认随机一个主节点
# --cluster-master-id <arg>    #给新节点指定主节点,值为节点的运行id# 添加主节点
# 不传入--cluster-slave --cluster-master-id 参数,表示添加一个主节点。
# 注意,当添加的是一个主节点时,此时,该主节点没有任何槽位,可以使用rebalance或者reshard来迁移槽位给它。
redis-cli --cluster add-node 127.0.0.1:6007 127.0.0.1:6001 -a 123456# 槽位平衡:自动将16384个槽位,分配给集群的每一个master,不用手动指定槽位分配
redis-cli --cluster rebalance 127.0.0.1:6001 --cluster-use-empty-masters --cluster-threshold 1 -a 123456# 添加从节点(方式1)
# 假设现在集群中有6001 6002 6003 6007四个主节点,想为6007添加一个从节点127.0.0.1:6008,命令如下:
redis-cli --cluster add-node 127.0.0.1:6008 127.0.0.1:6001 --cluster-slave --cluster-master-id 0115ad0b7bbb3b95ff8e94388c14cf9189b8d2fe -a 123456# 添加从节点(方式2),随机跟一个主节点
# 注意,如果没有指定主节点,那么会去一个副本数更少的主节点做副本;如果副本数都一样,那么就随机跟一个主节点;
redis-cli --cluster add-node 127.0.0.1:6008 127.0.0.1:6001 --cluster-slave -a 123456

说明:redis集群扩容,槽位迁移时,可能会遇到超时问题,解决方案具体见下文的常见错误-问题4

集群缩容 del-node

  • 缩容步骤:
    • 第一步:先迁移槽位 or 槽位平衡
    • 第二步:删除节点
# 命令解释
# del-node host:port node_id     #删除给定的一个节点,成功后关闭该节点服务
# 用于从集群中删除指定的节点。host:port是执行命令的节点地址和端口,node_id是要删除的节点ID。# 删除从节点
redis-cli --cluster del-node 127.0.0.1:6008 98da58b16dc8becd4a1474e772ae4e24b44f0e1e -a 123456# 按权重分配槽位:把node4上的槽位,平均分配到其他主节点上去
# 注意,如果把主节点的 slot 都迁移走了,那么该主节点下的从库会自动转移到其他有 slot 的主节点去
redis-cli --cluster rebalance 127.0.0.1:6001 --cluster-weight c2fce950a3fb1c2243009f0ae34b9165f2c0242d=1 f413bd23d52255b292119d144fe0e44093044cd0=1 9470d0c3955a334efdcfa8ba79103f4b7593c8c9=1 c3f2a562b827d96e39bc285d9c33269c4e2e0d1f=0 -a 123456 # 删除主节点
redis-cli --cluster del-node 127.0.0.1:6007 07f3c418b8796197621fe9e9ea839a2c0c1289b3 -a 123456

修复集群 fix

# 修复集群 # --cluster-search-multiple-owners:是否修复多个拥有者的槽位。当集群中的槽位在迁移过程中,出现意外时,使用fix可修复该槽位。redis-cli --cluster fix 127.0.0.1:6001 --cluster-search-multiple-owners -a 123456redis-cli --cluster fix 127.0.0.1:5001 -a 123456# --cluster-fix-with-unreachable-masters:是否修复不可达的主节点上的槽位。例如,集群中某个主节点坏掉了,也没有故障转移成功。此时如何恢复该主节点上的所有槽位呢?这时就可以使用该参数,会将处于该主节点上的所有槽位恢复到存活的主节点上(之前的数据会丢失,仅仅是恢复了槽位)。redis-cli --cluster fix 127.0.0.1:6001 --cluster-fix-with-unreachable-masters -a 123456

集群上执行命令 call

# 命令解释
# call host:port command arg arg .. arg      #在集群的所有节点执行相关命令
# --cluster-only-masters                     #是否只在主节点上执行
# --cluster-only-replicas                    #是否只在从节点上执行redis-cli --cluster call 127.0.0.1:6001 keys * -a 123456
redis-cli --cluster call 127.0.0.1:6001 set a aaa -a 123456
redis-cli --cluster call 127.0.0.1:6001 set b bbb -a 123456
redis-cli --cluster call 127.0.0.1:6001 set c ccc -a 123456
redis-cli --cluster call 127.0.0.1:6001 set d ddd -a 123456

集群节点超时时间设置 set-timeout

  • 不建议在线去设置,有遇到过在线设置,设置成功但导致主节点挂掉的情况
# 命令解释
# set-timeout host:port milliseconds     #设置整个集群的cluster-node-timeout时间redis-cli --cluster set-timeout 127.0.0.1:6001 15000 -a 123456

导入数据至集群 import

  • 实际项目上,数据导入应该用 redis-shake 工具的比较多。
# 命令解释
# import         host:port
# --cluster-from host:port  # 来源redis node,不能为cluster node
# --cluster-from-user <arg> # 
# --cluster-from-pass <arg> # 来源redis node的密码
# --cluster-from-askpass
# --cluster-copy              #migrate时指定类型为copy
# --cluster-replace           #migrate时指定类型为replace# 说明:外部Redis实例(127.0.0.2:6379)导入到集群中的任意一节点,导入之后,原来集群的key变为空,导入到新集群的key会自动分片到各个master节点的slot
# --cluster-replace 如果集群(127.0.01:6379)中存在外部redis实例(127.0.0.2:6379)的key,则会覆盖掉(10.35.2.68:6379)的value
# --cluster-copy 默认情况下,import 命令在向集群导入数据的同时,还会删除单机服务器中源数据。如果用户想要保留单机服务器中的数据,那么可以在执行命令的同时给定 –cluster-copy 选项 该命令将正在运行的实例的所有键(从源实例中删除键)移动到指定的预先存在的 Redis 集群。redis-cli --cluster import 127.0.0.1:6001 --cluster-from 127.0.0.1:6379  --cluster-replace --cluster-copy -a 123456

备份集群rdb文件 backup

# 命令解释
# backup host:port backup_directory     #备份主节点上的数据RDB文件mkdir backup
redis-cli --cluster backup 127.0.0.1:6001 ./backup -a 123456

五、常见错误

问题1:redis集群扩容,槽位迁移时,出现超时问题,导致只迁移完成部分

  • redis版本:redis-7.4.0
  • 执行命令:redis-cli --cluster rebalance 127.0.0.1:6001 --cluster-use-empty-masters --cluster-threshold 1 -a 123456
  • 错误信息:clusterManagerMoveSlot: IOERR error or timeout writing to target instance
  • 原因分析:分析的步骤如下
# 添加主节点(成功)
[root@centos7 redis-cluster]#redis-cli --cluster add-node 127.0.0.1:6001 172.18.31.17:5001 -a 123456
省略部分日志信息... ...
>>> Getting functions from cluster
>>> Send FUNCTION LIST to 127.0.0.1:6001 to verify there is no functions in it
>>> Send FUNCTION RESTORE to 127.0.0.1:6001
>>> Send CLUSTER MEET to node 127.0.0.1:6001 to make it join the cluster.
[OK] New node added correctly.# 第一次,执行 rebalance 槽位迁移(提示迁移超时)
[root@centos7 redis-cluster]#redis-cli --cluster rebalance 127.0.0.1:6001 --cluster-use-empty-masters --cluster-threshold 1 -a 123456
省略部分日志信息... ...
[OK] All 16384 slots covered.
>>> Rebalancing across 4 nodes. Total weight = 4.00
Moving 1366 slots from 172.18.31.17:5001 to 127.0.0.1:6001
########################################################################################################################################################################################
Node 172.18.31.17:5001 replied with error:
IOERR error or timeout writing to target instance
*** clusterManagerMoveSlot: IOERR error or timeout writing to target instance# 第二次,执行 rebalance 槽位迁移(提示5798这个slot处于migrating或importing状态,因此需要修复该slot)
[root@centos7 redis-cluster]#redis-cli --cluster rebalance 127.0.0.1:6001 --cluster-use-empty-masters --cluster-threshold 1 -a 123456
省略部分日志信息... ...
[WARNING] Node 127.0.0.1:6001 has slots in importing state 5798.
[WARNING] Node 172.18.31.17:5001 has slots in migrating state 5798.
[WARNING] The following slots are open: 5798.
>>> Check slots coverage...
[OK] All 16384 slots covered.
*** Please fix your cluster problems before rebalancing# 按照提示,在rebalance前,先执行fix尝试修复(任然报如下错误)
[root@centos7 redis-cluster]#redis-cli --cluster fix 127.0.0.1:6001 -a 123456
省略部分日志信息... ...
>>> Check for open slots...
[WARNING] Node 127.0.0.1:6001 has slots in importing state 5798.
[WARNING] Node 172.18.31.17:5001 has slots in migrating state 5798.
[WARNING] The following slots are open: 5798.
>>> Fixing open slot 5798
Set as migrating in: 172.18.31.17:5001
Set as importing in: 127.0.0.1:6001
>>> Case 1: Moving slot 5798 from 172.18.31.17:5001 to 127.0.0.1:6001
Moving slot 5798 from 172.18.31.17:5001 to 127.0.0.1:6001: 
Node 172.18.31.17:5001 replied with error:
IOERR error or timeout writing to target instance
  • 解决方案:
# 登录相应节点
redis-cli -h 127.0.0.1 -p 6001 -c -a 123456# 修复有问题的slot
cluster setslot 5798 stable# 再次执行fix修复操作(可能不需要该步骤,因无法复现迁移超时的问题,暂时先放在这,不影响该问题的解决)
redis-cli --cluster fix 127.0.0.1:5001 -a 123456# 再次执行槽位迁移(成功)
redis-cli --cluster rebalance 127.0.0.1:5001 -a 123456

参考资料

Redis数据库——主从、哨兵、群集
Redis集群的维护(redis-cli --cluster 命令用法)
Redis6集群安装与运维管理【重要】
全面剖析Redis Cluster原理和应用
Redis官方文档
Redis-3.2.0集群配置(含常见错误)【重要】

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在 Ubuntu 22.04 上安装 phpMyAdmin

简介 PHPMyAdmin 是在 Ubuntu 22.04 上管理 MySQL 数据库的绝佳选择。它是一个流行的工具&#xff0c;拥有简单、高效且用户友好的基于 Web 的界面&#xff0c;让你能够轻松地管理 MySQL 数据库。因此&#xff0c;许多开发人员、数据库管理员和网站所有者都信任 PHPMyAdmin 来…

大数据-256 离线数仓 - Atlas 数据仓库元数据管理 正式安装 启动服务访问 Hive血缘关系导入

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; Java篇开始了&#xff01; 目前开始更新 MyBatis&#xff0c;一起深入浅出&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff0…

[Python3] Sanic中间件

在 Sanic 中&#xff0c;中间件&#xff08;middleware&#xff09;是指在请求和响应之间执行的代码。它们是一个非常强大的工具&#xff0c;用于处理请求的预处理、响应的后处理、全局错误处理、日志记录、认证、权限校验、跨域资源共享&#xff08;CORS&#xff09;等任务。中…

使用 OpenCV 绘制线条和矩形

OpenCV 是一个功能强大的计算机视觉库&#xff0c;它不仅提供了丰富的图像处理功能&#xff0c;还支持图像的绘制。绘制简单的几何图形&#xff08;如线条和矩形&#xff09;是 OpenCV 中常见的操作。在本篇文章中&#xff0c;我们将介绍如何使用 OpenCV 在图像上绘制线条和矩形…

操作系统课程设计

摘 要 本项目旨在深入设计与实现一套基于Java的模拟操作系统&#xff0c;模拟和实现常见操作系统的核心功能&#xff0c;包括进程管理、内存分配与调度、高效的文件系统和多样化设备的管理。通过该模拟操作系统的开发&#xff0c;探索计算机操作系统的基础理论与实际工程细节…

css改变输入右下角图标

前言 正常情况下&#xff0c;HTML textarea 多行文本输入框会存如下图所示图标&#xff0c; 用户可拉动它改变高度&#xff0c;这是我们不想看到的&#xff0c;所以要去掉它。 去掉后&#xff1a; 解决方案 设置 resize 属性即可&#xff0c;如下代码所示&#xff1a; <…

HTML-CSS(day01)

W3C标准&#xff1a; W3C&#xff08; World Wide Web Consortium&#xff0c;万维网联盟&#xff09; W3C是万维网联盟&#xff0c;这个组成是用来定义标准的。他们规定了一个网页是由三部分组成&#xff0c;分别是&#xff1a; 三个组成部分&#xff1a;&#xff08;1&…

2024-12-24 NO1. XR Interaction ToolKit 环境配置

文章目录 1 软件配置2 安装 XRToolKit3 配置 OpenXR4 安装示例场景5 运行测试 1 软件配置 Unity 版本&#xff1a;Unity6000.0.26 ​ 2 安装 XRToolKit 创建新项目&#xff08;URP 3D&#xff09;&#xff0c;点击进入 Asset Store。 进入“Unity Registry”页签&#xff0…

C语言基础——指针(4)

一&#xff0e; 字符指针变量 字符指针变量的使用和整型指针变量的使用方法相似&#xff0c;以下是其基本使用方法的例子&#xff1a; &#xff08;1&#xff09;字符指针变量还有一种使用方法&#xff1a; const char* p "abcd" 需…

week 11 - BCNF

1. More on functional dependencies (功能依赖的更多内容) Lossless decomposition (无损分解) 研究如何在分解表的过程中不丢失信息&#xff0c;也就是说&#xff0c;通过分解后的表可以无损地重建原始表。 2. BCNF (Boyce-Codd Normal Form, BCNF范式) &#xff08;1&…

嵌入式学习-QT-Day06

嵌入式学习-QT-Day06 六、多窗口编程 1、QMessageBox 消息对话框 2、QWidget类 3、parent参数 4、堆栈窗口&#xff08;QStackedWidget&#xff09; 5、新建自定义窗口类 6、对象传值 6.1 父对象 → 子对象 6.2 子对象 → 父对象 7、事件机制 8、QMainWindow主窗口类 8.1 QMenu…

《战神:诸神黄昏》游戏运行时提示找不到gamede.dll文件怎么办?gamede.dll丢失的修复指南

在沉浸于《战神&#xff1a;诸神黄昏》的壮阔世界时&#xff0c;突然弹出的“找不到gamede.dll文件”错误提示可能会让玩家措手不及。作为一名经验丰富的软件开发从业者&#xff0c;我深知这类问题对游戏体验的影响。今天&#xff0c;我将为大家详细解析gamede.dll文件丢失的原…

1.系统学习-线性回归

系统学习-线性回归 前言线性回归介绍误差函数梯度下降梯度下降示例 回归问题常见的评价函数1. MAE, mean absolutely error2. MSE, mean squared error3. R square &#xff08;决定系数或R方&#xff09; 机器学习建模流程模型正则化拓展阅读作业 链接: 2.系统学习-逻辑回归 …

基于微信小程序的校园访客登记系统

基于微信小程序的校园访客登记系统 功能列表 用户端功能 注册与登录 &#xff1a;支持用户通过手机号短信验证码注册和登录。个人资料管理 &#xff1a;允许用户编辑和更新个人信息及其密码。站内信消息通知&#xff1a;通知公告。来访预约&#xff1a;提交来访预约支持车牌…

H3C MPLS跨域optionB

实验拓扑 实验需求 如图,VPN1 和 VPN2 分别通过运营商 MPLS VPN 连接各自分支机构按照图示配置 IP 地址,VPN1 和 VPN2 连接同一个 PE 设备的私网 IP 网段存在地址复用,使用多 VRF 技术来防止 IP 冲突AS 100 和 AS 200 内部的公共网络中各自运行 OSPF 使 AS 内各设备的 Loo…

【项目管理】根据业务流程进行函数结构设计和模块化设计

在开发一个复杂的系统时&#xff0c;根据业务流程进行函数结构设计和模块化设计是一个非常重要的步骤。通过这种方式&#xff0c;能够将复杂的业务逻辑拆分成多个功能模块和函数&#xff0c;使代码更清晰、易维护、易扩展。我们在写代码的时候需要基于对于业务的理解来编程&…

VMware虚拟机中CentOS系统/dev/mapper/centos-home分区扩容指南

要将VMware上新扩展的磁盘添加到CentOS虚拟机,并将其扩容到/dev/mapper/centos-home下,你可以按照以下步骤操作: 一、在VMware中扩展虚拟机磁盘 关闭CentOS虚拟机:确保在扩展磁盘之前,CentOS虚拟机已经关闭。 编辑虚拟机设置:在VMware中,右键点击CentOS虚拟机,选择“设…

GPUStack v0.4.1 单节点与多节点安装与部署指南 Docker PowerShell

Introduce GPUStack 是一个开源的 GPU 集群管理器&#xff0c;专为运行 AI 模型而设计。它以其广泛的硬件兼容性而闻名&#xff0c;支持多种品牌的 GPU&#xff0c;并能在 Apple MacBook、Windows PC 和 Linux 服务器上运行。 GPUStack支持各种AI模型&#xff0c;包括大型语言…

【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析

Hiヽ(゜▽゜ )&#xff0d;欢迎来到蓝染Aizen的CSDN博客~ &#x1f525; 博客主页&#xff1a; 【✨蓝染 の Blog&#x1f618;】 &#x1f496;感谢大家点赞&#x1f44d; 收藏⭐ 评论✍ 文章目录 行为型模式1、模板方法模式&#xff08;1&#xff09;概述&#xff08;2&…

【解决报错】AttributeError: ‘NoneType‘ object has no attribute ‘group‘

学习爬虫时&#xff0c;遇到如下报错&#xff1a; 报错原因&#xff1a; 正则表达式的 search 或 finditer 方法没有找到任何匹配项&#xff0c;可能是换行符处理不当等。 解决方法如下&#xff1a; 在正则表达式末尾加上re.S即可&#xff0c;re.S是一个编译标志&#xff0c…