dockercompose部署redis哨兵模式并集成springboot

news2024/11/17 0:03:44

第一步 编写compose文件

docker-compose.yml

version: '3.8'

networks:
  redis-network:
    driver: bridge

services:
  redis-master:
    image: redis:7.2.4
    container_name: redis-master
    command: ["sh", "-c", "redis-server --protected-mode no --slave-announce-ip 192.168.0.5 --slave-announce-port 6379 --requirepass 123456"]
    ports:
      - "6379:6379"
    networks:
      - redis-network

  redis-slave1:
    image: redis:7.2.4
    container_name: redis-slave1
    ports:
      - "6380:6379"
    depends_on:
      - redis-master
    command: ["sh", "-c", "redis-server --slaveof redis-master 6379 --masterauth 123456 --requirepass 123456 --protected-mode no --slave-announce-ip 192.168.0.5 --slave-announce-port 6380"]
    networks:
      - redis-network

  redis-slave2:
    image: redis:7.2.4
    container_name: redis-slave2
    ports:
      - "6381:6379"
    depends_on:
      - redis-master
    command: ["sh", "-c", "redis-server --slaveof redis-master 6379 --masterauth 123456 --requirepass 123456 --protected-mode no --slave-announce-ip 192.168.0.5 --slave-announce-port 6381"]
    networks:
      - redis-network

  redis-sentinel1:
    image: redis:7.2.4
    container_name: redis-sentinel1
    depends_on:
      - redis-master
      - redis-slave1
      - redis-slave2
    command: >
      sh -c "mkdir -p /usr/local/etc/redis &&
             echo 'port 26379' > /usr/local/etc/redis/sentinel.conf &&
             echo 'protected-mode no' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel auth-pass mymaster 123456' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel announce-ip 192.168.0.5' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel announce-port 26379' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel monitor mymaster 192.168.0.5 6379 2' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel down-after-milliseconds mymaster 5000' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel failover-timeout mymaster 10000' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel parallel-syncs mymaster 1' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel resolve-hostnames yes' >> /usr/local/etc/redis/sentinel.conf &&
             redis-sentinel /usr/local/etc/redis/sentinel.conf"
    ports:
      - "26379:26379"
    networks:
      - redis-network

  redis-sentinel2:
    image: redis:7.2.4
    container_name: redis-sentinel2
    depends_on:
      - redis-master
      - redis-slave1
      - redis-slave2
    command: >
      sh -c "mkdir -p /usr/local/etc/redis &&
             echo 'port 26379' > /usr/local/etc/redis/sentinel.conf &&
             echo 'protected-mode no' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel auth-pass mymaster 123456' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel announce-ip 192.168.0.5' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel announce-port 26380' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel monitor mymaster 192.168.0.5 6379 2' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel down-after-milliseconds mymaster 5000' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel failover-timeout mymaster 10000' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel parallel-syncs mymaster 1' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel resolve-hostnames yes' >> /usr/local/etc/redis/sentinel.conf &&
             redis-sentinel /usr/local/etc/redis/sentinel.conf"
    ports:
      - "26380:26379"
    networks:
      - redis-network

  redis-sentinel3:
    image: redis:7.2.4
    container_name: redis-sentinel3
    depends_on:
      - redis-master
      - redis-slave1
      - redis-slave2
    command: >
      sh -c "mkdir -p /usr/local/etc/redis &&
             echo 'port 26379' > /usr/local/etc/redis/sentinel.conf &&
             echo 'protected-mode no' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel auth-pass mymaster 123456' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel announce-ip 192.168.0.5' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel announce-port 26381' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel monitor mymaster 192.168.0.5 6379 2' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel down-after-milliseconds mymaster 5000' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel failover-timeout mymaster 10000' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel parallel-syncs mymaster 1' >> /usr/local/etc/redis/sentinel.conf &&
             echo 'sentinel resolve-hostnames yes' >> /usr/local/etc/redis/sentinel.conf &&
             redis-sentinel /usr/local/etc/redis/sentinel.conf"
    ports:
      - "26381:26379"
    networks:
      - redis-network

到对应目录下面执行 docker-compose up -d命令

注意事项:

1、--slave-announce-ip 设置的是主机的IP,一定要设置,不然springboot无法访问到redis服务(主从都要设置)

2、--slave-announce-port 设置的是映射到主机的端口,也需要设置(主从都要设置)

3、--requirepass  redis的密码,也需要设置,不然springboot会报错redis不安全(主从都要设置)

4、--masterauth 从redis连接主redis的密码认证,必不可少(从redis都要设置)

5、sentinel announce-ip和sentinel announce-port 设置的是哨兵暴露出去的IP和端口(所有哨兵都要设置)

6、sentinel monitor mymaster 192.168.0.5 6379 2  这里得填主redis的外部ip,也就是主redis设置的slave-announce-ip参数

7、如果遇到sentinel.conf权限不够的需要设置权限 chmod 777  sentinel.conf(之前用其他方式的时候遇到过)

8、如果需要挂载文件的,需要自己根据这个yml做适当调整

第二步 验证

去主redis命令行执行

redis-cli -a 123456 info

查看从redis是否都已连接上

查看sentinel哨兵是否正常:

执行 redis-cli -p 26379

info sentinel

一切正常!(再不正常我就该疯了......踩了无数坑)

第三步 springboot集成

1、添加依赖

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.25.2</version>
        </dependency>
<dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>

2、yml配置文件

server:
  port: 8084
spring:
  redisson:
    #  单机模式
    host: 192.168.0.5
    port: 6379
    # 哨兵模式
    sentinel:
      master: mymaster
      nodes: 192.168.0.5:26379,192.168.0.5:26380,192.168.0.5:26381
    # 集群模式
    cluster: 192.168.0.5:6379,192.168.0.5:6380,192.168.0.5:6381
    # 密码
    password: 123456

ip地址请换成自己的主机ip

3、config配置

package com.example.demo.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.redisson.config.Config;
import org.redisson.config.ReadMode;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Slf4j
@Configuration
public class RedissonConfig {
    @Value("${spring.redisson.sentinel.nodes}")
    private  String sentinel;
    @Value("${spring.redisson.sentinel.master}")
    private String masterName;

    @Value("${spring.redisson.cluster}")
    private  String cluster;

    @Value("${spring.redisson.host}")
    private String host;

    @Value("${spring.redisson.port}")
    private  String port;

    @Value("${spring.redisson.password}")
    private String password;




    private int timeout = 2000;
    private int scanInterval = 60000;
    private static String ADDRESS_PREFIX = "redis://";

    /**
     * 单机模式
     */
    @Bean
    public RedissonClient initBean() {
        // 哨兵模式
        if (StringUtils.isNotBlank(sentinel)) {
            log.info("redis is sentinel mode");
            return redissonSentinel();
        }
        // 集群模式
        if (StringUtils.isNotBlank(cluster)) {
            log.info("redis is cluster mode");
            return redissonCluster();
        }
        // 单机模式
        if (StringUtils.isNotBlank(host)) {
            log.info("redis is single mode");
            return redissonSingle();
        }

        log.error("redisson config can not support this redis mode");
        return null;
    }

    /**
     * 单机模式
     */
    private RedissonClient redissonSingle() {
        Config config = new Config();
        String address = ADDRESS_PREFIX+host+":"+port;
        //设置
        config.setCodec(new StringCodec())
                //这是用的集群server
                .useSingleServer()
                .setAddress(address)
                .setTimeout(timeout)
                .setPassword(password);
        return Redisson.create(config);
    }


    /**
     * 哨兵模式
     */
    private RedissonClient redissonSentinel() {

        String[] nodes = sentinel.split(",");
        //redisson版本是3.5,集群的ip前面要加上“redis://”,不然会报错,3.2版本可不加
        for(int i=0;i<nodes.length;i++){
            nodes[i] = ADDRESS_PREFIX+nodes[i];
        }
        Config config = new Config();
        //设置
        config.setCodec(new StringCodec())
                .useSentinelServers()
                .setMasterName(masterName)
                .setPassword(password)
                .setTimeout(timeout)
                .addSentinelAddress(nodes)
                // 在Redisson启动期间启用sentinels列表检查,默认为true,这里我们设置为false,不检查
                .setCheckSentinelsList(false);
        return Redisson.create(config);
    }

    /**
     * 集群模式
     */
    private RedissonClient redissonCluster() {
        String[] nodes = cluster.split(",");
        //redisson版本是3.5,集群的ip前面要加上“redis://”,不然会报错,3.2版本可不加
        for(int i=0;i<nodes.length;i++){
            nodes[i] = ADDRESS_PREFIX+nodes[i];
        }
        Config config = new Config();
        //设置
        config.setCodec(new StringCodec())
                //这是用的集群server
                .useClusterServers()
                //设置集群状态扫描时间
                .setScanInterval(scanInterval)
                .addNodeAddress(nodes)
                .setPassword(password)
                .setReadMode(ReadMode.MASTER);;
        return Redisson.create(config);
    }

}

4、测试

package com.example.demo.service;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;


@Service
@Slf4j
public class RedissonTestService {


    @Resource
    private RedissonClient redissonClient;

    //锁过期时间
    private static final Long LOCK_KEY_TIME = 120L;

    public void doTest() {
        //定时任务执行周期较短,为防止数据重复修改,加入锁
        RLock lock = redissonClient.getLock("test");
        // 尝试获取锁并设定锁的过期时间
        boolean acquired = false;
        try {
            //获取锁
            acquired = lock.tryLock(0, LOCK_KEY_TIME, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            log.error("取锁失败");
        }
        if (acquired) {
            try {
                // 执行业务逻辑
                Thread.sleep(10000);

            }catch (Exception e) {
                log.error("处理失败");
                //业务异常处理逻辑

            }finally {
                // 释放锁
                lock.unlock();
            }

        } else {
            // 获取锁失败,说明有其他线程或进程正在处理数据
            // 可以进行重试或触发告警机制

        }
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1857585.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WSL安装的Ubuntu与docker desktop集成

WSL安装的Ubuntu与docker desktop集成 最近因为项目需要&#xff0c;要在本地利用WSL搭建一个docker和Ubuntu的部署环境。一开始并不知道docker desktop与Ubuntu可以集成使用&#xff0c;所以在Ubuntu上独立安装了docker引擎&#xff0c;但在安装docker-compose的时候出现以下…

av1支持的CU划分

av1只有4叉划分支持递归划分 只有四叉允许递归划分&#xff0c;其余划分只划分到本层。最大编码单元也扩展到128x128&#xff0c;最小编码单元4x4。

“流处理引擎” RisingWave 的三种经典交互方式

作为流数据库&#xff0c;RisingWave 在大数据生态中通常扮演着流处理引擎的角色。它从各种数据源读取数据&#xff0c;并将其写入不同的目的地。在此过程中&#xff0c;RisingWave 清洗、转换和聚合数据&#xff0c;最终得出计算的结果。 RisingWave 为用户提供了丰富的交互和…

flask-socket的实践

1.长连接和短连接的由来 1&#xff09;TCP在真正的读写操作之前&#xff0c;server与client之间必须建立一个连接&#xff0c; 当读写操作完成后&#xff0c;双方不再需要这个连接时它们可以释放这个连接&#xff0c; 连接的建立通过三次握手&#xff0c;释放则需要四次握手…

哪种无线麦克风比较好?一文读懂什么品牌的无线麦克风比较好!

​在这个信息爆炸的时代&#xff0c;网络直播和短视频成为了人们获取信息、娱乐和社交的重要方式。作为自媒体人&#xff0c;拥有一款优秀的领夹式无线麦克风是必不可少的。它不仅能够帮助你在各种环境中保持清晰的声音&#xff0c;还能提升你的作品质量和专业度。然而&#xf…

中霖教育:二级建造师报名后缺考有影响吗?

在完成二级建造师的报名程序后&#xff0c;考生无法进行退考。如果是不参加考试&#xff0c;可以选择弃考。弃考对个人并没有负面影响&#xff0c;缺席考试的话也不会被记录在个人诚信档案中。当然&#xff0c;如果弃考的话此次考试的成绩将被记为0&#xff0c;下一年参加考试按…

极验行为式验证码适配Harmony 鸿蒙SDK下载

现阶段&#xff0c;越来越多的开发者正在积极加入鸿蒙生态系统。随着更多开发者的参与&#xff0c;早在去年9月&#xff0c;极验就成为首批拥有鸿蒙NEXT内测版本和手机系统测试机会的验证码供应商。 为了提高各开发者及企业客户集成鸿蒙版本行为验4.0的效率&#xff0c;方便大家…

CodeFuse 开源官网上线啦~

Hello ! 这里是 CodeFuse ~ CodeFuse 的使命是开发专门设计用于支持整个软件开发生命周期的大型代码语言模型&#xff08;Code LLMs&#xff09;&#xff0c;涵盖设计、需求、编码、测试、部署、运维等关键阶段。我们致力于打造创新的解决方案&#xff0c;让软件开发者们在研发…

web开发学习(web简单入门)

前言&#xff1a; 从我刚接触博客没多久我就萌发了搭建一个个人博客网站的想法&#xff08;用来装逼&#xff09;&#xff0c;但碍于学校屁事太多迟迟没有开始&#xff0c;最近学校课已经都差不多结课了&#xff0c;距离期末还有一段时间&#xff0c;我也得以抽出时间来学习我一…

设计模式原则——迪米特法则原则

设计模式原则 设计模式示例代码库地址&#xff1a; https://gitee.com/Jasonpupil/designPatterns 迪米特法则原则&#xff1a; 意义在于降低类之间的耦合。由于每个对象尽量减少对于其他对象的了解&#xff0c;因此&#xff0c;很容易使得系统的功能模块功能独立&#xff…

【产品经理】订单处理8-智能分仓

在电商ERP系统中&#xff0c;通常智能分仓策略是系统中最重要的功能之一&#xff0c;大公司若仓库较多时&#xff0c;智能分仓策略中也会加入大数据团队&#xff0c;通过算法来计算最优仓库。 本次讲解的智能分仓适用于中小公司&#xff0c;适合拥有2个以上10个以下仓库的公司…

『FPGA通信接口』LVDS接口(2)硬件设计

文章目录 1.LVDS原理2.xilinx器件对于LVDS的支持3.LVDS信号PCB布线要求4.传送门 1.LVDS原理 如上图所LVDS的工作原理示意图&#xff0c;其Driver驱动器由一个恒流源是LVDS发送端&#xff08;通常为 3.5mA&#xff09;驱动一对差分信号线组成。驱动状态会翻转就产生正负电压的变…

【分布式事务】分布式事务理论

CAP 理论 一致性&#xff08;Consistency&#xff09; 分布式系统中所有数据备份&#xff0c;在同一时刻是否是同样的值 可用性&#xff08;Availability&#xff09; 集群中一部分节点故障后&#xff0c;集群整体是否还能响应客户端的读写请求 分区容错性&#xff08;Partit…

【机器学习 复习】第5章 朴素贝叶斯分类器

一、概念 1.贝叶斯定理&#xff1a; &#xff08;1&#xff09;就是“某个特征”属于“某种东西”的概率&#xff0c;公式就是最下面那个公式。 2.朴素贝叶斯算法概述 &#xff08;1&#xff09;是为数不多的基于概率论的分类算法&#xff0c;即通过考虑特征概率来预测分类。 …

数字化转型中的数据资产价值发现之旅:通过深度挖掘与分析,释放数据资产的巨大潜力,为企业开拓更多商业机会,引领业务创新与发展

一、引言 随着信息技术的飞速发展&#xff0c;数字化转型已成为企业不可逆转的趋势。在这一转型过程中&#xff0c;数据资产作为核心驱动力&#xff0c;正逐渐展现出其巨大的商业价值。然而&#xff0c;如何有效挖掘和利用这些数据资产&#xff0c;将其转化为实际的生产力和创…

高位图像的增强处理 DR图像等

输入16位图像 经过增强算法处理后的输出&#xff1a;

vscode使用内置插件断点调试vue2项目

1、首先项目中要开启source-map 在vue.config.js 文件中 module.exports {configureWebpack: {devtool: process.env.NODE_ENV ! "production" ? "source-map" : ,} }2、项目根目录新建.vscode/launch.js文件 {"configurations": [{"ty…

五、在Qt下加载QVTKWidget控件(VTK8.2.0),生成Visual Studio项目,显示点云(C++)

前言&#xff1a;因为项目需要通过Qt进行显示点云&#xff0c;参考了很多博文&#xff0c;但是并没有全部正确的&#xff0c;东拼西凑算是实现了&#xff0c;花费了两天时间&#xff0c;时间有点久&#xff0c;能力还有有待提升~~ 为此写篇博文记录一下。感谢各位大佬&#xff…

Windows C++ 应用软件开发从入门到精通详解

目录 1、引言 2、IDE 开发环境介绍 2.1、Visual Studio 2.2、Qt Creator 3、 C语言特性 3.1、熟悉泛型编程 3.2、了解C/C异常处理 3.3、熟练使用STL容器 3.4、熟悉C11新特性 4、Windows 平台的编程技术与调试技能 4.1、需要掌握的若干编程技术和基础知识 4.2、需…

java文件处理

重命名文件-旧file.renameTo&#xff08;新file&#xff09; import java.io.File; /*** 文件重命名-ffmpeg合并文件时不允许覆盖原文件&#xff0c;所以合并时&#xff0c;修改源文件名&#xff0c;合并后文件名为源文件名** param fileName* return*/public String RenameFi…