[TOC]

0x00 Redis 安装

Redis Windows下安装是非常之简单所以,还是主要以linux安装为主,方便后面实现集群;

官网地址:http://redis.io/download
环境准备:CentOS Linux release 7.6.1810 (Core)
Linux WeiyiGeek 3.10.0-957.1.3.el7.x86_64

安装步骤:

#1.官网下载并Make
$ wget http://download.redis.io/releases/redis-5.0.4.tar.gz
$ tar xzf redis-5.0.4.tar.gz
$ cd redis-5.0.4
$ make

#2.编译后的redis服务程序redis-server,还有用于测试的客户端程序redis-cli,两个程序位于安装目录 src 目录下:
redis-server #服务端
redis-cli #客户端

#3.启动服务和配置文件
$ cp redis.conf /etc/redis.conf
$ ln -s /opt/redis/redis-5.0.4/src/redis-server /usr/bin/redis-server #建立软链接
$ ln -s /opt/redis/redis-5.0.4/src/redis-cli /usr/bin/redis-cli
$ redis-server /etc/redis.conf #利用配置文件启动redis

#4.验证服务是不是成功
#使用测试客户端程序redis-cli和redis服务交互了
$ redis-cli
redis> set foo bar
redis> get foo # "bar"
redis> ping # PONG 测试redis状态

0x01 Redis安全配置

Redis安全规范:

#1.配置文件
$vim /etc/redis/redis.conf
bind 127.0.0.1 #信任的内网运行,尽量避免有公网访问(如果存在内网中其他固定IP则需要设置防火墙)
#绑定redis监听的网络接口(通过redis配置项bind,可同时绑定多个IP)
port 63791 #把6379改为其他得端口
#开启redis密码认证,并设置高复杂度密码设置 echo -e "weiyigeek"|sha256sum
requirepass 097575a79efcd7ea7b1efa2bcda78a4fc7cbd0820736b2f2708e72c3d21f8b61 #redis因查询效率高,auth这种命令每秒能处理10w次以上(所以需要增加强度)
echo
#2.防火墙设置
iptables -A INPUT -s x.x.x.x -p tcp --dport 6379 -j ACCEPT #如果需要其他机器访问或者设置了slave模式,那就记得加上相应的防火墙设置(Centos6)
firewall-cmd --add-rich-rule="rule family="ipv4" source address="x.x.x.x" port protocol="tcp" port="6379" accept" --permanent #(Centos7)


#3.禁止root用户启动redis
#设置一个单独的redis账户很有必要,redis crackit就利用到了root用户的特性来重置authorized_keys。首先创建一个redis账户,然后通过该账户启动。
$useradd redis
$setsid sudo -u redis redis-server /etc/redis.conf
$ps -elf|grep redis #可以看到是redis用户启动
4 S root 9048 1 0 80 0 - 59753 poll_s 19:43 ? 00:00:00 sudo -u redis redis-server /etc redis.conf
4 S redis 9049 9048 0 80 0 - 38471 ep_pol 19:43 ? 00:00:00 redis-server


#4.限制redis文件目录访问权限
#设置redis的主目录权限为700,如果redis配置文件独立于redis主目录,权限修过为600,因为redis密码明文存储在配置文件中.
[[email protected] ~]$ chmod 700 /opt/redis/redis-5.0.4/
[[email protected] ~]$ chmod 600 /etc/redis.conf
[[email protected] redis-5.0.4]$ chown redis:redis /etc/redis.conf
[[email protected] redis-5.0.4]$ chown redis:redis /opt/redis/redis-5.0.4/


#5.禁用或者重命名危险命令
#漏洞就利用config/save两个命令完成攻击 。 因redis无用户权限限制,建议危险的命令,使用rename配置项进行禁用或重命名,这样外部不了解重命名规则攻击者,就不能执行这类命令
FLUSHDB, FLUSHALL, KEYS, PEXPIRE, DEL, CONFIG, SHUTDOWN, BGREWRITEAOF, BGSAVE, SAVE, SPOP, SREM, RENAME, DEBUG, EVAL
#以下示例:redis.config文件禁用FLUSHDB、FLUSHALL两个命令;重命名CONFIG、SHUTDOWN命令,添加一个特殊的后缀。 这样redis启动后,只能运行CONFIG_b9fc8327c4dee7命令,不能执行CONFIG命令。
rename-command CONFIG CONFIG_b9fc8327c4dee7 #重命名
rename-command SHUTDOWN SHUTDOWN_b9fc8327c4dee7
rename-command FLUSHDB ""
rename-command FLUSHALL ""
#上述配置将config,flushdb,flushall设置为了空,即禁用该命令,我们也可以命名为一些攻击者难以猜测,我们自己却容易记住的的名字。保存之后,执行/etc/init.d/redis-server restart 重启生效。


#6.禁止redis中存储敏感的明文数据
Redis设计旨在提供高性能的KV服务,至少目前在权限访问控制和数据持久化方面比较弱化

#7.安全监控(日志监控)
建立蜜罐网络,有攻击尝试时,可及时发现监控redis安全状态,cmdstat_auth cmdstat_flushdb/flushall监控报警;
logfile "/usr/local/redis/redis.log" #日志文件存放目录
loglevel verbose #记录访问信息

0x02 Redis运维

Redis命令一览表:

$ redis-cli --raw  #redis-cli --raw
$ redis-cli -h host -p port -a password #链接其他Redis主机
$ redis-cli -h host -p port shutdown #可以通过杀进程的方式强制关闭服务也可采用下面这种
$ redis-server --maxclients 100000 #启动参数设置最大连接数


############## redis> 内部命令###########################
redis> COMMAND #返回所有的Redis命令的详细信息,以数组形式展示
redis> COMMAND COUNT #返回命令总数 (integer) 200
redis> COMMAND GETKEYS MSET a b c d e f #获取给定命令的所有键
redis> COMMAND INFO get set eval #获取 redis 命令的描述信息

redis> INFO #服务器得统计信息
redis> CONFIG RESETSTAT #重置服务器得统计信息
redis> echo "Redis Test" #打印字符串

127.0.0.1:6379> keys * #获取所有得keys
redis> set foo bar # 设置 key
redis> get foo # 获取key得值 "bar"
redis> ping # PONG 测试redis状态
redis> SHUTDOWN [NOSAVE] [SAVE] #关闭 redis 服务器(server)

redis> auth foobared #密码认证(默认密码)
redis> auth 097575a79efcd7ea7b1efa2bcda78a4fc7cbd0820736b2f2708e72c3d21f8b61 #设置的密码

redis> select 1 #切换到指定的数据库
redis[1]> quit #关闭当前连接
redis> time #返回当前服务器时间
1) "1555514501"
2) "504765"
redis> lastsave #返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式表示
(integer) 1555514754

redis> MONITOR #实时打印出 Redis 服务器接收到的命令,调试用

#查询执行时间指的是不包括像客户端响应(talking)、发送回复等 IO 操作,而单单是执行一个查询命令所耗费的时间
redis > SLOWLOG LEN #管理 redis 的慢日志 ,查看当前日志的数量 (integer) 14
redis > SLOWLOG RESET #清空 slowlog OK 上面 LEN 变成0

redis> DBSIZE #返回当前数据库的 key 的数量 (integer) 6
redis> DEBUG OBJECT foo #DEBUG OBJECT key

redis> FLUSHALL #删除所有数据库的所有key
redis> FLUSHDB #删除当前数据库的所有key


#通过 CONFIG 命令查看或设置配置项
> CONFIG GET * #查看所有配置
13) "pidfile"
14) "/var/run/redis_6379.pid"
> CONFIG GET loglevel
1) "loglevel"
2) "notice"
redis > CONFIG SET loglevel "notice" #修改配置
redis > CONFIG REWRITE # 将 loglevel 的修改写入到 redis.conf 中
OK
# 通过 redis 的配置文件或者在redis-cli设置密码参数
> CONFIG set requirepass "runoob"

# Redis 数据备份与恢复
redis > SAVE #SAVE 命令在 redis 安装目录中创建dump.rdb文件
redis > CONFIG GET dir #需将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可
1) "dir"
2) "/usr/local/redis/bin" #输出的 redis 安装目录
redis > BGSAVE #后台执行 使用命令 BGSAVE


# Redis 性能测试是通过同时执行多个命令实现的,该命令是在 redis 的目录下执行的
./redis-benchmark [option] [option value]
$ ./redis-benchmark -h 127.0.0.1 -p 6379 -t set,lpush -n 10000 -q
$ ./redis-benchmark -n 10000 -q #同时执行 10000 个请求来检测性能,通过 -q 参数让结果只显示每秒执行的请求数
PING_INLINE: 41493.78 requests per second
PING_BULK: 44843.05 requests per second
SET: 42194.09 requests per second
GET: 44052.86 requests per second
INCR: 43290.04 requests per second
LPUSH: 42194.09 requests per second
RPUSH: 42372.88 requests per second
LPOP: 42194.09 requests per second
RPOP: 42194.09 requests per second
SADD: 43668.12 requests per second
HSET: 42372.88 requests per second
SPOP: 44843.05 requests per second
LPUSH (needed to benchmark LRANGE): 42553.19 requests per second
LRANGE_100 (first 100 elements): 21367.52 requests per second
LRANGE_300 (first 300 elements): 9451.80 requests per second
LRANGE_500 (first 450 elements): 6807.35 requests per second
LRANGE_600 (first 600 elements): 5350.46 requests per second
MSET (10 keys): 36363.64 requests per second

WeiyiGeek.redis-benchmark



Redis 客户端连接
Redis 通过监听一个 TCP 端口或者 Unix socket 的方式来接收来自客户端的连接,当一个连接建立后Redis 内部会进行以下一些操作:

  • 首先客户端 socket 会被设置为非阻塞模式,因为 Redis 在网络事件处理上采用的是非阻塞多路复用模型。
  • 然后为这个 socket 设置 TCP_NODELAY 属性,禁用 Nagle 算法
  • 然后创建一个可读的文件事件用于监听这个客户端 socket 的数据发送
#可以在 redis.conf 中对这个值进行修改
> config get maxclients
1) "maxclients"
2) "4064"

> client help #帮助
> CLIENT id #当前连接ID (integer) 1257
> client setname weiyi #设置服务名称
> client getname #获取通过 CLIENT SETNAME 命令设置的服务名称 "weiyi"
> CLIENT PAUSE 100 #阻塞客户端命令一段时间
> CLIENT LIST #返回连接到 redis 服务的客户端列表
id=1256 addr=127.0.0.1:41306 fd=7 name= age=708 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client
> CLIENT kill 127.0.0.1:41306 #关闭客户端连接
OK

Redis 管道技术
Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。通常情况下一个请求会遵循以下步骤:

  • 客户端向服务端发送一个查询请求,并监听Socket返回,通常是以阻塞模式等待服务端响应。
  • 服务端处理命令,并将结果返回给客户端。

管道技术的优势

  • 提高了 redis 服务的性能,速度效率提升
  • 管道技术可以一次性读取所有服务端的响应。
#启动redis-server 
$(echo -en "PING\r\n SET runoobkey redis\r\nGET runoobkey\r\nINCR visitor\r\nINCR visitor\r\nINCR visitor\r\n"; sleep 10) | nc localhost 6379
#通过使用 PING 命令查看redis服务是否可用, 之后我们设置了 runoobkey 的值为 redis,然后我们获取 runoobkey 的值并使得 visitor 自增 3 次
+PONG
+OK
redis
:1
:2
:3



Redis分区
分区是分割数据到多个Redis实例的处理过程,因此每个实例只保存key的一个子集

分区的优势:

  • 利用多台计算机内存的和值,允许我们构造更大的数据库
  • 通过多核和多台计算机,允许我们扩展计算能力;通过多台计算机和网络适配器,允许我们扩展网络带宽。

分区的不足:

  • 涉及多个key的操作通常是不被支持的
  • 涉及多个key的redis事务不能使用。
  • 当使用分区时数据处理较为复杂
  • 增加或删除容量也比较复杂(redis集群)

Redis 有两种类型分区:有不同的系统来映射某个key到某个Redis服务
(1)按范围分区
就是映射一定范围的对象到特定的Redis实例;比如ID从0到10000的用户会保存到实例R0,ID从10001到 20000的用户会保存到R1,以此类推。

(2)哈希分区
对任何key都适用,也无需是object_name:这种形式,用一个hash函数将key转换为一个数字,

  • 比如使用crc32 hash函数对key foobar 执行会输出类似93024922的整数;
  • 对这个整数取模将其转化为0-3之间的数字,就可以将这个整数映射到4个Redis实例中的一个了。
  • 93024922 % 4 = 2 ===>>> 就是说key foobar应该被存到R2实例中。

0x03 Redis集群主从

Redis 集群采用了P2P的模式,完全去中心化,把所有的 Key 分成了 16384 个 slot,每个 Redis 实例负责其中一部分 slot;集群中的所有信息(节点、端口、slot等),都通过节点之间定期的数据交换而更新

原理:Redis 客户端可以在任意一个 Redis 实例发出请求,如果所需数据不在该实例中,通过重定向命令引导客户端访问所需的实例。

cluster特性(已测试):
1):节点自动发现
2):slave->master 选举,集群容错
3):Hot resharding:在线分片
4):集群管理:cluster xxx
5):基于配置(nodes-port.conf)的集群管理
6):ASK 转向/MOVED 转向机制.

Q:什么是redis-cluster选举容错?
答:(1)选举过程是集群中所有master参与,如果半数以上master节点与故障节点通信超过(cluster-node-timeout),认为该节点故障,自动触发故障转移操作.
(2):什么时候整个集群不可用(cluster_state:fail)?

a:如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成集群的slot映射[0-16383]不完整时进入fail状态.ps : redis-3.0.0.rc1 加入cluster-require-full-coverage 参数,默认关闭,打开集群兼容部分失败.
b:如果集群超过半数以上master挂掉,无论是否有slave集群进入fail状态.
ps:当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误

redis-cluster不足:
1)cluster环境下slave默认不接受任何读写操作,在slave执行readonly命令后,可执行读操作
2)client端不支持多key操作(mget,mset等),但当keys集合对应的slot相同时支持mget操作见:hash_tag
3)不支持多数据库,只有一个db select 0(无select 1)
4)JedisCluster 没有针对byte[]的API,需要自己扩展(附件是我加的基于byte[]的BinaryJedisCluster api)

redis-cluter架构图:
WeiyiGeek.架构图

redis-cluter架构细节:

  • 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
  • 节点的fail是通过集群中超过半数的节点检测失效时才生效.
  • 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
  • redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->key
  • Redis集群预分好16384个桶,当需要在 Redis 集群中放置一个key-value 时,根据 CRC16(key) mod 16384的值,决定将一个key放到哪个桶中。

安装环境:

#重点:Redis集群中要求奇数节点,至少要有三个节点,并且每个节点至少有一备份节点,所以至少需要6个redis服务实例。
OS:Centos7.10 / Centos6.10
Reids版本:5.0.4

#3台服务器,每台起3个服务,共9个节点
Centos7:192.168.1.99/24 {7000,7001,7002}
Centos6-1:192.168.1.100/24 {7000,7001,7002}
Centos6-2:192.168.1.101/24 {7000,7001,7002}

#额外需要下载包
$ yum update -y && yum uograde -y
lib / zlib / ruby / rubugems #述均安装最新版本,否则会和redis版本不匹配

安装流程:

1. 分别在三台服务器安装redis这里不多说安装与上面一致(更新依赖)
2. 准备目录结构和redis配置
$ mkdir -p /data/redis/redis-cluster/{7000,7001,7002}
$ vim /data/redis/redis-cluster/7000/redis.conf
$ mkdir -p /etc/redis/cluster/run/ #7建立集群配置文件cluster-config-file路径

####建立通用配置 #### (注意注意:注释不能放在配置文件后)
#指定端口
port 7000

#暂时这么更改
bind 0.0.0.0

#修改安全模式
protected-mode no

#后台运行
daemonize yes
masterauth 123456
requirepass 123456

#启用集群
cluster-enabled yes
#指定集群配置文件名称,该文件记录集群运行时信息
#注意:可以用绝对路径,但必须保证路径已经存在,否则启动失败;如果只有文件名称的话,文件生成在工作路径下
cluster-config-file /etc/redis/cluster/run/nodes-7000.conf

#集群超时时间
cluster-node-timeout 5000

#指定进程pid文件
pidfile /var/run/redis_7000.pid

#指定日志文件
logfile /var/log/redis_7000.log

#指定数据库文件存放路径
dir /data/redis/redis-cluster/7000

#开启AOF模式
appendonly yes

#appendonly日志文件
appendfilename appendonly-7000.aof

#每次有写操作的时候都同步
appendfsync always


3. 将配置文件分别复制到其他目录并修改端口号
cp /data/redis/redis-cluster/7000/redis.conf /data/redis/redis-cluster/7001/redis.conf
cp /data/redis/redis-cluster/7000/redis.conf /data/redis/redis-cluster/7002/redis.conf
sed -i 's/7000/7001/g' /data/redis/redis-cluster/7001/redis.conf
sed -i 's/7000/7002/g' /data/redis/redis-cluster/7002/redis.conf
#注意,上述有些配置项要对应服务和目录,三个目录按照上述配置好后,启动服务


4.开启与关闭集群脚本 cluster-control.sh
#!/bin/bash
function start_cluster()
{
for i in {0..2}
do
/usr/bin/redis-server /data/redis/redis-cluster/700$i/redis.conf;
done
}

function stop_cluster()
{
# -c 连接到集群
for i in {0..2}
do
/usr/bin/redis-cli -a 123456 -c -p 700${i} shutdown save;
done
}

if [ $# -eq 0 ];then
echo "Usage: cluster-control.sh [start|sop]"
else
case $1 in
start) echo "开启redis集群"
start_cluster
;;
stop) echo "停止Redis集群"
stop_cluster
;;
esac
fi

#之后将开启集群
./cluster_control.sh start
[[email protected]/data1/data2 ~]$ ps -ef | grep "redis"
root 6171 1 0 11:25 ? 00:00:00 /usr/bin/redis-server 0.0.0.0:7000 [cluster]
root 6178 1 0 11:25 ? 00:00:00 /usr/bin/redis-server 0.0.0.0:7001 [cluster]
root 6182 1 0 11:25 ? 00:00:00 /usr/bin/redis-server 0.0.0.0:7002 [cluster]
root 6198 3732 0 11:26 pts/0 00:00:00 grep --color=auto redis


5. 创建集群
#注意:在任意一台上运行 不要在每台机器上都运行,一台就够了我们就选用CentOS7作为主
#Redis 官方提供了 redis-trib.rb 这个工具,就在解压目录的 /opt/redis/redis-5.0.4/utils/create-cluster 目录中

./redis-trib.rb create --replicas 1 192.168.1.99:7000 192.168.1.99:7001 192.168.1.99:7002 192.168.1.100:7000 192.168.1.100:7001 192.168.1.100:7002 192.168.1.101:7000 192.168.1.101:7001 192.168.1.101:7002 -a [密码]#redis-4.0.10 版本
redis-cli --cluster create 192.168.1.99:7000 192.168.1.99:7001 192.168.1.99:7002 192.168.1.100:7000 192.168.1.100:7001 192.168.1.100:7002 192.168.1.101:7000 192.168.1.101:7001 192.168.1.101:7002 --cluster-replicas 1 -a [密码] #redis-5.0.4 版本

>>> Performing hash slots allocation on 9 nodes... #9个节点
Master[0] -> Slots 0 - 4095
Master[1] -> Slots 4096 - 8191
Master[2] -> Slots 8192 - 12287
Master[3] -> Slots 12288 - 16383
Adding replica 192.168.1.101:7001 to 192.168.1.99:7000
Adding replica 192.168.1.99:7002 to 192.168.1.100:7000
Adding replica 192.168.1.100:7002 to 192.168.1.101:7000
Adding replica 192.168.1.101:7002 to 192.168.1.99:7001
Adding extra replicas...
Adding replica 192.168.1.100:7001 to 192.168.1.99:7000
M: 8c5a037999975a052e422bc030c3fc72053d059e 192.168.1.99:7000
slots:[0-4095] (4096 slots) master
M: 4877856114a8efc62325dc0d32adede6256eb9ef 192.168.1.99:7001
slots:[12288-16383] (4096 slots) master
S: 3bd40f9a2d95a9865f58706b55f4559e6c43dd7e 192.168.1.99:7002
replicates 6df7e2ad828ba148239dd4465235d17ce0e0af10
M: 6df7e2ad828ba148239dd4465235d17ce0e0af10 192.168.1.100:7000
slots:[4096-8191] (4096 slots) master
S: 35756a64813b68bf5fea92b6ee2b1a7020b8cc7a 192.168.1.100:7001
replicates 8c5a037999975a052e422bc030c3fc72053d059e
S: f467098bffa3761868842556eb4cfff7cc8bc363 192.168.1.100:7002
replicates 660590807a4417e901c6d2277b29a306c1ea07e3
M: 660590807a4417e901c6d2277b29a306c1ea07e3 192.168.1.101:7000
slots:[8192-12287] (4096 slots) master
S: cd7fb4d0a48a114629c1f34e0f75da5235910995 192.168.1.101:7001
replicates 8c5a037999975a052e422bc030c3fc72053d059e
S: 8d1cab296fe88e1809e550ecd482f6df67c61e7b 192.168.1.101:7002
replicates 4877856114a8efc62325dc0d32adede6256eb9ef
#选择:YES
#显示了集群和slot分配结果 4主/5从
>>> Performing Cluster Check (using node 192.168.1.99:7000)
M: 8c5a037999975a052e422bc030c3fc72053d059e 192.168.1.99:7000
slots:[0-4095] (4096 slots) master
2 additional replica(s)
S: cd7fb4d0a48a114629c1f34e0f75da5235910995 192.168.1.101:7001
slots: (0 slots) slave
replicates 8c5a037999975a052e422bc030c3fc72053d059e
S: 35756a64813b68bf5fea92b6ee2b1a7020b8cc7a 192.168.1.100:7001
slots: (0 slots) slave
replicates 8c5a037999975a052e422bc030c3fc72053d059e
M: 4877856114a8efc62325dc0d32adede6256eb9ef 192.168.1.99:7001
slots:[12288-16383] (4096 slots) master
1 additional replica(s)
M: 6df7e2ad828ba148239dd4465235d17ce0e0af10 192.168.1.100:7000
slots:[4096-8191] (4096 slots) master
1 additional replica(s)
S: 3bd40f9a2d95a9865f58706b55f4559e6c43dd7e 192.168.1.99:7002
slots: (0 slots) slave
replicates 6df7e2ad828ba148239dd4465235d17ce0e0af10
S: f467098bffa3761868842556eb4cfff7cc8bc363 192.168.1.100:7002
slots: (0 slots) slave
replicates 660590807a4417e901c6d2277b29a306c1ea07e3
S: 8d1cab296fe88e1809e550ecd482f6df67c61e7b 192.168.1.101:7002
slots: (0 slots) slave
replicates 4877856114a8efc62325dc0d32adede6256eb9ef
M: 660590807a4417e901c6d2277b29a306c1ea07e3 192.168.1.101:7000
slots:[8192-12287] (4096 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

#如果要重新配置集群,先停止集群,然后将cluster-config-file配置的所有文件删除,再重新启动集群,就可以重新配置集群
#当出现集群无法启动时,删除集群配置文件,再次重新启动每一个redis服务,然后重新构件集群环境。


6.验证集群
[[email protected] ~]$ redis-cli --cluster check 192.168.1.99:7000 #查看节点7000端口号的集群信息

[[email protected] ~]$ redis-cli -c -p 7000 -h 192.168.1.99 #连接集群(-c参数得重要特性)
192.168.1.99:7000> auth 123456
OK
192.168.1.99:7000> get name #如果该redis实例中没有key则切换到其他得机器得redis实例中进行获取
-> Redirected to slot [5798] located at 192.168.1.100:7000
(error) NOAUTH Authentication required.
192.168.1.100:7000> auth 123456
OK
192.168.1.100:7000> get name
"weiyi"

192.168.1.100:7000> cluster info #查看集群状态
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:9
cluster_size:4
cluster_current_epoch:9
cluster_my_epoch:4
cluster_stats_messages_ping_sent:1100
cluster_stats_messages_pong_sent:984
cluster_stats_messages_sent:2084
cluster_stats_messages_ping_received:984
cluster_stats_messages_pong_received:1087
cluster_stats_messages_received:2071


192.168.1.100:7000> cluster nodes #集群节点
8d1cab296fe88e1809e550ecd482f6df67c61e7b 192.168.1.101:[email protected] slave 4877856114a8efc62325dc0d32adede6256eb9ef 0 1555559362575 9 connected
f467098bffa3761868842556eb4cfff7cc8bc363 192.168.1.100:[email protected] slave 660590807a4417e901c6d2277b29a306c1ea07e3 0 1555559363077 7 connected
8c5a037999975a052e422bc030c3fc72053d059e 192.168.1.99:[email protected] master - 0 1555559362172 1 connected 0-4095
cd7fb4d0a48a114629c1f34e0f75da5235910995 192.168.1.101:[email protected] slave 8c5a037999975a052e422bc030c3fc72053d059e 0 1555559363582 8 connected
660590807a4417e901c6d2277b29a306c1ea07e3 192.168.1.101:[email protected] master - 0 1555559362575 7 connected 8192-12287
6df7e2ad828ba148239dd4465235d17ce0e0af10 192.168.1.100:[email protected] myself,master - 0 1555559362000 4 connected 4096-8191
35756a64813b68bf5fea92b6ee2b1a7020b8cc7a 192.168.1.100:[email protected] slave 8c5a037999975a052e422bc030c3fc72053d059e 0 1555559363000 5 connected
4877856114a8efc62325dc0d32adede6256eb9ef 192.168.1.99:[email protected] master - 0 1555559362070 2 connected 12288-16383
3bd40f9a2d95a9865f58706b55f4559e6c43dd7e 192.168.1.99:[email protected] slave 6df7e2ad828ba148239dd4465235d17ce0e0af10 0 1555559363078 4 connected


192.168.1.100:7000> CLUSTER SLOTS #查看集群信息- cluster info
1) 1) (integer) 0
2) (integer) 4095
3) 1) "192.168.1.99"
2) (integer) 7000
3) "8c5a037999975a052e422bc030c3fc72053d059e"
4) 1) "192.168.1.101"
2) (integer) 7001
3) "cd7fb4d0a48a114629c1f34e0f75da5235910995"
5) 1) "192.168.1.100"
2) (integer) 7001
3) "35756a64813b68bf5fea92b6ee2b1a7020b8cc7a"
2) 1) (integer) 8192
2) (integer) 12287
3) 1) "192.168.1.101"
2) (integer) 7000
3) "660590807a4417e901c6d2277b29a306c1ea07e3"
4) 1) "192.168.1.100"
2) (integer) 7002
3) "f467098bffa3761868842556eb4cfff7cc8bc363"
3) 1) (integer) 4096
2) (integer) 8191
3) 1) "192.168.1.100"
2) (integer) 7000
3) "6df7e2ad828ba148239dd4465235d17ce0e0af10"
4) 1) "192.168.1.99"
2) (integer) 7002
3) "3bd40f9a2d95a9865f58706b55f4559e6c43dd7e"
4) 1) (integer) 12288
2) (integer) 16383
3) 1) "192.168.1.99"
2) (integer) 7001
3) "4877856114a8efc62325dc0d32adede6256eb9ef"
4) 1) "192.168.1.101"
2) (integer) 7002
3) "8d1cab296fe88e1809e550ecd482f6df67c61e7b"

集群操作常用命令
redis-cli –cluster help

  1. create:创建一个集群环境host1:port1 … hostN:portN(集群中的主从节点比例)
  2. call:可以执行redis命令
  3. add-node:将一个节点添加到集群里,第一个参数为新节点的ip:port,第二个参数为集群中任意一个已经存在的节点的4. ip:port
  4. del-node:移除一个节点
  5. reshard:重新分片
#交互命令
//集群(cluster)
CLUSTER INFO #打印集群的信息
CLUSTER NODES #列出集群当前已知的所有节点(node),以及这些节点的相关信息。
CLUSTER SLOTS #用于当前的集群状态,以数组形式展,返回值 IP/端口嵌套的列表数组


//节点(node)
CLUSTER MEET <ip> <port> #将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
CLUSTER FORGET <node_id> #从集群中移除 node_id 指定的节点。
CLUSTER REPLICATE <node_id> #将当前节点设置为 node_id 指定的节点的从节点。
CLUSTER SAVECONFIG #将节点的配置文件保存到硬盘里面。

//槽(slot)
CLUSTER ADDSLOTS <slot> [slot ...] 将一个或多个槽(slot)指派(assign)给当前节点。
CLUSTER DELSLOTS <slot> [slot ...] 移除一个或多个槽对当前节点的指派。
CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
CLUSTER SETSLOT <slot> NODE <node_id> 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。
CLUSTER SETSLOT <slot> MIGRATING <node_id> 将本节点的槽 slot 迁移到 node_id 指定的节点中。
CLUSTER SETSLOT <slot> IMPORTING <node_id> 从 node_id 指定的节点中导入槽 slot 到本节点。
CLUSTER SETSLOT <slot> STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。

//键 (key)
CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上。
CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量。
CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 个 slot 槽中的键。


#**** 向集群中添加节点或删除节点 *****#
redis-cli --cluster add-node 127.0.0.1:7000 127.0.0.1:7001 #将刚才删除的端口7000的节点添加到集群中的7001的主节点,如果原来存在且被删除得节点需要重启服务/并删除节点node_700x配置文件
>>> Adding node 192.168.1.100:7002 to cluster 192.168.1.99:7000
>>> Performing Cluster Check (using node 192.168.1.99:7000)

redis-cli --cluster del-node 127.0.0.1:7000 f467098bffa3761868842556eb4cfff7cc8bc363 -a 123456 #该节点将会被shutdown
redis-cli --cluster rebalance -a 123456 --cluster-threshold 1 127.0.0.1:8007 #平衡各节点槽数量

#把7000节点的10个slots移到7001节点上,键入命令如下,
redis-cli -–cluster reshard 127.0.0.1:7000 -–cluster-from a7b511330bffe28357cd21d6ee543e59f0a38dea -–cluster-to a7ab1aa24c9030d1fb42bbac3ad72c15bf683ef4 –-cluster-slots 10 –cluster-yes

主从同步配置/验证:

####设置步骤 
主: 192.168.1.100 6379 AUTH 123456
从: 192.168.1.100 6380

0. 主服务器redis最简配置
protected-mode no #保护模式,默认是开启状态,只允许本地客户端连接
daemonize yes #默认情况下 redis 不是作为守护进程运行的,如果你想让它在后台运行,你就把它改成 yes。当redis作为守护进程运行的时候,它会写一个 pid 到 /var/run/redis.pid 文件里面
appendonly yes # 默认redis使用的是rdb方式持久化,这种方式在许多应用中已经足够用了。但是redis如果中途宕机,会导致可能有几分钟的数据丢失,根据save来策略进行持久化,Append Only File是另一种持久化方式,可以提供更好的持久化特性。 Redis会把每次写入的数据在接收后都写入appendonly.aof文件,每次启
reuirepass 123456 #连接密码

1. 在从服务器redis配置文件中加入(在上面配置文件得基础之上)
slaveof 192.168.1.100 6379 #Redis主节点IP 端口
masterauth 123456 #注意:如果主节点有密码需要在从服务器配置中加入123456为密码自行替换)

[[email protected] run]# redis-server /root/redis6379.conf
[[email protected] run]# redis-server /root/redis6380.conf
[[email protected] run]# ps -ef | grep "redis"
root 7183 1 0 14:25 ? 00:00:00 redis-server *:6379
root 7188 1 0 14:25 ? 00:00:00 redis-server *:6380
root 7195 6981 0 14:25 pts/0 00:00:00 grep redis


#####测试主从
[[email protected] run]# redis-cli -p 6379 -a 123456
127.0.0.1:6379> set test weiyigeek #在主节点设置keys/value (注意单主从只能从主同步到从,且从库不能写)
OK
127.0.0.1:6379> get test
"weiyigeek"
127.0.0.1:6379> sync # 命令用于同步主从服务器。 (一般会自动进行同步)
"PING"
[[email protected] run]# redis-cli -p 6380 -a 123456
127.0.0.1:6380> get test #从服务器上也能执行
"weiyigeek"


#将当前服务器转变为指定服务器的从属服务器(slave server)
> ROLE #查看主从实例所属的角色,角色有master, slave, sentinel。
127.0.0.1:6380> role
1) "slave"
2) "192.168.1.100"
3) (integer) 6379
4) "connected"
5) (integer) 467


#用于异步执行一个 AOF(AppendOnly File) 文件重写操作。重写会创建一个当前 AOF 文件的体积优化版本。
#注意:从 Redis 2.4 开始, AOF 重写由 Redis 自行触发, BGREWRITEAOF 仅仅用于手动触发重写操作。
redis> BGREWRITEAOF
#即使 Bgrewriteaof 执行失败,也不会有任何数据丢失,因为旧的 AOF 文件在 Bgrewriteaof 成功之前不会被修改。
Background append only file rewriting started


#如果当前服务器已经是某个主服务器(master server)的从属服务器,那么执行 SLAVEOF host port 将使当前服务器停止对旧主服务器的同步,丢弃旧数据集,转而开始对新主服务器进行同步。
redis redis> SLAVEOF 127.0.0.1 6379 #将当前服务器转变为指定服务器的从属服务器(slave server)
OK
#另外,对一个从属服务器执行命令 SLAVEOF NO ONE 将使得这个从属服务器关闭复制功能,并从从属服务器转变回主服务器,原来同步所得的数据集不会被丢弃。
redis redis> SLAVEOF NO ONE #这时从库可以写但不会同步
OK

0x04 Redis配置文件

配置详细:https://github.com/linli8/cnblogs/blob/master/redis%E5%89%AF%E6%9C%AC.conf

redis > CONFIG GET *

activerehashing yes #指定是否激活重置哈希,默认为开启

bind 127.0.0.1 #绑定的主机地址 0.0.0.0 表示所有得都能连接
protected-mode yes #3.0以后增加了保护机制,目标机器调用可能会报错,优势需要设置为no

port 6379 #Redis监听端口
tcp-backlog 511
timeout 0 #客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
tcp-keepalive 300
daemonize no #使用yes启用守护进程,即是否后台启动 Redis
pidfile /var/run/redis_6379.pid #当Redis以守护进程方式运行时会把pid写入/var/run/redis.pid文件

#指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件
include /path/to/local.conf

loglevel notice #指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose
logfile stdout #如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null

databases 16 #设置数据库的数量,可以使用SELECT <dbid> 命令在连接上指定数据库id

#指定在多长时间内,有多少次更新操作,就将数据同步到数据文件
#分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。
save 900 1
save 300 10
save 60 10000

rdbcompression yes #指定存储至本地数据库时是否压缩数据,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大

rdbchecksum yes
dbfilename dump.rdb #指定本地数据库文件名,默认值为dump.rdb
dir ./ #指定本地数据库存放目录
requirepass 097575a79efcd7ea7b1efa2bcda78a4fc7cbd0820736b2f2708e72c3d21f8b61 # 账号密码


#指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no
appendonly no

#指定更新日志文件名,默认为appendonly.aof
appendfilename "appendonly.aof"

# 指定更新日志条件,共有3个可选值:
# no:表示等操作系统进行数据缓存同步到磁盘(快)
# always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
# everysec:表示每秒同步一次(折中,默认值)
appendfsync everysec

#设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步
slaveof <masterip> <masterport>

#当master服务设置了密码保护时,slav服务连接master的密码
masterauth <master-password>

supervised no
always-show-logo yes
stop-writes-on-bgsave-error yes

replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
replica-priority 100

lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no

no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100

client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes

# 集群设置
#cluster-require-full-coverage #默认关闭即可,兼容集群容错

0x05 Redis配置入坑

Q:(1)redis集群问题
问题:[ERR] Node 127.0.0.1:8000 is not empty. Either the node already knows other nodes (check with CLUSTE
解决方法:删除生成的配置文件/etc/redis/cluster/run/nodes_8000.conf;如果不行则说明现在创建的结点包括了旧集群的结点信息,需要删除redis的持久化文件后再重启redis,比如:appendonly.aof、dump.rdb