redis主从、redis哨兵、redis集群配置搭建和使用

redis主从、redis哨兵、redis集群配置搭建和使用

redis主从

redis主从是基于redis复制上来使用和配置的,从服务器(slave)可以精确的复制主服务器(master)的内容。当主服务发生宕机之后,那么需要主服务器重启,恢复数据,需要消耗一定的时候,如果做了主从,可以直接切到从服务器。

三个主要机制
  • 当一个 master 实例和一个 slave 实例连接正常时, master 会发送一连串的命令流来保持对 slave 的更新,以便于将自身数据集的改变复制给 slave , :包括客户端的写入、key 的过期或被逐出等等。
  • 当 master 和 slave 之间的连接断开之后,因为网络问题、或者是主从意识到连接超时, slave 重新连接上 master 并会尝试进行部分重同步:这意味着它会尝试只获取在断开连接期间内丢失的命令流。
  • 当无法进行部分重同步时, slave 会请求进行全量重同步。这会涉及到一个更复杂的过程,例如 master 需要创建所有数据的快照,将之发送给 slave ,之后在数据集更改时持续发送命令流到 slave 。
redis复制特性
  • slave和master之间是异步来确认数据同步
  • 一个master可以有多个slave,在4.0之后slave下也可以有slave
  • slave默认是只可读
复制过程

每一个 Redis master 都有一个 replication ID :这是一个较大的伪随机字符串,标记了一个给定的数据集。每个 master 也持有一个偏移量,master 将自己产生的复制流发送给 slave 时,发送多少个字节的数据,自身的偏移量就会增加多少,目的是当有新的操作修改自己的数据集时,它可以以此更新 slave 的状态。复制偏移量即使在没有一个 slave 连接到 master 时,也会自增,所以基本上每一对给定的

Replication ID, offset

都会标识一个 master 数据集的确切版本。

当 slave 连接到 master 时,它们使用 PSYNC 命令来发送它们记录的旧的 master replication ID 和它们至今为止处理的偏移量。通过这种方式, master 能够仅发送 slave 所需的增量部分。但是如果 master 的缓冲区中没有足够的命令积压缓冲记录,或者如果 slave 引用了不再知道的历史记录(replication ID),则会转而进行一个全量重同步:在这种情况下, slave 会得到一个完整的数据集副本,从头开始。

搭建主从服务

首先复制两份配置

cp /opt/redis-5.0.5/redis.conf /opt/redis-5.0.5/copy/master.conf
cp /opt/redis-5.0.5/redis.conf /opt/redis-5.0.5/copy/slave.conf

修改一下服务配置信息

#master.conf
port 6379
#修改slave.conf
port 6380
slaveof 127.0.0.1 6379

启动服务

redis-cli ./copy/master.conf
redis-cli ./copy/slave.conf

查看主从节点的信息

#主服务
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=21826,lag=1
master_replid:682b6cb7a4b93f72725c97c1f06096e602936048
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:21826
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:21826
#从服务
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:4
master_sync_in_progress:0
slave_repl_offset:21742
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:682b6cb7a4b93f72725c97c1f06096e602936048
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:21742
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:21742

redis哨兵

哨兵介绍

顾名思义,哨兵的作用就是用来监控redis系统运行状况。主要有以下两个功能

  • 用来监控redis主服务和从服务是否正常运行
  • 当主服务发生宕机的时候,自动将从服务升级为主服务

其实哨兵在主从的的服务上减少了一部分运维的工作,如果只是做主从,当主节点挂了时候,需要手动的切换到从节点,那么使用哨兵来监控主和从节点的运行状态,当主服务挂了的时候,会自动选取一个从节点作为主节点,当宕机的主节点启动的时候变成了从节点。

一个哨兵:

多个哨兵:

哨兵搭建和部署

我这个测试是一主两从,在单机上面创建的

首先复制三份配置信息

cp /opt/redis-5.0.5/redis.conf /opt/redis-5.0.5/sentinel/redis1.conf
cp /opt/redis-5.0.5/redis.conf /opt/redis-5.0.5/sentinel/redis2.conf
cp /opt/redis-5.0.5/redis.conf /opt/redis-5.0.5/sentinel/redis3.conf

cp /opt/redis-5.0.5/sentinel.conf /opt/redis-5.0.5/sentinel/sentinel.conf

修改redis服务信息

#redis1.conf作为主节点不用动
port 6379
#redis2.conf
port 6380
slaveof 127.0.0.1 6379
#redis3.conf
port 6381
slaveof 127.0.0.1 6379

修改哨兵配置信息

port 26379
daemonize yes
sentinel monitor mymaster 127.0.0.1 6379 1
#mymaster 这个是主服务的名称,可以随便命名
#127.0.0.1 6379 主服务的ip和port
#1 选择主节点的时候的投票数,1表示有一个sentinel同意则可以升级为master

启动服务

redis-server ./sentinel/redis1.conf &
redis-server ./sentinel/redis2.conf &
redis-server ./sentinel/redis3.conf &
redis-server ./sentinel/sentinel.conf --sentinel &

查看配置信息

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=128067,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=128067,lag=1
master_replid:92256269552621fa0b87c9c2cadbd0efab672cb2
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:128067
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:128067
测试主从节点切换
模拟主节点宕机
redis-cli -p 6379 shutdown

从命令窗口看到的日志

#启动哨兵,哨兵发现两个新的节点
11357:X 28 Jul 2020 16:47:09.216 # +monitor master mymaster 127.0.0.1 6379 quorum 2
11357:X 28 Jul 2020 16:47:09.216 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
11357:X 28 Jul 2020 16:47:09.219 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379

#哨兵认为主节点挂了
11471:X 28 Jul 2020 16:49:03.528 # +sdown master mymaster 127.0.0.1 6379
#哨兵认为主节点服务停止了
11471:X 28 Jul 2020 16:49:03.528 # +odown master mymaster 127.0.0.1 6379 #quorum 1/1
11471:X 28 Jul 2020 16:49:03.528 # +new-epoch 1
#开始故障恢复
11471:X 28 Jul 2020 16:49:03.528 # +try-failover master mymaster 127.0.0.1 6379
11471:X 28 Jul 2020 16:49:03.531 # +vote-for-leader 497fc511623b8fdd6b63057eeffaa8e918bd835e 1
11471:X 28 Jul 2020 16:49:03.531 # +elected-leader master mymaster 127.0.0.1 6379
11471:X 28 Jul 2020 16:49:03.531 # +failover-state-select-slave master mymaster 127.0.0.1 6379
11471:X 28 Jul 2020 16:49:03.603 # +selected-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
11471:X 28 Jul 2020 16:49:03.603 * +failover-state-send-slaveof-noone slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
11471:X 28 Jul 2020 16:49:03.703 * +failover-state-wait-promotion slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
11471:X 28 Jul 2020 16:49:04.257 # +promoted-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
11471:X 28 Jul 2020 16:49:04.257 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6379
11471:X 28 Jul 2020 16:49:04.310 * +slave-reconf-sent slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
11471:X 28 Jul 2020 16:49:05.299 * +slave-reconf-inprog slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
11471:X 28 Jul 2020 16:49:05.299 * +slave-reconf-done slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
#故障恢复完成
11471:X 28 Jul 2020 16:49:05.371 # +failover-end master mymaster 127.0.0.1 6379
#故障迁移,选择127.0.0.1 6381为主节点
11471:X 28 Jul 2020 16:49:05.371 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6381
11471:X 28 Jul 2020 16:49:05.371 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6381
11471:X 28 Jul 2020 16:49:05.371 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381
11471:X 28 Jul 2020 16:49:35.386 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381

查看127.0.0.1 6381信息

127.0.0.1:6381> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=49725,lag=1
master_replid:a7eabb97618a9e8550d436865d639c38fedeedaf
master_replid2:3f2cd991dfcc9641aa852d3876fe7613624504ce
master_repl_offset:49725
second_repl_offset:6100
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:49725

java代码连接

public class RedisTest {

	public static void main(String[] args) throws InterruptedException {
		RedisURI redisURI = RedisURI.builder()
				.withSentinel("139.129.228.249", 26379)
				.withSentinelMasterId("mymaster").build();
		RedisClient redisClient = RedisClient.create(redisURI);
		StatefulRedisConnection<String, String> connect = redisClient.connect();
		for (int i=0;i<30;i++){
			Thread.sleep(2000);
			RedisCommands<String, String> sync =
					connect.sync();
			String list = sync.get("list");
			System.out.println(list);
		}
	}
}

redis集群

集群介绍

Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。

Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误.

Redis 集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令. Redis 集群的优势:

  • 自动分割数据到不同的节点上。
  • 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。

配置redis集群至少配置6个redis节点,为什么需要配置6台,在官方文档当中有写到

Note that the minimal cluster that works as expected requires to contain at least three master nodes.

redis最小的集群需要6个redis节点,三主三从。

集群配置及搭建

因为我这个是在单机上进行测试,所以只需要复制6个redis.conf文件就好了

我这里创建了一个cluster的文件夹分别创建了

cp /opt/redis-5.0.5/redis.conf  /opt/redis-5.0.5/cluster/redis1.conf
cp /opt/redis-5.0.5/redis.conf  /opt/redis-5.0.5/cluster/redis2.conf
cp /opt/redis-5.0.5/redis.conf  /opt/redis-5.0.5/cluster/redis3.conf
cp /opt/redis-5.0.5/redis.conf  /opt/redis-5.0.5/cluster/redis4.conf
cp /opt/redis-5.0.5/redis.conf  /opt/redis-5.0.5/cluster/redis5.conf
cp /opt/redis-5.0.5/redis.conf  /opt/redis-5.0.5/cluster/redis6.conf

如下图所示:

修改每个文件的配置
port 6379 ~6384
cluster-enabled yes
cluster-config-file nodes.conf  这个需要看怎么配置(如果在redis.conf在同一个文件夹下,nodes.conf的文件名称不能一致)  
cluster-node-timeout  
appendonly yesru

如下图所示:

启动每个配置redis节点
redis-server /opt/redis-5.0.5/cluster/redis1.conf &
redis-server /opt/redis-5.0.5/cluster/redis2.conf &
redis-server /opt/redis-5.0.5/cluster/redis3.conf &
redis-server /opt/redis-5.0.5/cluster/redis4.conf &
redis-server /opt/redis-5.0.5/cluster/redis5.conf &
redis-server /opt/redis-5.0.5/cluster/redis6.conf &

创建redis集群

创建redis集群命令如下

redis-cli --cluster create 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 --cluster-replicas 1

创建结果:

[root@iZm5e90lblkm0fx24i4930Z src]# redis-cli --cluster create 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 127.0.0.1:6383 to 127.0.0.1:6379
Adding replica 127.0.0.1:6384 to 127.0.0.1:6380
Adding replica 127.0.0.1:6382 to 127.0.0.1:6381
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 08de62ed947790050e41ec92c78f955345ff1477 127.0.0.1:6379
   slots:[0-5460] (5461 slots) master
M: 6e17d6b6832a6ac4d3cbb3677ab731d119bc9ce8 127.0.0.1:6380
   slots:[5461-10922] (5462 slots) master
M: c33f6ae2025223a04509eebd507e42c515e76b06 127.0.0.1:6381
   slots:[10923-16383] (5461 slots) master
S: b05ec5cbdfcd8f6f9cd193bbb62662955e74ef52 127.0.0.1:6382
   replicates 08de62ed947790050e41ec92c78f955345ff1477
S: 5eb36c9614fa2b63be65e8a09afb0371490548b3 127.0.0.1:6383
   replicates 6e17d6b6832a6ac4d3cbb3677ab731d119bc9ce8
S: e4c47754052c36dccbed4a0f81596138765bf08c 127.0.0.1:6384
   replicates c33f6ae2025223a04509eebd507e42c515e76b06
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
...
>>> Performing Cluster Check (using node 127.0.0.1:6379)
M: 08de62ed947790050e41ec92c78f955345ff1477 127.0.0.1:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: b05ec5cbdfcd8f6f9cd193bbb62662955e74ef52 127.0.0.1:6382
   slots: (0 slots) slave
   replicates 08de62ed947790050e41ec92c78f955345ff1477
S: e4c47754052c36dccbed4a0f81596138765bf08c 127.0.0.1:6384
   slots: (0 slots) slave
   replicates c33f6ae2025223a04509eebd507e42c515e76b06
M: 6e17d6b6832a6ac4d3cbb3677ab731d119bc9ce8 127.0.0.1:6380
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 5eb36c9614fa2b63be65e8a09afb0371490548b3 127.0.0.1:6383
   slots: (0 slots) slave
   replicates 6e17d6b6832a6ac4d3cbb3677ab731d119bc9ce8
M: c33f6ae2025223a04509eebd507e42c515e76b06 127.0.0.1:6381
   slots:[10923-16383] (5461 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.

查询集群信息

随便登录哪一台redis,输入cluster info

127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:10951
cluster_stats_messages_pong_sent:10891
cluster_stats_messages_sent:21842
cluster_stats_messages_ping_received:10886
cluster_stats_messages_pong_received:10951
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:21842

cluster_state:ok; cluster_size:3;cluster_slots_ok:16384

在集群中,每个key存储都是存储在槽中(slot),每个节点负责一部分槽,所以redis集群不支持mget等命令。

集群分片

Redis 集群没有使用一致性hash, 而是引入了 哈希槽的概念.

Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么:

  • 节点 A 包含 0 到 5500号哈希槽.
  • 节点 B 包含5501 到 11000 号哈希槽.
  • 节点 C 包含11001 到 16384号哈希槽.

这种结构很容易添加或者删除节点. 比如如果我想新添加个节点D, 我需要从节点 A, B, C中得部分槽到D上. 如果我想移除节点A,需要将A中的槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可. 由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态.

键哈希标签

计算哈希槽可以实现哈希标签(hash tags),但这有一个例外。哈希标签是确保两个键都在同一个哈希槽里的一种方式。将来也许会使用到哈希标签,例如为了在集群稳定的情况下(没有在做碎片重组操作)允许某些多键操作。

为了实现哈希标签,哈希槽是用另一种不同的方式计算的。基本来说,如果一个键包含一个 “{…}” 这样的模式,只有 { 和 } 之间的字符串会被用来做哈希以获取哈希槽。但是由于可能出现多个 { 或 },计算的算法如下:

  • 如果键包含一个 { 字符。
  • 那么在 { 的右边就会有一个 }。
  • 在 { 和 } 之间会有一个或多个字符,第一个 } 一定是出现在第一个 { 之后。

然后不是直接计算键的哈希,只有在第一个 { 和它右边第一个 } 之间的内容会被用来计算哈希值。

例子:

  • 比如这两个键 {user1000}.following 和 {user1000}.followers 会被哈希到同一个哈希槽里,因为只有 user1000 这个子串会被用来计算哈希值。
  • 对于 foo{}{bar} 这个键,整个键都会被用来计算哈希值,因为第一个出现的 { 和它右边第一个出现的 } 之间没有任何字符。
  • 对于 foozap 这个键,用来计算哈希值的是 {bar 这个子串,因为它是第一个 { 及其右边第一个 } 之间的内容。
  • 对于 foo{bar}{zap} 这个键,用来计算哈希值的是 bar 这个子串,因为算法会在第一次有效或无效(比如中间没有任何字节)地匹配到 { 和 } 的时候停止。
  • 按照这个算法,如果一个键是以 {} 开头的话,那么就当作整个键会被用来计算哈希值。当使用二进制数据做为键名称的时候,这是非常有用的。
集群测试代码
#我这里使用的是lettuce客户端来测试的
public class RedisClusterTest {

	public static void main(String[] args) {
		RedisURI uri = RedisURI.builder().withHost("139.129.228.249").withPort(6380).build();
		RedisClusterClient redisClusterClient = RedisClusterClient.create(uri);
		StatefulRedisClusterConnection<String, String> connection = redisClusterClient.connect();
		RedisAdvancedClusterCommands<String, String> commands = connection.sync();
//  commands.all();  // 所有节点
//  commands.masters();  // 主节点
		// 从节点只读
		NodeSelection<String, String> masters = commands.masters();
		NodeSelectionCommands<String, String> nodeSelectionCommands = masters.commands();
		// 这里只是演示,一般应该禁用keys *命令
		Executions<List<String>> keys = nodeSelectionCommands.keys("*");
		keys.forEach(key -> System.out.println("11"+key));
		connection.close();
		redisClusterClient.shutdown();
	}

总结

从上面描述了redis主从、redis哨兵、redis集群,简单的梳理一下三者之间的区别

redis主从:简单的描述就是一个备份的关系,从服务会精确的备份主服务的数据,当主服务挂了的时候可以直接切到从服务。

redis哨兵:哨兵的作用主要是监控作用,保证了故障的切换,当主服务挂了的时候,哨兵会选举出来从服务成为主服务

redis集群:集群的作用高并发,相对于redis主从、redis哨兵单节点,而集群多个主节点,同时数据也会存在不同的槽中

redis主从备份数据、redis哨兵保证故障的切换、redis集群高可用。具体可以根据业务场景来选择

参考:

猜你喜欢

转载自www.cnblogs.com/JackQiang/p/13394467.html