influxdb无法实现关联表_双汇:从棘手的InfluxDB+Redis到TDengine
雙匯發展多個分廠的能源管控大數據系統主要采用兩種技術棧:InfluxDB/Redis和Kafka/Redis/HBase/Flink,對于中小型研發團隊來講,無論是系統搭建,還是實施運維都非常棘手。經過對InfluxDB/Redis和TDengine大數據平臺的功能和性能對比測試,最終將TDengine作為實施方案。
1. 項目背景
基于雙匯發展對能源管控的需求,利用云平臺技術以及電氣自動化處理手段,對雙匯發展的一級、二級、三級能源儀表進行整體改造,實現儀表組網,進一步通過邊緣網關進行能源在線監測數據的采集,并上報至云平臺,建立統一能源管理信息化系統,實現能源的實時監控、報表統計、能源流向分析與預測,降低企業單位產品能源消耗,提高經濟效益,最終實現企業能源精細化管理。
2. 總體架構
能源管控平臺基于私有云構建,包括完整的IaaS層、PaaS層和SaaS層,而能源采集系統作為管控平臺中最為重要的一環,采用TDengine作為核心數據引擎,通過Restful接口進行儀表在線數據插入,并實現大規模時序數據的高效穩定存儲,同時,也為能源管控應用層提供實時數據查詢、歷史聚合統計、流計算和訂閱服務等功能,實現能源地圖監控、能耗預警、能源流向預測和能源互聯綜合決策,具體架構如下圖所示。
圖1 能源采集系統架構
3. TDengine關鍵應用
3.1 Connector選擇
本項目數據采集最關鍵的環節,就是將訂閱到的MQTT數據插入到TDengine中,于是也就涉及到了TDengine連接器的選擇,我們平時項目中java使用居多,而且JDBC的性能也相對較強,理論上,應該選擇JDBC API,但最終選擇了RESTful Connector,主要考慮以下幾點:
1)簡潔性
毫無疑問,RESTful通用性最強,TDengine直接通過HTTP POST 請求BODY中包含的SQL語句來操作數據庫,而且TDengine本身作為時序數據庫并不提供存儲過程或者事務機制,基本上都是每次執行單條SQL語句,所以RESTful在使用上很簡便。
2)可移植性
本項目的Java應用都是部署在Kubernetes中,所以向TDengine插入數據的Java應用需要容器化部署,而之前了解到,JDBC需要依賴的本地函數庫libtaos.so文件,所以容器化部署可能較為麻煩,而RESTful僅需采用OKHttp庫即可實現,移植性較強。
3)數據規模
本項目數采規模不大,大約每分鐘7000條數據,甚至后續數采功能擴展到其他分廠,RESTful也完全滿足性能要求。
但總體來講,JDBC是在插入與查詢性能上具有一定優勢的,而且支持從firstEp和secondEp選擇有效節點進行連接(類似于Nginx的keepalive高可用),目前TDengine版本發布情況上看,JDBC的維護與提升也是重中之重,后續項目也可能會向JDBC遷移。
3.2 RESTful代碼實現
1)ThreadPoolExecutor線程池
訂閱EMQX和RESTful插入TDengine的代碼寫在了同一個java服務中,每接收到一條MQTT訂閱消息,便開啟一個線程向TDengine插入數據,線程均來自于線程池,初始化如下:
ExecutorService pool = new ThreadPoolExecutor(150, 300, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue(100), Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardOldestPolicy());線程池采用基于數組的先進先出隊列,采用丟棄早期任務的拒絕策略,因為本次場景中單次RESTful插入數據量大約在100~200條,執行速度快,遲遲未執行完極可能是SQL語句異常或連接taosd服務異常等原因,應該丟棄任務。核心線程數設為150,相對較高,主要為了保證高峰抗壓能力。
2)OKHttp線程池
在每個ThreadPoolExecutor線程中,基于OKHttp庫進行RESTful插入操作,也是采用ConnectionPool管理 HTTP 和 HTTP/2 連接的重用,以減少網絡延遲,OKHttp重點配置如下:
public ConnectionPool pool() { return new ConnectionPool(20, 5, TimeUnit.MINUTES);}即最大空閑連接數為20,每個連接最大空閑時間為5分鐘,每個OKHttp插入操作采用異步調用方式,主要代碼如下:
public void excuteTdengineWithSqlAsync(String sql,Callback callback) { try{ okhttp3.MediaType mediaType = okhttp3.MediaType.parse("application/octet-stream"); RequestBody body = RequestBody.create(mediaType, sql); Request request = new Request.Builder() .url(tdengineHost) .post(body) .addHeader("Authorization", "Basic cm9vdDp0YW9zZGF0YQ==") .addHeader("cache-control", "no-cache") .build(); mOkHttpClient.newCall(request).enqueue(callback); } catch (Exception e) { logger.error("執行tdengine操作報錯:"+ e.getMessage()); }}3)Java打包鏡像
長期壓力測試顯示,每秒執行200次RESTful插入請求,單次請求包含100條數據,每條數據包含5組標簽,Java服務內存穩定在300M~600M。而且上述模擬規模僅針對單個Java應用而言,在Kubernetes可以跑多個這樣pod來消費不同的MQTT主題,所以并發能力完全夠用。打包鏡像時,堆內存最大值設為1024MB,主要語句為:
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-XX:MaxRAM=2000m","-Xms1024m","-jar","/app.jar"]3.3 性能測試
1)RESTful插入性能
按照3.2小節中的RESTful代碼進行數據插入,Java程序和TDengine集群均運行在私有云中,虛擬機之間配備萬兆光纖交換機,Java程序具體如3.2小節所示,TDengine集群部署在3個虛擬機中,配置均為1TB硬盤、12核、12GB(私有云中CPU比較充裕,但內存比較緊張),經過大約三周的生產環境運行,性能總結如下:
表1 生產環境下RESTful插入性能測試
生產環境下,單條插入性能極高,完全滿足需求,當然前期也進行過稍大規模的插入場景模擬,主要是基于2.0.4.0以后的版本,注意到2.0.4.0之前的TDengine版本RESTful的SQL語句上限為64KB。模擬環境下,RESTful插入性能非常優秀,具體如下表所示。
表2 模擬環境下RESTful插入性能測試
2)RESTful查詢性能
使用RESTful進行SQL查詢時,性能也是非常好,目前真實生產環境中,數據總量為800萬,相對單薄,所以查詢性能測試在模擬環境下進行,在8億數據量下,LAST_ROW函數可以達到10ms響應速度,count、interval、group by等相關函數執行速度均在百毫秒量級上。
3.4 實施方案
本項目針對雙匯發展下屬的6個分廠(后續會繼續擴充)進行能源數據采集,大約1200多塊儀表(后續會繼續擴充),每塊儀表包括3至5個采集標簽,采集頻率均為1分鐘,數據接入規模不大。六個廠各自有獨立的租戶空間,為了方便各自的時序數據庫管理,同時也方便各廠間的聚合查詢(目前六個分廠均從屬雙匯發展總部),所以各分廠分別建立超級表,每個超級表包括4個tag,分別為廠編號、儀表級別、所屬工序和儀表編號,具體超級表建表情況如下圖所示。
主要用到的集群包括TDengine集群、EMQX集群和Redis集群,其中Redis集群在數據采集方面,僅僅用于緩存儀表連接狀態,其重點在于緩存業務系統數據;EMQX集群用于支撐MQTT數據的發布與訂閱,部署在Kubernetes中,可以實現資源靈活擴展;TDengine集群部署在IaaS虛擬機中,支持大規模時序數據的存儲與查詢。
表3 集群配置信息
按照TDengine官方的建議,“一個數據采集點一張表,同一類型數據采集點一張超級表”,我針對不同分廠的水表、電表、蒸汽表和燃氣表分別建立的超級表,每個儀表單獨建表,保證每張表的時間戳嚴格遞增。在實踐TDengine的過程中,重點體會如下:
1)集群搭建門檻低
TDengine集群安裝部署非常便捷,尤其相比于其他集群,僅需要簡單的配置就可以實現生產環境級的搭建,官方文檔也比較豐富,社區活躍,也大為降低了后續運維成本。
2)插入與查詢效率極高
TDengine的插入與查詢性能極高,這點在實際運行時也深有感觸,用last_row函數查詢儀表最新數據,基本上可以達到毫秒級,在幾十億級的數據上進行聚合查詢操作,也可達到百毫秒級,極大提供了系統的響應速度。
3)全棧式時序處理引擎
在未使用TDengine之前,我們主要采用InfluxDB/Redis和Kafka/Redis/HBase/Flink兩種技術棧,對于我們中小型研發團隊來講,無論是系統搭建,還是實施運維都非常棘手。但是使用TDengine后,一切都簡化了,TDengine將數據庫、消息隊列、緩存、流式計算等功能融合一起,以一種全棧的方式,為我們的大數據系統帶來了便捷。技術方案的對比如表4所示。
注:方案一為InfluxDB/Redis,方案二為Kafka/Redis/HBase/Flink,方案三為TDengine
表4 數據采集方案對比
從表4的對比方案中可以看出,TDengine(方案三)是有著很大的優勢,尤其在開源EMQX Broker的支持上也非常好(主要依賴于Restful接口),其他的例如Kafka和InfluxDB只能和企業版EMQX集成;在數據插入和查詢效率方面,上述三種方案關鍵在于TDengine、HBase和InfluxDB的對比,官網有非常詳細的測試報告,TDengine也是有絕對優勢,這里就不過多敘述。所以選擇TDengine是勢在必行的。
3.5 技術期望
在時序數據庫性能方面,TDengine有著很大的優勢,并且也集成了消息訂閱和流計算功能,可以說在中小型物聯場景下,是無需部署Kafka和Flink的。當然個人理解TDengine不是為了完全取代Kafka和Flink而生的,尤其是在大型云服務項目中,更多是共存。
但是在邊緣端,TDengine憑借著極低的資源占用率和優秀的時序處理性能,將會產生更大的能量,期望能徹底集成邊緣流計算和MQTT broker等功能,擴充Modbus、OPC-UA等常見工業協議支持,向下連接工業設備或者物聯設施,向上和邊緣Kubernetes生態(如KubeEdge、K3S等)協同,或者直接和云中心協同。
3.6 系統運行界面
項目重點是能耗統計,而在線采集到TDengine里的數據都是累計量,所以在計算能耗時,需要在不同的超級表執行按表分組、按時間周期采樣的查詢,類似下面語法:
select last(累計列) as max_val,first(累計列) as min_val from [超級表名] where [標簽欄相關過濾] and ts>=now-10h INTERVAL(1h) group by [儀表編號] ;得益于TDengine的極佳性能,基本能保證不超過百毫秒的訪問延時,下面是一些相關的PC端、移動端界面(我們移動端是用H5做的,為了直接能跑在Android和iOS上)。
寫在最后
其實從2019年開始就一直在關注TDengine,也看了很多陶總的演講,受益匪淺,尤其在今年8月份,TDengine進行了集群版開源,也正好準備啟動能源數據采集項目,所以果斷采用TDengine作為核心時序引擎,目前也是收獲了非常的效果。本次項目實施過程中,尤其感謝濤思數據的蘇曉慰工程師,多次協助解決TDengine相關的實施問題。計劃在后續其他項目也也會繼續推廣TDengine,同時也愿意為一些商業版功能付費,支持國產,支持濤思。
作者介紹于淼,學歷碩士,副研究員,主要從事MES系統研發以及智能制造相關理論和標準研究,主要研究方向:數字工廠使能技術、制造執行系統關鍵技術和智能制造標準體系等,參與國家級項目及企業項目十余項,包括國家重點研發計劃以及國家智能制造專項等。
總結
以上是生活随笔為你收集整理的influxdb无法实现关联表_双汇:从棘手的InfluxDB+Redis到TDengine的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android笔记之Snackbar的基
- 下一篇: mysql 两列数据互换_mysql 实