go 延時(shí)任務(wù)模塊delaytask-go

延時(shí)任務(wù)經(jīng)常在項(xiàng)目中被用到,比如生成訂單之后15分鐘訂單過(guò)期刀诬,發(fā)送xx事件開(kāi)始前的用戶(hù)提醒短信,周期性一致性檢查等;在go中可以通過(guò)ticker很方便的實(shí)現(xiàn)一個(gè)簡(jiǎn)單的延時(shí)任務(wù)功能涉波;但是如果要實(shí)現(xiàn)分布式的,獨(dú)立的延時(shí)任務(wù)進(jìn)程炭序,沒(méi)有找到適合的模塊啤覆;本文描述了一個(gè)精度為1s的延時(shí)任務(wù)的實(shí)現(xiàn);可以實(shí)現(xiàn)分布式多進(jìn)程部署惭聂,也能夠很方便的實(shí)現(xiàn)負(fù)載均衡窗声;
github地址 https://github.com/heteddy/delaytask-go

通常延時(shí)任務(wù)通過(guò)時(shí)間輪的方式實(shí)現(xiàn),可以參照下面的圖辜纲,時(shí)間輪包含8個(gè)slot笨觅,每個(gè)slot關(guān)聯(lián)一個(gè)鏈表拦耐,定時(shí)器觸發(fā)旋轉(zhuǎn)一個(gè)slot,并執(zhí)行對(duì)應(yīng)的任務(wù)见剩;


2826805-6a42019d063a576c.png

kafka中定時(shí)任務(wù)也是采用了時(shí)間輪杀糯,采用了多層輪的概念,如果任務(wù)時(shí)間超過(guò)下層輪的周期苍苞,就依次向上放入上層的輪中固翰,但這種多層的輪需要隨著時(shí)間移動(dòng)對(duì)應(yīng)的task;管理上比較復(fù)雜羹呵。


20180614194206760.png

delaytask-go 采用了在任務(wù)的鏈表節(jié)點(diǎn)中加入round 概念骂际,即運(yùn)行round圈之后再執(zhí)行當(dāng)前的task;定義如下:

type TaskNode struct {
    Runner
    round uint64 // 當(dāng)運(yùn)行輪數(shù)之后冈欢,再運(yùn)行
    // pool 的接口
    worker IWorker // 執(zhí)行task的worker pool
}
type runnerInfo struct {
    task *TaskNode // runner所在的taskNode
    slot int64     // runner在wheel中的插槽
}

type Wheel struct {
    ticks time.Duration
    // 時(shí)間輪 槽的數(shù)量
    count int64
    // 索引
    index int64
    // 槽
    slots []*Node // 時(shí)間輪插槽歉铝,每個(gè)包含TaskNode 鏈表和taskNode count
    // 保存task和task所在的index
    runnerMap map[int64]*runnerInfo
}

實(shí)現(xiàn)延時(shí)任務(wù)有以下幾個(gè)關(guān)鍵點(diǎn)

  • 保證任務(wù)的時(shí)間精度,不能出現(xiàn)過(guò)多的延時(shí)
  • 內(nèi)存占用凑耻,當(dāng)任務(wù)比較多太示,延時(shí)比較長(zhǎng)的任務(wù),進(jìn)程盡可能少的占用內(nèi)存香浩,
  • 分布式部署
  • 現(xiàn)場(chǎng)恢復(fù)先匪,當(dāng)執(zhí)行任務(wù)模塊宕機(jī)之后,盡快回復(fù)現(xiàn)場(chǎng)

任務(wù)精度

為了保證定時(shí)任務(wù)的執(zhí)行弃衍,定時(shí)任務(wù)通常切換到獨(dú)立的goroutine 池中執(zhí)行呀非;同時(shí)為了保證添加任務(wù)和定時(shí)器的觸發(fā)的Sequential Process 順序處理;因此把時(shí)間輪也放入一個(gè)單獨(dú)的goroutine中镜盯,添加任務(wù)和定時(shí)器事件都切換到timewheel goroutine中執(zhí)行岸裙,保證了順序性;而且避免了使用鎖速缆;

內(nèi)存占用

如果任務(wù)很少降允,直接放入內(nèi)存;但是如果有百萬(wàn)級(jí)別的任務(wù)艺糜,尤其是延時(shí)比較長(zhǎng)的任務(wù)剧董,全部放入內(nèi)存,本機(jī)內(nèi)存使用率很低破停;delaytask-go根據(jù)timewheel內(nèi)置了一個(gè)threshold(timewheel round time的整數(shù)倍)翅楼,當(dāng)執(zhí)行時(shí)間>這個(gè)threshold的時(shí)候,將任務(wù)序列化放入redis中真慢,通過(guò)sorted set管理waiting task毅臊;timewheel每轉(zhuǎn)一圈(round time)就去redis中取出來(lái)即將要執(zhí)行的任務(wù)

分布式部署

通過(guò)redis pub/sub,客戶(hù)端將任務(wù)序列化之后,發(fā)送到redis中黑界,delaytask-go訂閱任務(wù)管嬉;如果要做到負(fù)載均衡皂林,可以通過(guò)訂閱的channel做到,比如delaytaskchannel-0蚯撩,delaytaskchannel-1础倍,delaytaskchannel-2;客戶(hù)端通過(guò)一定的負(fù)載均衡算法將任務(wù)發(fā)送的指定的channel中胎挎;

現(xiàn)場(chǎng)的恢復(fù)

將進(jìn)入timewheel中的task序列化到 redis ongoing task list著隆;每當(dāng)task執(zhí)行完成之后就從ongoing中刪除對(duì)應(yīng)的task;如果系統(tǒng)崩潰呀癣,重啟時(shí)先從ongoing task中讀取task 如果task未超時(shí),放入timewheel中執(zhí)行弦赖。

測(cè)試

測(cè)試機(jī) macbook:

  • 4 * Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz
  • 16G內(nèi)存

執(zhí)行了50000次 http get 百度的任務(wù)(部分超時(shí)失敗项栏,設(shè)置了1s超時(shí))之后內(nèi)存消耗大約為8M,峰值大約為12M蹬竖,每秒500+個(gè)任務(wù)并發(fā)的測(cè)試結(jié)果:任務(wù)的 計(jì)劃執(zhí)行時(shí)間 ToRunAt實(shí)際執(zhí)行時(shí)間RunAt誤差小于1s沼沈;

可以根據(jù)任務(wù)的類(lèi)型修改goroutine池中worker的數(shù)量。io任務(wù)可以適當(dāng)增加worker數(shù)量币厕;默認(rèn)為cpu number

cpu的性能測(cè)試火焰圖列另,


屏幕快照 2019-01-18 16.30.27.png

cpu 統(tǒng)計(jì),除了系統(tǒng)調(diào)度占用旦装,logrus 和 redis操作占用了很多時(shí)間页衙,去掉log應(yīng)該可以運(yùn)行的更快;


屏幕快照 2019-01-18 19.04.56.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末阴绢,一起剝皮案震驚了整個(gè)濱河市店乐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌呻袭,老刑警劉巖眨八,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異左电,居然都是意外死亡廉侧,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)篓足,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)段誊,“玉大人,你說(shuō)我怎么就攤上這事栈拖≌砩ǎ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵辱魁,是天一觀(guān)的道長(zhǎng)烟瞧。 經(jīng)常有香客問(wèn)我诗鸭,道長(zhǎng),這世上最難降的妖魔是什么参滴? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任强岸,我火速辦了婚禮,結(jié)果婚禮上砾赔,老公的妹妹穿的比我還像新娘蝌箍。我一直安慰自己,他們只是感情好暴心,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布妓盲。 她就那樣靜靜地躺著,像睡著了一般专普。 火紅的嫁衣襯著肌膚如雪悯衬。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,764評(píng)論 1 290
  • 那天檀夹,我揣著相機(jī)與錄音筋粗,去河邊找鬼。 笑死炸渡,一個(gè)胖子當(dāng)著我的面吹牛娜亿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蚌堵,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼买决,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了吼畏?” 一聲冷哼從身側(cè)響起策州,我...
    開(kāi)封第一講書(shū)人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宫仗,沒(méi)想到半個(gè)月后够挂,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡藕夫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年孽糖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毅贮。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡办悟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出滩褥,到底是詐尸還是另有隱情病蛉,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站铺然,受9級(jí)特大地震影響俗孝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜魄健,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一赋铝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧沽瘦,春花似錦革骨、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至助隧,卻和暖如春筑凫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背喇颁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嚎货,地道東北人橘霎。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像殖属,于是被迫代替她去往敵國(guó)和親姐叁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容