Cloudflare如何分析每秒上百萬的DNS查詢

上週五,我們宣佈了所有Cloudflare DNS分析工具。 由於我們的規模很大(當你讀完這篇文章的時候,Cloudflare DNS將處理數以百萬計的DNS查詢) 我們必須非常有創意的解決該問題。 在本文中,我們將介紹DNS分析工具的組件,這些組件幫助我們每月處理數以萬億計的日誌。

Cloudflare如何分析每秒上百万的DNS查询

Cloudflare已經有一個用於HTTP日誌的數據管道。我們希望DNS分析工具可以利用該功能。每當邊緣服務處理一個HTTP請求時,它就會以Cap'n Proto格式生成一個結構化的日誌消息,並將其發送到本地多路複用服務。考慮到數據量,我們只記錄部分DNS消息數據,只包含我們感興趣的數據,例如響應碼,大小或query name,這使得我們每個消息平均只保留約150字節數據。然後將其與元數據處理(例如在查詢處理期間觸發的定時信息和異常)融合。在邊緣融合數據和元數據的好處是,我們可以將計算成本分散到成千上萬的邊緣服務器,並且只記錄我們需要的信息。

多路複用服務(稱為“日誌轉發器”)正在每個邊緣節點上運行,從多個服務組裝日誌消息並將其傳輸到我們的倉庫,以便通過TLS安全通道進行處理。運行在倉庫中的對應服務將日誌接收並解分解到幾個Apache Kafka集群中。Apache Kafka用於生產者和下游消費者之間做緩衝,防止消費者故障或需要維護時的數據丟失。自0.10版本以來,Kafka允許通過機架感知分配副本,從而提高對機架或站點故障的恢復能力,為我們提供容錯的未處理消息存儲。

Cloudflare如何分析每秒上百万的DNS查询

擁有結構化日誌隊列使我們能夠追溯性地查問題,而不需要訪問生產節點。 在項目的早期階段,我們會跳過隊列並找到我們所需的粗略時間段的偏移量,然後將數據以Parquet格式提取到HDFS中,以供離線分析。

關於聚合

HTTP分析服務是圍繞生成聚合的流處理器構建的,因此我們計劃利用Apache Spark將日誌自動傳輸到HDFS。由於Parquet本身不支持索引以避免全表掃描,因此在線分析或通過API提供報告是不切實際的。雖然有像parquet-index這樣的擴展可以在數據上創建索引,但也不能實時運行。鑑於此,最初的設計是僅向客戶顯示彙總報告,並保留原始數據用以內部故障排除。

彙總摘要的問題在於,它們只能處理基數較低(大量唯一值)的列。通過聚合,給定時間範圍內的每個列都會擴展到很大的行數(與唯一條目個數相等),因此可以將響應碼(例如只有12個可能的值,但不包含查詢名稱)進行聚合。如果域名受歡迎,假設每分鐘被查詢1000次,那麼可以預期每分鐘做聚合可以減少1000倍的數據,然而實際上並不是這樣。

由於DNS緩存的存在,解析器在TTL期間不會進行DNS查詢。 TTL往往超過一分鐘。因此,服務器多次看到相同的請求,而我們的數據則偏向於不可緩存的查詢,如拼寫錯誤或隨機前綴子域名攻擊。在實踐中,當用域名進行聚合時,我們可以看到最多可以減少為原來的1/60的行數,而多個分辨率存儲聚合幾乎可以抵消行減少。使用多個分辨率和鍵組合也可以完成聚合,因此聚合在高基數列上甚至可以產生比原始數據更多的行。

Cloudflare如何分析每秒上百万的DNS查询

由於這些原因,我們首先在zone層次上彙總日誌,這對於趨勢分析來說已經足夠,但是對於具體原因分析來說則太過粗糙。例如,我們正在調查其中一個數據中心的流量短暫爆發。具有未聚合的數據使我們能夠將問題縮小到特定DNS查詢,然後將查詢與錯誤配置的防火牆規則相關聯。像這樣的情況下,只有彙總日誌就有問題,因為它只聚合一小部分請求。

所以我們開始研究幾個OLAP系統。我們研究的第一個系統是Druid。我們對前端(Pivot和以前的Caravel)是如何切分數據的能力印象很深刻,他使我們能夠生成具有任意維度的報告。 Druid已經被部署在類似的環境中,每天超過1000億事件,所以我們對它可以工作很有信心,但是在對抽樣數據進行測試之後,我們無法證明數百個節點的硬件成本。幾乎在同一時間,Yandex開源了他們的OLAP系統ClickHouse。

ClickHouse

ClickHouse的系統設計更加簡單,集群中的所有節點具有相同的功能,使用ZooKeeper進行協調。我們建立了一個由幾個節點組成的集群,發現性能相當可觀,所以我們繼續構建了一個概念驗證。我們遇到的第一個障礙是缺少工具和社區規模的規模太小,所以我們鑽研了ClickHouse設計,以瞭解它是如何工作的。

ClickHouse不直接支持Kafka,因為它只是一個數據庫,所以我們使用Go寫了一個適配器服務。它讀取來自Kafka的使用Cap'n Proto編碼的消息,將它們轉換為TSV,並通過HTTP接口分批插入ClickHouse。後來,我們講ClickHouse的HTTP接口替換為GO SQL驅動,以提高性能。從那以後,我們就開始為該項目提供了性能改進。我們在性能評估過程中學到的一件事是,ClickHouse寫入性能很大程度上取決於批量的大小,即一次插入的行數。為了理解為什麼,我們需要進一步瞭解了ClickHouse如何存儲數據。

ClickHouse用於存儲的最常見的表引擎是MergeTree系列。它在概念上類似於Google的BigTable或Apache Cassandra中使用的LSM算法,但它避免了中間內存表,並直接寫入磁盤。這使得寫入吞吐量非常出色,因為每個插入的批次只能通過“主鍵”進行排序,壓縮並寫入磁盤以形成一個段。沒有內存表也意味著他僅僅追加數據,並且不支持數據修改或刪除。當前刪除數據的唯一方法是按日曆月份刪除數據,因為段不會與月份邊界重疊。 ClickHouse團隊正在積極致力於使這個功能可配置。另一方面,這使得寫入和段合併無衝突,因此吞吐量與並行插入的數量成線性比例關係,直到I/O跑滿。但是,這也意味著它不適合小批量生產,這就是為什麼我們依靠Kafka和插入器服務進行緩衝的原因。 ClickHouse在後臺不斷合併,所以很多段將被合併和寫多次(從而增加寫放大),太多未合併的段將觸發寫入限流,直到合併完成。我們發現,每秒鐘每張表的插入一次效果最好。

表讀性能的關鍵是索引和數據在磁盤上的排列。無論處理速度有多快,當引擎需要從磁盤掃描太多數據時,這都需要大量時間。ClickHouse是一個列式存儲,因此每個段都包含每個列的文件,每行都有排序值。通過這種方式,可以跳過查詢中不存在的列,然後可以通過向量化執行並行處理多個單元。為了避免完整的掃描,每個段也有一個稀疏的索引文件。鑑於所有列都按“主鍵”排序,索引文件僅包含每第N行的標記(捕獲行),以便即使對於非常大的表也可以將其保留在內存中。例如,默認設置是每隔8192行做一個標記。這種方式只需要122,070個標記來具有1萬億行的表格進行索引。在這裡可以查看ClickHouse中的主鍵,深入瞭解它的工作原理。

使用主鍵列查詢時,索引返回考慮行的大致範圍。理想情況下,範圍應該是寬而連續的。例如,當典型用法是為單個區域生成報告時,將區域放在主鍵的第一個位置將導致按每個區域進行排序,使得磁盤讀取單個區域連續,而如果按主要時間戳排序則在生成報告是無法保證連續。行只能以一種方式排序,因此必須仔細選擇主鍵,並考慮典型的查詢負載。在我們的例子中,我們優化了單個區域的讀取查詢,併為探索性查詢提供了一個帶有采樣數據的獨立表格。從中吸取的教訓是,我們不是試圖為了各種目的而優化索引,而是分解差異並多加一些表。

這樣專有化設計的結果就是在區域上聚合的表格。由於沒有辦法過濾數據,因此掃描所有行的查詢都要昂貴得多。這使得分析師在長時間計算基本聚合時不那麼實際,所以我們決定使用物化視圖來增量計算預定義聚合,例如計數器,唯一鍵和分位數。物化視圖利用批量插入的排序階段來執行生產性工作 - 計算聚合。因此,在新插入的段被排序之後,它也會生成一個表格,其中的行代表維度,而列代表聚合函數狀態。聚合狀態和最終結果之間的區別在於,我們可以使用任意時間分辨率生成報告,而無需實際存儲多個分辨率的預計算數據。在某些情況下,狀態和結果可能是相同的 - 例如基本計數器,每小時計數可以通過累計每分鐘計數來產生,但是對獨特的訪問者或延遲分位數求和是沒有意義的。這是聚合狀態更有用的時候,因為它允許有意義地合併更復雜的狀態,如HyperLogLog(HLL)位圖,以便每小時聚合生成每小時獨立訪問者估計值。缺點是存儲狀態可能比存儲最終值要昂貴的多 - 上述HLL狀態在壓縮時大概有20-100字節/行,而計數器只有8字節(平均壓縮1個字節)。使用這些表可以快速地將整個區域或站點的總體趨勢形象化, 並且我們的 API 服務也使用它們做簡單查詢。在同一位置同時使用增量聚合和沒有聚合的數據, 我們可以通過流處理完全簡化體系結構。

基礎設施和數據整合

我們使用12個6TB磁盤做RAID-10,但在一次磁盤故障之後重新進行了評估。在第二次迭代中,我們遷移到了RAID-0,原因有兩個。首先,不能熱插拔有故障的磁盤,其次陣列重建花費了數十個小時,這降低了I/O性能。更換故障節點並使用內部複製通過網絡(2x10GbE)填充數據比等待陣列完成重建要快得多。為了彌補節點故障的可能性較高,我們切換到3路複製,並將每個分片的副本分配到不同的機架,並開始規劃複製到單獨的數據倉庫。

另一個磁盤故障突出了我們使用的文件系統的問題。最初我們使用XFS,但它在複製過程中開始在同一時間從2個對等點進行鎖定, 從而在完成之前中斷了段複製。這個問題表現為大量I/O活動,由於損壞的部分被刪除,磁盤使用量增加很少,所以我們逐漸遷移到了ext4,該文件系統就沒有這個問題。

數據可視化

當時我們只依靠Pandas和ClickHouse的HTTP接口進行臨時分析,但是我們希望使分析和監控更容易。 因為我們知道Caravel(現在更名為Superset ),我們就把它和ClickHouse進行了整合。

Cloudflare如何分析每秒上百万的DNS查询

Superset是一個直觀的數據可視化平臺,它允許分析人員在不寫一行SQL的情況下交互地切片和切分數據。 它最初是由AirBnB為Druid構建和開源的,但是隨著時間的推移,它已經通過使用SQLAlchemy(一種抽象和ORM)為數十種不同的數據庫方言提供了基於SQL的後端的支持。 所以我們編寫並開源了一個ClickHouse方言,並集成到Superset。

Superset為我們提供了特別的可視化服務,但是對於我們的監控用例來說,它仍然不夠完善。 在Cloudflare,我們大量使用Grafana來可視化所有指標,所以我們將它與Grafana集成並進行開源。

Cloudflare如何分析每秒上百万的DNS查询

它使我們能夠用新的分析數據無縫地擴展我們現有的監測儀表板。 我們非常喜歡這個功能,因此我們希望能夠為用戶提供同樣的能力來查看分析數據。 因此,我們構建了一個Grafana應用程序,以便可視化來自Cloudflare DNS Analytics的數據。 最後,我們在您的Cloudflare儀表板分析中提供了它。 隨著時間的推移,我們將添加新的數據源,維度和其他有用的方法來顯示Cloudflare中的數據。


分享到:


相關文章: