1. 程式人生 > >某定時任務系統的方案設計------軟體系統設計能力很重要

某定時任務系統的方案設計------軟體系統設計能力很重要

        來看這樣一個問題:

        某賬號系統的賬號都在unsigned int內, 也就是0-42億左右。 在這42億賬號中, 有大約1億賬號是相對非常活躍的使用者, 使用者和使用者之間可以建立好友關係(類似於微信那樣的好友關係)。 現在要設計一個定時贈言系統, 比如: 今天是2017年3月25日, 那麼使用者A可以給他的好友B送定時贈言(精確到未來某天, 不包括今天), 預期未來這天到達。而且任何使用者都可以給他的多個好友多次送定時贈言。試給出合理的大致設計方案奮鬥奮鬥奮鬥

        我們一起來逐步看下, 這裡肯定要把定時任務先落地到儲存中, 到了設定的定時日期, 讀出來, 併發出去。 那儲存的資料結構該怎樣組織呢? 這是本問題的核心所在。

       方案一:

       對於每一個定時任務, 用四元組把它存起來, 即{傳送者賬號, 接受者賬號, 定時時間, 贈言}, 對於n個贈言操作, 就有了n個四元組, 然後把這n個四元組儲存起來。 然後每天都讀取任務, 讀取到n個四元組任務後, 根據定時時間篩選出該傳送的, 傳送出去。

       舉個例子, 在2017年3月25日, 使用者123給好友456送了定時贈言“”“I miss you”, 期望2017年3月28日到, 那麼對應的四元組是{123, 456, 20170328, "I miss you"},  然後儲存起來, 於是乎, 在2017年3月26日, 遍歷讀取儲存中的眾多定時任務, 發現了{123, 456, 20170328, "I miss you"}, 但時間不對,所以暫時不發。 等2017年3月27日再讀取, 發現時間又不對, 所以暫時不發。 等2017年3月28日再讀取, 發現時間對了, 就立即發出訊息。 

       我們來審視下這個方案, 很容易發現, 這是個相當低階的設計, 2017年3月26日和2017年3月27日做了兩次無用的嘗試啊。 從整體來看, 這種無用次數的數量難以想象。問題顯而易見, 我們沒有按照時間來儲存這些定時任務。 於是繼續改造。

       方案二:

       以設定的定時時間為key, 將所有定時在這一天的任務, 落地到同一個儲存區。 按照上面的例子, 簡單來說就是,  以20170328為key,  於是上述贈言操作就對應一個三元組,{123, 456, "I miss you"}, 讀取的時候, 按天讀取任務, 然後發出。 這種方案就好多了。 但還是有問題: 三元組作為value, 有n個留言操作, 就是n個三元組的拼接, 太龐大了, 不滿足系統的key value儲存要求。 於是繼續優化。

      方案三:

      以{20170328, 123}做key, 用{456, "I miss you"}做value,   這樣, 通過增加key的個數,來減少value的長度。 但問題在於, 讀取的時候怎麼去索引呢? 難道要遍歷{20170328, 0} --- {20170328, 42億}  ? 我們要考慮到, 只有少數活躍使用者啊, 這種42億的全遍歷肯定是不行的。 

      這裡問題的本質是什麼? 本質就是漫無目的暴力地去遍歷key,  何不把有實際操作的key存下來呢? 

      方案四: 以20170328為一級key,  將有實際操作的使用者作為value, 於是形成了這樣的資料結構:20170328--->{123, 231, 101...},  其中123, 231, 101都是有實際贈言操作的使用者。 然後以{20170328, 123}位作為二級key來存放 {456, "I miss you"}.  到了2017年3月28日這邊, 讀取操作就很順暢了, 先讀取一級value {20170328, 123}, 然後以第一級value為key讀取二級value  {456, "I miss you"}..    但發現還有個問題, 二級value的值還是太大(m個二元組的拼接, 很大)。繼續優化。

      方案五: 根據傳送者尾號(比如取尾4位數)對key進行打散, 於是使用者123和使用者9870123的一級key就是一樣的了, 都是{20170328,0123}.  該怎麼讀取呢? 到了2017年3月28日那邊, 遍歷{20170328, 0000}---{20170328, 9999}這一萬個key(幾乎可以肯定的是, 不會存在空遍歷的情況),  於是查到123這個使用者有贈言操作,於是繼續用{20170328, 0123, 123}來獲取到二級value  {456, "I miss you"}, 然後把訊息發出。

       好了, 對比下方案一和方案五, 就知道優劣了。 隨便說兩點:

       1. 方案一沒法用多程序跑讀任務, 慢得蛋疼, 呵呵噠。

       2. 方案一沒法在緊急情況時取消任務, 都雜糅在一起了, 取消很蛋疼的。

       當然, 方案的優化是無止境的, 目前來看, 方案五跑得很順暢。 

       蠻力要不得, 任何事情, 都得講點策略得意得意得意