Spring Boot配置Redis Sentinel的例子

原文地址:https://chanjarster.github.io...node

本文介紹Spring Boot鏈接Redis Sentinel的例子。git

本文關聯的源碼:githubgithub

基本信息

拓撲(M表明redis-master,S表明redis-sentinel,R表明redis-slave,C表明Spring Boot Application):redis

+---------------------------+
     |                           |
  +-----+       +-----+       +-----+
  |  M  |-------|  S  |-------|  R  |
  +-----+       +-----+       +-----+
     |             |
     |          +-----+
     +----------|  C  |
                +-----+

application.yaml配置:spring

spring:
  redis:
#    host: redis-master
#    port: 6379
    password: abc
    sentinel:
      master: springboot
      nodes:
        - redis-sentinel:26379

注意這裏不須要配置master的host和port,這些信息會從Redis Sentinel中獲得。docker

演示步驟

打包並構建鏡像:mvn clean install dockerfile:buildspringboot

進入docker目錄,執行docker-compose up -dbash

觀察Spring Boot Application的日誌:docker logs -f docker_spring-boot_1,會發現每隔3秒執行INCR fooapp

07:53:49.205  INFO  hello.Application                    : INCR foo: 1
07:53:52.212  INFO  hello.Application                    : INCR foo: 2
07:53:55.213  INFO  hello.Application                    : INCR foo: 3
07:53:58.216  INFO  hello.Application                    : INCR foo: 4
07:54:01.217  INFO  hello.Application                    : INCR foo: 5

中止redis-master:docker stop docker_redis-master_1,會看到Spring Boot Application的Redis連接出現了問題:spring-boot

07:54:37.206  INFO  hello.Application                    : INCR foo: 17
07:54:40.204  INFO  hello.Application                    : INCR foo: 18
07:54:42.238  INFO  i.l.core.protocol.ConnectionWatchdog : Reconnecting, last destination was /10.0.19.4:6379
07:54:52.247  WARN  i.l.core.protocol.ConnectionWatchdog : Cannot reconnect: io.netty.channel.ConnectTimeoutException: connection timed out: /10.0.19.4:6379
...
07:55:22.560  INFO  i.l.core.protocol.ConnectionWatchdog : Reconnecting, last destination was 10.0.19.4:6379
07:55:22.842  WARN  i.l.core.protocol.ConnectionWatchdog : Cannot reconnect: io.netty.channel.AbstractChannel$AnnotatedNoRouteToHostException: Host is unreachable: /10.0.19.4:6379
...
07:55:29.582  INFO i.l.core.protocol.ConnectionWatchdog  : Reconnecting, last destination was 10.0.19.4:6379
07:55:32.353  WARN i.l.core.protocol.ConnectionWatchdog  : Cannot reconnect: io.netty.channel.AbstractChannel$AnnotatedNoRouteToHostException: Host is unreachable: /10.0.19.4:6379
...

等待大約60秒,Redis Sentinel介入,將redis-slave提拔爲master,連接恢復:

07:55:43.860  INFO i.l.core.protocol.ConnectionWatchdog  : Reconnecting, last destination was 10.0.19.4:6379
07:55:43.882  INFO i.l.core.protocol.ReconnectionHandler : Reconnected to 10.0.19.6:6379
07:55:43.887  INFO hello.Application                     : INCR foo: 20
07:55:43.889  INFO hello.Application                     : INCR foo: 21
07:55:43.891  INFO hello.Application                     : INCR foo: 22
07:55:43.892  INFO hello.Application                     : INCR foo: 23

此時拓撲變成這樣:

+-------------//------------+
     |                           |
  +-----+       +-----+       +-----+
  |  M  |--//---|  S  |-------| [M] |
  +-----+       +-----+       +-----+
     |             |             |
     |          +-----+          |
     +----//----|  C  |----------+
                +-----+

清理容器:docker-compose down

Master重啓以後的問題

這個問題和Spring Boot沒有關係,是Redis自己的。若是咱們把前面停掉的master重啓,sentinel是不會感知到這個master的,由於這個master的ip變了(見這個comment):

你能夠觀察重啓之之後的master的INFO:

$ docker exec docker_redis-master_1 redis-cli -a abc INFO replication
# Replication
role:master
...

能夠看到它啓動以後仍是master,不是slave。這樣的話就等於出現了兩個master,這就出問題了。

BTW,redis的配置中可使用hostname,好比slaveof redis-master。可是redis-sentinel,使用的是ip,即便你配置的是hostname,最終也是ip。執行下面命令能夠看見sentinel的配置:

$ docker exec docker_redis-sentinel_1 cat /bitnami/redis-sentinel/conf/sentinel.conf | grep springboot

sentinel monitor springboot 10.0.25.2 6379 1
sentinel down-after-milliseconds springboot 60000
sentinel auth-pass springboot abc
sentinel config-epoch springboot 0
sentinel leader-epoch springboot 0
sentinel known-slave springboot 10.0.25.5 6379

解決辦法1:使用host network

使用host network來部署redis-master、redis-slave,使用<host-ip>:<container-port>來訪問它們,由於host的ip是比較固定的,能夠緩解這個問題。

用host network則還有一個限制:不能在同一個host上啓動兩個相同container-port的容器。

解決辦法2:publish端口

把redis-master、redis-slave的端口publish到host上,redis.config中把slave-announce-ipslave-announce-port設置爲host-ip和host-port,最後使用<host-ip>:<host-port>訪問,一樣也是利用host的ip固定特性來解決這個問題。

相關文章
相關標籤/搜索