redis 进阶二

户外

Redis进阶

Sentinel

redis中master宕机了,我们就要从其它slave中选取一个出来当master,这个时候就有Sentinel了,Sentinel中的哨兵开始执行职责了

哨兵

哨兵(sentinel) 是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master。

哨兵的作用

  • 监控

监控master和slave,不断的检查master和slave是否正常运行,master存活检测、master与slave运行情况检测

  • 通知(提醒)

当被监控的服务器出现问题时,向其他(哨兵间,客户端)发送通知

  • 自动故障转移

断开master与slave连接,选取一个slave作为master,将其他slave连接新的master,并告知客户端新的服务器地址

  • 注意

哨兵也是一台redis服务器,只是不提供数据相关服务,通常哨兵的数量配置为单数

哨兵配置

  • 设置哨兵监听的主服务器信息, sentinel_number表示参与投票的哨兵数量
1
sentinel monitor master_name  master_host master_port  sentinel_number
  • 设置判定服务器宕机时长,该设置控制是否进行主从切换
1
sentinel down-after-milliseconds master_name million_seconds
  • 设置故障切换的最大超时时长
1
sentinel failover-timeout master_name million_seconds
  • 设置主从切换后,同时进行数据同步的slave数量,数值越大,要求网络资源越高,数值越小,同步时间越长
1
sentinel parallel-syncs master_name sync_slave_number

「sentinel.conf」

1
2
3
4
5
6
7
8
port 26379
daemonize yes
pidfile "/var/run/redis-sentinel26379.pid"
logfile "/export/server/sentinel-26379/log/log.log"
dir "/export/server/sentinel- 26379/data"
sentinel monitor mymaster 0.0.0.0 6379 2
sentinel resolve-hostnames no
sentinel announce-hostnames no

「配置命令」

  • 主服务
1
./bin/redis-server redis.conf
  • sentinel监听
1
./bin/redis-server redis.conf slaveof 主ip 主端口

java原生连接sentinel

  • pom.xml
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
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.dream.xiaobo</groupId>
<artifactId>redis_operation</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<!-- <verbal>true</verbal>-->
</configuration>
</plugin>
</plugins>
</build>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

</project>
  • test
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
public class RedisSentinelTest {

private JedisSentinelPool jedisSentinelPool;

@BeforeTest
public void beforeTest(){

// 配置对象
JedisPoolConfig config = new JedisPoolConfig();

// 最大空闲连接
config.setMaxIdle(10);
// 最小空闲连接
config.setMinIdle(5);

// 连接时最大等待时间
config.setMaxWaitMillis(3000);

// 最大连接数
config.setMaxTotal(100);


Set<String> sentinel = new HashSet<>();

sentinel.add("152.136.22.223:26379");
sentinel.add("152.136.22.223:26380");
sentinel.add("152.136.22.223:26381");


jedisSentinelPool = new JedisSentinelPool("mymaster",sentinel,config);

}



@Test
public void keysTest(){
Jedis jedis = jedisSentinelPool.getResource();

Set<String> keys = jedis.keys("*");

for (String key : keys) {
System.out.println(key);
}


}




@AfterTest
public void afterTest(){
jedisSentinelPool.close();
}


}

spring连接sentinel

  • application.yml
1
2
3
4
5
spring:
redis:
sentinel:
nodes: 0.0.0.0:26379,0.0.0.0::26380,0.0.0.0::26381
master: mymaster
  • test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@SpringBootTest
class RedisBootOperationApplicationTests {

@Autowired
private RedisTemplate redisTemplate;

@Test
void contextLoads() {

redisTemplate.opsForValue().set("name","xiaobo");

Object name = redisTemplate.opsForValue().get("name");

System.out.println(name);

redisTemplate.boundValueOps("age").set(22);

Object age = redisTemplate.boundValueOps("age").get();

System.out.println(age);

}

}

Redis集群 Cluster

集群就是使用网络将若干台计算机联通起来,并提供统一的管理方式,使其对外呈现单机的服务效果

集群的作用

  • 分散单台服务器的访问压力,实现负载均衡
  • 分散单台服务器的存储压力,实现可扩展性
  • 降低单台服务器宕机带来的业务灾难

集群搭建

  • 配置服务器(3主3从)
  • 建立通信(Meet)
  • 分槽(Slot)
  • 搭建主从(master-slave)

「最少3主」

搭建步骤

  • 创建6台redis服务
  • 修改配置文件
1
2
3
4
5
6
7
8
9
10
11
port 7001
bind 0.0.0.0
protected-mode no
daemonize yes
pidfile /var/run/redis_7001.pid
logfile "/export/server/redis-7001/log/redis.log"
dir /export/server/redis-7001/data/
appendonly yes
cluster-enabled yes
cluster-config-file nodes-7001.conf
cluster-node-timeout 15000
  • 使6台机器集群
1
redis-cli --cluster create 0.0.0.0:7001 0.0.0.0:7002 0.0.0.0:7003 0.0.0.0:7004 0.0.0.0:7005 0.0.0.0:7006 --cluster-replicas 1
  • 每台机器分槽
1
./bin/redis-cli --cluster fix 0.0.0.0:端口号

输入 yes

  • 连接cluster
1
./bin/redis-cli -c -h 0.0.0.0 -p 端口号

cluster集群配置

  • 是否启用cluster,加入cluster节点
1
cluster-enabled yes|no
  • cluster配置文件名,该文件属于自动生成,仅用于快速查找文件并查询文件内容
1
cluster-config-file filename
  • 节点服务响应超时时间,用于判定该节点是否下线或切换为从节点
1
cluster-node-timeout milliseconds
  • master连接的slave最小数量
1
cluster-migration-barrier min_slave_number

Cluster节点操作命令

  • 查看集群节点信息
1
cluster nodes
  • 更改slave指向新的master
1
cluster replicate master-id
  • 发现一个新节点,新增master
1
cluster meet ip:port
  • 忽略一个没有solt的节点
1
cluster forget server_id
  • 手动故障转移
1
cluster failover

集群操作命令

  • 创建集群
1
redis-cli –-cluster create masterhost1:masterport1 masterhost2:masterport2  masterhost3:masterport3 [masterhostn:masterportn …] slavehost1:slaveport1  slavehost2:slaveport2 slavehost3:slaveport3 -–cluster-replicas n
  • 添加master到当前集群中,连接时可以指定任意现有节点地址与端口
1
redis-cli --cluster add-node new-master-host:new-master-port now-host:now-port
  • 添加slave
1
redis-cli --cluster add-node new-slave-host:new-slave-port master-host:master-port --cluster-slave --cluster-master-id masterid
  • 删除节点,如果删除的节点是master,必须保障其中没有槽slot
1
redis-cli --cluster del-node del-slave-host:del-slave-port del-slave-id
  • 重新分槽,分槽是从具有槽的master中划分一部分给其他master,过程中不创建新的槽
1
redis-cli --cluster reshard new-master-host:new-master:port --cluster-from src-  master-id1, src-master-id2, src-master-idn --cluster-to target-master-id --  cluster-slots slots
  • 重新分配槽,从具有槽的master中分配指定数量的槽到另一个master中,常用于清空指定master中的槽
1
redis-cli --cluster reshard src-master-host:src-master-port --cluster-from src-  master-id --cluster-to target-master-id --cluster-slots slots --cluster-yes

java原生连接Cluster

  • test
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
public class RedisClusterTest {

private JedisCluster jedisCluster;

@BeforeTest
public void beforeTest(){

JedisPoolConfig config = new JedisPoolConfig();

// 最大空闲连接
config.setMaxIdle(10);
// 最小空闲连接
config.setMinIdle(5);

// 连接时最大等待时间
config.setMaxWaitMillis(3000);

// 最大连接数
config.setMaxTotal(100);

Set<HostAndPort> nodes = new HashSet<>();

nodes.add(new HostAndPort("152.136.22.223",7001));
nodes.add(new HostAndPort("152.136.22.223",7002));
nodes.add(new HostAndPort("152.136.22.223",7003));
nodes.add(new HostAndPort("152.136.22.223",7004));
nodes.add(new HostAndPort("152.136.22.223",7005));
nodes.add(new HostAndPort("152.136.22.223",7006));

jedisCluster = new JedisCluster(nodes,config);

}



@Test
public void test(){

jedisCluster.set("name","xiaobo");

String a = jedisCluster.get("a");

System.out.println(a);

}

@AfterTest
public void afterTest(){
try {
jedisCluster.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}


}

springboot连接Cluster

  • application.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
spring:
redis:
pool:
max-idle: 100
min-idle: 1
max-active: 1000
max-wait: -1
cluster:
nodes:
- 0.0.0.0:7001
- 0.0.0.0:7002
- 0.0.0.0:7003
- 0.0.0.0:7004
- 0.0.0.0:7005
- 0.0.0.0:7006
database: 0
timeout: 15000
connect-timeout: 5000
  • test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@SpringBootTest
class RedisBootOperationApplicationTests {

@Autowired
private RedisTemplate redisTemplate;

@Test
void contextLoads() {

redisTemplate.opsForValue().set("name","xiaobo");

Object name = redisTemplate.opsForValue().get("name");

System.out.println(name);

redisTemplate.boundValueOps("age").set(22);

Object age = redisTemplate.boundValueOps("age").get();

System.out.println(age);

}

}

「你知道的越多 你不知道的越多 嘿 我是小博 带你一起看我目之所及的世界……」

-------------本文结束 感谢您的阅读-------------

本文标题:redis 进阶二

文章作者:小博

发布时间:2022年08月12日 - 22:09

最后更新:2022年08月12日 - 22:17

原始链接:https://codexiaobo.github.io/posts/4249312075/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。