Open WilliamUUUU opened 1 year ago
下载地址: https://github.com/MicrosoftArchive/redis/releases
将下载好的文件解压
进入解压好的文件夹中,在地址栏输入"cmd",打开命令行窗口,输入以下命令
redis-server.exe redis.windows.conf
见到以下界面说明启动成功,Redis默认启动端口是6379。如果需要修改,可以在redis.windows.conf里修改
测试是否可以连接,在文件夹中双击打开redis-cli.exe,输入ping,如果输出PONG则表示连接成功。
以命令行方式启动很多缺点,如每次电脑重启都要打开那个黑窗口,万一不小心关掉了,服务就停止了。所以把它制作成windows服务,就可以开机自动启动,也不会任务栏展示。
进入解压的文件夹中,在地址栏输入"cmd",打开命令行窗口,输入以下命令
redis-server --service-install redis.windows.conf
在服务里找到并启动Redis
使用redis-cli.exe进行测试。
卸载服务:redis-server --service-uninstall
下载地址:https://redis.io/download/
将下载好的文件通过xftp上传到服务器上,可以放在tmp目录下
使用下列命令进行解压,版本不一样,文件名也要变
tar -zvxf redis-7.0.8.tar.gz -C /opt
进入/opt目录,使用以下命令进行重命名(这个步骤可以不用)
mv -i redis-7.0.8/ redis
由于Redis是C语言编写的,所以需要gcc,可以先用
gcc -v
来查看是否已经安装了gcc,如果没有安装,使用以下命令进行安装
yum -y install gcc
进入redis目录,使用make命令进行编译,这时控制台会输出编译信息,等待编译完成。输入命令
make install
自此redis已经安装完成
在启动redis之前推荐修改配置文件(redis.conf)中以下内容
redis启动
redis-server redis.conf
使用RedisDesktopManager进行连接
新建redis.service文件
vim /usr/lib/systemd/system/redis.service
写入以下内容
[Unit]
Description=Redis
After=syslog.target network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/var/run/redis.pid
ExecStart=/opt/redis/src/redis-server /opt/redis/redis.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
重载系统服务
systemctl daemon-reload
启动redis服务
systemctl start redis
设置开机自起
systemctl enable redis.service
以下测试都是在windows上进行的
get xxx
set key value [EX seconds|PX milliseconds] [NX|XX]
EX|PX表示设置值的生存时间,EX对应秒,PX对应毫秒
NX表示当key不存在时才进行设置值的操作
XX表示当key存在时才进行设置值的操作
mset key value [key value...]
# 不包含NX、XX、PX、EX等参数
# 如果带上EX、PX参数,不会报错,但实际上不生效
# 如果带上NX、XX参数,会直接报错
mget key [key...]
incr key 对key对应的数值加一
incrby key increment 对key对应的数值加increment
decr key 对key对应的数据减一
decrby key decrement 对key对应的数值减decrement
append key value 把value追加到key原值的后面,数值型的也是直接追加到后面。1 append 2 -> 12
getrange key start end
setrange key offset value
getset key value
# 不能追加EX、PX、NX、XX参数
# 如果key对应的值存在,则会用value覆盖旧值,同时返回旧值;
# 如果key对应的值不存在,也会设值,但会返回nil。
hset key field value
# 只能一对一对的设置,同时多个设置会报错
hget key field
hsetnx key field value
hkeys key
hvals key
hgetall key
hexists key field
# 存在返回1,不存在返回0,不写field报错
hdel key field [field...]
lpush key element [element...]
rpush key element [element...]
lindex key index
# 不带索引会报错
# 索引从0开始
# 如果index超过会返回nil
# 如果index为负,会返回第一个元素
lpushx key element 从头部插入
rpushx key element 从尾部插入
# 只能一个个插入,多个元素会报错
lpop key 从头部出队
rpop key 从尾部出队
# key不存在则返回nil
lrange key start stop
# [start stop]是闭区间,0 2 会返回3个值
# 如果start > stop 会返回空
# stop大于结束索引会取结束索引
lset key index element
# index可以为负,-1表示修改最后一个
# 超过最大索引会报错
lrem key count element
# 当count等于0时,删除该列表例所有值是element的数据
# 当count大于0时,删除从头到尾方向数量为count个、值是element的数据
# 当count小于0时,删除从尾到头方向数量为count个、值是element的数据
sadd key member [member...]
smembers key
sismember key member
# 存在返回1,不存在返回0
sinter key [key ...]
# 交集:所有属于集合A且属于集合B的元素所组成的集合
sunion key [key ...]
# 并集:属于集合A与属于集合B的元素所有的元素合并在一起组成的集合
sdiff key [key ...]
# 差集:所有属于A但不属于B元素构成的集合
srem key member [member ...]
# 如果从一个不存在的集合中删除数据,会返回0
# 如果从一个非集合对象中删除数据,会报错
在有序集合中,每个数据都会对应一个score参数,以此来描述该数据的分数
zadd key [NX|XX] [CH] [INCR] score member [score member ...]
# NX参数表示只有当key对应的有序集合不存在时才添加member元素
# XX参数表示当有序集合存在时才添加member元素
# CH参数指定该zadd命令修改时返回的个数(默认返回0)
# 当待插入的member不存在时,INCR参数不会起作用
# 当member存在时,会让score加上由INCR指定的数值
# score参数是用来描述元素的数值(也叫权重),即元素在集合中的重要程度
# zadd命令能够同时添加一个或多个score member元素对
同分数问题:不同的member有相同的分数,redis会按时ascill码的先后顺序进行排序
zrange key start stop [WITHSCORES]
# WITHSCORES参数控制读取后带不带scores信息输出
zreverange key start stop [WITHSCORES]
# WITHSCORES参数控制读取后带不带scores信息输出
zincrby key increment member
# 如果修改一个不存在的member,相当于添加一个元素,分数为increment
# increment表示为减
zscore key member
zrank key member
zrevrank key member
zrem key member [member ...]
zremrangebyrank key start stop
zremrangebyscore key min max
底层是一个zset
geoadd key [nx|xx] [ch] longitude latitude member [longitude latitude member ...]
geopos key member [member ...]
geodist key member1 member2 [m|km|ft|mi]
# 如果其中有一个不存在则返回nil
# m:米 km:千米 ft:英尺 mi:英里
geosearch key [frommember member] [fromlonlat longitude latitude] [byradius radius m|km|ft|mi] [bybox width height m|km|ft|mi] [asc|desc] [count count [any]] [withcoord] [withdist] [withhash]
key:提供一个geoadd的空间集合key
[frommember member]:在我们指定的空间集合中选择一个空间元素作为中心点
[fromlonlat longitude latitude]:我们指定经纬度来作为中心点
[byradius radius m|km|ft|mi]:根据给定的radius范围在圆形区域内搜素(参考雷达图)
[bybox width height m|km|ft|mi]:根据给定的width X坐标 height Y坐标 中轴对齐的矩形内中心点搜素
[asc|desc]:返回结果按照离中心节点的距离做升序或者降序
[count count [any]]:指定返回结果的数量
[withcoord]:返回的结果中包含经纬度
[withdist]:返回的结果中包含离中心点的位置距离
[withhash]:返回的结果中包含geohash(此值用来表示经纬度,但是用hash不是太准)
注:frommember与fromlonlat不能同时出现,只能选择其一
注:byradius与bybox不能同时出现,只能选择其一
setbit key offset value
getbit key offset
# 不存在返回0
bitcount key [start end]
bitop operation destkey key [key...]
# opeartion可选操作为 AND(与)、OR(或)、XOR(异或)、NOT(非)
# 除NOT外,其他操作都可以输入多个key
# destkey 运算结果保存的key值
bitfield key [get type offset] [set type offset value] [incrby type offset increment] [overflow wrap|sat|fail]
# get 返回指定的位域
# set 设置指定位域的值并返回它的原值
# incrby 自增或自减指定位域的值并返回它的新值
# overflow 设置溢出行为 WRAP: 回环算法 WRAP: 回环算法 FAIL: 失败算法
# 当需要一个整型时,有符号整型需在位数前加i,无符号在位数前加u
select 1 选择数据库,从0开始
dbsize 查看当前数据库中key的数量
keys * 查看所有的key,* 正则表达式
flushall 清空所有数据库
flushdb 清空当前数据库
del key [key...] 删除key
exists key [key...] 指定key是否存在
expire key seconds 给指定key设置过期时间,单位:秒
pexpire key milliseconds 给指定key设置过期时间,单位:毫秒
ttl key 返回key的剩余时间,单位:秒 已过期返回-2,没有过期时间返回-1
pttl key 返回key的剩余时间,单位:毫秒 已过期返回-2,没有过期时间返回-1
创建一个maven工程,将jedis依赖引入项目中
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.1</version>
</dependency>
编写工具类
package com.growatt.redis1.util;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisUtil
{
// jedis连接池
private static JedisPool jedisPool;
private static final String host = "127.0.0.1";
private static final int port = 6379;
private static final int timeout = 10000;
private static final String password = "redispass";
// 默认数据库
private static final int defaultDatebase = 10;
// 初始化
static void init()
{
if (jedisPool == null)
{
// 配置连接参数
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(200);//最大空闲链接
poolConfig.setMaxTotal(500);//最大连接数
poolConfig.setMaxWaitMillis(1000 * 10);//最大等待毫秒数
poolConfig.setTestOnBorrow(true);//获取链接检查有效性
poolConfig.setTestOnReturn(false);//返回验证
poolConfig.setBlockWhenExhausted(true);//链接好近是否阻塞
poolConfig.setTestOnCreate(true);//部署时 为True;
try
{
jedisPool = new JedisPool(poolConfig, host, port, timeout, password);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
// 获取一个jedis
private synchronized static Jedis getJedis() {
return getJedis(defaultDatebase);
}
/**
* 获取一个jedis
* @param dbIndex 需要操作的数据库索引
* @return
*/
private synchronized static Jedis getJedis(int dbIndex) {
Jedis jedis = null;
JedisUtil.init();
if (jedisPool != null) {
try {
jedis = jedisPool.getResource();
jedis.select(dbIndex);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
return jedis;
}
// 释放redis资源
private static void releaseResource(Jedis jedis) {
if (jedis != null) {
try {
jedis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 获取对应key的值
* @param key redis key
* @return
*/
public static String get(String key) {
return get(key, defaultDatebase);
}
/**
* 获取指定数据库中对应key的值
* @param key redis key
* @param dbIndex 数据库索引
* @return
*/
public static String get(String key, int dbIndex) {
Jedis jedis = getJedis(dbIndex);
if(jedis == null){
return null;
}
try {
return jedis.get(key);
} catch (Exception e) {
e.printStackTrace();
} finally {
releaseResource(jedis);
}
return null;
}
/**
* 插入数据
* @param key redis key
* @param value redis value
* @param seconds 过期时长(秒)
* @return
*/
public synchronized static Boolean save(String key, String value, int seconds) {
return save(key, value, seconds, defaultDatebase);
}
/**
* 插入数据
* @param key redis key
* @param value redis value
* @param seconds 过期时长(秒)
* @param dbIndex 数据库索引
* @return
*/
public synchronized static Boolean save(String key, String value, int seconds, int dbIndex) {
Jedis jedis = getJedis(dbIndex);
if(jedis == null){
return false;
}
try {
jedis.del(key);
jedis.set(key, value);
if (seconds != 0) {
jedis.expire(key, seconds);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
releaseResource(jedis);
}
}
}
这里实现了通过传入数据库的索引来访问不同数据库
测试默认数据库
public static void main(String[] args)
{
JedisUtil.save("1", "张三", 100);
}
结果
测试其他数据库
public static void main(String[] args)
{
JedisUtil.save("1", "张三", 1000, 12);
}
测试默认获取
public static void main(String[] args)
{
System.out.println(JedisUtil.get("1"));
}
测试其他数据库获取
public static void main(String[] args)
{
System.out.println(JedisUtil.get("1", 12));
}
Lettuce是一个高性能基于Java编写的Redis驱动框架,底层集成了Project Reactor提供自然的反应式编程,通讯框架集成了Netty使用了非阻塞IO,5.x版本以后融合了JDK1.8的异步编程特性,在保证高性能的同时提供了十分丰富易用的API。
创建一个maven工程,将lettuce-core依赖引入项目中
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.1.8.RELEASE</version>
</dependency>
简单插值
public static void main(String[] args)
{
RedisURI redisURI = RedisURI.builder().withHost("127.0.0.1").withPort(6379).withPassword("redispass").build();
RedisClient redisClient = RedisClient.create(redisURI);
StatefulRedisConnection<String, String> connect = redisClient.connect();
try
{
RedisCommands<String, String> redisCommands = connect.sync();
redisCommands.select(10);
redisCommands.set("lettuce", "1234");
redisCommands.expire("lettuce", 60 * 1000); // 以秒为单位
} catch (Exception e)
{
e.printStackTrace();
} finally
{
connect.close();
redisClient.shutdown();
}
}
取值
public static void main(String[] args)
{
RedisURI redisURI = RedisURI.builder().withHost("127.0.0.1").withPort(6379).withPassword("redispass").build();
RedisClient redisClient = RedisClient.create(redisURI);
StatefulRedisConnection<String, String> connect = redisClient.connect();
try
{
RedisCommands<String, String> redisCommands = connect.sync();
redisCommands.select(10);
String lettuce = redisCommands.get("lettuce");
log.info("get redis = " + lettuce);
} catch (Exception e)
{
e.printStackTrace();
} finally
{
connect.close();
redisClient.shutdown();
}
}
// 输出
14:32:33.784 [main] get redis = 1234
创建一个springboot工程,将spring-boot-starter-data-redis依赖引入项目中
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
编写配置文件application.yml
server:
port: 9745
spring:
redis:
host: 127.0.01
port: 6379
password: redispass
jedis:
pool:
max-active: 50
max-wait: -1
min-idle: 0
timeout: 10000
database: 10
编写测试类
@SpringBootTest
public class RedisTest3
{
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Test
public void test1()
{
redisTemplate.boundValueOps("redisTemplate").set("123456", 60, TimeUnit.SECONDS);
}
}
redis作为目前主流的缓存服务器,同样会发生宕机的问题。为了实现redis的高可用,所以集群就应运而生。
redis为解决单点故障问题引入了主从模式,但是master节点如果故障就需要人工进行切换,才能够恢复服务。为了解决这一问题,redis引入了哨兵模式,哨兵是一个独立的进程,作为进程,它独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。当哨兵监测到Redis主机宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他服务器,修改配置文件,让他们换主机。主从模式和哨兵模式每个节点上都存着全量数据,对于资源的利用是比较差的,所以后来redis又发布了redis cluster,实现了真正的数据分片存储。
详细介绍见:https://blog.csdn.net/a745233700/article/details/112691126
参考:https://juejin.cn/post/6922690589347545102#heading-1
本次搭建的集群为3主3从,共6个节点。其拓扑图如下
环境准备
首先去官网下载tar包,地址:https://redis.io/download/
使用xftp把tar包上传到服务器中,随便放个位置,我放在/data目录下
使用解压命令
tar -zxvf redis-7.0.9.tar.gz
将解压好的包放到/usr/local/redis下
mv -i redis-7.0.9 /usr/local/redis/
进入redis的目录中使用命令
make install
等待安装完成
编写配置文件
vim redis-cluster-6379.conf
bind 0.0.0.0
port 6379 // 这里需要根据节点变动
daemonize yes
requirepass "XXXX" // 密码
logfile "./cluster-6379.log" // 这里需要根据节点变动
dbfilename "cluster-6379.rdb" // 这里需要根据节点变动
dir "./"
masterauth "XXXX" // 密码
#是否开启集群
cluster-enabled yes
# 生成的node文件,记录集群节点信息,默认为nodes.conf
cluster-config-file nodes-6379.conf // 这里需要根据节点变动
#节点连接超时时间
cluster-node-timeout 20000
#集群节点映射端口
cluster-announce-port 6379 // 这里需要根据节点变动
#集群节点总线端口,节点之间互相通信,常规端口+1万
cluster-announce-bus-port 16379 // 这里需要根据节点变动
后续5个节点都按上面配置好
配置好后就可以启动6个实例
./src/redis-server redis-cluster-6379.conf
./src/redis-server redis-cluster-6380.conf
./src/redis-server redis-cluster-6381.conf
./src/redis-server redis-cluster-6479.conf
./src/redis-server redis-cluster-6480.conf
./src/redis-server redis-cluster-6481.conf
此时可以查看6个实例的状态
ps -ef | grep redis
使用命令进行集群的创建
./src/redis-cli -a xxxx --cluster create 120.XX.XX.171:6379 120.XX.XX.171:6380 120.XX.XX.171:6381 120.XX.XX.171:6479 120.XX.XX.171:6480 120.XX.XX.171:6481 --cluster-replicas 1
# 这里有几个注意的点
# xxxx是你写在配置文件的密码
# 后面的 IP:PORT这里一定要写公网地址,如果你的项目也是在本机运行可以写成127.0.0.1
# 后面的 --cluster-replicas 1 表示一个主节点下面的从节点个数
如果想要使用想要远程连接记得把使用的端口全打开,不然只能在本机访问
至此简单的3主3从redis集群已经搭建完毕
解决方法,首先确认是否6个端口全部开放。redis占用的端口不只默认(6379)的,还会占用+1W的端口用于通讯,所以也要将16379等几个端口开放
解决方法,先停掉实例,将生成的nodes-6379.conf与cluster-6379.rdb等全部删除掉,再重新启动,然后再执行命令
<!-- 集成redis依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
编写配置文件
server:
port: 8041
spring:
redis:
database: 10
password: xxxx
jedis:
pool:
max-active: 50
max-wait: -1
min-idle: 0
timeout: 10000
cluster:
nodes:
- 120.xx.xx.171:6379
- 120.xx.xx.171:6380
- 120.xx.xx.171:6381
- 120.xx.xx.171:6479
- 120.xx.xx.171:6480
- 120.xx.xx.171:6481
max-redirects
修改序列化方式
@Configuration
public class RedisTemplateConfig
{
@Autowired
private RedisConnectionFactory factory;
@Bean
public RedisTemplate<String, Object> redisTemplate()
{
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
return redisTemplate;
}
}
写个controller调用
@RestController
@Slf4j
@RequestMapping("/clusterTest")
public class ClusterTestController
{
@Autowired
private RedisTemplate<String, String> redisTemplate;
@GetMapping("/write")
public String write()
{
log.info("开始写入redis");
for (int i = 0; i < 500; i++)
{
redisTemplate.opsForValue().set(""+i, String.valueOf(i));
}
return "success";
}
}
启动项目,调用方法
如果你用的是云服务器,可能会出现的问题
读取的连接是本机127.0.0.1,这个问题就是在create的时候,ip写的127.0.0.1导致
解决方法:见4.2.2
配置里配的是外网地址,但连接的是内网的地址
解决方法:
先停掉实例,修改生成的nodes-6379.conf(全部都要改)里面的myself前面的ip,改成自己的外网地址。然后重启实例。
重启springboot服务,调用方法成功写入。
使用命令查看节点的pid
ps -ef | grep redis
使用命令杀掉进程
kill -9 17919
查看其他节点的日志
进入其中一个节点查看集群信息
6479节点已经切换成master节点,6379节点被标记为fail
此时redis依旧可以提供服务。
此时redis已经停止服务了
可以看到依旧是slave节点,此时redis并没有恢复
启动master节点,redis恢复服务
杀掉一对主从节点的任一节点,redis都可以继续提供服务;
杀掉一对主从节点的所有节点,redis停止服务;
启动master节点而不启动slave节点,redis恢复服务;
启动slave节点而不启动master节点,redis不会恢复服务。
复制一个配置文件
cp redis-cluster-6379.conf redis-cluster-6382.conf
编辑配置文件,修改内容如下
bind 0.0.0.0
port 6382
daemonize yes
requirepass "xxxx"
logfile "./cluster-6382.log"
dbfilename "cluster-6382.rdb"
dir "./"
masterauth "xxxx"
#是否开启集群
cluster-enabled yes
# 生成的node文件,记录集群节点信息,默认为nodes.conf
cluster-config-file nodes-6382.conf
#节点连接超时时间
cluster-node-timeout 20000
#集群节点映射端口
cluster-announce-port 6382
#集群节点总线端口,节点之间互相通信,常规端口+1万
cluster-announce-bus-port 16382
启动6382节点
./src/redis-server redis-cluster-6382.conf
将新启动的节点加入到redis集群中
./src/redis-cli -a xxxx --cluster add-node 120.xx.xx.171:6382 120.xx.xx.171:6379
查看节点信息
新的节点已经加入,并成为主节点,此时这个节点并不会提供服务,因为没有给它分配槽位,所以我们需要重新分配
./src/redis-cli -a xxxx --cluster reshard 120.xx.xx.171:6382
执行命令后会询问你下列问题:
How many slots do you want to move (from 1 to 16384)?
表示需要移动槽的数量
What is the receiving node ID?
表示哪个id来接收它
Source node #1
从那个节点id上移动散列插槽。如果需要平均节点插槽,那么每个主节点的id都写上或者写all,然后需要移动的节点数量处理主节点数。
Do you want to proceed with the proposed reshard plan (yes/no)?
确定要移动这些槽的计划吗?输入yes或者no
查看是否添加成功
最后不要忘记修改nodes-6379.conf等几个文件的内容,把内网地址改成外网地址,重启集群
修改springboot配置文件,重启项目,写入数据
进入6382节点,查看节点内的数据
前几步和4.5.1相同
复制一个配置文件
cp redis-cluster-6379.conf redis-cluster-6482.conf
编辑配置文件,修改内容如下
bind 0.0.0.0
port 6482
daemonize yes
requirepass "xxxx"
logfile "./cluster-6482.log"
dbfilename "cluster-6482.rdb"
dir "./"
masterauth "xxxx"
#是否开启集群
cluster-enabled yes
# 生成的node文件,记录集群节点信息,默认为nodes.conf
cluster-config-file nodes-6482.conf
#节点连接超时时间
cluster-node-timeout 20000
#集群节点映射端口
cluster-announce-port 6482
#集群节点总线端口,节点之间互相通信,常规端口+1万
cluster-announce-bus-port 16482
启动节点
./src/redis-server redis-cluster-6482.conf
添加到集群中设置为从节点
./src/redis-cli -a xxxx --cluster add-node 120.xx.xx.171:6482 120.xx.xx.171:6382 -a xxxx --cluster-slave 382e8a64bca8a26e2efd8ed94b6733052cc84700
# 命令
redis-cli -a [password] --cluster add-node [new_host:new_port] [old_host:old_port] -a [password] --cluster-slave [old_id]
-a [password] redis的密码
[new_host:new_port] 新的节点ip:port
[old_host:old_port] 集群中任一ip:port
[old_id] 如果没有ID则随机分配
查看集群信息
最后不要忘记修改nodes-6379.conf等几个文件的内容,把内网地址改成外网地址,重启集群
./src/redis-cli -a xxxx --cluster del-node 120.xx.xx.171:6482 80d479b32adc4d689ac4314b5d86487683ba0e24
查看集群状态
此时可以看到6482节点已经不在集群内了,再kill掉6482的进程就完成删除了
删除一个主节点会比较麻烦,因为主节点上存放着数据,如果直接删除会导致数据丢失,所以需要先将数据给转移到节点中
./src/redis-cli -a xxxx --cluster reshard 120.xx.xx.171:6382 --cluster-from 382e8a64bca8a26e2efd8ed94b6733052cc84700 --cluster-to 0bb8cef1c276292da7d3d25b49f1f95385028040 --cluster-slots 1356 --cluster-yes
# --cluster-from 表示从哪个节点转移
# --cluster-to 表示哪个节点接收
# --cluster-slots 1356 表示要移动的槽数,由于我们是删除节点,所以要全部移出去
# --cluster-yes 不需要确认直接移动
等待槽移动完毕,查看节点信息会发现原来的主节点已经变成了从节点,直接从集群中删除节点即可
如果移动之后发现三个节点的槽数相差过大,可以使用命令进行平均
./src/redis-cli -a xxxx --cluster rebalance 120.xx.xx.171:6380
init