1. 引子
從2個面試題說起,第一個問題: 如果一臺機器上有10w個定時任務,如何做到高效觸發?
具體場景是:
有一個APP實時消息通道系統,對每個用戶會維護一個APP到服務器的TCP連接,用來實時收發消息,對這個TCP連接,有這樣一個需求:“如果連續30s沒有請求包(例如登錄,消息,keepalive包),服務端就要將這個用戶的狀態置爲離線”。
其中,單機TCP同時在線量約在10w級別,keepalive請求包較分散大概30s一次,吞吐量約在3000qps。
怎麼做?
常用方案使用time定時任務,每秒掃描一次所有連接的集合Map<uid, last_packet_time>,把連接時間(每次有新的請求更新對應連接的連接時間)比當前時間的差值大30s的連接找出來處理。
另一種方案,使用環形隊列法:
三個重要的數據結構:
- 30s超時,就創建一個index從0到30的環形隊列(本質是個數組)
- 環上每一個slot是一個Set<uid>,任務集合
- 同時還有一個Map<uid, index>,記錄uid落在環上的哪個slot裏
這樣當有某用戶uid有請求包到達時:
- 從Map結構中,查找出這個uid存儲在哪一個slot裏
- 從這個slot的Set結構中,刪除這個uid
- 將uid重新加入到新的slot中,具體是哪一個slot呢 => Current Index指針所指向的上一個slot,因爲這個slot,會被timer在30s之後掃描到
- 更新Map,這個uid對應slot的index值
原文鏈接:【https://www.infoq.cn/article/ErdajpJ5EpIr65IczxZI】。未經作者許可,禁止轉載。