摘要:并且這種格式沒有事先對時間序列的數量做任何限制。使用格式來存儲時間序列數據的兩種可能的。其中存放了時間列序列列和數值列三列。隨著數據規模的繼續增長,基于的應用程序越來越不適合處理這樣規模的時間序列數據了。
就像我們在前一章提到的,一個時間序列是一系列數值,每個數值都伴隨著一個時間值,代表數據被記錄時的時間。時間序列數據存入后就很少再需要修改了,查詢時經常是查詢一個連續時間段的數據,也可能查詢匯總或者聚合后的數據。時間序列數據庫是一種儲存多個時間序列的方式,在其中檢索一個或幾個時間序列的某一個特定時間段的數據是特別高效的。同樣地,主要用來查詢一個時間段數據的應用程序也適合使用時間序列數據庫來實現。像之前所解釋的,本書的主題是存儲和處理大規模時間序列數據,為了實現這個目標,首選技術是非關系型NoSQL數據庫,比如Apache HBase或MapR-DB。
為大規模時間序列數據庫的實際實現提供務實的建議,是本書的目標,所以我們需要聚焦于一些可以簡化和增強真實世界中應用程序發展進程的一些基本步驟。我們會簡單看看適用于中小型數據集的方法,然后深入探究我們主要關注的問題:如何實現大規模TSDB。
為了得到一個扎實的實現,有幾種可供選擇的設計方法。如何選擇取決于數據的屬性。有多少種不同的時間序列?獲得的數據是什么類型的?使用怎樣的速度采集數據?需要存儲多久的數據?這些問題的答案有助于我們確定最優的實現策略。
這一章中的主要思想路線
盡管我們已經提到處理時間序列數據的一些主要方面,這一章會比之前更深入地探討存儲和訪問時間序列數據的基本方法。第四章會提供如何使用現有開源軟件來最好地實現這些概念的建議。這兩章有比較多的內容需要理解。然后你就可以記住如果將這些關鍵的想法集中到一起而不是迷失在細節中,這里是一個本章內容的一個簡單路線圖:
平面文件
對時間序列數據來說是受限的工具,不適合快速增長的數據,查詢起來也會效率低下
真正的數據庫:關系型數據庫
擴展性不好,常見的星型模式(star schema)不適合處理時間序列數據
真正的數據庫:非關系型NoSQL數據庫
首選方案,因為它可擴展型好、高效、能快速響應基于時間段的查詢
基本設計
使用包含時間序列ID的唯一row key,列是不同時間偏移的數值
存儲多于一個時間序列
可選設計
使用寬表逐點存儲數據
混合寬表和blob類型的設計
將數據緩存到內存,然后blob直寫
我們已經回顧了主要思想,現在我們更詳細地重溫一下并且解釋它們的重要性。
最簡單的數據存儲:平面文件你可以擴展非常簡單的設計(比如簡單的二維表),使用更聰明的文件格式來使其更先進,比如列存儲的Parquet格式。Parquet是一個有效并且簡單的現代化格式,可以存儲時間和一些可選值。圖3-1展示了兩種記錄時間序列數據的Parquet schema。左圖中的schema適合你已經知道怎么合理使用時間序列數據的情況,它是一個特定場景的存儲方案。例子中,只存了明確指定的4個時間序列的數據(一個存放時間的t和一個存放數據的tempIn組合起來,為一個時間序列。t和它對應的tempIn、pressureIn、tempOut、pressureOut即4個時間序列),如果需要增加新的,就需要修改schema。右圖中的Parguet schema抽象程度更高,對你想要往文件里嵌入更多元數據的場景更適合。并且這種格式沒有事先對時間序列的數量做任何限制。如果你想要構建一個給其他人使用的時間序列庫,右邊的格式會更合適一些。
圖3-1。使用Parquet格式來存儲時間序列數據的兩種可能的schema。左邊的schema使用固定的類型名稱將問題域確定了。在不改變schema的情況下,只可以存儲4個時間序列。相反地,右邊的schema更加靈活,你可以增加新的時間序列。另外它的抽象層次也更高,把幾個單一的時間序列(一對time、value)按照tags分組,然后放到一個多帶帶的block中。
這樣的一種時間序列數據(特別是使用類似Parquet格式的情況)是非常有用的,但前提是你需要分析的時間序列數量相對較小,并且所感興趣的時間范圍相對于單個文件所存儲數據的時間跨度很大(比如每個文件存放一個月的數據,你查的時候也應該每次查一個月的數據,而不是每次查一天的)。
系統最初使用平面文件來實現是一種非常普遍的情況,而且不久之后這種簡單的實現不再適應快速增長的數據的情況也是很普遍的。基本問題是單一文件中的時間序列數量增加了,任何特定的查詢中,真正有用的數據占所讀取數據的比例就下降了,因為多數讀取到的數據其實是屬于其他時間序列的。
同樣地,在文件中的時間跨度比平均查詢的時間范圍已經長很多的情況,真正有用的數據占所被讀取數據的比例又下降了,因為文件中的大部分數據已經在你感興趣的時間范圍之外了(比如數據記錄了1個月的數據,而查詢時一般只查某一天的,那為了定位到這一天,需要先讀大量前邊的實際不需要的數據)。努力解決這些問題的同時一般又會引入其他的問題。使用大量的文件來確保每個文件中只有較少的時間序列,會使文件數量大幅增長。同樣地,減少每個文件所存儲數據的時間范圍會使得文件數量翻倍增長。當在一個類似Apache Hadoop中HDFS的文件系統存儲數據時,大量的文件會導致嚴重的穩定性問題。基于Hadoop的上層系統,如MapR可以輕松處理大量的文件,但檢索和管理大量的小文件也是很低效的,因為需要增加很多搜索時間。
為了避免這些問題,很自然的一步是轉而使用某些形式的真正的數據庫來存儲這些數據。選擇合適的數據庫的方法并不是顯而易見的,但基于數據庫的類型和它的設計方案,你有幾個選項。我們會研究這些問題來幫助你作選擇。
改用真正的數據庫:RDBMS怎么樣?即使是經過良好分區的平面文件,在處理大規模時間序列數據時也會力不從心,所以你也行會考慮使用某些類型的真正的數據庫。當第一次在數據庫中存儲時間序列數據時,使用所謂的星型模式(star schema)設計,并且將數據存放到RDBMS是個很誘人的選擇。在這樣一種數據庫設計中,核心數據存放在事實表(fact table),就像圖3-2展示的那樣。
圖3-2。將時間序列數據存放到RDBMS的一個事實表的設計。其中存放了時間(TIme列)、序列ID(Time series ID列)和數值(Value列)三列。序列的細節存放在維表(dimension table)中(這一對Time、Value是一個時間序列,但這個時間序列的細節,比如Value的含義是什么,存放在另一張表中,可以使用Time series ID去那個表查)。
在星型模式中,一個表存儲主要的數據,并且會引用其他表(維表)。該設計一個核心假定是維表要相對小巧,而且不常變動。圖3-2中的時間序列事實表里,唯一被引用的維表,就是存放這個時間序列詳細信息的維表,它的內容是表中數據(Value列)的含義。比如,如果我們的時間序列數據是從一個工廠的泵或者其他設備從采集的,我們會希望在獲取這個泵的多個維度的數據,如入口和出口的壓強和溫度、泵在不同頻段的震動和泵自身的溫度等。這其中的每個泵的每一個維度,都是一個多帶帶的時間序列,每個時間序列會有類似泵的序列號、位置、商標、型號等信息,這些信息都存放在維表中。
實際上一些應用程序已經使用像這樣的星型模式來存放時間序列數據了。我們在多數NoSQL數據庫中也可以使用這樣的設計。星型模式解決了有大量不同時間序列的問題,在數據點的規模達到數億甚至數十億的情況下也可以工作得很好。然而就像我們在第一章中看到的,即使是19世紀的航運數據也會產生上十億的數據點。在2014年,納斯達克證券交易所在過去三個月就會處理十億規模的交易量。記錄一個中型計算機集群的運行環境的話,一天會產生五億的數據點。
并且簡單地將這些數據存儲起來是一回事,對其檢索和處理就是另一回事了。現代的應用程序如機器學習系統甚至狀態顯示系統都需要每秒檢索和處理上百萬的數據點。
雖然RDBMS可以擴展到這些大小、速度需求的下限,但帶來的消耗和引入的復雜性會急劇上升。隨著數據規模的繼續增長,基于RDBMS的應用程序越來越不適合處理這樣規模的時間序列數據了。使用星型模式但轉而使用NoSQL數據庫的話,也沒有特別的幫助,因為這個問題的核心是星型模式帶來的,而不只是數據量。
使用寬表(wide table)的NoSQL數據庫星型模式所觸及的核心問題是每次測量都要使用一行。一個增加時間序列數據庫中數據檢索速度的技術是在每一行存儲很多數值。在一些像Apache HBase或者MapR-DB的NoSQL數據庫中,列的數量幾乎是不受限制的,只要任何特定一行中有數據的列的數量在幾十萬之內。這種能力可以被用來在每行存放多個數值。這樣做的話,數據點就可以被更高速地檢索,因為掃描數據的最大速度部分取決于需要掃描的行的數量,部分取決于待檢索數據點的總數,部分取決于待檢索數據的總量。減少行的數量,就大幅減少了一部分檢索開銷,檢索速度就提升了。圖3-3展示了使用寬表來減少時間序列數據行數量的一種方式。這個技術和OpenTSDB(一個開源的數據庫,我們會在第四章詳細講到)之中使用的默認表結構很相似。需要注意這樣的表設計,和那些需要提前定義詳細schema的系統的表設計是很不一樣的。有一件事情,如果你想把schema寫下來,那將異常龐大。
圖3-3,在NoSQL時間序列數據庫中一個寬表的使用。關鍵的結構是直觀的,在真正的應用程序中,使用的會是一個二進制的格式,但這樣順序的屬性是一樣的。
因為HBase和MapR-DB都是按照主鍵的順序來存儲數據,圖3-3中的鍵設計會導致每行包含一小段時間的數據在磁盤上是連續存儲的(因為Row key是按時間順序增長,HBase和MapR-DB是按列族存放數據的,Data values中的數據就會全部按照時間順序存放在磁盤上)。這個設計意味著檢索一個特定時間段的數據,涉及的主要是順序磁盤操作,就會比數據按行分散開的情況快很多。為了從這個表結構獲得性能優勢,每個時間窗口的采樣點要足夠富裕,這樣就可以減少行的數量,從而提升檢索速度。典型情況,時間窗口會被調整成每一行包括100-1000采樣點的樣子。
混合模式設計的NoSQL數據庫圖3-3中的表設計可以繼續改進,通過將一行中的所有數據壓縮成一個單一的被稱作blob的數據結構。Blob可以高度壓縮,所以需要從磁盤讀取的數據量就更少了。并且,如果使用HBase來存儲時間序列數據,每行只有一列的情況會減少了每列數據在HBase所使用的磁盤文件格式上的開銷,這樣又進一步提高了性能。圖3-4的混合式表結構中,一些行的數據已經被壓縮,另一些行沒有。
圖3-4。在混合模式設計中,行中的數據可以被存儲成一個單一的數據結構(blob)。注意實際壓縮的數據更可能是二進制的格式。這里使用JSON格式顯示是為了更容易理解。
圖3-3中的寬表格式可以進化成圖3-4的壓縮格式(blob樣式),只要確保那些被壓縮的行對應的時間窗口不會或者很少再有新增的數據。一般地,一旦時間窗口結束后,新的數據就不屬于這個時間窗口了,然后對這個時間窗口中數據的壓縮就可以開始了。因為在同一行中,已壓縮和未壓縮的數據可以共存,如果在對行壓縮之后,又有新數據過來了,可以再簡單地重新壓縮這一行,將新數據合并進來。
圖3-5展示的是概念上的混合式時間序列數據庫的數據流。
在后臺將數據從舊格式轉換成blob格式,會讓renderer(圖3-5中所顯示的)檢索數據并繪制出來的速度有質的提升。例如,在4個節點的MapR集群中,數據以壓縮格式存放的話,3千萬的數據點可以在大概20秒內被檢索、聚合、繪制出來。
圖3-5。混合式時間序列數據庫的數據流。數據從數據源到達catcher,然后被插入到NoSQL數據庫中。之后blob maker在后臺定時將數據壓縮成blob格式。數據由renderer檢索和格式化。
再進一步:blob直寫設計(The Direct Blob Insertion Design)壓縮舊數據依然存在一個性能瓶頸。因為數據以未壓縮的格式插入進來,每個數據點到來后都需要對行做一個更新來將數值插入到數據庫中。對行的更新操作會限制數據的插入速度到每個集群中的每個節點上只有每秒2萬個數據點。
另一方面,圖3-6中的blob直寫方式的數據流允許插入速度增加了大概1千倍。為什么blob直寫方式會帶來如此大的性能提升?基本的區別是blob maker被轉移到catcher和NoSQL時間序列數據庫之間了。使用這種方式,blob maker就可以從內存的數據緩存中直接讀取輸入的數據,而不是從存儲層的寬表中提取之前已經被寫入進去的數據。
基本的思想是數據到達后先被存放在內存中。這些數據同時也被寫入到日志文件中。這些日志文件就是圖3-6中的restart logs,它們是在Hadoop系統存放的平面文件,不是存儲層的一部分。Restart logs允許內存中的數據緩存被重新導入,在數據管道必須被重建的時候。
在正常操作中,在時間窗口的末尾,新的內存中數據結構會被創建,現在舊的內存中數據結構就可以用來創建壓縮的blob然后寫入數據庫了。一旦blob被寫入了,日志文件就被刪除了。這樣就無需像之前的混合設計中將數據兩次寫入。在圖3-5中的混合設計中,全部的輸入數據流都會逐點寫入到存儲層,然后再被blob maker讀取。讀的情況和寫大致一樣。一旦數據被壓縮成了blob,它又被寫入到數據庫中。相反地,在圖3-6的blob直寫設計的數據流中,完整的數據流只寫入到內存中(這樣速度很快),而不是寫入到數據庫中。數據在壓縮成blob之前不會被寫入到數據庫,所以寫入速度大幅提升。數據庫操作的次數從之前數據點的數量變成了blob的數量,很容易將次數減少到之前幾千分之一這樣的量級。
圖3-6。Blob直寫方式的數據流。Catcher在內存中暫存數據,并且將其寫入到restart logs中。Blob maker周期地從緩存中讀取數據,然后將壓縮成的blob寫入到數據庫中。這個設計的性能提升來自于renderer可以同時從內存和數據庫中獲取數據。
blob直寫方式的優勢是什么?一個真實世界的例子展示了它可以做什么。使用了這個架構,僅使用了一個10節點的MapR集群中的4個節點,就可以實現每秒往MapR-DB的表中插入超過一億的數據點。這些節點都有著很高的性能,其中每個節點有15個CPU核、大量內存和12塊高配置磁盤,但你使用多數硬件都可以達到這個性能級別的1/5到1/2。
這個性能級別聽起來是用來處理海量數據的,可能超出了我們所需要的處理能力,但是在第五章我們會展示為什么這樣的性能是非常有用的,即使是對那些相對溫和的應用程序。
為什么關系型數據庫不是很合適在這一點,詢問為什么一個關系型數據庫不能處理和使用混合模式的MapR-DB或者HBase所能承受的插入和分析數據的負載是公平的。當只有blob數據被插入而不使用寬表的情況,這個問題特別有趣,因為現代關系型數據庫通常支持blob或者array類型。
這個問題的答案是,關系型數據庫主要解決的問題不是提高插入和檢索數據的速度,它現在這樣運行是有其合理性的。使用關系型數據庫的主要原因也不是因為它有更好的性能。如果使用關系系型數據庫的blob格式存儲數據,就意味著需要放棄大多數其他好處。此外,SQL沒有提供一個好的抽象方法,來隱藏訪問blob格式數據中的細節。SQL不能用任何合理的方式來訪問這些數據,并且像多行事務等特性也完全派不上用場了。事務在這里還會成為問題,因為即使不使用,它也會成為一種消耗。一個關系型數據庫需要滿足多行事務的需求,這使它更難被擴展到多個節點上。盡管使用如Oracle的高成本數據庫可以在單個節點實現很高的性能。而使用類似Apache Hbase或者MapR-DB的NoSQL數據庫,你可以簡單地通過加硬件的方式實現更高的性能。
為自己用不到的特性買單的模式在一些高性能系統中是存在的。為了可擴展而犧牲傳統關系型數據庫的一些固有特性也是常見的,但即使你這樣做了,還是得不到自己想要的擴展性。在這種情況,使用類似HBase或者MapR-DB的替代方案是有實質上的好處的,因為你同時得到了性能和可擴展性。
混合模式設計:我可以從哪得到一個?這些寬表、blob混合的表設計是非常誘人的。它們所許諾的巨大性能級別令人興奮,而且它們能運行在有容錯機制、基于Hadoop的系統(比如MapR),從運維的角度看也是很吸引人的。這些新方法都不是空想,它們已經被構建出來,并且被證明有著驚人的結果。然而我們在這里呈現的,很大程度都是概念上的東西。有真正已經實現的嗎?下一章我們會講到如何使用OpenTSDB(一個開源時間序列數據庫工具)和幾個開源的MapR擴展,來實現這些新的設計。結果是利用本章所描述的概念以達到高性能的時間序列數據庫是現代使用場景所需要的。
付費解決 Windows、Linux、Shell、C、C++、AHK、Python、JavaScript、Lua 等領域相關問題,靈活定價,歡迎咨詢,微信 ly50247。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/17462.html
摘要:后端服務將后端服務視為可拔插的資源后端服務是一種在應用在網絡上正常運行時消費的任意一種服務。一份因子應用的部署可以不經過任何代碼修改將本地數據庫替換成第三方的服務如。因子應用將這些數據庫看做可拔插資源,在部署時是松耦合的。 IV 后端服務 將后端服務視為可拔插的資源 后端服務是一種在應用在網絡上正常運行時消費的任意一種服務。包括數據庫(如MySQL或CouchDB),消息/隊列系統(如...
摘要:文章來自原文在給開發者的源碼系列的第三篇文章,我們打算擴展上一篇文章來幫助理解內部是怎么工作的。進入在的核心代碼中,變量被稱為。要轉換一個為值,就調用函數。有了這個東西,我們可以看到函數馬上調用函數。 文章來自:http://www.hoohack.me/2016/02/12/phps-source-code-for-php-developers-part3-variables-ch...
摘要:前言這將是一個分為兩部分,內容是關于在生產環境下,跑應用的最佳實踐。潛在的攻擊者可以通過它們進行針對性的攻擊。 前言 這將是一個分為兩部分,內容是關于在生產環境下,跑Express應用的最佳實踐。第一部分會關注安全性,第二部分最會關注性能和可靠性。當你讀這篇文章時,假設你已經對Node.js和web開發有所了解,并且對生產環境有了概念。 概覽 生產環境,指的是軟件生命循環中的某個階段。...
摘要:如果期間有其它線程更新了,則會先拿到新的值重新運算一次多運算的競爭條件這些運算符成功避免了單運算中的競爭條件。 作者:Lin Clark 譯者:Cody Chan 原帖鏈接:Avoiding race conditions in SharedArrayBuffers with Atomics 這是圖解 SharedArrayBuffers 系列的第三篇: 內存管理碰撞課程 圖...
閱讀 3648·2021-10-09 09:58
閱讀 1188·2021-09-22 15:20
閱讀 2495·2019-08-30 15:54
閱讀 3510·2019-08-30 14:08
閱讀 887·2019-08-30 13:06
閱讀 1818·2019-08-26 12:16
閱讀 2679·2019-08-26 12:11
閱讀 2508·2019-08-26 10:38