您好,登錄后才能下訂單哦!
本篇內容介紹了“Apache TDB性能優化的知識點有哪些”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
關于存儲組
現在每個存儲組是一個相對獨立的引擎,而且讀寫鎖是存儲組級別的。因此把存儲組從1改到10,讀寫基本能增速8倍。單個 IoTDB 實例推薦設置 CPU 核數個存儲組。存儲組越多,并行度就越高。我們之后打算把鎖粒度下放到設備層。
設備
設備這個概念沒有在 SQL 語句里顯示的定義出來,而是在服務器端處理時候默認將倒數第二層設置為設備,導致大家容易忽略這個概念。先說一下設備影響什么。
(1)區分順序數據 和 亂序數據是以設備為粒度的。舉個例子,假如一個設備在內存里寫了時間戳 1-10 的數據(不論寫哪些測點,時間戳都會算到這個設備頭上),落盤了,再寫時間戳<=10 的數據,這些數據就會被當做亂序數據緩存并落盤。
(2)設備粒度的時間范圍索引。對于每個 TsFile 文件,會構造設備粒度的索引在內存里,假如所有設備都活躍,N 個 TsFile,D 個設備,就有 N*D 條索引。百萬級設備的索引內存會吃不消。這個東西我們會在一兩個版本內改掉。
再說一下怎么設計建模來控制設備數。對于實際應用設備和傳感器層次比較簡單的情況比較好說,設備下直接是傳感器層,一般不會建錯。對于設備下有多層結構的就要注意了。
比如我一個設備下有10個傳感器(s1,s2,...,s10),每個傳感器采集10個時間序列的數據(f1,f2,...f10)。這時候很容易建成 root.xxx.device.s1.f1 這種。當你建成這種時候,你以為的 device 就不再是你以為的 device 了,實際的device 變成了 root.xxx.device.s1 。 實際 device 數量就是你以為的 10 倍了。
怎么辦嘞,如果設備下的子設備不多,這樣建模也沒啥問題,只要你心里清楚系統中實際有多少個設備就行,這樣溝通不會出現偏差,便于以后排查問題。
如果子設備非常多,可以把設備后的那幾層壓成一層,比如 root.xxx.device.s1_f1 。由于我們是以 . 作為分隔符的,這樣 s1_f1 就變成 1 層了。 實際的設備還是 root.xxx.device。
Measurement 定義
Measurement 也就是最后一層的測點。假如一個測點是 INT32 或者 INT64 類型的,而且大部分時間這個數據的值都一樣,沒什么變化,這時候用 RLE 編碼就很好。可以大大節省磁盤空間,當然刷盤速度也會變快。壓縮方式開著 SNAPPY 就挺好。
Tag & Attribute
0.10.0 引入的這兩個概念,容易分不清這兩個有啥區別。 雖然都是 key-value 類型的屬性。但是 Tag 是可以反向查詢時間序列的元數據的,假如有個 tag 的 key 是 owner,就可以用 show timeseries where owner=Thanos 查滅霸擁有的時間序列。Tag 常駐內存,有Tag到時間序列的索引。
Attribute 就是普通屬性了,比如有個屬性是 description="this is my series"。這些屬性只能是給定時間序列的路徑順帶展示一下,輔助人查看的。
因此,要根據實際需求進行區分,那些需要做反向查詢的屬性,就建成 tag,其他的就搞成 attribute 就行了。
讀寫優化
讀和寫關系密切,數據的寫入和參數配置會影響查詢性能。
寫入接口
以 0.10 為例,先同類比較,insertRecords 接口肯定比 insertRecord 接口要快,這個類似 JDBC 的 executeBatch 和 execute 的區別,節省了網絡通信次數。同理,insertTablets 比 insertTablet 要快,createMultiTimeseries 也比 createTimeseries 要快。
進一步,insertRecords 方法我們提供了兩種,一種是傳 Object 的 value,一種是傳 String 的 value。如果客戶端能獲取 value 的類型,建議用 Object 的,會比 String 的快 25% 左右。
跨類比較的話,如果不考慮客戶端做格式轉化的耗時,insertTablet 比 insertRecords 要快很多,可能 8 倍以上,節省了很多對象封裝的耗時,batch size 1000左右就可以。
insertTablet 這個接口默認是沒排序的,如果你能保證一個 Tablet 數據的時間戳是非遞減的,那就可以多加一個 sorted 為 true 的參數。就節省了客戶端的排序。
在統計耗時的時候,還需要注意客戶端做格式轉化的耗時,可以把接口參數構造的時間和執行的時間分開統計。
查詢接口
查詢接口比較簡單,Session 默認的 hasNext 和 next 會返回 RowRecord 結構,這個結構不一定大家都需要,可以用 SessionDataSet 的 iterator 得到一個迭代器,然后通過類似 JDBC 的接口去得到原始數據,避免很多沒用的對象生成。
順序寫入
對于時序數據庫,時序是一個很重要的概念,最好不要亂來。IoTDB 支持數據的亂序寫入,但是亂序數據會影響查詢性能,主要是對于聚合查詢,原理是亂序數據會讓預計算的統計信息失效,把聚合查詢降維打擊到讀原始數據。
正常情況下,有個幾倍的亂序都沒問題,但是如果往一個時間段寫入了過多(幾萬倍)的亂序數據,查詢時候有可能爆內存。舉個例子,內存緩沖區寫了時間戳1-10的數據落盤了,然后又寫了 9999 遍 1-10 的緩沖區,這樣磁盤上就有 1 萬個時間戳是 1-10 的數據塊。查詢時候需要將 1萬 個數據塊都讀出來進行合并,內存占用就比較大了。
面對這種場景,我們會后臺做數據整理來處理亂序(在0.9引入的merge,但是0.9版本有bug,0.10修掉了,但是先默認關掉了,會在0.11重新開放merge),但是如果能在客戶端避免亂序,就盡量寫入的時候避免掉。一個設備就按遞增的順序寫入。
如果前邊接了 kafka,最好注意一下,把設備 id 作為分區粒度,這樣一個設備的數據都會發送到一個分區里,消費的時候同一個分區也能保證順序。
內存緩沖區
先介紹一下每個序列在內存里能緩存多少個點的怎么算的,用 memtable 大小除以序列數,再除以每個點的大小,比如long類型就是 16字節(8字節時間戳,8字節值),float是12字節。
memtable 的大小可以從日志里看到,搜 reaches,大概日志就是 the memtable size xxx reaches the threshold。如果配置文件里的 enable_parameter_adapter 沒有改為 false,這個 memtable 大小就不固定,隨著注冊的序列數量調整的。
內存緩沖區在一定范圍內盡可能大有利于讀寫。平均每個序列能緩沖100萬點以下是比較好的。但是不建議太大,查詢時候會臨時排序,如果內存中數據點過多,比如千萬級,查詢時候內存排序會占個十幾秒。
為了避免這個問題,0.10.0 里加了個參數,avg_series_point_number_threshold ,默認是 10000,也就是內存緩沖區中每個序列最多緩存這么多點就會刷盤,這個默認參數沒給好,可以改成50萬或者100萬。
memtable_size_threshold 這個參數越大,寫入速度快,一般在幾百M到一兩G左右。不要設置的過小,比如幾M,會嚴重影響寫入速度。在設置這個參數時候需要注意不要超內存限制,調這個參數之前需要保證 enable_parameter_adapter 改為 false。
多數據目錄
數據庫的瓶頸在磁盤IO,簡單的提升磁盤IO能力的就是配置多盤。IoTDB 的數據目錄可以在 data_dirs 參數配置,用逗號分隔多個目錄。可以每塊盤一個目錄。在寫數據的時候會到這幾個盤里找最空閑的寫。
客戶端優化
剛才說了存儲組級別的鎖,對于同一個存儲組的N個寫線程,這N個寫線程都會搶一把鎖,一個存儲組對應不超過50個客戶端比較好,寫線程過多會導致過多的鎖競爭。
線程池 SessionPool 的容量,一般搞個服務器 CPU 核數就可以了,不要過多。
客戶端的內存,數據的生產和消費速率也可以監控起來,避免提交的任務積壓過多,如果客戶端內存滿了,會出現一個現象:客戶端發送請求到服務器,服務器執行和返回很快,但是客戶端接收結果會很慢。
容易爆內存的點
select * from root 這個語句在序列過多時候最好不要做,這個操作會把整個庫當做一張表,一下查出來所有列的一批數據,容易爆內存,我們會在0.11版本加個檢查,及時拒絕。
show timeseries 在 0.10 及以前的版本會把系統所有序列在內存里拷貝一遍傳給客戶端,如果序列過多,最好指定前綴做個過濾。或者 show child paths 一層一層往下查。
時間序列過多(億級),元數據可能爆內存,可以按照一條時間序列 200字節估計一下,大概1千萬序列會占2G元數據(就是那個元數據樹)。
“Apache TDB性能優化的知識點有哪些”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。