一,Redis-Sentinel集群搭建
1,集群架构
* 一主机
* 二从机
* 三哨兵
* 架构图如下:
2,主机端口列表
HOST | PORT | |
---|---|---|
主节点 | 192.168.91.128 | 6379 |
从节点_1 | 192.168.91.129 | 6379 |
从节点_2 | 192.168.91.130 | 6379 |
哨兵_1 | 192.168.91.128 | 26379 |
哨兵_2 | 192.168.91.129 | 26379 |
哨兵_3 | 192.168.91.130 | 26379 |
3,环境构建
A, 在三台虚拟机上分别搭建一台服务节点和一台哨兵节点,根据不同的文件进行区分
B,redis服务安装
// 构建文件
mkdir -p /usr/develop/redis/redis-sentinel
// 解压redis tar包到该文件
tar -zxvf /usr/myapp/redis-3.2.8.tar.gz -C /usr/develop/redis/redis-sentinel/
// 对文件进行改名
mv redis-3.2.8 redis-master // 表示主节点
// 文件编译
cd ./redis-master/src
make
// 启动服务查看服务是否可以正常启动
./redis-server ../redis.conf
// 进入客户端
./redis-cli
C,集群结构构建
* 如上图复制一份redis-master为redis-sentinel
cp -r redis-master redis-sentinel
* 三台服务器最终的两个节点结构图如下
D,配置文件修改
a,整体修改
// redis.conf修改
// 后台启动
daemonize yes
// 绑定节点, 必须修改为0.0.0.0
bind 0.0.0.0
// sentinel.conf修改
// 添加bind属性,
bind 0.0.0.0
// 链接主机配置, ip为主节点IP,端口为主节点服务端口, 2主节点投票最少需要同意的哨兵数量
// 三条哨兵的ip端口配置都为主节点的ip和端口, 不以自身端口为准
// 哨兵连接主节点后,会通过路由识别到其他服务节点和哨兵节点
sentinel monitor mymaster 192.168.91.128 6379 2
// 宕机判断时间
sentinel down-after-milliseconds mymaster 10000
// 启动失败判断时间
sentinel failover-timeout mymaster 20000
b,服务节点配置修改
// 主节点无需修改
// 从节点添加slaveof属性, ip为主节点ip, 端口为主节点端口
slaveof 192.168.91.128 6379
E,节点启动
a,注意关闭防火墙,或者对6379,26379端口放开
b,服务节点和哨兵节点都需要配置属性
// bind不能注释, 不能是127.0.0.1或者真实IP
bind 0.0.0.0
c,启动节点
// 先启动服务节点,再启动哨兵节点,在src目录下启动
// 服务节点启动
./redis-servicer ../redis.conf
// 哨兵节点启动
./redis-sentinel ../sentinel.conf
d,进入客户端查看状态
-- 主节点状态
-- 从节点状态
4,使用Jedis连接Redis-Sentinel进行数据操作
a,依赖导入 -- jedis
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
b,代码实现
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import java.util.HashSet;
import java.util.Set;
public class RedisSentinelTest {
public static void main(String[] args) {
// 添加哨兵主机和端口到Set集合
Set<String> lstSentinel = new HashSet<>(10);
lstSentinel.add("192.168.91.128:26379");
lstSentinel.add("192.168.91.129:26379");
lstSentinel.add("192.168.91.130:26379");
// 根据哨兵连接到集群
JedisSentinelPool jedisSentinelPool =
new JedisSentinelPool("mymaster", lstSentinel);
// 获取jedis操作平台
Jedis jedis = jedisSentinelPool.getResource();
// 获取值
String test = jedis.get("test");
System.out.println(test);
// set值
String set = jedis.set("javaTest", "javaValue");
System.out.println(set);
}
}
c,运行结果
5,节点宕机演示
A,服务节点宕机
a,目前主机
b,停掉主机
c,哨兵监控到主机宕机,进行选举
B,哨兵节点宕机
a,停掉130机器上的哨兵
b,其他机器同步监控到宕机状态
c,继续停掉主机128,如下图并不影响主节点选举
d,上线停掉的所有服务节点和哨兵节点,从主节点日志可以看出,全部停掉的服务被加回到集群中
二,Redis-Cluster集群搭建
1,集群架构
* 三主三从六个节点
* 架构图
2,服务结构
* 集群在三台服务上搭建,每台服务器存在一主一从两个节点
主节点 | 从节点 | |
---|---|---|
服务器_1 | 192.168.91.128:6379 | 192.168.91.128:6380 |
服务器_2 | 192.168.91.129:6379 | 192.168.91.129:6380 |
服务器_3 | 192.168.91.130:6379 | 192.168.91.130:6380 |
* 文件结构,移动./src下的文件redis-trib.rb文件到集群文件位置
3,配置修改
// bind属性修改
bind 0.0.0.0
// 端口修改
// master端口
port 6370
// slave端口
port 6380
// 集群配置信息
// 后台启动
daemonize yes
// 启动集群
cluster-enabled yes
cluster-config-file nodes-{port}.conf
cluster-node-timeout 15000
// 开启aof存储方式
appendonly yes
4,ruby脚本安装
* 安装ruby
// 安装ruby
yum install ruby
// 安装rubygems
yum install rubygems
* 安装redis-trib.rb运行依赖,在redis-cluster文件下安装
// 安装依赖包
gem install redis-3.2.2.gem
* 依赖包安装可能会报错,从仓库中找不到依赖包
* 可以从浏览器下载后安装,注意在redis-cluster路径下进行下载安装,或者上传现有包到该路径进行安装
// 下载
wget rubygems.global.ssl.fastly.net/gems/redis-3.2.2.gem
// 安装
gem install redis
5,启动redis节点
// 启动主节点
./redis-master/src/redis-server ./redis-master/redis.conf &
// 启动从节点
./redis-slave/src/redis-server ./redis-slave/redis.conf &
// 带主机端口信息进入客户端
./redis-master/src/redis-cli -h 192.168.91.128 -p 6379
* 状态查看
6,使用redis-trib.rb创建集群
// --replicas 1 表示为每一个主节点创建一个从节点
// host:port表示全部需要构建集群的节点
./redis-trib.rb create --replicas 1 192.168.91.128:6379 192.168.91.128:6380 192.168.91.129:6379 192.168.91.129:6380 192.168.91.130:6379 192.168.91.130:6380
* 加载出下列信息说明集群构建完成
7,集群存取值测试
* 随便存储一个节点信息到集群中
// 连接集群, 添加-c
./redis-cli -c -p 6379
// 存值
set clustertest 123
* 可以看到该key值根据hash分配的槽点为1519,分配的节点信息在192.168.91.128:6380,且当前节点直接被切换到了6380
* 重新连接节点为192.168.91.128:6379,尝试直接取值,可以看到系统直接跳到6380节点进行取值
8,集群节点选举测试
* 关掉128:6380节点,模拟宕机
* 检查128:6380节点状态
[root@localhost redis-cluster]# ./redis-trib.rb check 192.168.91.128:6380
* 检查集群状态
// host:port可以为任意一台集群内节点
[root@localhost redis-cluster]# ./redis-trib.rb check 192.168.91.128:6379
* 可以看到128:6380节点已经丢失,集群中剩余五台机器
* 查看数据是否丢失 --> 数据已经成功转移到129:6379节点下
* 重启128:6380节点,查看节点状态
9,集群节点添加
* 添加节点
// 添加节点
// 131主机表示新节点, 128主机表示集群内任意一台节点
./redis-trib.rb add-node 129.168.91.131:6379 129.168.91.128:6379
* 添加节点后,发现新添加的为主节点,但是并没有分配到槽点,这时候需要分配槽点
// host:port表示节点内的任意一台机器
[root@localhost redis-cluster]# ./redis-trib.rb reshard 192.168.91.128:6379
* 槽点分配可能报错
* 可通过fix命令进行修复
// 此时的host:port指的是故障节点
[root@localhost redis-cluster]# ./redis-trib.rb fix 192.168.91.130:6380
* 槽点分配需要手动输入槽点,通过四个节点平分,可以输入4096
* 完成之后需要输入接收改槽点的节点ID,这里输入不存在槽点的主节点ID
* 完成之后需要选择是从某一节点进行槽点分配,还是多个节点平均进行槽点分配,这里输入all,表示平均分配
* 重新查看槽点分布
10,新增从节点
* 目前集群中,四主三从,再往单独的主节点上添加一个从节点
// [nodeId]只需要添加的目标主节点的ID,
// 第一个host:port指需要添加的从节点信息
// 第二个host:port指集群中任意一点节点,表示当前集群
// 单独添加slave节点, 不需要指定mastId
./redis-trib.rb add-node --slave --master-id $[nodeid] 192.168.91.131:6380 192.168.91.128:6379
* 添加节点到目标主节点
* 查看集群状态
11,移除主节点
* 移除命令
// host:port为当前集群内任一节点, 表示当前集群
// nodeid必填, 表示移除指定节点
[root@localhost redis-cluster]# ./redis-trib.rb del-node 192.168.91.128:6379 72c64deb75bf42f9ec6db185fa252e057c906d9c
* 移除结果,移除失败,当前节点不为空,已经参与了槽点分配
* 重新进行槽点分配,移除目标主节点上的槽点
// 重新进行数据分片, host:port依旧标识当前集群
[root@localhost redis-cluster]# ./redis-trib.rb reshard 192.168.91.128:6379
* 输入移出的槽点数量,输入nodeid为其他主节点
* 输入给出的nodeid,并输入yes继续
* 查看节点所属槽点状态,此时131:6379没有槽点,128:6379存在8192个槽点
* 继续移除主节点
* 查询集群状态,存在主节点有两个从节点情况
Java API连接测试
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import java.util.HashSet;
import java.util.Set;
public class RedisClusterTest {
public static void main(String[] args) {
// 连接redis-cluster
Set<HostAndPort> set = new HashSet<>(10);
set.add(new HostAndPort("192.168.91.128", 6379));
set.add(new HostAndPort("192.168.91.128", 6380));
set.add(new HostAndPort("192.168.91.129", 6379));
set.add(new HostAndPort("192.168.91.129", 6380));
set.add(new HostAndPort("192.168.91.130", 6379));
set.add(new HostAndPort("192.168.91.130", 6380));
JedisCluster jedisCluster = new JedisCluster(set);
// 添加消息
String result = jedisCluster.set("javatest", "javatest");
System.out.println(result);
// 查看消息
String resultStr = jedisCluster.get("javatest");
System.out.println(resultStr);
// hash桶概念, {}保证hash算法以{}内为主, 保证同一范围数据存储在同一服务器
jedisCluster.set("apple.{user}.redistags", "testtags");
jedisCluster.set("balana.{user}.redistags", "testtags");
jedisCluster.set("orange.{user}.redistags", "testtags");
jedisCluster.set("watermelon.{user}.redistags", "testtags");
jedisCluster.set("pineapple.{user}.redistags", "testtags");
System.out.println("OK");
}
}