實時湖倉技術選型,企業如何借實時湖倉贏在“數據驅動”時代

来源:https://www.cnblogs.com/DTinsight/archive/2023/12/20/17915942.html
-Advertisement-
Play Games

在之前三期的實時湖倉系列文章中,我們從業務側、產品側、應用側等幾個方向,為大家介紹了實時湖倉方方面面的內容,包括實時湖倉對於企業數字化佈局的重要性以及如何進行實時湖倉的落地實踐等。 本文將從純技術的角度,為大家解析實時湖倉的存儲原理以及生態選型,為企業建設實時湖倉給出技術方面的參考意見。 實時湖倉能 ...


在之前三期的實時湖倉系列文章中,我們從業務側、產品側、應用側等幾個方向,為大家介紹了實時湖倉方方面面的內容,包括實時湖倉對於企業數字化佈局的重要性以及如何進行實時湖倉的落地實踐等。

本文將從純技術的角度,為大家解析實時湖倉的存儲原理以及生態選型,為企業建設實時湖倉給出技術方面的參考意見。

實時湖倉能解決什麼問題?

大部分人可能都會有這樣一個疑問,企業為什麼要引入實時湖倉?

如下圖所示,引入實時湖倉可以降低運維難度,實現低成本統一存儲、中間狀態可查,以及提升開發效率。

file

實時湖倉能夠在低成本存儲的同時,極大降低數據指標的時延,從傳統的 T+1 的時延,降低到到分鐘級。

file

實時湖倉解決方案,利用湖存儲的特性和 Flink 的流批計算能力,統一存儲和計算,解決業務對數據時效性高要求的需求。

file

實時湖倉存儲原理

下文將從大數據常用技術和大數據存儲常用理論兩個方面為大家解析實時湖倉的存儲原理。

大數據常用技術分析

Hive 事務表

Hive 是基於 Hadoop 的一個數據倉庫工具,用來進行數據提取、轉化、載入,這是一種可以存儲、查詢和分析存儲在 Hadoop 中的大規模數據的機制。Hive 數據倉庫工具能將結構化的數據文件映射為一張資料庫表,並提供 SQL 查詢功能,能將 SQL 語句轉變成 MapReduce 任務來執行。

file

file

ACID 事務表中會包含三類文件,分別是 base、delta 以及 delete。

file

Hbase——LSM-Tree模型

LSM-Tree,即日誌結構合併樹(Log-Structured Merge-Tree)是 Google BigTable 和 HBase 的基本存儲演算法。HBase 是基於 LSM-Tree 模型實現的,所有的數據寫入操作都首先會順序寫到日誌 HLog,再寫入 Memstore。當 MemStore 中數據達到指定大小之後再將這些數據批量寫入磁碟,生成一個新的 HFile 文件,這個動作叫 Memstore flush

file

LSM 樹架構有如下幾個非常明顯的優勢:

· 這種寫入方式將一次隨機 IO 寫入轉換成一個順序 IO 寫入(HLog 順序寫入)加上一次記憶體寫入(MemStore 寫入),使得寫入性能得到極大提升

· HFile 中 KeyValue 數據需要按照 Key 排序,排序之後可以在文件級別根據有序的 Key 建立索引樹,極大提升數據讀取效率,然而 HDFS 本身只允許順序讀寫,不能更新,因此需要數據在落盤生成 HFile 之前就完成排序工作,MemStore 就是 KeyValue 數據排序的實際執行者

· MemStore 作為一個緩存級的存儲組件,總是緩存著最近寫入的數據,對於很多業務來說,最新寫入的數據被讀取的概率會更大,最典型的比如時序數據,80%的請求都會落到最近一天的數據上,實際上對於某些場景,新寫入的數據存儲在 MemStore 對讀取性能的提升至關重要

· 在數據寫入 HFile 之前,可以在記憶體中對 KeyValue 數據進行很多更高級的優化。比如,如果業務數據保留版本僅設置為1,在業務更新比較頻繁的場景下,MemStore 中可能會存儲某些數據的多個版本,這樣,MemStore 在將數據寫入 HFile 之前實際上可以丟棄老版本數據,僅保留最新版本數據

MemStore 使用數據結構 ConcurrentSkipListMap 來實際存儲 KeyValue,優點是能夠非常友好地支持大規模併發寫入,同時跳躍表本身是有序存儲的,這有利於數據有序落盤,以及有利於提升 MemStore 中的 KeyValue 查找性能。

KeyValue 寫入 MemStore 並不會每次都隨機在堆上創建一個記憶體對象,然後再放到 ConcurrentSkipListMap 中,這會帶來非常嚴重的記憶體碎片,進而可能頻繁觸發 Full GC。HBase 使用 MemStore-Local Allocation Buffer(MSLAB) 機制預先申請一個大的(2M)的 Chunk 記憶體,寫入的 KeyValue 會進行一次封裝,順序拷貝這個 Chunk 中。

這樣,MemStore 中的數據從記憶體 flush 到硬碟的時候,JVM 記憶體留下來的就不再是小的無法使用的記憶體碎片,而是大的可用的記憶體片段。基於這樣的設計思路,MemStore 的寫入流程可以表述為以下3步:

· 檢查當前可用的 Chunk 是否寫滿,如果寫滿,重新申請一個2M的 Chunk

· 將當前 KeyValue 在記憶體中重新構建,在可用 Chunk 的指定 offset 處申請記憶體,創建一個新的 KeyValue 對象

· 將新創建的 KeyValue 對象寫入 ConcurrentSkipListMap 中

Hbase在實現中,是把整個記憶體在一定閾值後,flush 到 disk 中,形成一個 file。這個 file 的存儲也就是一個小的B+樹,因為 Hbase 一般是部署在 HDFS 上,HDFS 不支持對文件的 update 操作,所以 Hbase 整體記憶體 flush,而不是和磁碟中的小樹 merge update。記憶體 flush 到磁碟上的小樹,定期也會合併成一個大樹,整體上 Hbase 就是用了 LSM-Tree 的思路。

因為小樹先寫到記憶體中,為了防止記憶體數據丟失,寫記憶體的同時需要暫時持久化到磁碟,對應了 HBase 的 HLog(WAL)和 MemStore。

MemStore 上的樹達到一定大小之後,需要 flush 到 HRegion 磁碟中(一般是 Hadoop DataNode),這樣 MemStore 就變成了 DataNode 上的磁碟文件 StoreFile,定期 HRegionServer 對 DataNode 的數據做 merge 操作。徹底刪除無效空間,多棵小樹在這個時機合併成大樹,來增強讀性能。

Hudi

● Hudi 表格式

Hudi 表類型定義瞭如何在 DFS 上對數據進行索引和佈局,以及如何在此類組織上實現上述操作和時間軸活動(即如何寫入數據)。同樣,查詢類型定義了底層數據如何暴露給查詢(即如何讀取數據)。

file

· Table Types:

1)Copy on Write : 使用列式存儲來存儲數據(parquet), 通過在寫入期間執行同步合併來簡單地更新和重現文件

file

2)Merge on Read : 使用列式存儲(parquet)+ 行式文件(avro)組合存儲數據,更新記錄到增量文件(avro)中,然後進行同步或非同步壓縮來生成新版本的列式文件

file

· 查詢類型

1)Snapshot Queries: 在此視圖上的查詢可以查看給定提交或壓縮操作時表的最新快照。對於讀時合併表(MOR表) 該視圖通過動態合併最新文件切片的基本文件(例如 parquet)和增量文件(例如 avro)來提供近實時數據集(幾分鐘的延遲);對於寫時複製表(COW 表),它提供了現有 parquet 表的插入式替換,同時提供了插入/刪除和其他寫側功能

2)Incremental Queries: 對該視圖的查詢只能看到從某個提交/壓縮後寫入數據集的新數據,該視圖有效地提供了更改流,來支持增量數據管道

3)Read Optimized Queries: 在此視圖上的查詢將查看給定提交或壓縮操作中數據集的最新快照,該視圖僅將最新文件切片中的基本/列文件暴露給查詢,並保證與非 Hudi 列式數據集相比,具有相同的列式查詢性能

file

● Hudi 索引

Hudi 通過索引機制,將給定的 hoodie key(record key + partition path)一致映射到 file id,從而提供高效的上傳功能。一旦記錄的第一個版本被寫入文件, record key 和 file group/file id 之間的映射就永遠不會改變。簡而言之,映射的 file group 包含一組記錄的所有版本。

對於 "寫入即複製 "表來說,這樣就不需要 join 整個數據集來確定要重寫哪些文件,從而實現了快速的上傳/刪除操作。

對於 "讀取合併 "表,這種設計允許 Hudi 對任何給定基礎文件需要合併的記錄數量進行約束。具體來說,一個給定的基礎文件只需要針對屬於該基礎文件的記錄更新進行合併。相比之下,沒有索引組件的設計(如 Apache Hive ACID)最終可能需要針對所有傳入的更新/刪除記錄合併所有基礎文件。

目前,Hudi 支持以下索引類型,在 Spark 引擎上預設為 SIMPLE,在 Flink 和 Java 引擎上預設為 INMEMORY。

· BLOOM:採用由 record keys 構建的 Bloom 過濾器,也可選擇使用 record keys 範圍修剪候選文件

· GLOBAL_BLOOM:使用由 record keys 構建的 Bloom 過濾器,也可選擇使用 record keys 範圍剪切候選文件,表中的所有分區都會強制執行 key 唯一性

· SIMPLE(Spark 引擎預設): Spark 引擎的預設索引類型,根據從存儲表中提取的 key 對輸入記錄執行精益 join,在分區內強制執行 key 的唯一性

· GLOBAL_SIMPLE: 根據從存儲表中提取的 key 對輸入記錄執行精簡 join,在表的所有分區中強制執行 key 的唯一性

· HBASE:管理外部 Apache HBase 表中的索引映射

· INMEMORY(Flink 和 Java 的預設值): 在 Spark 和 Java 引擎中使用記憶體 hashmap,在 Flink 中使用 Flink 記憶體 state 索引

· BUCKET:使用桶 hashing 定位包含記錄的文件組,尤其適用於大規模數據量的表,使用 hoodie.index.bucket.engine 選擇桶引擎類型,即如何生成桶

1)SIMPLE(預設):每個分區的文件組使用固定數量的桶,這些桶不能收縮或擴展,這適用於 COW 表和 MOR 表。由於桶的數量不能改變,而且桶和文件組之間設計了一對一的映射,因此這種索引可能不太適合高度傾斜的分區

2)CONSISTENT_HASHING:支持桶的動態數量和桶的大小調整,以適當調整每個桶的大小。這解決了潛在的數據傾斜問題,即數據量大的分區可以動態調整大小,以擁有多個大小合理的桶,而 SIMPLE 桶引擎類型中每個分區的桶數量是固定的,這隻適用於 MOR 表

· RECORD_INDEX:在 Hudi 元數據表中保存 record keys 到位置映射的索引,記錄索引是全局索引,可確保表中所有分區的密鑰唯一性,支持分片,以實現極高的規模,可以擴展 HoodieIndex 來實現自定義索引

Iceberg

Iceberg 在 V1 的格式中定義瞭如何使用不可變類型的文件(Parquet、ORC、AVRO)來管理大型分析型的表,包括元數據文件、屬性、數據類型、表的模式,分區信息,以及如何寫入與讀取。

而在 V2 的格式中,在 V1 的基礎上增加瞭如何通過這些類型的表實現行級別的更新與刪除功能。其最主要的改變是引入了 delete file 記錄需要刪除的行數據,這樣可以在不重寫原有(數據)文件的前提下,實現行數據的更新與刪除。

file
file
file
file

Paimon

● Paimon 表格式

file
file

得益於 LSM 數據結構的追加寫能力,Paimon 在大規模的更新數據輸入的場景中提供了出色的性能。

Paimon 創新地結合了 湖存儲 + LSM + 列式格式(ORC, Parquet),為湖存儲帶來大規模實時更新能力。Paimon 的 LSM 的文件組織結構如下:

file
· 高性能更新:LSM 的 Minor Compaction,保障寫入的性能和穩定性

· 高性能合併:LSM 的有序合併效率非常高

· 高性能查詢:LSM 的 基本有序性,保障查詢可以基於主鍵做文件的 Skipping

LSM 是一個面向寫友好的格式,它在寫入的時候可以看到整個流程,但它不用理解具體的流程。大致的思路是,寫入發生在 Flink Sink 中,當檢查點到達時,它會對記憶體中的數據進行排序,並將記錄刷新到 Level0 文件中。

得益於 LSM 這種原生非同步的 Minor Compaction,它可以通過非同步 Compaction 落到最下層,也可以在上層就發生一些 Minor 的 Compaction 和 Minor 的合併,這樣壓縮之後它可以保持 LSM 不會有太多的 level。保證了讀取 merge read 的性能,且不會帶來很大的寫放大。

另外,Flink Sink 會自動清理過期的快照和文件,還可以配置分區的清理策略。所以整個 Paimon 提供了吞吐大的 Append 寫,消耗低的局部 Compaction,全自動的清理以及有序的合併。所以它的寫吞吐很大,merge read 不會太慢。

● Paimon Changelog Producers

Changelog-Producer 配置 Changelog 生產的模式:None,Input,Lookup, Full Compaction。

· None:最適合資料庫系統等消費者

file

· Input:適合完整的 change log,database CDC

file

· Lookup:沒有完整的 change log,又不想用 normalized operator,commit 前執行

file

· Full Compaction:比 Lookup 時延更長,通常是多個 commit

file

大數據存儲中的常用理論

磁碟存儲

在介紹大數據存儲的常用理論之前,先講講磁碟存儲

file

· 磁軌移動到對應的磁軌,這是由馬達控制的機械動作,一般為10ms左右(取決於磁頭位置和目標磁軌的距離),這叫做尋道時間

· 等待對應的扇區旋轉到磁頭位置(磁頭是不動的),按現在主流磁碟轉速7200轉/分鐘,旋轉一周需要8.33ms,這叫等待時間

· 對應扇區在磁頭旋轉而過,數據就被讀寫完成了,一般一個磁軌又63個扇區,一個扇區掠過磁頭的時間為 8.33ms/63=0.13ms,我們叫它傳輸時間

· 存取時間 = 尋道時間(t1) + 等待時間(t2) + 傳輸時間(t3)

● 希捷硬碟

7200轉、256MB緩存、SAS 12Gbps介面,最大持續傳輸速度524MB/s,隨機4K QD16讀取為304 IOPS、隨機4K QD16寫入最大448 IOPS,平均延遲4.16ms,平均運行功耗12W左右。

● 固態硬碟

固態硬碟中,4K 是最小的讀寫單元固態硬碟。例如,如果我們需要寫入 2K 的數據,我們實際上必須寫入 4K;如果我們需要寫入 13K 的數據,就必須寫入 16K 的數據(這裡不考慮寫入放大)。

file

對於固態硬碟,順序讀的速度仍然能達到隨機讀的3倍左右。但是隨機寫還是順序寫,差別不大。

file

行式存儲/列式存儲

● 行式存儲

· 數據是按行存儲的

· 沒有建立索引的查詢將消耗很大的 IO

· 建立索引和視圖需要花費一定的物理空間和時間資源

· 面對大量的查詢,複雜的查詢資料庫必須被大量膨脹才能滿足性能需求

file
file

● 列式存儲

· 數據是按列存儲的,每一列單獨存放

· 只訪問查詢涉及的列大量降低系統 IO

· 數據類型一致,數據特征相似高效的壓縮

file
file

行式存儲和列式存儲的對比如下:

file

Merge-On-Read & Copy On Write

● Merge-On-Read (MOR)

· 最適合頻繁寫入/更新的表

· 使用讀取時合併時,不會重寫文件,而是將更改寫入新文件

· 當讀取數據時,更改將應用或合併到原始數據文件中,以在處理過程中形成數據的新狀態

● Copy-On-Write (COW)

· 寫入時複製(COW),最適合頻繁讀取、不頻繁寫入/更新或大批量更新的表

· 使用 COW 時,當對某一行或多行進行刪除或更新時,包含這些行的數據文件會被覆制,但新版本包含更新的行,這會導致寫入速度變慢,取決於有多少數據文件必須重寫,可能會導致併發寫入發生衝突,並可能超過重試次數而失敗

· 如果要更新大量記錄,COW 是理想的選擇,但是,如果只更新幾行,則仍需重寫整個數據文件,這就使得小規模或頻繁的更改代價高昂

· 在讀取方面,COW 是理想的選擇,因為讀取不需要額外的數據處理,讀取查詢有很大的文件可以讀取,吞吐量很高

Merge-On-Read 和 Copy On Write 的對比如下:

file

WAL&LSM

file

RDBMS 中我們需要B+樹(或者廣義地說,索引),一句話總結,減少尋道時間。在存儲系統中廣泛使用的 HDD 是磁性介質+機械旋轉的,這就使得其順序訪問較快而隨機訪問較慢。使用B+樹組織數據可以較好地利用 HDD 的這種特點,其本質是多路平衡查找樹。

B+樹最大的性能問題是會產生大量的隨機 IO,隨著新數據的插入,葉子節點會慢慢分裂,邏輯上連續的葉子節點在物理上往往不連續,甚至分離的很遠,但做範圍查詢時,會產生大量讀隨機 IO。

為了剋服B+樹的弱點,引入了 LSM 樹的概念,即 Log-Structured Merge-Trees。

file

Delta Store

基本思想是犧牲寫入性能,換取更高的讀性能。當獲取 CDC 數據後,通過主鍵索引,可以定位到這條記錄原來所在的位置、文件(或者 Block),然後在這個 Block 旁邊放一個 Delta Store,用來保存對於這個 Block 的增量修改。這個 Delta Store 里保存的不是主鍵而是數據記錄在 Block 里的行號(RowId)。

查詢時讀到原始 Block,然後根據 RowId 與 Delta 數據進行合併更新並返回最新數據給上層引擎。由於 Delta 數據是按行號組織的,與 Merge-on-Read 按照 Key 進行合併比,查詢性能好很多。不過這種方式會破壞二級索引,因為對 Block 做修改後,他的索引相當於失效了,想要在更新後再維護索引複雜度會很高。

這種方式寫入性能差(要查詢索引,定位原數據),但讀取的性能好很多。另外因為引入了主鍵索引和 Delta Store,複雜性也較高。

file

Delete-and-Insert

思路也是犧牲部分寫性能,極大地優化讀的性能。原理也是引入主鍵索引,通過主鍵索引定位原來這條記錄所在位置,找到記錄後只需要給這條記錄打個刪除標記(Delete Bitmap),表示這條記錄是被刪除的,然後所有其它 update 記錄可以當成新增數據插入到新的 Block 裡面。

這樣的好處是讀取時直接把所有的 Block 都可以並行載入,然後只需要根據 Delete Bitmap 標記過濾已經刪除的記錄。

StarRocks 新的支持實時更新的 Primary Key 表就是用到這個 Delete+Insert 的方式實現的,另外還有阿裡雲的 ADB 和 Hologres 也用到在這種方式。

file

數據湖的一致性

● Flink 二階段提交

file
file

● 對比 MySQL 二階段提交

因為最開始 MySQL 里並沒有 InnoDB 引擎。MySQL 自帶的引擎是 MyISAM,但是 MyISAM 沒有 crash-safe 的能力,binlog 日誌只能用於歸檔,而 InnoDB 是另一個公司以插件形式引入 MySQL 的。既然只依靠 binlog 是沒有 crash-safe 能力的,所以 InnoDB 使用另外一套日誌系統,也就是 redo log 來實現 crash-safe 能力。

file

假設執行一條 SQL 語句:update T set c=c+1 where ID=2;

file
· 時刻 A Crash

也就是寫入 redo log 處於 prepare 階段之後,寫 binlog 之前,發生了崩潰(crash),由於此時 binlog 還沒寫,redo log 也還沒提交,所以崩潰恢復的時候,這個事務會回滾。

· 時刻 B Crash

看一下崩潰恢復時的判斷規則:

1)如果 redo log 裡面的事務是 完整的,也就是已經有了 commit 標識,則直接提交

2)如果 redo log 裡面的事務只有完整的 prepare,則判斷對應的事務 binlog 是否存在並完整:

a. 如果是,則提交事務;

b. 否則,回滾事務。

這裡,時刻 B 發生 crash 對應的就是 2(a) 的情況,崩潰恢復過程中事務會被提交。

實時湖倉生態選型

在介紹實時湖倉生態選型之前,先看看流計算 + 湖存儲的歷史和發展。

· Storm : 流計算 += 不准確的實時預處理

· Spark : 流計算 += Mini-Batch 預處理

· Flink + HBase/Redis/Mysql : 流計算 += 準確的實時預處理

· Flink + OLAP : 流計算 += 實時數倉,預處理和成本的權衡,高性能 OLAP 帶來了一定的靈活度

· Flink + 數據湖 : 流計算 += 離線數倉部分實時化

· Flink + 流式數據湖 : 流計算 += CDC 流式增量計算,解決更多痛點

· 未來 : Streaming Lakehouse,通用的 Lakehouse 架構

計算

● Spark(Structured Streaming)、Flink

Spark 流計算國外用的比較多,Spark RDD/Dataset 相關 API;Flink 流計算國內生態社區比較完善,絕大部分需求可以直接使用 SQL 完成。

●Trino、Doris、StarRocks

· Trino

1)優點:純 Java 項目;代碼質量較好;Hive 優化細節處理比較完善

2)缺點:執行性能比向量化引擎低;聯邦查詢較慢(缺少自己的元數據管理)

· Doris/StarRocks

1)優點:向量化引擎執行效率高;國內社區活躍;功能迭代快

2)缺點:C++ 門檻較高,遇到問題難排查

file

存儲

根據計算選擇存儲,有如下推薦:

● Flink + Paimon/Iceberg

Paimon 早期是 Flink 內部存儲,叫作 Table Store,後來進入Apache 孵化,改名為 Paimon。

● Spark + Hudi

Hudi 是從 Spark 解耦出來的,很多功能是和 Spark 綁定的,Spark 支持的最好,有很多存儲過程

● Doris/StarRocks 自帶的存儲

file

元數據

● Hive MetaStore

· 傳統數倉,用戶非常多

· 存儲有局限性:不同計算引擎的邏輯類型和 Hive 不一致,例如 timestamp 類型屬性只能以 key value 的形式存儲到 Hive 表的 Properties 裡面

· Hive metastore 瓶頸:高併發請求元數據時,經常 CPU 打滿

file

● Hudi MetaServer

Hudi 裡面開發了一個可以存儲 Hudi 元數據的服務,服務主要基於 Thrift 協議去開發,通過 MyBatis 保存元數據到 MySQL 中。

file

● HDFS/OSS

元數據存儲在 HDFS 或者在對象存儲上面:.hoodie / .iceberg(metadata) / .paimon(metadata)

● 二次開發

基於 Spring 生態去開發 Web 服務,元數據存儲在 MySQL 中。

湖倉治理

EasyLake

袋鼠雲 EasyLake 湖表治理功能支持數據文件治理,支持快照文件治理,支持 Hudi MOR 增量文件合併,將小文件數量控制在一定的範圍內,提升治理效率。

file

具體實踐請點擊該鏈接:《如何構建新一代實時湖倉?袋鼠雲基於數據湖的探索升級之路》

https://mp.weixin.qq.com/s/V5CTGJOkeZFuYPJhMk4o_Q

Amoro

Amoro 為用戶、平臺和產品構建湖原生數據倉庫和架構。

file

Dremio

基於 Apache Parquet、Apache Iceberg 和 Apache Arrow 等社區驅動標準的開放數據湖倉一體,使組織能夠使用一流的處理引擎並消除供應商鎖定。

file

本文根據《實時湖倉實踐五講第四期》直播內容總結而來,感興趣的朋友們可點擊鏈接觀看直播回放視頻及免費獲取直播課件。

直播課件:https://www.dtstack.com/resources/1055?src=szsm

直播視頻:https://www.bilibili.com/video/BV1EC4y1w7WX/?spm_id_from=333.999.0.0

《數棧產品白皮書》下載地址:https://www.dtstack.com/resources/1004?src=szsm

《數據治理行業實踐白皮書》下載地址:https://www.dtstack.com/resources/1001?src=szsm

想瞭解或咨詢更多有關大數據產品、行業解決方案、客戶案例的朋友,瀏覽袋鼠雲官網:https://www.dtstack.com/?src=szbky


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • create database step2_unit12; go use step2_unit12; go -- 部門表 CREATE TABLE [dbo].[Department]( [Id] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL, [Name] [v ...
  • create database step2_unit13; go use step2_unit13; go -- 創建數據表 CREATE TABLE account ( id INT PRIMARY KEY identity, NAME VARCHAR(10), balance decimal(1 ...
  • 概述:.NET依賴註入(DI)通過反射自動註冊服務,示例展示了註冊指定類、帶特性類、項目下所有介面實現的類。簡化配置,提高可維護性。 在.NET中,進行依賴註入(DI)的自動註冊,可以通過反射機制和程式集掃描來實現。以下是詳細的步驟以及相應的C#源代碼示例,包括註冊指定類、註冊帶有自定義特性的類、以 ...
  • 問題 在調試接收串口數據的Qt程式中發現,數據存在延遲和粘包現象。下位機發送數據包頻率是100Hz,一包56位元組,波特率115200,在列印port->readAll()的值的時候發現並不是每10ms讀到一包數據,而是大概每50ms左右一次接收到5包數據,在其他電腦上調試,以及下載其他串口助手調試後 ...
  • Flink中的處理函數(ProcessFunction和KeyedProcessFunction)在對於數據進行顆粒化的精確計算時使用較多,處理函數提供了一個定時服務(TimerService),可以向未來註冊一個定時服務, ...
  • 一、按照月分片 使用場景為按照自然月來分片,每個自然月為一個分片,但是一年有12個月,是不是要有12個數據節點才行呢?並不是。例如我現在只有三個分片資料庫,這樣就可以1月在第一個數據分片中,2月在第二個數據分片中,3月在第三個數據分片中,當來到4月的時候,就會重新開始分片,4月在第一個數據分片,5月 ...
  • 1. 基礎知識回顧 1、索引的有序性,索引本身就是有序的 2、InnoDB中間隙鎖的唯一目的是防止其他事務插入間隙。間隙鎖可以共存。一個事務取得的間隙鎖並不會阻止另一個事務取得同一間隙上的間隙鎖。共用和獨占間隔鎖之間沒有區別。它們彼此之間不衝突,並且執行相同的功能。 3、MySQL預設隔離級別是 R ...
  • 芋道源碼相信很多朋友都很瞭解了,今天我們試著基於FastGPT實現芋道框架的代碼生成。芋道的代碼生成,是基於資料庫表欄位實現的,那我們的思路就是看看如何使用GPT幫我們生成資料庫表結構,只要資料庫表欄位有了,代碼也就生成好了。實現這個需求我們就需要用到FastGPT的高級編排功能。編排的整體思路如下 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...