怎么使用docker搭建redis主从哨兵模式,并整合进springboot项目

这篇文章主要介绍“怎么使用docker搭建redis主从哨兵模式,并整合进springboot项目”,在日常操作中,相信很多人在怎么使用docker搭建redis主从哨兵模式,并整合进springboot项目问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么使用docker搭建redis主从哨兵模式,并整合进springboot项目”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

其实上一篇的思路做法是百度后参考各种博客文章搭的,但是发现最后还是有问题后,就直接去官网看文档了,于是在之前的熟悉的基础的下,重新搭了一遍,在基于容器网络的情况下,实现主备来回自动切换功能。

1,先上redis主备编排文件,master-slave/docker-compose.yml

version: "3"
services:
  master:
    image: redis:latest
    container_name: redis-master
    command: redis-server /usr/local/etc/redis/redis.conf
    ports:
    - "6379:6379"
    volumes:
    - "/root/redis/redis-master.conf:/usr/local/etc/redis/redis.conf"
    networks:
    - sentinel-master
  slave1:
    image: redis:latest
    container_name: redis-slave-1
    command: redis-server /usr/local/etc/redis/redis.conf
    depends_on:
    - master
    ports:
    - "6380:6379"
    volumes:
    - "/root/redis/redis-slave-1.conf:/usr/local/etc/redis/redis.conf"
    networks:
    - sentinel-master
  slave2:
    image: redis:latest
    container_name: redis-slave-2
    command: redis-server /usr/local/etc/redis/redis.conf
    depends_on:
    - master
    ports:
    - "6381:6379"
    volumes:
    - "/root/redis/redis-slave-2.conf:/usr/local/etc/redis/redis.conf"
    networks:
    - sentinel-master
networks:
  sentinel-master:

这里还是使用配置文件,加多了两个配置项,用于宣布ip和端口给哨兵,防止哨兵取容器内网ip

redis-master.conf

port 6379
requirepass 123456

#  防止重启后,作为从节点加入集群时认证失败
masterauth 123456

# 宣布给哨兵的ip,如不配置,哨兵会取容器内部ip,这样客户端就无法访问了
slave-announce-ip 192.168.1.254

# 宣布给哨兵的端口
slave-announce-port 6379

redis-slave-1.conf

port 6379
requirepass 123456

slaveof 192.168.1.254 6379
masterauth 123456
slave-announce-ip 192.168.1.254
slave-announce-port 6380

redis-slave-2.conf

port 6379
requirepass 123456

slaveof 192.168.1.254 6379
masterauth 123456
slave-announce-ip 192.168.1.254
slave-announce-port 6381

2,哨兵编排文件,sentinel/docker-compose.yml

# Example sentinel.conf can be downloaded from http://download.redis.io/redis-stable/sentinel.conf
version: "3"
services:
  sentinel1:
    image: redis:latest
    container_name: redis-sentinel-1
    command: redis-sentinel /usr/local/etc/redis/sentinel.conf
    ports:
    - "26379:26379"
    volumes:
    - "/root/redis/sentinel1.conf:/usr/local/etc/redis/sentinel.conf"
  sentinel2:
    image: redis:latest
    container_name: redis-sentinel-2
    command: redis-sentinel /usr/local/etc/redis/sentinel.conf
    ports:
    - "26380:26379"
    volumes:
    - "/root/redis/sentinel2.conf:/usr/local/etc/redis/sentinel.conf"
  sentinel3:
    image: redis:latest
    container_name: redis-sentinel-3
    command: redis-sentinel /usr/local/etc/redis/sentinel.conf
    ports:
    - "26381:26379"
    volumes:
    - "/root/redis/sentinel3.conf:/usr/local/etc/redis/sentinel.conf"
networks:
  default:
    external:
      name: "master-slave_sentinel-master"

sentinel1.conf,sentinel2.conf, sentinel3.conf 初始的内容完全一样,只是会在哨兵启动重写会变得不一样,这个是由哨兵自动完成的

port 26379
dir /tmp
sentinel monitor mymaster 192.168.1.254 6379 2
sentinel auth-pass mymaster 123456
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 10000
sentinel deny-scripts-reconfig yes

3,springboot整合,及测试程序还是一样

引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

application.yml

spring:
  redis:
    sentinel:
      master: mymaster
      nodes:
      - "192.168.1.254:26379"
      - "192.168.1.254:26380"
      - "192.168.1.254:26381"
    host: 192.168.1.254
    password: 123456
    jedis:
      pool:
        min-idle: 8
        max-active: 100
        max-wait: 3000
        max-idle: 100

测试程序,3个线程模拟并发插入数据,一共3000条

@Test
public void testRedisMasterSlave() throws Exception {
	ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
	ExecutorService es = Executors.newFixedThreadPool(3);
	for (int j = 0; j < 3; j++) {
		es.submit(() -> {
			for (int i = 0; i < 1000; i++) {
				try {
					String threadName = Thread.currentThread().getName();
					valueOperations.set(threadName + i, i + "", 30L, TimeUnit.MINUTES);
					TimeUnit.MILLISECONDS.sleep(200L);
				} catch (InterruptedException e) {
					System.out.println("error: " + e.getMessage());
				}
			}
		});
	}
	es.shutdown();
	es.awaitTermination(30L, TimeUnit.MINUTES);
}

准备完成,分别启动redis( master-slave/docker-compose.yml),哨兵(sentinel/docker-compose.yml)

执行junit测试程序,并在中途停掉redis-master节点

2019-10-06 21:50:24.199  INFO 128256 --- [pool-1-thread-1] io.lettuce.core.EpollProvider            : Starting without optional epoll library
2019-10-06 21:50:24.201  INFO 128256 --- [pool-1-thread-1] io.lettuce.core.KqueueProvider           : Starting without optional kqueue library
2019-10-06 21:51:11.141  INFO 128256 --- [xecutorLoop-1-6] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was /192.168.1.254:6379
2019-10-06 21:51:13.161  WARN 128256 --- [ioEventLoop-4-4] i.l.core.protocol.ConnectionWatchdog     : Cannot reconnect: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /192.168.1.254:6379
2019-10-06 21:51:17.440  INFO 128256 --- [xecutorLoop-1-7] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was 192.168.1.254:6379
2019-10-06 21:51:19.450  WARN 128256 --- [ioEventLoop-4-2] i.l.core.protocol.ConnectionWatchdog     : Cannot reconnect: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /192.168.1.254:6379
2019-10-06 21:51:23.741  INFO 128256 --- [xecutorLoop-1-8] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was 192.168.1.254:6379
2019-10-06 21:51:25.748  WARN 128256 --- [ioEventLoop-4-8] i.l.core.protocol.ConnectionWatchdog     : Cannot reconnect: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /192.168.1.254:6379
2019-10-06 21:51:30.840  INFO 128256 --- [xecutorLoop-1-3] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was 192.168.1.254:6379
2019-10-06 21:51:32.848  WARN 128256 --- [ioEventLoop-4-6] i.l.core.protocol.ConnectionWatchdog     : Cannot reconnect: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /192.168.1.254:6379
2019-10-06 21:51:38.041  INFO 128256 --- [xecutorLoop-1-7] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was 192.168.1.254:6379
2019-10-06 21:51:40.050  WARN 128256 --- [ioEventLoop-4-2] i.l.core.protocol.ConnectionWatchdog     : Cannot reconnect: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /192.168.1.254:6379
2019-10-06 21:51:44.241  INFO 128256 --- [xecutorLoop-1-2] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was 192.168.1.254:6379
2019-10-06 21:51:44.248  INFO 128256 --- [ioEventLoop-4-4] i.l.core.protocol.ReconnectionHandler    : Reconnected to 192.168.1.254:6380

控制台打印的消息由6379端口,切换到了6380端口,证明哨兵已经完成主备切换了。

接下来再把redis-master节点重新启动,查看容器启动日志

2019-10-05T19:05:51.594625998Z 1:S 05 Oct 2019 19:05:51.594 * Before turning into a replica, using my master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer.
2019-10-05T19:05:51.594679191Z 1:S 05 Oct 2019 19:05:51.594 * REPLICAOF 192.168.1.254:6380 enabled (user request from 'id=4 addr=172.23.0.1:43460 fd=9 name=sentinel-36a0e6b8-cmd age=10 idle=0 flags=x db=0 sub=0 psub=0 multi=3 qbuf=153 qbuf-free=32615 obl=36 oll=0 omem=0 events=r cmd=exec')
2019-10-05T19:05:51.594683850Z 1:S 05 Oct 2019 19:05:51.594 # CONFIG REWRITE failed: Permission denied
2019-10-05T19:05:51.961959923Z 1:S 05 Oct 2019 19:05:51.961 * Connecting to MASTER 192.168.1.254:6380
2019-10-05T19:05:51.961989715Z 1:S 05 Oct 2019 19:05:51.961 * MASTER <-> REPLICA sync started
2019-10-05T19:05:51.961995348Z 1:S 05 Oct 2019 19:05:51.961 * Non blocking connect for SYNC fired the event.
2019-10-05T19:05:51.962964412Z 1:S 05 Oct 2019 19:05:51.962 * Master replied to PING, replication can continue...
2019-10-05T19:05:51.963959151Z 1:S 05 Oct 2019 19:05:51.963 * Trying a partial resynchronization (request d0c6a5694d17b9337656d0ef009aa580e0743431:1).
2019-10-05T19:05:51.967159605Z 1:S 05 Oct 2019 19:05:51.966 * Full resync from master: bfcd3bb8bbfb2393ded951443e9e2100ed490548:133911
2019-10-05T19:05:51.967200123Z 1:S 05 Oct 2019 19:05:51.966 * Discarding previously cached master state.
2019-10-05T19:05:52.064097244Z 1:S 05 Oct 2019 19:05:52.062 * MASTER <-> REPLICA sync: receiving 51791 bytes from master
2019-10-05T19:05:52.064114578Z 1:S 05 Oct 2019 19:05:52.062 * MASTER <-> REPLICA sync: Flushing old data
2019-10-05T19:05:52.064124761Z 1:S 05 Oct 2019 19:05:52.062 * MASTER <-> REPLICA sync: Loading DB in memory
2019-10-05T19:05:52.064128120Z 1:S 05 Oct 2019 19:05:52.063 * MASTER <-> REPLICA sync: Finished with success

发现节点已经主动找到当前master节点192.168.1.254:6380,并进行全量复制了。

再进入哨兵节点查看slave节点信息

127.0.0.1:26379> sentinel slaves mymaster
1)  1) "name"
    2) "192.168.1.254:6379"
    3) "ip"
    4) "192.168.1.254"
    5) "port"
    6) "6379"
    7) "runid"
    8) "d4d7ce3f1cc4d5c6cca2345318e4dcfebe12fcce"
    9) "flags"
   10) "slave"
   11) "link-pending-commands"
   12) "0"
   13) "link-refcount"
   14) "1"
   15) "last-ping-sent"
   16) "0"
   17) "last-ok-ping-reply"
   18) "872"
   19) "last-ping-reply"
   20) "872"
   21) "down-after-milliseconds"
   22) "30000"
   23) "info-refresh"
   24) "2519"
   25) "role-reported"
   26) "slave"
   27) "role-reported-time"
   28) "5867007"
   29) "master-link-down-time"
   30) "0"
   31) "master-link-status"
   32) "ok"
   33) "master-host"
   34) "192.168.1.254"
   35) "master-port"
   36) "6380"
   37) "slave-priority"
   38) "100"
   39) "slave-repl-offset"
   40) "1526467"
2)  1) "name"
    2) "192.168.1.254:6381"
    3) "ip"
    4) "192.168.1.254"
    5) "port"
    6) "6381"
    7) "runid"
    8) "2fecd472915d77b55d230c339f5982491ee55d69"
    9) "flags"
   10) "slave"
   11) "link-pending-commands"
   12) "0"
   13) "link-refcount"
   14) "1"
   15) "last-ping-sent"
   16) "0"
   17) "last-ok-ping-reply"
   18) "872"
   19) "last-ping-reply"
   20) "872"
   21) "down-after-milliseconds"
   22) "30000"
   23) "info-refresh"
   24) "6520"
   25) "role-reported"
   26) "slave"
   27) "role-reported-time"
   28) "5940478"
   29) "master-link-down-time"
   30) "0"
   31) "master-link-status"
   32) "ok"
   33) "master-host"
   34) "192.168.1.254"
   35) "master-port"
   36) "6380"
   37) "slave-priority"
   38) "100"
   39) "slave-repl-offset"
   40) "1525639"

发现6379节点也已经加入到slave节点了,到此哨兵模式高可用方案就算完成了。

到此,关于“怎么使用docker搭建redis主从哨兵模式,并整合进springboot项目”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!