意思是所有的节点都要有一个主节点
特点:就是一个路由作用。
缺点:中心挂了,服务就挂了,中心处理数据的能力有限,不能把节点性能发挥到最大。
特点:去掉路由,我自己来路由
如何连接集群:连接集群中的任意一个主redis,都相当于连上了集群,因为该集群是去中心化的。
向集群中写数据的流程:
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。
当你往Redis Cluster中加入一个Key时,会根据crc16(key) mod 16384
计算这个key应该分布到哪个hash slot中,一个hash slot中会有很多key和value。你可以理解成表的分区,使用单节点时的redis时只有一个表,所有的key都放在这个表里;改用Redis Cluster以后会自动为你生成16384个分区表,你insert数据时会根据上面的简单算法来决定你的key应该存在哪个分区,每个分区里有很多key。
去中心化
机器编号 | ip | port |
---|---|---|
1 | 47.105.128.151 | 7000 |
2 | 47.105.128.151 | 7001 |
3 | 47.105.128.151 | 7002 |
4 | 47.105.128.151 | 7003 |
5 | 47.105.128.151 | 7004 |
6 | 47.105.128.151 | 7005 |
mkdir redis-cluster
redis-server
,方便启动Redis服务准备6个redis的配置文件:
#redis-7000.conf 后面几个配置文件如法炮制,修改后面编号就行
bind 0.0.0.0
port 7000
daemonize yes
# 打开aof 持久化
appendonly yes
# 开启集群
cluster-enabled yes
# 集群的配置文件,该文件自动生成 此处的编号也要修改
cluster-config-file nodes-7000.conf
# 集群的超时时间
cluster-node-timeout 5000
/usr/local/redis/bin/redis-server /usr/local/redis/conf/credis-cluster/redis-7000.conf
其他五个一样启动。
使用docker下载redis-trib
的镜像运行
yum install docker
启动docker
systemctl start docker
下载镜像
docker pull inem0o/redis-trib
开启集群(IP地址和端口号按上面的规则)
docker run -it --net host inem0o/redis-trib create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
-it
是为了可以输入,--net host
是为了让docker容器能连接上本地的宿主机。
测试集群环境
./redis-cli -c -h 127.0.0.1 -p 7000
-c 表示连接集群
至此,集群搭建完毕。
注意:
-a passwod
,如:docker run -it --net host inem0o/redis-trib create --replicas 1 127.0.0.1:7000 -a password 127.0.0.1:7001 -a password 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
查询集群:
-c
:表示以集群方式连接惹redis
-h
:指定IP地址
-p
:指定端口
cluster nodes
:查询集群节点信息
cluster info
: 查询集群状态信息
查询集群节点信息:
如:/usr/local/redis/bin/redis-cli -c -h 127.0.0.1 -p 7001 cluster nodes
myself:表示当前所查的服务节点;
master:表示主服务,最后的数字范围表示哈希槽范围;
slave:表示从服务。
查询集群节点信息:
如:/usr/local/redis/bin/redis-cli -c -h 127.0.0.1 -p 7001 cluster info
为防止地址端口冲突,以及宿主机为docker重启后分配地址变化的情况发生,可以使用docker创建一个专用的网卡,命令如下:
docker network create 网卡名 --subnet 子网掩码(如:172.38.0.0/16)
通过命令docker network ls
可以查看到目前已知的docker网络,
也可以通过docker network inspect 网卡名
查看网络的详细信息
创建六个redis启动所需要的配置文件,命令创建,路径可自定义,
cluster相关的配置一定要有,port 就是之后启动容器时必须要映射的端口,这里不要配置daemonize yes
,会影响docker的启动,默认为no,这是受docker的机制影响的,如果将其设置为yes,也会导致docker容器启动失败。
mkdir -p /usr/local/redis/docker/node-${port}/conf
touch /usr/local/redis/docker/node-${port}/conf/redis.conf
cat << EOF >/usr/local/redis/docker/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
挂载刚才创建好的配置文件,并使用其配置文件启动redis:
docker run -p 7001:6379 -p 17001:16379 --privileged=true --name redis-1 \
> -v /usr/local/redis/docker/node-1/data:/data \
> -v /usr/local/redis/docker/node-1/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.11 redis:5.0.14 redis-server /etc/redis/redis.conf
注意:
7001~7006
,以及总集线端口(端口号+10000)17001~17006
;--privileged=true
是为了防止Centos将启动停止,Centos7的安全机制;--ip
一定是刚才自己建的网卡ip地址,每个容器对应一个;输入docker ps
显示如下信息表示启动成功并正常运行:
输入docker ps -a
显示如下信息,表示异常退出:
补充知识:docker有一个机制,后台运行的程序必须有一个前台程序,否则这个docker容器就会觉得自己无事可做而自杀。
当六个Redis都正常运行时,就可以创建节点了,进入任意一个redis服务:
docker exec -it 容器名 bash
创建节点:
redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
ip号一定要和创建容器时的ip对应,端口也要和redis配置文件中的端口对应。
遇到询问,输入yes
即可
到此,搭建工作完成
进入集群一定注意输入:redis-cli -c -p 端口号
而不是原来的单体redis-cli -p 端口号
,默认端口是6379
输入cluster info
查看该集群节点信息;
输入cluster nodes
查看所有节点信息,master表示主机,slave表示从机,myself表示当前所在节点
向主机中写入数据,发现根据哈希算法计算,得到**[15495]**所以自动插入到3号主机的哈希槽中
测试故障转移:
故意关掉三号主机:docker stop redis-3
,获取刚才插入的值
发现已经转移到4号redis上,并且可以发现4号机已经自动升级成了master,说明转移成功。
自此,搭建完成!!!
参考视频:狂神说java[Docker搭建Redis集群部署实战]
新的风暴已经出现…
按着前面搭建集群的方法确实可以搭建成功,但是有个问题,那就是只能在自己的虚拟机中访问,通过外界工具无法访问,外部连接此集群会存在无法连接的情况,这不符和我的要求。。。
初步分析,竟然内部能操作集群,但是外部不能访问,猜测大概是网络的问题,前面创建reids容器时,是让它在自己创建的dcoker的redis网络中运行,外部无法访问,之前我的理解是,宿主机可以直接通过端口映射就能访问集群了,没考虑过是否与网络有关。
之前创建容器时使用的redis网络,那么这次我就直接使用docker的host网络,和宿主机关联;redis的启动配置文件没做改动,创建容器的命令只需要修改网络部分,将--net redis
改为--net host
,为了能看到启动失败时的错误信息,我没有选择后台运行:
docker run -p 7001:6379 -p 17001:16379 --privileged=true --name redis-1 \
> -v /usr/local/redis/docker/node-1/data:/data \
> -v /usr/local/redis/docker/node-1/conf/redis.conf:/etc/redis/redis.conf \
> --net host redis:5.0.14 redis-server /etc/redis/redis.conf
果然,启动失败,,,
原因是我的6379端口被占用,看了一下我的6379端口是我宿主机的redis在用;那么问题来了,前面创建docker内部集群时,映射的端口全是6379和16379;为什么这次会报被占用的错呢?估计是因为我把网络改成了本地宿主机,docker映射时直接映射在了宿主机上,所以才产生了冲突;尝试着修改配置文件再试试,其中一个修改如下:
#每个配置文件的端口都要不一样 我的是7001~7006
port 7006
bind 0.0.0.0
#这里的配置是在官网看到的,redis的一种安全保护机制,3.2开始的,防止外部网络访问,这里我直接禁用掉
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
#修改
cluster-announce-port 7006
#修改
cluster-announce-bus-port 17006
appendonly yes
protected-mode详细说明
重新启动,修改启动中的端口映射:
docker run -p 7001:7001 -p 17001:17001 --privileged=true --name redis-1 \
> -v /usr/local/redis/docker/node-1/data:/data \
> -v /usr/local/redis/docker/node-1/conf/redis.conf:/etc/redis/redis.conf \
> -d --net host redis:5.0.14 redis-server /etc/redis/redis.conf
启动成功!!!
依次启动其余五个容器,
再通过命令建立集群,记得修改每个容器的ip和端口:
docker run -it --net host inem0o/redis-trib create --replicas 1 宿主机ip:7001 宿主机ip:7002 宿主机ip:7003 宿主机ip:7004 宿主机ip:7005 宿主机ip:7006
之后的测试和前面的一样,另外这时也可以通过外界访问了!!!
通过管理工具存入"hello world"键值对:
在集群中查看:
我的最终目的是在java程序中也能访问集群,尝试通过java程序访问:
@Test
public void testClusters(){
//创建集群服务
Set<HostAndPort> hostAndPorts = new HashSet<>();
hostAndPorts.add(new HostAndPort("192.168.**.**",7001));//这里是自己宿主机的ip
hostAndPorts.add(new HostAndPort("192.168.**.**",7002));
hostAndPorts.add(new HostAndPort("192.168.**.**",7003));
hostAndPorts.add(new HostAndPort("192.168.**.**",7004));
hostAndPorts.add(new HostAndPort("192.168.**.**",7005));
hostAndPorts.add(new HostAndPort("192.168.**.**",7006));
//创建集群
JedisCluster cluster = new JedisCluster(hostAndPorts);
cluster.set("JAVA", "NO1");
System.out.println("set = " + cluster.get("JAVA"));
cluster.close();
}
输出台输出:
再查看Redis集群中:
目的达成,完结撒花!!!
Waiting for cluster join...
,主要原因是ip地址和端口不正确,无法找到节点,最好的方式就是自己为docker创建一个网卡,可以避免很多不必要的麻烦,但是这样外部就不能访问了,如果需要外部访问,还是得使用宿主机的ip地址,这时每个容器的端口也必须唯一,不能都是默认的6379了;not IP:端口 as a cluster nodes
,这是因为创建容器时,没有将Redis中的cluster-enabled
设置为yes;-d
,就能发现错误原因;chmod 777 redis.conf
;--privileged=true
;cluster-enabled
为no,并且很多集群相关的配置信息都没有,所以要仔细检查数据卷的挂载路径宿主机路径:容器内路径
,注意一个-v
表示配置文件目录,另一个-v
表示docker以后生成的数据文件存储目录,并且不能以/
结束,redis的启动文件以docker内的路径为准,因为这时已经将路径映射到宿主机上了。因为对网络部分的知识和redis不熟悉,走了很多弯路,此篇文章记录下自己的问题解决过程,加深印象。