此處的負載均衡指的是FE層的負載均衡.
當部署多個 FE 節點時,使用者可以在多個 FE 之上部署負載均衡層來實現 Doris 的高可用。官方檔案描述: 負載均衡 。
實現方式有多種,如下列舉。
開發者在應用層自己進行重試與負載均衡。
發現一個連線掛掉,就自動在其他連線上進行重試。應用層程式碼重試需要應用自己設定多個 doris 前端節點地址。
通過 JDBC Connector實現自動重試與均衡負載:
jdbc:mysql:loadbalance://[host:port],[host:port].../[database][?propertyName1][=propertyValue1][&propertyName2][=propertyValue
架設一層代理,通過ProxySQL代理層實現負載。
通過閘道器反向代理實現負載。
由於資料在分割區或分桶或者是源資料端的資料儲存就不均勻,因此在匯入到Doris中分佈不均勻,導致Doris的效能和穩定性不好。
Doris出現資料傾斜的原因有多種,其中一些常見的原因包括:
為了解決Doris的資料傾斜問題,可以嘗試以下方法:
點查: 是指通過等值條件(例如 WHERE 子句中的等值條件)來查詢單個行或單個資料點的查詢操作。點查詢通常用於檢索具有特定鍵值的行或資料,其特點是通過提供唯一的主鍵值或唯一索引值來定位並返回一行資料/單個資料點。
在高並行服務場景中,如果使用者希望從系統中獲取整行資料,對於列存格式引擎,在表寬時,列存格式將大大放大隨機讀取IO,這就會導致讀取效能降低;其次,FE層是對外提供的是存取服務,同時會分析、解析SQL,也可能會導致高並行查詢時的高CPU開銷。為了解決效能問題,引入了行存、短查詢路徑、PreparedStatement解決。官方檔案描述: 高並行點查 。
僅僅支援在建表時開啟行存模式,但需要額外的空間來儲存行存資料。實現邏輯是將行存編碼後存在單獨的一列中,用於簡化行存的實現。在create的property中指定屬性:
"store_row_column = "true"
行存(Row Storage)
- 儲存方式:行存以行為單位儲存資料,即將每一行的資料儲存在一起。
- 特點:每一行的所有列資料都儲存在相鄰的位置,形成一個資料塊。這種儲存方式對於整行的讀寫操作是高效的,適合於 OLTP(線上事務處理)場景,其中通常需要快速地執行對單個行的操作。
- 適用場景:適用於需要頻繁進行整行讀寫的場景,如交易處理系統等。
列存(Column Storage)
- 儲存方式:列存以列為單位儲存資料,即將同一列的資料儲存在一起。
- 特點:每一列的所有行資料都儲存在相鄰的位置,形成一個資料塊。這種儲存方式對於聚合操作和分析查詢是高效的,因為查詢通常只涉及到部分列的資料。列存適用於 OLAP(線上分析處理)場景,其中通常需要執行復雜的分析查詢。
- 適用場景:適用於需要進行大規模資料分析和聚合查詢的場景,如資料倉儲和資料分析平臺等。
由於列儲存是按列儲存的,獲取整行資料需要從不同列的資料塊中進行隨機讀取,增加了磁碟I/0操作的次數;如果列寬度較大,那麼需要讀取的資料塊數量就會增加,導致隨機讀取的開銷放大;同時較大的列寬導致單個記錄的大小較大,需要傳輸更多的資料量到查詢引擎。這會增加網路傳輸的開銷,尤其是在分散式系統中,如果資料分佈在多個節點上,點查詢可能需要從多個節點傳輸資料。
Unique模型支援合併時寫入(Merge-On-Write)策略,當開啟該策略結合行存時,對於主鍵的點查會走短路徑對SQL執行優化,僅需執行一次RPC查詢即可完成。如下範例:
CREATE TABLE `tbl_point_query` (
`key` int(11) NULL,
`v1` decimal(27, 9) NULL,
`v2` varchar(30) NULL,
`v3` varchar(30) NULL,
`v4` date NULL,
`v5` datetime NULL,
`v6` float NULL,
`v7` datev2 NULL
) ENGINE=OLAP
UNIQUE KEY(`key`)
COMMENT 'OLAP'
DISTRIBUTED BY HASH(`key`) BUCKETS 1
PROPERTIES (
"replication_allocation" = "tag.location.default: 1",
"enable_unique_key_merge_on_write" = "true",
"light_schema_change" = "true",
"store_row_column" = "true"
);
注意:
Doris在FE層提供了與MySQL協定相容的PreparedStatement
特性(目前只支援主鍵點查)。當PreparedStatement
開啟時,SQL與其表示式將被提前計算並快取到Session級別的記憶體快取中,後續的查詢直接使用快取物件即可。
範例:
url = jdbc:mysql://127.0.0.1:9030/ycsb?useServerPrepStmts=true
PreparedStatement
// use `?` for placement holders, readStatement should be reused
PreparedStatement readStatement = conn.prepareStatement("select * from tbl_point_query where key = ?");
...
readStatement.setInt(1234);
ResultSet resultSet = readStatement.executeQuery();
...
readStatement.setInt(1235);
resultSet = readStatement.executeQuery();
...
PreparedStatement
支援使用預留位置引數(如?)來表示 SQL 語句中的變數部分。在執行語句之前,可以通過設定引數的方式為預留位置提供實際的數值。這有助於防止 SQL 注入攻擊,並提高安全性。
對於前面提到的行存,一行裡包括了多列資料,Doris預設支援的列快取可能被大查詢給刷掉,為了增加行快取命中率,單獨引入了行存快取,行快取複用了 Doris 中的 LRU Cache 機制來保障記憶體的使用,通過指定下面的的BE設定來開啟
disable_storage_row_cache
是否開啟行快取, 預設不開啟。row_cache_mem_limit
指定 Row cache 佔用記憶體的百分比, 預設 20% 記憶體。