推薦閱讀:阿里二面涼經:虛擬機+MySQL+中間件+設計模式+緩存+Spring+併發等難題,全部迎刃而解
前言
之前給大家推薦的幾款延遲任務處理隊列,對於一些要求比較高的場景是無法運用於生產環境的,一旦機器宕機或者應用重啓會導致隊列消息丟失,從而造成無法挽回的損失。今天給大家分享一款高可用延遲隊列 Redisson
。
簡介
Redisson
在基於 NIO
的 Netty
框架上,充分利用了 Redis
鍵值數據庫提供的一系列優勢,在 Java
實用工具包中常用接口的基礎上,爲使用者提供了一系列具有分佈式特性的常用工具類。使得原本作爲協調單機多線程併發程序的工具包獲得了協調分佈式多機多線程併發系統的能力,大大降低了設計和研發大規模分佈式系統的難度。同時結合各富特色的分佈式服務,更進一步簡化了分佈式環境中程序相互之間的協作。
代碼案例
框架支持多種 redis
集成部署方式,包括單節點,主從模式,集羣模式,哨兵模式等等。
項目pom.xml
引入:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.12.1</version>
</dependency>
定義紅包信息實體類,必須實現序列並定義空構造方法:
/**
* 紅包信息
*/
public class RedPacketMessage implements Serializable {
/**
* 紅包 ID
*/
private long redPacketId;
/**
* 創建時間戳
*/
private long timestamp;
public RedPacketMessage() {
}
public RedPacketMessage(long redPacketId) {
this.redPacketId = redPacketId;
this.timestamp = System.currentTimeMillis();
}
public long getRedPacketId() {
return redPacketId;
}
public long getTimestamp() {
return timestamp;
}
}
代碼案例:
/**
* 紅包過期失效 高可用延遲隊列
*/
public class RedPacketDelayQueue {
private static final Logger LOGGER = LoggerFactory.getLogger(RedPacketDelayQueue.class);
public static void main(String[] args) throws Exception {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379").setPassword("123456").setDatabase(2);
RedissonClient redissonClient = Redisson.create(config);
/**
* 紅包目標隊列
*/
RBlockingQueue<RedPacketMessage> blockingRedPacketQueue
= redissonClient.getBlockingQueue("redPacketDelayQueue");
/**
* 定時任務將到期的元素轉移到目標隊列
*/
RDelayedQueue<RedPacketMessage> delayedRedPacketQueue
= redissonClient.getDelayedQueue(blockingRedPacketQueue);
/**
* 延時信息入隊列
*/
delayedRedPacketQueue.offer(new RedPacketMessage(20200113), 3, TimeUnit.SECONDS);
delayedRedPacketQueue.offer(new RedPacketMessage(20200114), 5, TimeUnit.SECONDS);
delayedRedPacketQueue.offer(new RedPacketMessage(20200115), 10, TimeUnit.SECONDS);
while (true){
/**
* 取出失效紅包
*/
RedPacketMessage redPacket = blockingRedPacketQueue.take();
LOGGER.info("紅包ID:{}過期失效",redPacket.getRedPacketId());
/**
* 處理相關業務邏輯:記錄相關信息並退還剩餘紅包金額
*/
}
}
}
高可用
主從部署方式:
/**
* 主從部署方式
*/
Config config = new Config();
config.useMasterSlaveServers()
//設置redis主節點
.setMasterAddress("redis://192.168.1.120:6379")
//設置redis從節點
.addSlaveAddress("redis://192.168.1.130:6379", "redis://192.168.1.140:6379");
RedissonClient redisson = Redisson.create(config);
集羣部署方式:
/**
* 集羣部署方式
* cluster方式至少6個節點
* 3主3從,3主做sharding,3從用來保證主宕機後可以高可用
*/
Config config = new Config();
config.useClusterServers()
.setScanInterval(2000)//集羣狀態掃描間隔時間,單位是毫秒
.addNodeAddress("redis://192.168.1.120:6379")
.addNodeAddress("redis://192.168.1.130:6379")
.addNodeAddress("redis://192.168.1.140:6379")
.addNodeAddress("redis://192.168.1.150:6379")
.addNodeAddress("redis://192.168.1.160:6379")
.addNodeAddress("redis://192.168.1.170:6379");
RedissonClient redissonClient = Redisson.create(config);
哨兵部署方式:
/**
* 哨兵部署方式
* sentinel是採用 Paxos拜占庭協議,一般sentinel至少3個節點
*/
Config config = new Config();
config.useSentinelServers()
.setMasterName("my-sentinel-name")
.addSentinelAddress("redis://192.168.1.120:6379")
.addSentinelAddress("redis://192.168.1.130:6379")
.addSentinelAddress("redis://192.168.1.140:6379");
RedissonClient redisson = Redisson.create(config);
雲託管部署方式:
/**
* 雲託管部署方式
* 這種方式主要解決redis提供商爲雲服務的提供商的redis連接
* 比如亞馬遜雲、微軟雲
*/
config.useReplicatedServers()
//主節點變化掃描間隔時間
.setScanInterval(2000)
.addNodeAddress("redis://192.168.1.120:6379")
.addNodeAddress("redis://192.168.1.130:6379")
.addNodeAddress("redis://192.168.1.140:6379");
RedissonClient redisson = Redisson.create(config);
小結
無論是JDK
內置的延遲隊列還是基於時間輪算法的隊列,都無法保證生產系統的高可用性,而Redisson
很好的解決了這個問題。
源碼
https://gitee.com/52itstyle/spring-boot-seckill