工業領域基於MongoDB設計時序數據庫及應用

首先什麼是時序數據庫算法

工業領域大部分都是使用的實時數據庫,對於物聯網到來的今天,傳統的實時數據庫已經不能知足如今的需求。他們有不少共同點:數據庫

  • 都帶有時間戳
  • 按時間順序生成的
  • 大多爲結構化數據
  • 採集頻率高
  • 數據量大

實時數據庫通常具有一下特定:緩存

高速寫入的能力:工業實時數據庫一般會對寫入的速度有很高的要求。以流程工業的場景爲例,每一個環節都會設置傳感器,每一個傳感器的採集頻率都很高,因此寫入的併發量會特別大,有時甚至會要求每秒上百萬的測點。因此除了對軟件的要求以外,也會選用一些高性能的服務器。服務器

快速查詢的能力:查詢的需求分爲兩塊,一是要響應實時的查詢請求,用於及時反映系統的狀態;二是歷史數據也要能快速被查詢,因爲歷史數據的量很是大,在查詢時須要對特定時間段的數據作聚合,須要作到即便是查一全年的數據狀況,也能很快的反應出來。數據結構

超強數據壓縮能力:上面提到監控數據會被存儲很長時間,5年甚至是10年都是常有的事,在存儲容量有限的狀況下,就須要對數據作必定的壓縮,一般壓縮方式會分紅無損壓縮和有損壓縮,相比而言,有損壓縮的壓縮比會更大一些,有時甚至會達到1:30-40,這就須要設計合理的算法來保留數據中的細節,使數據在還原後仍能保留重要的特徵。架構

積累豐富的工具:傳統的實時數據庫的解決方案通常是從採集開始到直可視化的一整套系統,有多年積累造成的豐富的工具包,好比會積攢上百種的協議,或者各類場景的數據模型,這些都是工業軟件的重要競爭力。併發

追求極致穩定:工業上對軟件的穩定性要求特別高,除了用主備來保證高可用外,徹底由軟件的質量來保證程序的持續運行,工程師會自豪地拍胸脯保證軟件跑十年也不會出錯。app

時序數據庫特色:數據庫設計

1. 單條數據不會很長,可是數據量很大分佈式

2. 它們都帶有時間戳,且按順序生成

3. 數據大部分都是結構化的,用於描述某個參數在某個時間點的特徵

4. 寫入的頻率會比查詢的頻率高不少

5. 已存儲的數據不多有更新的需求

6. 用戶會更關心一段時間的數據特徵,而不是某一個時間點

7. 數據的查詢分析大多基於某一個時間段或者某個數值範圍

8. 須要進行統計和可視化的展現

隨着IoT和工業互聯網帶來的新一波風口,一系列新的生產方式、組織方式和商業模式開始涌現。物聯網技術逐步滲透工業,不斷增加的傳感器、飆升的數據量,以及更高的大數據分析需求對實時數據庫傳統的技術架構提出了挑戰。有些問題是須要直面的:

擴展性遇到瓶頸。傳統的技術架構雖然能保證單機具有極高的性能,也能夠經過增長機器使性能線性擴展,可是不能像分佈式系統那樣實現動態靈活的擴容和縮容,須要提早進行規劃。當業務升級須要系統擴容時,老架構的擴展性就很難知足需求了。

沒法和大數據生態對接。數據採集的最終目的是被理解和使用,大數據產業中對於海量數據的存儲分析已經有很成熟的方案,不管是hadoop仍是spark的生態圈,都面臨着新老技術的對接。不少工業企業由於想使用新的大數據分析技術,不得不對現有的系統進行升級或是替換。

價格高昂。傳統的工業實時數據庫解決方案價格都十分昂貴,通常只有大型企業能忍痛接受。可是隨着新技術新理念的普及,更多的中小企業也意識到數據的重要性,但考慮到資金投入,會傾向於尋找價格更低廉的方案。

這時候來自互聯網你們庭的時序數據庫方案就展示出了一些先天優點,好比:

分佈式架構的自然優點:傳統的實時數據庫可能是主備的部署架構,一般要求有較高配置的機器,來追求單機極致的性能;同時,在穩定性方面,會對運行軟件的穩定性作極高的要求,徹底由高質量的代碼來保證運行的穩定;因爲存儲容量有限,也會要求超高的數據壓縮比。可是時序數據庫的分佈式架構,使得系統可以輕鬆的進行水平擴展,讓數據庫再也不依賴昂貴的硬件和存儲設備,以集羣自然的優點來實現高可用,不會出現單點的瓶頸或故障,在普通的x86服務器甚至是虛擬機上均可以運行,大大下降了使用成本。

更靈活的數據模型:傳統的實時數據庫因爲工業場景的特殊性,常使用的是單值模型,一個被監控的參數稱爲一個測點,在寫入時會對每個測點建一個模型,好比一個風機的溫度指標算一個測點,十個風機的十個指標就是100個測點,每一個測點會附帶描述信息(名稱、精度、數據類型、開關量/模擬量等)查詢的時候就會針對每一個測點去查詢數值。單值模型的寫入效率會很高。

接下來就是我本身基於MongoDB設計時序數據庫架構的思路:(沒有一個架構設計能適合全部的應用場景規範。不管哪一種架構,都須要權衡利弊)

對每一個數據Tag,創建一個Collection  以PK命名 以下圖:

數據機構設計:

_id:MongoDB Document pk

Count:Document 數據大小

Data:數據     s:時間戳(差值:能夠有效減數據大小)v:數值 

StartTimeStamp:起始時間

LastTimeStamp:結束時間

能夠看到數據存儲在Data裏面 隨着數據量不斷擴大 Data 線性增加 能夠對Data數據進行簡單優化:

對 s v 數據類型進行設計可有效減小磁盤空間的佔用 s 時間戳 利用差值存儲 4byte 便可 根據須要存儲的數據類型 v float類型 也是 4byte 知足大部分應用場景   這樣 每一個數據 僅佔8byte 磁盤空間  固然還能夠進一步優化及壓縮 之後再說。

按照數據數量分組分段(Document)

分段數據具備顯着的優點。基於時間的分段將整整一段時間的數據存儲到單個文檔中。在諸如 IoT 的基於時間的應用中,傳感器數據能夠以不規則的間隔生成,而且一些傳感器能夠提供比其餘傳感器數據更多的數據。在這些場景中,基於時間的分段可能不是架構設計的最佳方法。另外一種策略是基於大小的分組。

經過基於大小的分組,咱們根據必定數量的發射傳感器事件或一成天(以先到者爲準)圍繞一個文檔設計咱們的模式。

要查看基於大小的存儲分區,請考慮存儲傳感器數據並將存儲區大小限制爲每一個文檔3600個事件或一天(以先到者爲準)的方案。注意:3600限制是任意數字,能夠根據須要進行更改,無需更改應用程序或模式遷移。

以下圖:

數據庫設計完畢,目前場景下可知足數據的存儲需求。但 IoT場景下有大量的傳感器及信息要存儲對於吞吐量有很大的要求。通過測試MongoDB 寫入數據速度並非很快 大體5000條/秒(沒仔細測過,不一樣硬件配置 數值也可能不一樣),對於工業場景寫入數據量也不算很大,這樣須要對時序數據庫增長緩存隊列。能夠採用Kafka,這裏咱們本身設計一套簡單的消息隊列讓其知足萬級數據量的隊列存儲。

緩存隊列設計以下:

      00 01 02 03   04 05 06 07
PK 0000-0000 FF FF FF FF   FF FF FF FF
                   
0000-03FF                  
var0  meta 0000-0400 head   tail
DATA 0000-0408 data.k   data.v
0000-0418 data.k   data.v
  data.k   data.v
0001-03FF data.k   data.v
var1 meta 0001-0400 head   tail
DATA 0000-0408 data.k   data.v
  data.k   data.v
  data.k   data.v
0002-03FF data.k   data.v
var2 meta 0002-0400 head   tail
DATA 0000-0408 data.k   data.v
  data.k   data.v
  data.k   data.v
0003-03FF data.k   data.v
                       
var1023 meta 03FF-0400 head   tail
DATA 03FF-0408 data.k   data.v
  data.k   data.v
  data.k   data.v
03FF-03FF data.k   data.v

利用MomeryMappedFile既能保證隊列存儲在內存中,又能防止數據丟失問題產生。打開一個文件,映射到內存一塊區域。灰色區域用來存儲Tag的PK,來標識數據。每一個數都有必定大小(可設置)的存儲空間, 其中黃色區域是數據的mate 用來存儲隊列head(隊列第一個的地址)tail(隊列最後一個的地址),綠色區域DATA用來存儲有效數據 根據以前設計的數據結構data.k 存儲時間戳 data.v 存儲數值。

隊列(FIFO)的基本原理是:

入隊時:把入隊數據寫到tail後面的地址  並更新meta中tail的地址。須要增長一個判斷是否到達內存空間的最後一個地址若是當前tail是最後一個地址,則將數據寫到第一個地址並把meta中tail更新到第一個地址。若是tail中的地址正好等於head中的地址,則表示數據空間已滿,實現FIFO時head須要更新到下一個地址。

出隊時:讀取當前head地址中的數據,並更新head地址到下一個地址。須要增值一個判斷head地址=tail地址 則隊列爲空,不作任何操做。

以上是內存映射隊列的一個基本思路,還須要考慮鎖和併發問題。目前用netcore2.1實現 並已經在項目中應用。

這樣一個簡單的時序數據庫,就設計完成了。固然還有不少不足,也沒有通過大量的測試。

相關文章
相關標籤/搜索