redis哨兵配置总结

本文内容涵盖

  1. windows下单机部署redis多实例(docker、linux下的配置也可参考本文)
  2. redis主从配置
  3. redis哨兵配置

以spring boot redis demo下一个存action,一个取action为例进行演示。

本文只讲配置,不讲原理(原理随便都是,配置完整完善且简洁的少)

redis 命令介绍

  1. 启动实例 D:\Redis-6379> redis-server.exe redis.windows.conf
  2. 指定进入哪个redis实例,redis的默认客户端是redis-cli, D:\Redis-6379> redis-cli -h 192.168.154.128 -p 6379 # 默认为localhost:6379
  3. 显示某个redis实例信息,先用redis-cli进入到redis实例,192.168.154.128:6379 > info replication
  4. 设置主从关系。 只需要操作从库,无需操作主库。1. redis-cli 2. 192.168.154.128:6379 > slaveof 172.17.0.3 6379 # 192.168.154.128:6379就变成172.17.0.3 6379 的从库了
  5. 取消主从关系。操作从库,slaveof no one
  6. 启动哨兵进程 D:\Redis-6379> redis-server.exe sentinel.conf --sentinel

准备材料

Redis-x64-3.0.504.zip

1. windows下单机部署redis多实例

解压后拷贝三份

redis主从配置

分别设置 redis.windows.conf, 这里以79为主库,80,81位从库

修改配置项:

79:
port 6379

80:
port 6380
slaveof 127.0.0.1 6379 # 表示此库作为127.0.0.1 6379的从库

81:
port 6381
slaveof 127.0.0.1 6379

此时主从的配置已经完成。

依次启动三个实例

  1. D:\Redis-6379>redis-server.exe redis.windows.conf
  2. D:\Redis-6380>redis-server.exe redis.windows.conf
  3. D:\Redis-6381>redis-server.exe redis.windows.conf

再启动一个redis-cli

D:\Redis-6379>redis-cli.exe -h 127.0.0.1 -p 6379

查看当前实例信息,可以看到,有两个slave。connected_slaves:2

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=133629,lag=1
slave1:ip=127.0.0.1,port=6381,state=online,offset=133895,lag=0
master_repl_offset:133895
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:133894

再来测试下主从,发个请求往79里塞值,看80,81是否能同步数据。(主库读写,从库只读)

这里的程序demo不做展开,网上找下很多。

pom.xml

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

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

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

properties:

# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
# localhost master:6379  slaves: 6380 6381
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
#连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=5000
/**
 * RedisSerializer redisSerializer =new StringRedisSerializer();
 * 因为redisTemplate默认会序列化key,我们查看的时候,key就是序列化后的key,不方便查看.
 * 所以我们先序列化一把key,redisTemplate再序列化一把。当然存取的序列化要一致,不然匹配不到key
 */
@Service
public class RedisService {
    @Resource
    private RedisTemplate<String,Object> redisTemplate;

    public void set(String key, Object value) {
        //更改在redis里面查看key编码问题
        RedisSerializer redisSerializer =new StringRedisSerializer();
        redisTemplate.setKeySerializer(redisSerializer);

        ValueOperations<String,Object> vo = redisTemplate.opsForValue();
        vo.set(key, value);

    }

    public Object get(String key) {
        RedisSerializer redisSerializer =new StringRedisSerializer();
        redisTemplate.setKeySerializer(redisSerializer); 

        ValueOperations<String,Object> vo = redisTemplate.opsForValue();
        return vo.get(key); 
    }

}
@RestController
public class CityController {

    @Autowired
    private RedisService redisService;

    //http://localhost:8888/saveCity?cityName=北京&cityIntroduce=中国首都&cityId=1
    @GetMapping(value = "saveCity")
    public String saveCity(int cityId, String cityName, String cityIntroduce) {
        City city = new City(cityId, cityName, cityIntroduce);
        redisService.set(cityId + "", city);
        return "success";
    }

    //http://localhost:8888/getCityById?cityId=1
    @GetMapping(value = "getCityById")
    public City getCity(String cityId) {
        City city = (City) redisService.get(cityId + "");
        return city;
    }
}

如上配置完spring boot demo for redis 后

  1. 塞值 http://localhost:8888/saveCity?cityName=%E5%8C%97%E4%BA%AC&cityIntroduce=%E4%B8%AD%E5%9B%BD%E9%A6%96%E9%83%BD&cityId=1

  2. 用redis-cli(如果你有别的redis客户端也一样)分别进到三个实例中进行数据获取:

可以看到三个实例数据已经同步。

主从测试通过。

redis哨兵配置

  1. 三个实例目录下分别新建sentinel.conf, 端口为26379,26380,26381,其他一致
port 26379
sentinel monitor mymaster 127.0.0.1 6379 2
daemonize yes

(哨兵就是个独立的进程,用来监听实例信息的变化,且对相关操作做出反应,这里对每个实例都配一个哨兵进程)

  1. 启动三个哨兵进程

  2. D:\Redis-6379>redis-server.exe sentinel.conf --sentinel
  3. D:\Redis-6380>redis-server.exe sentinel.conf --sentinel
  4. D:\Redis-6381>redis-server.exe sentinel.conf --sentinel

至此,哨兵配置且启动完成。

测试,停掉主库79的进程,这里就是在79实例的cmd(非哨兵cmd)下ctrl+c

观察另外两个实例在cmd中输出的日志

81的日志

简单分析下日志

  1. 老大下线了
  2. 疯狂的发送心跳进行询问(老大,你死了没?没回答,就应该是死了,哨兵进程辅助slave(s)建立新的老大)
  3. 自己成为老大 MASTER MODE enabled
  4. 其他小弟进行数据请求
  5. 新的主从建立
[15112] 09 Sep 14:57:23.699 # Connection with master lost.
[15112] 09 Sep 14:57:23.700 * Caching the disconnected master state.
[15112] 09 Sep 14:57:24.420 * Connecting to MASTER 127.0.0.1:6379
[15112] 09 Sep 14:57:24.420 * MASTER <-> SLAVE sync started
[15112] 09 Sep 14:57:25.421 * Non blocking connect for SYNC fired the event.
[15112] 09 Sep 14:57:25.421 # Sending command to master in replication handshake: -Writing to master: Unknown error
[15112] 09 Sep 14:57:25.423 * Connecting to MASTER 127.0.0.1:6379
[15112] 09 Sep 14:57:25.423 * MASTER <-> SLAVE sync started
[15112] 09 Sep 14:57:26.424 * Non blocking connect for SYNC fired the event.
[15112] 09 Sep 14:57:26.424 # Sending command to master in replication handshake: -Writing to master: Unknown error
[15112] 09 Sep 14:57:26.426 * Connecting to MASTER 127.0.0.1:6379
[15112] 09 Sep 14:57:26.426 * MASTER <-> SLAVE sync started
[15112] 09 Sep 14:57:27.427 * Non blocking connect for SYNC fired the event.
[15112] 09 Sep 14:57:27.427 # Sending command to master in replication handshake: -Writing to master: Unknown error
。。。。。。。。。。。。。。。。。。。。
[15112] 09 Sep 14:57:53.517 * Connecting to MASTER 127.0.0.1:6379
[15112] 09 Sep 14:57:53.517 * MASTER <-> SLAVE sync started
[15112] 09 Sep 14:57:54.006 * Discarding previously cached master state.
[15112] 09 Sep 14:57:54.007 * MASTER MODE enabled (user request from 'id=8 addr=127.0.0.1:51668 fd=14 name=sentinel-efc4be2b-cmd age=70 idle=0 flags=x db=0 sub=0 psub=0 multi=3 qbuf=0 qbuf-free=32768 obl=36 oll=0 omem=0 events=rw cmd=exec')
[15112] 09 Sep 14:57:54.009 # CONFIG REWRITE executed with success.
[15112] 09 Sep 14:57:54.855 * Slave 127.0.0.1:6380 asks for synchronization
[15112] 09 Sep 14:57:54.855 * Full resync requested by slave 127.0.0.1:6380
[15112] 09 Sep 14:57:54.856 * Starting BGSAVE for SYNC with target: disk
[15112] 09 Sep 14:57:54.863 * Background saving started by pid 15712
[15112] 09 Sep 14:57:55.125 # fork operation complete
[15112] 09 Sep 14:57:55.126 * Background saving terminated with success
[15112] 09 Sep 14:57:55.129 * Synchronization with slave 127.0.0.1:6380 succeeded

观察哨兵cmd也会有相关的日志输出,这里就不展开了。

现在我们要确定哨兵进程是否帮我们建立新的master节点了。

redis-cli进入到81中

info replication

127.0.0.1:6381> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=17573,lag=1
master_repl_offset:17839
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:17838

role从slave变成了master

哨兵测试通过。

最后剩下spring boot中进行相关的设置。

properties新增

# name of Redis server  哨兵监听的Redis server的名称
spring.redis.sentinel.master=mymaster
# comma-separated list of host:port pairs  哨兵的配置列表
spring.redis.sentinel.nodes=127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381
package com.myredis.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;

import java.lang.reflect.Method;


@Configuration
@EnableCaching//开启缓存
public class RedisConfig extends CachingConfigurerSupport {

    @Value("${spring.redis.sentinel.nodes}")
    private String redisNodes;

    @Value("${spring.redis.sentinel.master}")
    private String master;

    /**
     * 自定义生成redis-key
     *
     * @return
     */
    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }
    @Bean
    public RedisSentinelConfiguration redisSentinelConfiguration(){
        RedisSentinelConfiguration configuration = new RedisSentinelConfiguration();
        String[] host = redisNodes.split(",");
        for(String redisHost : host){
            String[] item = redisHost.split(":");
            String ip = item[0];
            String port = item[1];
            configuration.addSentinel(new RedisNode(ip, Integer.parseInt(port)));
        }
        configuration.setMaster(master);
        return configuration;
    }  
}

程序起来后,kill掉某个主库或从库,看数据是否依然能读取。

that's all!!!

猜你喜欢

转载自www.cnblogs.com/joeymary/p/11492791.html