2019獨角獸企業重金招聘Python工程師標準>>>
假如有個直播間,在數據有更新的時候,能及時反映在客戶端上。通信方式來說,有兩種:
1、拉取模式。
2、推送+拉取模式(或者純推送)
?
拉取模式,技術簡單。但輪詢間隔設置比較難;如果設置得太大,數據更新不及時;如果設置得太小,那么服務端可能會多余很多無用請求(數據本來并無更新)。
推送模式,可以在數據有更新的情況下,才選擇通知客戶端。但如果在同一秒內,數據更新得太頻繁,可能會造成推送風暴。
這時候做一個簡單優化,如果距離上一次推送不超過一秒,當前數據更新不推送。那么也會有個問題,最后更新的數據,可能在很長一段時間內都更新不到客戶端。
下面介紹一個設計方法,如下是一個時間軸:
0? ? 0.2? ? ? ? ? ? ? ? ? ? ? ? ?1? ? ?1.3? ? ? ? ? ? ? ? ? ? ? ? 2? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 3? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 4
|------------------------|------------------------|------------------------|------------------------|
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0? ? 0.2? ? ? ? ? ? ? ? ? ? ? ? ?1? ? ? 1.3? ? ? ? ? ? ?
采用ThreadPoolExecutor來處理時間軸上面0/0.2/1/1.3的請求Task,而BlockingQueue則采用DelayedQueue來實現,進入線程池的任務的Task都實現Delayd接口并且設置延遲1秒。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
那么Task真正執行的時間點就如時間軸下面的數字。而由于設置了規則,距離上次推送間隔小于1秒的時候,不再繼續推送。所以 紅色的數字 0 和 1 表示會執行推送,而 藍色的數字 0.2 和 1.3 就不會推送。那么反饋到客戶端層面,當?紅色的數字 0 執行推送,會把當時 綠色的0/0.2/1狀態推送給客戶端(因為是全量更新,所以只需要查詢當前最新數據);而當 紅色的數字 1 執行推送,會把當時 綠色的1.3狀態推送給客戶端。那么這個過程中,最晚的更新數據也不會超過1秒的延遲到達客戶端。同時,只發生了兩次推送。
上面的任務執行過程中,涉及到上一次推送的時間變量的比較。那么這個時間變量存儲在哪里呢?
簡單的單進程,當然是在進程內定義一個變量就完事了。
假如是多進程,那么為了最大化優化性能邏輯,我們可以分別設置本地變量緩存以及全局的redis變量緩存。方法有很多,下面只介紹一種同步方式:
當進程內的任務執行,先對比本地變量;如果系統時間減去本地變量小于一秒,那么不繼續執行任務;如果系統時間減去本地變量大于一秒,那么通過redis的get獲取到上一次推送的時間戳;如果系統時間減去該全局時間戳小于一秒,那么不繼續執行任務并更新本地緩存,如果系統時間減去該全局時間戳大于一秒,通過redis的getset(value是系統時間)返回的全局時間戳,這時的時間戳如果還大于1秒那么就推送并且更新本地緩存為當前系統時間,否則不繼續執行(其它進程執行了推送)。
?