Netflix(Nasdaq NFLX),也就是網飛公司,成立於1997年,是一家在線影片[租賃]提供商,主要提供Netflix超大數量的[DVD]並免費遞送,總部位於美國加利福尼亞州洛斯蓋圖。1999年開始訂閱服務。2009年,該公司可提供多達10萬部DVD電影,並有1千萬的訂戶。2007年2月25日,Netflix宣佈已經售出第10億份DVD。html
Netflix已經連續五次被評爲顧客最滿意的網站。能夠經過PC、TV及iPad、iPhone收看電影、電視節目,可經過[Wii],[Xbox360],[PS3]等設備鏈接TV。Netflix是全球領先的經營在線業務公司。它成功地把傳統的影像租賃業務和現代化的市場營銷手段、先進的IT網絡技術結合起來,從而開創了在線影像租賃的新局面。Netflix經過整合其自身的營銷手段和最近的IT網絡技術,成功地改變了消費習慣和打造了本身的品牌優點。git
Netflix在2011年開始探索自制內容的舉動並不被看好。直到2013年,其首部自制劇《紙牌屋》取得爆紅後,輿論衝擊及股票下滑的趨勢才得以扭轉。這也讓Netflix成功打響了平臺自制內容的第一炮。
github
2019 年 7 月 4 日,網飛的原創劇《怪奇物語》第三季開播,一如往常地一口氣放出 12 集,再次掀起話題熱潮。取得這樣的成功,網飛天然是高興不已。7 月 8 日,這家一般並不愛自詡成績的公司表示,有近 4100 萬家庭在四天以內觀看了《怪奇物語》最新季,超過 1800 萬家庭已經把整 8 集所有刷完。若是須要對比數據的話,4 月份 HBO 發佈的《權力的遊戲》最終季首播集觀看人數爲 1740 萬。數據庫
在持續推進創新技術更新的同時,Netflix確保始終如一的出色的用戶體驗絕非易事。如何才能確信更新系統的時候不會影響用戶的使用?並且實際上如何獲得更多的反饋,能夠對系統進行不斷地改進也是一個巨大的挑戰。apache
最終,Netflix公司經過對設備的數據進行採集,使用來自設備的實時日誌做爲事件源,獲得了大量的數據,經過實時的大數據瞭解和量化了用戶設備,最終成功的近乎無縫地處理了視頻的瀏覽和回放,完美的解決了這些問題。緩存
下面咱們來具體瞭解一下:網絡
如上圖,整個系統架構經過對用戶設備日誌收集,經過kafka的消息傳遞,最終存儲在Druid中。架構
一旦有了這些數據,就將它們存入數據庫,這裏使用的是實時分析數據庫Druid。併發
每項數據流均標有關於所用設備類型的匿名詳細信息,例如,該設備是智能電視,iPad仍是Android手機。這使得可以根據各個方面對設備進行分類並查看數據。反過來,這又使咱們可以定向的分析僅影響特定人羣的問題,例如應用程序的版本,特定類型的設備或特定國家/地區。分佈式
可經過儀表板或臨時查詢當即使用此聚合數據進行查詢。還能夠連續檢查指標是否有警報信號,例如新版本是否正在影響某些用戶或設備的播放或瀏覽。這些檢查用於警告負責的團隊,他們能夠儘快解決該問題。
在軟件更新期間,爲部分用戶啓用新版本,並使用這些實時指標來比較新版本與之前版本的性能。指標中的任何問題都會使咱們馬上發現並停止更新,並將那些使新版本直接恢復到先前版本。
因爲每秒須要處理超過200萬個事件,所以將其放入能夠快速查詢的數據庫是一個很是艱鉅的任務。咱們須要一個擁有足夠的性能與多維度查詢的數據庫,來處理天天產生超過1,150億行的數據。在Netflix,最終選擇利用Apache Druid來應對這一挑戰。
Druid是一個分佈式的支持實時分析的數據存儲系統。通俗一點:高性能實時分析數據庫。
Apache Druid是一個高性能的實時分析數據庫。它是爲須要快速查詢和提取的工做流而設計的。德魯伊在即時數據可視性,即席查詢,運營分析和處理高併發方面表現出色。」 — druid.io
所以,Druid很是適合如今咱們面臨的這種用例。事件數據的攝取頻率很是高,具備大數據量和快速查詢要求。
Druid不是關係數據庫,可是某些概念是可移植的。咱們有數據源,而不是表。與關係數據庫同樣,這些是表示爲列的數據的邏輯分組。Druid的Join性能目前還不是很優秀。所以,咱們須要確保每一個數據源中都包含咱們要過濾或分組依據的任何列。
數據源中主要有三類列-時間,維度和指標。
德魯伊中的一切都取決於時間。每一個數據源都有一個timestamp列,它是主要的分區機制。維度是可用於過濾,查詢或分組依據的值。指標是能夠彙總的值,幾乎老是數字。
咱們假設數據由時間戳做爲鍵,Druid能夠對存儲,分配和查詢數據的方式進行一些優化,從而使咱們可以將數據源擴展到數萬億行,而且仍然能夠實現查詢響應時間在十毫秒內。
爲了達到這種級別的可伸縮性,Druid將存儲的數據劃分爲多個時間塊。時間塊的持續時間是可配置的。能夠根據您的數據和用例選擇適當的持續時間。對於咱們的數據和用例,咱們使用1小時時間塊。時間塊內的數據存儲在一個或多個段中。每一個段都保存有全部數據行,這些行均落在其時間戳鍵列所肯定的時間塊內。能夠配置段的大小,以使行數或段文件的總大小有上限。
查詢數據時,Druid將查詢發送到集羣中全部包含查詢範圍內時間塊的分段的節點。每一個節點在將中間結果發送回查詢代理節點以前,都會對所保存的數據進行並行處理。代理將執行最終合併和聚合,而後再將結果集發送回客戶端。
把數據實時插入到此數據庫。這些事件(在本例中爲指標)不是從單個記錄插入到數據源中,而是從Kafka流中讀取。每一個數據源使用1個主題。在Druid中,咱們使用Kafka索引編制任務,該任務建立了多個在實時節點中間管理者之間分佈的索引編制工做器。
這些索引器中的每個都訂閱該主題,並從流中讀取其事件共享。索引器根據攝入規範從事件消息中提取值,並將建立的行累積在內存中。一旦建立了行,就能夠對其進行查詢。到達索引器仍在填充一個段的時間塊的查詢將由索引器自己提供。因爲索引編制任務實際上執行兩項工做,即攝取和現場查詢,所以及時將數據發送到「歷史節點」以更優化的方式將查詢工做分擔給歷史節點很是重要。
Druid能夠在提取數據時對其進行彙總,以最大程度地減小須要存儲的原始數據量。匯老是一種彙總或預聚合的形式。在某些狀況下,彙總數據能夠極大地減小須要存儲的數據大小,從而有可能將行數減小几個數量級。可是,減小存儲量確實要付出必定的代價:咱們失去了查詢單個事件的能力,只能以預約義的查詢粒度進行查詢。對於咱們的用例,咱們選擇了1分鐘的查詢粒度。
在提取期間,若是任何行具備相同的維度,而且它們的時間戳在同一分鐘內(咱們的查詢粒度),則這些行將被彙總。這意味着經過將全部度量值加在一塊兒並增長一個計數器來合併行,所以咱們知道有多少事件促成了該行的值。這種彙總形式能夠顯着減小數據庫中的行數,從而加快查詢速度,由於這樣咱們就能夠減小要操做和聚合的行。
一旦累積的行數達到某個閾值,或者該段已打開太長時間,則將這些行寫入段文件中並卸載到深度存儲中。而後,索引器通知協調器段已準備好,以便協調器能夠告訴一個或多個歷史節點加載該段。一旦將段成功加載到「歷史」節點中,就能夠從索引器中將其卸載,而且歷史記錄節點如今將爲全部針對該數據的查詢提供服務。
就像您想象的那樣,隨着維數基數的增長,在同一分鐘內發生相同事件的可能性下降。管理基數以及所以彙總,是得到良好查詢性能的有力手段。
爲了達到所需的攝取速率,咱們運行了許多索引器實例。即便在索引任務中合併了相同行的彙總,在相同的索引任務實例中得到全部相同行的機會也很是低。爲了解決這個問題並實現最佳的彙總,咱們安排了一個任務,在將給定時間塊的全部段都移交給歷史節點以後運行。
計劃的壓縮任務從深度存儲中獲取全部分段以進行時間塊化,並執行映射/縮小做業以從新建立分段並實現完美的彙總。而後,由「歷史記錄」節點加載併發布新的細分,以替換並取代原始的,較少彙總的細分。在咱們的案例中,經過使用此額外的壓縮任務,咱們發現行數提升了2倍。
知道什麼時候收到給定時間塊的全部事件並非一件容易的事。可能有關於Kafka主題的遲到數據,或者索引器可能會花一些時間將這些片斷移交給「歷史」節點。爲了解決此問題,咱們在運行壓縮以前強加了一些限制並執行檢查。
首先,咱們丟棄任何很是遲到的數據。咱們認爲這太舊了,沒法在咱們的實時系統中使用。這樣就能夠肯定數據的延遲時間。其次,壓縮任務是有延遲地安排的,這給了段足夠的時間以正常流程分流到歷史節點。最後,當給定時間塊的計劃壓縮任務開始時,它查詢段元數據以檢查是否還有任何相關段仍在寫入或移交。若是有,它將等待幾分鐘後重試。這樣能夠確保全部數據都由壓縮做業處理。
若是沒有這些措施,咱們發現有時會丟失數據。開始壓縮時仍要寫入的段將被具備更高版本的新壓縮的段覆蓋,所以具備優先權。這有效地刪除了還沒有完成移交的那些段中包含的數據。
Druid支持兩種查詢語言:Druid SQL和原生查詢。在後臺,Druid SQL查詢被轉換爲本地查詢。原生查詢做爲JSON提交到REST端點,這是咱們使用的主要機制。
對集羣的大多數查詢都是由自定義內部工具(例如儀表板和警報系統)生成的。這些系統最初旨在與咱們內部開發的開源時間序列數據庫Atlas一塊兒使用。所以,這些工具使用Atlas Stack查詢語言。
爲了加快採用Druid查詢的速度並實現對現有工具的重用,咱們添加了一個轉換層,該層接受Atlas查詢,將其重寫爲Druid查詢,發佈查詢並將結果從新格式化爲Atlas結果。這個抽象層使現有工具能夠按原樣使用,而且不會爲用戶訪問咱們的Druid數據存儲中的數據建立任何額外的學習曲線。
在調整羣集節點的配置時,咱們以很高的速度運行了一系列可重複和可預測的查詢,以便得到每一個給定配置的響應時間和查詢吞吐量的基準。這些查詢旨在隔離集羣的各個部分,以檢查查詢性能是否有所改善或下降。
例如,咱們針對最新數據運行了有針對性的查詢。一樣,對於更長的持續時間,但只有較舊的數據能夠確保咱們僅查詢「歷史」節點以測試緩存配置。再次使用按很是高的基數維度分組的查詢,以檢查結果合併是如何受到影響的。咱們繼續調整並運行這些基準測試,直到對查詢性能感到滿意爲止。
在這些測試中,咱們發現調整緩衝區的大小,線程數,查詢隊列長度和分配給查詢緩存的內存對查詢性能產生了有效影響。可是,引入壓縮工做將佔用咱們彙總不良的細分,並以完美彙總將它們從新壓縮,這對查詢性能產生了更大的影響。
咱們還發現,在歷史節點上啓用緩存很是有好處,而在代理節點上啓用緩存則沒有那麼多。太多了,咱們不使用代理上的緩存。這多是因爲咱們的用例所致,可是咱們幾乎進行的每一個查詢都未命中代理上的緩存,這多是由於查詢一般包含最新數據,由於這些數據始終會到達,所以不會包含在任何緩存中。
通過屢次迭代,針對咱們的用例和數據速率進行了調整和定製,德魯伊已被證實具備咱們最初但願的能力。
咱們已經可以使用功能強大且可用的系統,可是還有更多工做要作。咱們的攝入量和攝入率不斷提升,查詢的數量和複雜性也在不斷增長。隨着更多團隊實現這些詳細數據的價值,咱們常常添加更多指標和維度,從而推進系統更加努力地工做。咱們必須繼續監視和調整,以保持查詢性能。
目前,咱們每秒接收超過200萬個事件,並查詢超過1.5萬億行,以深刻了解咱們的用戶如何體驗該服務。全部這些都有助於咱們保持高質量的Netflix體驗,同時實現不斷的創新。
實時流式計算與流媒體的碰撞纔剛剛開始,而Druid做爲一款極易上手的高性能實時查詢數據庫,也會獲得愈來愈多的普遍使用。
更多實時數據分析相關博文與科技資訊,歡迎關注 「實時流式計算」
獲取《Druid實時大數據分析》電子書,請在公號後臺回覆 「Druid」