100臺機器上海量IP如何查詢出現頻率 Top 100?

第十六封發表於2021-10-09

場景題

有 100 機器,每個機器的磁碟特別大,磁碟大小為 1T,但是記憶體大小隻有 4G,現在每臺機器上都產生了很多 ip 日誌檔案,每個檔案假設有50G,那麼如果計算出這 100 太機器上訪問量最多的 100 ip 呢?也就是Top 100。

思路

其實,一開始我有往布隆過濾器那邊考慮,但是布隆過濾器只能大致的判斷一個 ip 是否已經存在,而不能去統計數量,不符合該場景。

那麼一般這種大資料的問題,都是因為一次不能完全載入到記憶體,因此需要拆分,那怎麼拆呢?ip是32位的,也就是最多就 232 個, 常見的拆分方法都是 雜湊

  • 把大檔案通過雜湊演算法分配到不同的機器
  • 把大檔案通過雜湊演算法分配到不同的小檔案

上面所說,一臺機器的記憶體肯定不能把所有的 ip 全部載入進去,必須在不同機器上先 hash 區分,先看每臺機器上,50G 檔案,假設我們分成 100 個小檔案,那麼平均每個就500M,使用 Hash 函式將所有的 ip 分流到不同的檔案中。

這個時候相同的 ip 一定在相同的檔案中,當然不能排除資料全部傾斜於一個檔案的情況,也就是雖然 hash了,但是由於個別ip或者hash值相同的ip太多了,都分到了個別檔案上,那麼這個時候分流後的檔案依舊很大。這種情況我能想到的就是要是檔案還是很大,需要再hash,如果基本屬於同一個ip,那麼這個時候就可以分批次讀取,比如一次只讀 1G 到記憶體。

在處理每個小檔案時,使用 HashMap 來統計每個 ip 出現的頻率,統計完成後,遍歷,用最小根堆,獲取出現頻率最大的100個ip。這個時候,每個小檔案都獲取到了出現頻率最大的100個 ip,然後每個檔案的 Top 100 個ip 再進行排序即可(每個檔案的top100 都是不一樣的,因為前面進行 hash 之後保證相同的 ip 只會落到同一個檔案裡)。這樣就可以得到每臺機器上的 Top 100。

不同機器的 Top 100 再進行 加和排序,就可以得到Top 100 的ip。

為什麼加和? 因為不同機器上可能存在同樣的ip,前面的hash操作只是確保同一個機器的不同檔案裡面的ip一定不一樣。

但是上面的操作有什麼瑕疵麼?當然有!

假設我們又兩臺機器,有一臺機器 C1 的top 100 的ip是 192.128.1.1,top 101 是 192.128.1.2,那麼就可能存在另一臺機器 C2192.128.1.1 可能從來沒有出現過,但是 192.128.1.2 卻也排在 top 101,其實總數上 192.128.1.2 是超過192.128.1.1,但是很不幸的是,我們每臺機器只儲存了 top100,所以它在計算過程中被淘汰了,導致結果不準確。

解決方案:

先用 hash 演算法,把 ip 按照 hash 值雜湊到不同的機器上,保證相同的ip在相同的機器上,再對每個機器上的ip檔案再hash成小檔案,這個時候再分別統計小檔案的出現頻次,用最小根堆處理,不同檔案的結果排序,就可以得到每臺機器的top 100,再進行不同機器之間的結果排序,就可以得到真正的 top 100。


一般而言,像這種海量資料,比如 有一個包含100億個URL的大檔案,假設每個URL佔用64B,請找出其中所有重複的URL. ,記憶體一次性讀不下,只能通過 分而治之

hash 到不同的小檔案,一直這樣劃分,直到滿足資源的限制:

  • hash分流
  • hash表統計
  • 最小堆/外部排序

如果允許一定的誤差存在,其實還可以考慮使用布隆過濾器(Bloom filter),將URL挨個對映到每一個Bit,在此之前判斷該位置是否對映過,來證明它是否已經存在。(有一定的概率出現誤判,因為其他的URL也可能會對映到同一位置

【作者簡介】
秦懷,公眾號【秦懷雜貨店】作者,技術之路不在一時,山高水長,縱使緩慢,馳而不息。個人寫作方向:Java原始碼解析JDBCMybatisSpringredis分散式劍指OfferLeetCode等,認真寫好每一篇文章,不喜歡標題黨,不喜歡花裡胡哨,大多寫系列文章,不能保證我寫的都完全正確,但是我保證所寫的均經過實踐或者查詢資料。遺漏或者錯誤之處,還望指正。

劍指Offer全部題解PDF

2020年我寫了什麼?

開源程式設計筆記

相關文章