时常需要在云服务器上搭建测试环境,每次入手新的服务器配置集群环境时,跟着笔记敲一遍命令行挺麻烦的。简单了解 shell 脚本后,用脚本在单机服务器上部署 Redis 集群。
安装 Redis 服务器
参照 Redis 主从集群及自启动配置 实现自动安装,首先判断是否已安装,若存在 Redis 服务程序则跳过,否则安装。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| # Check redis command if [ ! -f "/usr/local/bin/redis-server" ]; then echo "Redis not ready, please install redis firstly!" echo "" echo "===== Install redis as follows =====" wget http://download.redis.io/releases/redis-5.0.7.tar.gz -P /usr/local/src cd /usr/local/src/ tar -zxvf redis-5.0.7.tar.gz cd redis-5.0.7 install GCC if not exists yum install -y gcc-c++ make MALLOC=libc install
echo "" echo "Redis Server Installation Finished!" fi
|
通过 if [ ! -f "/usr/local/bin/redis-server" ]
判断 server 程序是否存在,若存在则认为 Redis 已安装。
采用源码编译的方式安装 Redis,已指定 5.0.7 版本,防止出现兼容性问题。
生成 Redis 实例的配置文件
常量定义
1 2 3 4
| # Constants BASE_DIR=/usr/local/redis-cluster PORTS=`seq 7000 7005` START_UP=$BASE_DIR/startup.sh
|
- BASE_DIR 为集群配置 directory;
- PORTS 为集群在本地所占用的端口列表,
seq 7000 7005
生成 7000-7005 的整数数组;
- START_UP 为集群实例启动脚本,集群需要启动 6 个 Redis 实例,使用脚本简化操作。
准备工作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 创建工作目录,在工作目录下进行后续操作 mkdir -p $BASE_DIR cd $BASE_DIR
# 准备集群实例启动脚本,在每次实例配置循环时将启动命令追加到脚本中 echo "#!/bin/bash" > $START_UP servers= for port in $PORTS; do # 设置每个实例的工作目录, data为数据存放目录 mkdir -p $BASE_DIR/$port/data # 生成单个实例的配置文件 generate_instance_conf $port # 追加实例启动命令到启动脚本 echo "/usr/local/bin/redis-server $BASE_DIR/$port/redis.conf" >> $START_UP # 记录所有的实例位置,用于之后的集群启动 servers="$servers 127.0.0.1:$port " done
|
配置文件
每个实例的配置文件相似,只是端口号和工作目录不同。还有一点需要注意,要想可以从其它外部主机访问此主机上的 Redis 集群,需要将实例的集群地址设置为主机的外网地址,因此需要用户手动输入主机外网地址。
使用 shell 实现外网地址获取的交互模式:
1 2 3
| # User custom setting echo -n "Enter your host's public address(default 127.0.0.1):" read cluster_address
|
将实例配置依次写入 redis.conf 中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| # generate configuration files function generate_instance_conf() { echo "configuring server $1" # clean conf file echo "" > $1/redis.conf # write conf echo "port $1" >> $1/redis.conf echo "bind 0.0.0.0" >> $1/redis.conf echo "dir $BASE_DIR/$port/data" >> $1/redis.conf echo "cluster-enabled yes" >> $1/redis.conf echo "cluster-config-file nodes-$1.conf" >> $1/redis.conf echo "cluster-node-timeout 5000" >> $1/redis.conf if [ -n "$cluster_address" ]; then echo "cluster-announce-ip $cluster_address" >> $1/redis.conf else echo "cluster-announce-ip 127.0.0.1" >> $1/redis.conf fi echo "appendonly yes" >> $1/redis.conf echo "daemonize yes" >> $1/redis.conf } chmod +x $START_UP
|
如上步骤完成后,集群工作目录如下:
1 2 3 4 5 6 7
| drwxr-xr-x 3 root root 4096 Apr 19 11:07 7000 drwxr-xr-x 3 root root 4096 Apr 19 11:07 7001 drwxr-xr-x 3 root root 4096 Apr 19 11:07 7002 drwxr-xr-x 3 root root 4096 Apr 19 11:07 7003 drwxr-xr-x 3 root root 4096 Apr 19 11:07 7004 drwxr-xr-x 3 root root 4096 Apr 19 11:07 7005 -rwxr-xr-x 1 root root 426 Apr 19 11:07 startup.sh
|
启动实例并建立集群
启动 Redis 服务实例
1 2 3 4 5
| # startup instances echo "starting servers..." $START_UP sleep 5s echo "servers ready!"
|
执行启动脚本,启动 6 个 Redis 实例,并保持休眠 5 秒,等待集群启动完成,执行结果如下:
1 2 3 4 5 6 7 8 9
| starting servers... 27764:C 19 Apr 2020 11:07:58.874 27764:C 19 Apr 2020 11:07:58.874 27764:C 19 Apr 2020 11:07:58.874 ... 27777:C 19 Apr 2020 11:07:58.885 27777:C 19 Apr 2020 11:07:58.885 27777:C 19 Apr 2020 11:07:58.885 servers ready!
|
建立集群
1 2 3 4
| # create cluster echo "configuring cluster..." /usr/local/bin/redis-cli --cluster create $servers --cluster-replicas 1 echo "configured!"
|
使用 redis-cli 建立集群,指定所要包含实例的 host 和 port,$servers 中就是这些信息。
1 2 3 4 5 6 7 8 9 10 11 12 13
| configuring cluster... >>> Performing hash slots allocation on 6 nodes... Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 ... Can I set the above configuration? (type 'yes' to accept): yes ... [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. configured!
|
集群建立时需要用户手动确认槽数划分,输入 yes
即可。
至此集群部署完成,下面配置集群开机自启动。
systemd 自启动
使用 systemd 配置 Redis 集群启动服务,首先配置 service 文件:
1 2 3 4 5 6 7 8 9 10 11 12 13
| # generate redis-cluster service file cat << EOT > $BASE_DIR/redis-cluster.service [Unit] Description=Redis 5.0 Cluster Service After=network.target
[Service] Type=forking ExecStart=/usr/local/redis-cluster/startup.sh
[Install] WantedBy=default.target EOT
|
cat << EOT > $BASE_DIR/redis-cluster.service
表示向 redis-cluster.service
文件中覆盖一段内容,内容为下一行至 EOT
之间的内容。
1 2 3 4 5
| # create service echo "Creating redis cluster service..." # 在 systemd 文件夹下创建 service 的软连接并启动 redis 集群服务 ln -s $BASE_DIR/$SERVICE /etc/systemd/system/$SERVICE sudo systemctl daemon-reload && sudo systemctl enable $SERVICE && sudo systemctl start $SERVICE
|
集群删除
使用 --remove
参数执行集群删除操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| # Remove redis cluster function remove_cluster() { # 终止各 Reids 实例进程 ps -ef | grep redis-server | grep cluster | awk '{print $2}' | xargs kill -9 # 移除 systemd 服务 systemctl disable redis-cluster.service # 移除工作目录(配置文件和数据) if [ -d $BASE_DIR ]; then rm -rf $BASE_DIR fi }
if [ "$1" = "--remove" ]; then remove_cluster exit 0 fi
|
通过过滤器 grep
和流式编辑器 awk
查询到 Redis 实例的 pid,使用 kill
命令结束进程。
其中 awk '{print $2}'
为 awk -F ' ' '{print $2}'
的缩写,-F
表示分隔符参数,默认为空格,``awk -F ‘ ‘` 将如下内容分割为数组:
1
| root 27765 1 0 11:07 ? 00:00:03 /usr/local/bin/redis-server 0.0.0.0:7000 [cluster]
|
{print $2}
表述输出第 2 个元素,$0 表述输出整行。
完整的 shell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
| #!/bin/bash
BASE_DIR=/usr/local/redis-cluster
PORTS=`seq 7000 7005`
START_UP=$BASE_DIR/startup.sh
SERVICE=redis-cluster.service
# Remove redis cluster function remove_cluster() { # kill redis servers ps -ef | grep redis-server | grep cluster | awk '{print $2}' | xargs kill -9 # disable systemd systemctl disable redis-cluster.service # rm cluster data if [ -d $BASE_DIR ]; then rm -rf $BASE_DIR fi }
if [ "$1" = "--remove" ]; then remove_cluster exit 0 fi
# Check redis command if [ ! -f "/usr/local/bin/redis-server" ]; then echo "Redis not ready, please install redis firstly!" echo "" echo "===== Install redis as follows =====" wget http://download.redis.io/releases/redis-5.0.7.tar.gz -P /usr/local/src cd /usr/local/src/ tar -zxvf redis-5.0.7.tar.gz cd redis-5.0.7 install GCC if not exists yum install -y gcc-c++ make MALLOC=libc install
echo "" fi
# User custom setting echo -n "Enter your host's public address(default 127.0.0.1):" read cluster_address
# enter work directory mkdir -p $BASE_DIR cd $BASE_DIR
# generate configuration files function generate_instance_conf() { echo "configuring server $1" # clean conf file echo "" > $1/redis.conf # write conf echo "port $1" >> $1/redis.conf echo "bind 0.0.0.0" >> $1/redis.conf echo "dir $BASE_DIR/$1/data" >> $1/redis.conf echo "cluster-enabled yes" >> $1/redis.conf echo "cluster-config-file nodes-$1.conf" >> $1/redis.conf echo "cluster-node-timeout 5000" >> $1/redis.conf if [ -n "$cluster_address" ]; then echo "cluster-announce-ip $cluster_address" >> $1/redis.conf else echo "cluster-announce-ip 127.0.0.1" >> $1/redis.conf fi echo "appendonly yes" >> $1/redis.conf echo "daemonize yes" >> $1/redis.conf }
# mkdir dirs and setup startup.sh echo "#!/bin/bash" > $START_UP servers= for port in $PORTS; do mkdir -p $BASE_DIR/$port/data # generate conf files generate_instance_conf $port # echo "/usr/local/bin/redis-server $BASE_DIR/$port/redis.conf" >> $START_UP # servers servers="$servers 127.0.0.1:$port " done
# startup instances chmod +x $START_UP echo "starting servers..." $START_UP sleep 5s echo "servers ready!"
# create cluster echo "configuring cluster..." /usr/local/bin/redis-cli --cluster create $servers --cluster-replicas 1 echo "configured!"
# generate redis-cluster service file cat << EOT > $BASE_DIR/redis-cluster.service [Unit] Description=Redis 5.0 Cluster Service After=network.target
[Service] Type=forking ExecStart=/usr/local/redis-cluster/startup.sh
[Install] WantedBy=default.target EOT
# create service echo "Creating redis cluster service..." ln -s $BASE_DIR/$SERVICE /etc/systemd/system/$SERVICE sudo systemctl daemon-reload && sudo systemctl enable $SERVICE && sudo systemctl start $SERVICE
# Cluster OK echo "" echo "Completed!" echo "" echo "Test cluster with: /usr/local/bin/redis-cli -h 127.0.0.1 -p 7000" echo "" echo "127.0.0.1:7000>cluster nodes"
|
脚本下载:https://blogres.blackist.org/202004232347_404.sh
参考
https://blackist.org/2020/04/03/redis-cluster-masterandslave/
https://stackoverflow.com/questions/13910087/shell-script-to-capture-process-id-and-kill-it-if-exist
(完)