1. redission
redission 原理
Redis分布式鎖-這一篇全了解(Redission實現(xiàn)分布式鎖完美方案)
2.zk
2.1 指令
ls / / 下有哪些子節(jié)點(diǎn)
get /zookeeper 查看某個子節(jié)點(diǎn)內(nèi)容
create /aa “test”
delete /aa
set /aa “test01”
2.2 創(chuàng)建節(jié)點(diǎn)
模式 默認(rèn)創(chuàng)建永久create -e
創(chuàng)建臨時
create -e /zz “hello zz”create -s
創(chuàng)建 有序節(jié)點(diǎn)create -s -e
臨時序列化節(jié)點(diǎn)
2.3 節(jié)點(diǎn)事件監(jiān)聽
一次性的監(jiān)聽
-
節(jié)點(diǎn)創(chuàng)建 事件監(jiān)聽
NodeCreated
stat -w /xx -
節(jié)點(diǎn) 刪除 監(jiān)聽
NodeDeleted
stat -w -
節(jié)點(diǎn)數(shù)據(jù) 變化 監(jiān)聽
NodeDataChanged
get -w /bb
set /bb “cc” //修改節(jié)點(diǎn)數(shù)據(jù) -
子節(jié)點(diǎn) 監(jiān)聽
NodeChildrenChanged
ls -w /bb
create /bb/cc “test”
2.4 zk 分布式鎖
- 獨(dú)占、排它, 其他線程獲取不到
- 阻塞 解決自旋的消耗
臨時 有序節(jié)點(diǎn)
+ 事件 監(jiān)聽(監(jiān)聽 比他小1的節(jié)點(diǎn)),
讓最小的節(jié)點(diǎn) 獲取到鎖, 44節(jié)點(diǎn)監(jiān)聽43節(jié)點(diǎn),43 節(jié)點(diǎn)刪除后,喚醒后續(xù)44節(jié)點(diǎn) 獲得鎖。公平鎖
3. 鎖的可重入性
思路1: 在節(jié)點(diǎn)的內(nèi)容中記錄 服務(wù)器、線程、已經(jīng)重入信息
思路2 :Threadloacal: 線程的局部變量,線程私有
阻塞操作 獲取不到監(jiān)聽 并阻塞
創(chuàng)建 臨時 有序節(jié)點(diǎn) 返回節(jié)點(diǎn)路徑
// 獲取前置節(jié)點(diǎn) ,如果前置節(jié)點(diǎn)為空,那么獲得鎖成功,否則監(jiān)聽 前置節(jié)點(diǎn)
countdownLatch(1)
在監(jiān)聽事件的內(nèi)部 進(jìn)行一個countDown();
可重入鎖
threadloacal
在 trylock()
unlock 里面 判斷:
2.5 鎖
zk 的節(jié)點(diǎn) 存儲機(jī)制
+通知機(jī)制
zk 有4中節(jié)點(diǎn)類型,持久節(jié)點(diǎn)
,持久順序節(jié)點(diǎn)
、臨時節(jié)點(diǎn)
、臨時順序節(jié)點(diǎn)
持久和臨時 判斷標(biāo)準(zhǔn)依賴于客戶端 的生命周期
順序: 節(jié)點(diǎn)對應(yīng)的id
- 持久節(jié)點(diǎn)
- 持久順序節(jié)點(diǎn)
- 持久的非順序節(jié)點(diǎn)
- 臨時節(jié)點(diǎn)
- 臨時的非順序節(jié)點(diǎn)( 實現(xiàn)分布式鎖的條件)
- 臨時的順序節(jié)點(diǎn)
利用zk 支持的臨時順序節(jié)點(diǎn)
+通知機(jī)制
可以實現(xiàn)分布式鎖
- 加鎖:判斷是否持有了分布式鎖,判斷客戶端 創(chuàng)建的節(jié)點(diǎn)是否是
有序節(jié)點(diǎn)中 序號最小的一個
- 釋放鎖: 將自己的創(chuàng)建的節(jié)點(diǎn) 刪除即可。
3. redission zk 分布式鎖對比
4. 延時任務(wù)
4.0 場景
4.1 定時任務(wù)數(shù)據(jù)庫輪詢
- 定時任務(wù)輪詢數(shù)據(jù)庫,
采用定時任務(wù)失效延遲、對業(yè)務(wù)表進(jìn)行輪詢判斷,到點(diǎn)執(zhí)行。有一點(diǎn)點(diǎn)誤差
。
1) 使用單機(jī)版本的spring schedule +分布式鎖的實現(xiàn)。同一個服務(wù),多個節(jié)點(diǎn) 同時執(zhí)行
可能都會執(zhí)行,需要加分布式鎖
。
- 分布式調(diào)度框架 xxl-job
如果處理數(shù)據(jù)量較大,可以利用分布式調(diào)度系統(tǒng)的分片功能并行處理
,大大提升數(shù)據(jù)的處理能力,加快處理速度。
優(yōu)點(diǎn)
:
單機(jī)版 基于spring,實現(xiàn)簡單。不用引入各種中間件,各個模塊可以自行定義延遲規(guī)則。缺點(diǎn)
2. 完全由業(yè)務(wù)代碼進(jìn)行控制
,重復(fù)代碼多,不論是否有待執(zhí)行的數(shù)據(jù)
,都要空輪詢cpu 且頻繁的訪問數(shù)據(jù)庫 io 消耗
。
3. 由于是定時輪詢,存在一點(diǎn)誤差。
基于@schedule
取消訂單操作
基于xxl-job 的
4.2 Java 的DelayQueue
Java DelayQueue的使用及應(yīng)用場景
DelayQueue 的實現(xiàn)原理。
1) DelayQueue 是JDK提供的一個無界 BlockQueue ,用于放置實現(xiàn)了Delayed 接口的對象。其中的對象只能在其到期時,才能從隊列中拿走。這種隊列 是 有序的,即 隊頭對象的延遲到期時間最長。
注意不能將null 元素放置 到這種隊列中。
2)實現(xiàn)注意事項
隊列 里面的元素 需要實現(xiàn)Delayed 這個接口。getDelay 方法用于設(shè)置 延遲時間。 compareTo 方法用于對隊列的元素
進(jìn)行排序。
public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
implements BlockingQueue<E>
// 入隊
put(){
offer();} 線程安全 reentrantlock 加鎖
offer(); 線程安全
// 出隊
poll(); 非阻塞方法,沒有到期元素 直接返回 null
take(); 阻塞式 獲取,沒有到期元素,線程將會進(jìn)行等待。
優(yōu)點(diǎn):
jdk 自帶的,不需要引入其他框架 中間件,實現(xiàn)簡單。缺點(diǎn)
:
- 不支持分布式或者 持久化的,重啟會丟失。
- 如果 并發(fā)量 非常大,因為DelayQueue式無界的,隊列內(nèi)的對象越多。可能會造成oom 的風(fēng)險。
- 所以使用 delayQueue實現(xiàn)的定時任務(wù),只適用于任務(wù)量較小的情況。
4.3 消息中間件
rocketmq如何實現(xiàn)延時隊列
rocketmq 先把消息 按照延時時間段(1s,5s,10s) 發(fā)到指定的隊列中
,然后通過一個定時器輪詢這些隊列。
如果到期,就把 這個消息發(fā)到指定的topic 隊列。注意點(diǎn):
- rocketmq 延時消息的時長
不支持隨機(jī)時長的延遲
。是通過特定的延遲等級來指定的。
默認(rèn)支持18個等級的延遲消息。
延時等級 在rocketmq服務(wù)端的MessageStoreConfig類中
private String messageDelayLevel ='1s 5s 10s 30s
1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 30m 1h 2h'
發(fā)消息時: 設(shè)置delayLevel 等級即可 msg.setDelayLevel( level);
level ==0 消息非延遲
1<=level <=maxlevel 消息延遲特定的時間。
level >maxlevel 那么 level=maxlevel 例如leve=20,延遲2h
優(yōu)點(diǎn):
基于消息中間件可以快速實現(xiàn)延時隊列,而且天然支持消息消費(fèi)的有序性、消息持久化、ack機(jī)制
。缺點(diǎn):
需要額外的部署 和運(yùn)維成本。
4.4 redis zset、 key 過期回調(diào)
zrangebyScore
redis 127.0.0.1:6379> ZADD salary 2500 jack
# 測試數(shù)據(jù)
(integer) 0
redis 127.0.0.1:6379> ZADD salary 5000 tom
(integer) 0
redis 127.0.0.1:6379> ZADD salary 12000 peter
(integer) 0
redis 127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf
# 顯示整個有序集
1) "jack"
2) "tom"
3) "peter"
redis 127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf WITHSCORES
# 顯示整個有序集及成員的 score 值
1) "jack"
2) "2500"
3) "tom"
4) "5000"
5) "peter"
6) "12000"
redis 127.0.0.1:6379> ZRANGEBYSCORE salary -inf 5000 WITHSCORES
# 顯示工資 <=5000 的所有成員
1) "jack"
2) "2500"
3) "tom"
4) "5000"
redis 127.0.0.1:6379> ZRANGEBYSCORE salary (5000 400000
# 顯示工資大于 5000 小于等于 400000 的成員
1) "peter"
4.5 時間輪算法
核心參數(shù)
每個 刻度 代表一個duration 時長。
- tickDuration s 、mins、 h
每個刻度的時長 - round
第幾圈 后執(zhí)行,使用延期時長/ 一圈的時長得來
一個刻度1s,15s 后執(zhí)行,那么 需要 round =2,沒到指定位置,round -1; - ticksPerWheel
一圈下來有幾個刻度
工作原理
- 指針停在0處
- tickDuration=1
- ticksPerWheel=12
如果一個25秒才執(zhí)行的延時任務(wù)添加進(jìn)來,首先它會計算它的round和index,round=25/12 =2
index=25%12=1.
所以時間輪長這樣:文章來源:http://www.zghlxwxcb.cn/news/detail-701599.html
當(dāng)指針轉(zhuǎn)到index=1的刻度時,會判斷第一個task的round是不是為0,如果為0則取出來,去執(zhí)行,如果大于0,則將round-1.文章來源地址http://www.zghlxwxcb.cn/news/detail-701599.html
到了這里,關(guān)于分布式、鎖、延時任務(wù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!