SpringBoot2.0 整合 Redis集群 ,實現消息隊列場景

来源:https://www.cnblogs.com/cicada-smile/archive/2019/07/05/11136098.html
-Advertisement-
Play Games

一、Redis集群簡介 1、RedisCluster概念 Redis的分散式解決方案,在3.0版本後推出的方案,有效地解決了Redis分散式的需求,當一個服務宕機可以快速的切換到另外一個服務。redis cluster主要是針對海量數據+高併發+高可用的場景。 二、與SpringBoot2.0整合 ...


本文源碼
GitHub地址:知了一笑
https://github.com/cicadasmile/middle-ware-parent

一、Redis集群簡介

1、RedisCluster概念

Redis的分散式解決方案,在3.0版本後推出的方案,有效地解決了Redis分散式的需求,當一個服務宕機可以快速的切換到另外一個服務。redis cluster主要是針對海量數據+高併發+高可用的場景。

二、與SpringBoot2.0整合

1、核心依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>${spring-boot.version}</version>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>${redis-client.version}</version>
</dependency>

2、核心配置

spring:
  # Redis 集群
  redis:
    sentinel:
      # sentinel 配置
      master: mymaster
      nodes: 192.168.0.127:26379
      maxTotal: 60
      minIdle: 10
      maxWaitMillis: 10000
      testWhileIdle: true
      testOnBorrow: true
      testOnReturn: false
      timeBetweenEvictionRunsMillis: 10000

3、參數渲染類

@ConfigurationProperties(prefix = "spring.redis.sentinel")
public class RedisParam {
    private String nodes ;
    private String master ;
    private Integer maxTotal ;
    private Integer minIdle ;
    private Integer maxWaitMillis ;
    private Integer timeBetweenEvictionRunsMillis ;
    private boolean testWhileIdle ;
    private boolean testOnBorrow ;
    private boolean testOnReturn ;
    // 省略GET和SET方法
}

4、集群配置文件

@Configuration
@EnableConfigurationProperties(RedisParam.class)
public class RedisPool {
    @Resource
    private RedisParam redisParam ;
    @Bean("jedisSentinelPool")
    public JedisSentinelPool getRedisPool (){
        Set<String> sentinels = new HashSet<>();
        sentinels.addAll(Arrays.asList(redisParam.getNodes().split(",")));
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setMaxTotal(redisParam.getMaxTotal());
        poolConfig.setMinIdle(redisParam.getMinIdle());
        poolConfig.setMaxWaitMillis(redisParam.getMaxWaitMillis());
        poolConfig.setTestWhileIdle(redisParam.isTestWhileIdle());
        poolConfig.setTestOnBorrow(redisParam.isTestOnBorrow());
        poolConfig.setTestOnReturn(redisParam.isTestOnReturn());
        poolConfig.setTimeBetweenEvictionRunsMillis(redisParam.getTimeBetweenEvictionRunsMillis());
        JedisSentinelPool redisPool = new JedisSentinelPool(redisParam.getMaster(), sentinels, poolConfig);
        return redisPool;
    }
    @Bean
    SpringUtil springUtil() {
        return new SpringUtil();
    }
    @Bean
    RedisListener redisListener() {
        return new RedisListener();
    }
}

5、配置Redis模板類

@Configuration
public class RedisConfig {
    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        stringRedisTemplate.setConnectionFactory(factory);
        return stringRedisTemplate;
    }
}

三、模擬隊列場景案例

生產者消費者模式:客戶端監聽消息隊列,消息達到,消費者馬上消費,如果消息隊列裡面沒有消息,那麼消費者就繼續監聽。基於Redis的LPUSH(BLPUSH)把消息入隊,用 RPOP(BRPOP)獲取消息的模式。

1、加鎖解鎖工具

@Component
public class RedisLock {
    private static String keyPrefix = "RedisLock:";
    @Resource
    private JedisSentinelPool jedisSentinelPool;
    public boolean addLock(String key, long expire) {
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            /*
             * nxxx的值只能取NX或者XX,如果取NX,則只有當key不存在是才進行set,如果取XX,則只有當key已經存在時才進行set
             * expx的值只能取EX或者PX,代表數據過期時間的單位,EX代表秒,PX代表毫秒。
             */
            String value = jedis.set(keyPrefix + key, "1", "nx", "ex", expire);
            return value != null;
        } catch (Exception e){
            e.printStackTrace();
        }finally {
            if (jedis != null) jedis.close();
        }
        return false;
    }
    public void removeLock(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            jedis.del(keyPrefix + key);
        } finally {
            if (jedis != null) jedis.close();
        }
    }
}

2、消息消費

1)封裝介面

public interface RedisHandler  {
    /**
     * 隊列名稱
     */
    String queueName();

    /**
     * 隊列消息內容
     */
    String consume (String msgBody);
}

2)介面實現

@Component
public class LogAListen implements RedisHandler {
    private static final Logger LOG = LoggerFactory.getLogger(LogAListen.class) ;
    @Resource
    private RedisLock redisLock;
    @Override
    public String queueName() {
        return "LogA-key";
    }
    @Override
    public String consume(String msgBody) {
        // 加鎖,防止消息重覆投遞
        String lockKey = "lock-order-uuid-A";
        boolean lock = false;
        try {
            lock = redisLock.addLock(lockKey, 60);
            if (!lock) {
                return "success";
            }
            LOG.info("LogA-key == >>" + msgBody);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (lock) {
                redisLock.removeLock(lockKey);
            }
        }
        return "success";
    }
}

3、消息監聽器

public class RedisListener implements InitializingBean {
    /**
     * Redis 集群
     */
    @Resource
    private JedisSentinelPool jedisSentinelPool;
    private List<RedisHandler> handlers = null;
    private ExecutorService product = null;
    private ExecutorService consumer = null;
    /**
     * 初始化配置
     */
    @Override
    public void afterPropertiesSet() {
        handlers = SpringUtil.getBeans(RedisHandler.class) ;
        product = new ThreadPoolExecutor(10,15,60 * 3,
                TimeUnit.SECONDS,new SynchronousQueue<>());
        consumer = new ThreadPoolExecutor(10,15,60 * 3,
                TimeUnit.SECONDS,new SynchronousQueue<>());
        for (RedisHandler redisHandler : handlers){
            product.execute(() -> {
                redisTask(redisHandler);
            });
        }
    }
    /**
     * 隊列監聽
     */
    public void redisTask (RedisHandler redisHandler){
        Jedis jedis = null ;
        while (true){
            try {
                jedis = jedisSentinelPool.getResource() ;
                List<String> msgBodyList = jedis.brpop(0, redisHandler.queueName());
                if (msgBodyList != null && msgBodyList.size()>0){
                    consumer.execute(() -> {
                        redisHandler.consume(msgBodyList.get(1)) ;
                    });
                }
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                if (jedis != null) jedis.close();
            }
        }
    }
}

4、消息生產者

@Service
public class RedisServiceImpl implements RedisService {
    @Resource
    private JedisSentinelPool jedisSentinelPool;
    @Override
    public void saveQueue(String queueKey, String msgBody) {
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            jedis.lpush(queueKey,msgBody) ;
        } catch (Exception e){
          e.printStackTrace();
        } finally {
            if (jedis != null) jedis.close();
        }
    }
}

5、場景測試介面

@RestController
public class RedisController {
    @Resource
    private RedisService redisService ;
    /**
     * 隊列推消息
     */
    @RequestMapping("/saveQueue")
    public String saveQueue (){
        MsgBody msgBody = new MsgBody() ;
        msgBody.setName("LogAModel");
        msgBody.setDesc("描述");
        msgBody.setCreateTime(new Date());
        redisService.saveQueue("LogA-key", JSONObject.toJSONString(msgBody));
        return "success" ;
    }
}

四、源代碼地址

GitHub地址:知了一笑
https://github.com/cicadasmile/middle-ware-parent
碼雲地址:知了一笑
https://gitee.com/cicadasmile/middle-ware-parent



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 如果第二次看到我的文章,歡迎右側掃碼訂閱我喲~ 👉 每周五早8點 按時送達。當然了,也會時不時加個餐~ 在一個分散式系統的開發團隊中,有一些問題是很容易產生程式員之間矛盾的。 其中之一就是「業務歸屬」,就是當新加/修改一個業務的時候,代碼變更應該放到你負責的系統還是我負責的系統里? 一些業務輪廓很 ...
  • SpringCloud系列教程 | 第五篇:熔斷監控Hystrix Dashboard和Turbine Springboot: 2.1.6.RELEASE SpringCloud: Greenwich.SR1 如無特殊說明,本系列教程全採用以上版本 Hystrix dashboard是一款針對Hys ...
  • 郵箱核心業務場景: 發郵件 收郵件 查看郵件 郵箱業務我們關註的核心信息 草稿箱 收件箱 已發送郵件 未讀郵件 重要郵件 垃圾郵件 已刪除郵件 核心領域模型文字版 共三個模型,如下: 草稿郵件(DraftMail,聚合根): ID 標題 內容 所屬Owner郵箱地址 創建時間 支持場景:創建郵件(但 ...
  • 一個類如何表示 1. 第一格為類名 2. 第二格為類中欄位屬性 格式: 許可權:private、public 、protected、default,它們分別對應 、+、 、~ 3. 第三格為類的方法 格式: 返回類型可選 類之間的關係 多看幾次上圖,對比如下簡短說明,再結合實踐,相信你很快就可以搞清楚 ...
  • Web Service技術在我第一次接觸,又沒有實際使用時完全不理解這是什麼。以為是一種類似Spring,Shiro的編程框架。後來漸漸理解,WS(即Web Service縮寫)是一種通用的介面規範,並按照該規範編寫介面對外提供服務。 ...
  • 一、簡介 在使用mybatis時我們需要重覆的去創建pojo類、mapper文件以及dao類並且需要配置它們之間的依賴關係,比較麻煩且做了大量的重覆工作,mybatis官方也發現了這個問題, 因此給我們提供了mybatis generator工具來幫我們自動創建pojo類、mapper文件以及dao ...
  • 1. 為什麼是Spring Cloud Gateway 一句話,Spring Cloud已經放棄Netflix Zuul了。現在Spring Cloud中引用的還是Zuul 1.x版本,而這個版本是基於過濾器的,是阻塞IO,不支持長連接。Zuul 2.x版本跟1.x的架構大一樣,性能也有所提升。既然 ...
  • ​ 1.python的歷史 python2和python3的區別 python2 源碼不統一,重覆代碼 python 源碼統一,沒有重覆代碼 2004 Django框架的誕生 2.python是編程語言 3.python的種類 4.變數 變數定義的規則: 一個變數名在記憶體中只有一個。 5.常量 變數 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...