當前位置: 妍妍網 > 資訊

StarRocks 最佳實踐

2024-01-01資訊

本文從部署、建模、匯入、查詢和監控五個模組給大家分享下 StarRocks 的最佳使用方法,希望能幫助到大家使用 StarRocks 更快、更穩、更好的實作業務需求。

部署

  1. 容量規劃

StarRocks集群配置推薦

https://forum.mirrorship.cn/t/topic/567

2. 基礎環境配置

參考環境配置,尤其關註swap關閉、overcommit設定為1、ulimit配置合理

檢查環境配置

https://docs.starrocks.io/zh/docs/deployment/environment_configurations/

  1. 機器配置

  • FE節點

  • 建議8C32GB

  • 數據盤>=200GB SSD

  • BE節點

  • CPU:記憶體比,1:4,生產最小配置8C32GB

  • 單節點磁盤容量建議10TB,數據盤建議最大單盤2TB,建議SSD或者NVME(如果是HDD,建議吞吐>150MB/s,IOPS>500)

  • 集群中節點 同構 (機器規格一樣,避免木桶效應)

    1. 部署方案

  • 生產環境強制最小集群規模 3FE+3BE(FE和BE獨立部署),如果混合部署, 強制配置be.conf 中的mem_limit 為減去其他服務後剩余記憶體量,例如機器記憶體40G,上面已經部署了FE,理論上限會用8G,那麽配置下mem_limit=34G (40-8-2),2g是給系統預留

  • 生產強制 FE 高可用部署 ,1 Leader + 2 Follower,如果需要提高讀並行,可以擴容Observer節點

  • 生產強制使用負載均衡器連線集群進行讀寫,一般常用Nginx、Haproxy、F5等

  • 建模

    1. 建表規範

  • 僅支持UTF8編碼

  • 不支持修改表中的列名(即將支持)

  • VARCHAR最大長度1048576

  • KEY列不能使用FLOAT、DOUBLE型別

  • 數據目錄名、資料庫名、表名、檢視名、使用者名稱、角色名 大小寫敏感 ,列名和分區名 大小寫不敏感

  • 主鍵模型中,主鍵長度不超過128字節

    1. 模型選擇

  • 如果想要保留明細,建議使用明細模型

  • 如果有明確主鍵,主鍵非空,寫少讀多,非主鍵列要利用索引,建議使用主鍵模型

  • 如果有明確主鍵,主鍵可能為空,寫多讀少,建議使用更新模型

  • 如果只想保留聚合數據,建議使用聚合模型

    1. 排序列和字首索引選擇

    DUPLICATE KEY、AGGREGATE KEY、UNIQUE KEY中指定的列,3.0版本以前,主鍵模型中排序列透過PRIMARY KEY指定,3.0版本起,主鍵模型中排序列透過ORDER BY指定。

    字首索引是在排序列基礎上引入的稀疏索引,進一步提升查詢效率,全部載入在記憶體中

  • 經常作為查詢條件的列,建議選為排序列

  • 排序列建議選擇3-5列,過多會增大排序開銷,降低匯入效率

  • 字首索引不超過36字節,不能超過3列,遇到varchar會截斷,字首索引中不能包含 float 或 double 型別的列

  • 因此可以結合實際業務查詢場景,在確定 key 列以及欄位順序時,要充分考慮字首索引帶來的優勢。盡可能將經常需要查詢的key列欄位,放置在前面,欄位數據型別盡量選擇 date 日期型別或者 int 等整數型別。

    舉例:

    CREATETABLE site_access( site_id BIGINTDEFAULT'10', city_code INT, site_name VARCHAR(50), pv BIGINTDEFAULT'0')DUPLICATEKEY(site_id,city_code,site_name)DISTRIBUTEDBYHASH(site_id);

    在 site_access 表中,字首索引為 site_id( 8 Bytes ) + city_code( 4 Bytes ) + site_name(前 24 Bytes)

  • 如果查詢條件只包含 site_id city_code 兩列,如下所示,則可以大幅減少查詢過程中需要掃描的數據行:

  • select sum(pv) from site_access where site_id = 123 and city_code = 2;

  • 如果查詢條件只包含 site_id 一列,如下所示,可以定位到只包含 site_id 的數據行:

  • select sum(pv) from site_access where site_id = 123;

  • 如果查詢條件只包含 city_code 一列,如下所示,則需要掃描所有數據行,排序效果大打折扣:

  • select sum(pv) from site_access where city_code = 2;

  • 如果 site_id和city_code聯合查詢和單獨city_code的查詢占比不相上下,可以考慮建立同步物化檢視調整列順序來達到查詢效能提升,物化檢視中的city_code放到第一列

  • creatematerializedview site_access_city_code_mv asselect city_code, site_id, site_name, pvfrom site_access;Bad caseCREATETABLE site_access_bad( site_name VARCHAR(20), site_id BIGINTDEFAULT'10', city_code INT, pv BIGINTDEFAULT'0')PRIMARY KEY(site_id)DISTRIBUTEDBYHASH(site_id)ORDERBY(site_id,city_code);

    在 site_access_bad 表中,字首索引只有 site_name

    1. 分區選擇

  • 值不會變化的時間列經常用於where過濾,使用該列建立分區

  • 有數據淘汰需求的場景可以選擇動態分區

  • 數據更新有明顯的冷熱特征的,強制建立分區,例如經常更新最近一周的數據,可以按天分區

  • 單個分區數據量建議不要超過100GB

  • 超過50G或者5KW的表建議建立分區

  • 建議按需建立分區,避免後設資料太多占用fe的記憶體

  • 當前支持時間型別(Range分區、運算式分區)、字串(List分區)、數位(Range分區、List分區)

  • 預設最大支持1024個分區,可以透過參數調整,不過一般情況下不需要調整

    1. 分桶選擇

  • 生產強制使用 3 副本

  • 分桶個數判斷

  • 當表或者分區數據量超過50GB的時候按照每個桶1GB預估

  • 當表或者分區數據量小於50GB的時候按照每個桶500MB預估

  • 當按照以上策略估算出來的分桶個數小於be個數的時候,最終分桶個數以be個數為準,例如6個be節點,按照500MB每個桶預估分桶個數為1,最終分桶個數取6

  • 單個桶按照500MB~1GB預估,原始數據按照5GB~10GB(匯入starrocks後,壓縮比7:1~10:1)預估

  • 非分區表不要使用動態分桶,按照實際數據量估算分桶個數

  • 如果分區表的各個分區的數據差異很大,建議不要使用動態分桶策略

  • 分桶裁剪和數據傾斜如何抉擇?

  • 如果分桶列是where中經常用到的列,且分桶列的重復度比較低(例如使用者id、事物id等),則可以利用該列作為分桶列

  • 如果查詢條件中有city_id和site_id,city_id取值只有幾十,如果僅僅使用city_id分桶,則可能出現某些桶的數據量會比較大,出現數據傾斜,這個時候可以考慮使用city_id和site_id聯合作為分桶欄位,不過這樣做的缺點是如果查詢條件中只有city_id的時候,沒辦法利用分桶裁剪

  • 如果沒有合適的欄位作為分桶欄位打散數據,可以利用random分桶,不過這樣的話沒辦法利用分桶裁剪的內容

  • 2個或多個超過KW行以上的表join,建議使用colocate,具體參考 colocolocate join

  • Colocate Join

    https://docs.starrocks.io/zh/docs/using_starrocks/Colocate_join/

    1. 欄位型別

  • 建議不要使用null內容

  • 時間型別和數位型別的列選擇正確的型別,計算的開銷會比較大,例如時間型別的數據「2024-01-01 00:00:00」不要使用VARCHAR儲存,這樣沒辦法利用到starrocks內部的zonemap索引,沒辦法加速過濾

    1. 索引選擇

  • bitmap索引

  • 適合基數在10000-100000左右的列

  • 適合等值條件 (=) 查詢或 [NOT] IN 範圍查詢的列

  • 不支持為 FLOAT、DOUBLE、BOOLEAN 和 DECIMAL 型別的列建立 Bitmap 索引。

  • 城市、性別這些基數在255以下的列不需要建立bitmap索引,因為starrocks內部有低基數位典,會針對這些case自動建立低基數位典用於加速

  • 明細模型和主鍵模型,所有列可以建立bitmap索引,聚合模型和更新模型,只有Key列支持建立bitmap索引

  • blommfilter索引

  • 適合基數在100000+的列,列的重復度很低

  • 適合 in = 過濾條件的查詢

  • 不支持為 TINYINT、FLOAT、DOUBLE 和 DECIMAL 型別的列建立 Bloom filter 索引

  • 主鍵模型和明細模型中所有列都可以建立 Bloom filter 索引;聚合模型和更新模型中,只有維度列(即 Key 列)支持建立 Bloom filter 索引

  • 匯入

    1. 使用建議

  • 生產禁止使用insert into values() 導數據

  • 建議匯入批次間隔5s+,也就是攢批寫入,尤其是即時場景

  • 主鍵模型更新場景,建議開啟索引落盤,磁盤強制SSD、NVME或者更高效能的磁盤

  • 比較多ETL(insert into select)的場景,建議開啟spill落盤功能,避免記憶體超過限制

    1. 數據生命周期

  • 建議使用truncate刪除數據,不要使用delete

  • 完整的update語法只能用於3.0版本以後的主鍵模型,禁止高並行 update,建議每次update操作需要間隔分鐘以上

  • 如果使用delete刪除數據,需要帶上where條件,並且禁止並行執行delete,例如要刪除id=1,2,3,4,……1000,禁止delete xxx from tbl1 where id=1這樣的語句執行1000條,建議delete xxx from tbl1 where id in (1,2,3...,1000)

  • drop操作預設會進入FE 資源回收桶,預設保留86400(s),也就是1天(這個期間可以recover恢復,避免誤操作),受參數catalog_trash_expire_second控制,超過1天後會進入BE的trash目錄,預設保留259200(s),也就是3天(2.5.17,3.0.9,3.1.6之後預設值改為了86400,也就是1天),受參數trash_file_expire_time_sec控制,如果drop後需要盡快釋放磁盤,可以調小fe和be的trash保留時間、

  • 查詢

    1. 高並行場景

  • 盡可能利用分區分桶裁剪,具體參考上文的分區和分桶選擇部份

  • 調大客戶的並行限制,可以設定為1000,預設100,SET PROPERTY FOR 'jack' 'max_user_connections' = '1000';

  • 開啟page cache、query cache

    1. 數據精度

  • 如果需要精確結果的,強制使用decimal型別,不要使用float、double型別

    1. SQL查詢

  • 避免select *,建議指定需要查詢的列,例如select col0,col1 from tb1

  • 避免全表掃描,建議增加過濾的謂詞,例如select col0,col1 from tb1 where id=123,select col0,col1 from tb1 where dt>'2024-01-01'

  • 避免大數據量的下載,如果要使用,強制使用分頁,select col0,col1,col2,...,col50 from tb order by id limit 0,50000

  • 分頁操作需要加上order by,要不然是無序的

  • 避免使用一些不必要的函式或者運算式

  • 謂詞中含cast, 可以移除

  • -- Q1select l_tax from lineitem wherecast(l_shipdate asvarchar) > substr('1990-01-02 12:30:31',1,10);-- Q2select l_tax from lineitem where l_shipdate > '1990-01-02';

  • 過度使用函式處理運算式

  • -- Q1 bad caseselectcount(1) from lineitem where l_shipdate >= regexp_extract("TIME:1996-01-02 20:00:00", "(\\d{4}-\\d{2}-\\d{2})", 1);-- Q2 good caseselectcount(1) from lineitem where l_shipdate >= "1996-01-02"-- Q1 bad caseselectcount(1) from lineitem whereDATE_FORMAT(l_shipdate,'%Y-%m-%d') >= "1996-01-02"-- Q2 good caseselectcount(1) from lineitem where l_shipdate >= "1996-01-02"

  • JOIN

  • 查詢多個表需要指定連線條件

  • -- bad caseSELECT *FROM table1, table2;-- good caseSELECT *FROM table1, table2 ON table1.column1 = table2.column1;

  • 正確關聯子查詢

    子查詢 中,確保外部查詢和子查詢之間的列有明確的關聯

  • -- bad caseSELECT *FROM table1WHERE column1 IN (SELECT column2 FROM table2);-- good caseSELECT *FROM table1WHERE column1 IN (SELECT column2 FROM table2 WHERE table1.column3 = table2.column3);

  • 使用AND條件而不是OR

  • -- bad caseSELECT *FROM table1JOIN table2WHERE (table1.column1 = table2.column1 OR table1.column2 = table2.column2);-- good caseSELECT *FROM table1JOIN table2 ON table1.column1 = table2.column1 AND table1.column2 = table2.column2;

  • 關聯的欄位型別匹配,雖然starrocks已經在內部做了隱式轉換來達到最優的效能,不過建議大家使用型別一致的欄位join,避免使用float、double型別join,可能會導致結果不準確

  • 關聯欄位建議不要使用函式或者運算式,例如 join on DATE_FORMAT(tb1.col1,'%Y-%m-%d')=DATE_FORMAT(tb2.col1,'%Y-%m-%d')

  • 2個或多個KW行以上的表join,推薦colocate join

  • 避免笛卡爾積

    1. 使用物化檢視加速查詢

  • 精確去重

  • 以下範例基於一張廣告業務相關的明細表 advertiser_view_record ,其中記錄了點選日期 click_time 、廣告程式碼 advertiser 、點選渠道 channel 以及點選使用者 ID user_id

    CREATETABLE advertiser_view_record( click_time DATE, advertiser VARCHAR(10), channel VARCHAR(10), user_id INT) distributedBYhash(click_time);

    該場景需要頻繁使用如下語句查詢點選廣告的 UV。

    SELECT advertiser, channel, count(distinct user_id)FROM advertiser_view_recordGROUPBY advertiser, channel;

    如需實作精確去重查詢加速,您可以基於該明細表建立一張物化檢視,並使用 bitmap_union() 函式預先聚合數據。

    CREATEMATERIALIZEDVIEW advertiser_uv ASSELECT advertiser, channel, bitmap_union(to_bitmap(user_id))FROM advertiser_view_recordGROUPBY advertiser, channel;

    物化檢視建立完成後,後續查詢語句中的子查詢 count(distinct user_id) 會被自動覆寫為 bitmap_union_count (to_bitmap(user_id)) 以便查詢命中物化檢視。

  • 異步物化檢視最多支持3層巢狀

    1. 利用cache 加速查詢

  • Page cache,建議開啟,可以加速數據掃描場景,如果記憶體有冗余,可以盡可能調大限制,預設是mem_limit*20%

  • Query cache,建議開啟,可以加速單表或多表JOIN的聚合場景

  • 查詢中不能包含 rand random uuid sleep 等不確定性 (Nondeterminstic) 函式

  • Data Cache,用於存算分離和湖分析場景,建議這兩個場景下預設開啟

  • 監控

    1. 透過審計外掛程式把fe.audit.log的數據匯入一個表方便進行分析慢查詢。

    透過 Audit Loader 管理 StarRocks 中的審計日誌 @ audit_loader

    透過 Audit Loader 管理 StarRocks 中的審計日誌

    https://docs.starrocks.io/zh/docs/administration/audit_loader/

    1. 參考 https://docs.starrocks.io/zh/docs/2.5/administration/Monitor_and_Alert/ 部署prometheus+grafana

    2. 利用資源隔離大查詢熔斷,小查詢保底

    # shortquery_group 資源組用於核心業務重保CREATERESOURCEGROUP shortquery_groupTO (user='rg1_user1', role='rg1_role1', db='db1', query_type in ('select'), source_ip='192.168.x.x/24'),WITH ('type' = 'short_query','cpu_core_limit' = '10','mem_limit' = '20%');# bigquery_group 用於大查詢熔斷,避免大查詢將集群資源打滿CREATERESOURCEGROUP bigquery_groupTO (user='rg1_user2', role='rg1_role1', query_type in ('select')),WITH ("type" = 'normal','cpu_core_limit' = '10','mem_limit' = '20%','big_query_cpu_second_limit' = '100','big_query_scan_rows_limit' = '100000','big_query_mem_limit' = '1073741824');

    1. 大查詢定位

    檢視當前FE上正在執行的查詢

    SQL命令:show proc '/current_queries'

    返回結果包括以下幾列:

  • QueryId

  • ConnectionId

  • Database:當前查詢的DB

  • User:使用者

  • ScanBytes:當前已掃描的數據量,單位Bytes

  • ProcessRow:當前已掃描的數據行數

  • CPUCostSeconds:當前查詢已使用的CPU時間,單位秒。此為多個執行緒累加的CPU時間,舉個例子,如果有兩個執行緒分別占用1秒和2秒的CPU時間,那麽累加起來的CPU時間為3秒。

  • MemoryUsageBytes:當前占用的記憶體。如果查詢涉及到多個BE節點,此值即為該查詢在所有BE節點上占用的記憶體之和。

  • ExecTime:查詢從發起到現在的時長,單位為毫秒。

  • mysql> show proc '/current_queries';+--------------------------------------+--------------+------------+------+-----------+----------------+----------------+------------------+----------+| QueryId | ConnectionId | Database | User | ScanBytes | ProcessRows | CPUCostSeconds | MemoryUsageBytes | ExecTime |+--------------------------------------+--------------+------------+------+-----------+----------------+----------------+------------------+----------+| 7c56495f-ae8b-11ed-8ebf-00163e00accc |4| tpcds_100g | root | 37.88 MB |1075769 Rows | 11.13 Seconds |146.70 MB | 3804 || 7d543160-ae8b-11ed-8ebf-00163e00accc |6| tpcds_100g | root | 13.02 GB |487873176 Rows | 81.23 Seconds |6.37 GB | 2090 |+--------------------------------------+--------------+------------+------+-----------+----------------+----------------+------------------+----------+2 rows in set (0.01 sec)

    檢視某個查詢在每個BE節點上的資源消耗

    SQL命令:

    show proc '/current_queries/${query_id}/hosts'

    返回結果有多行,每行描述該查詢在對應BE節點上的執行資訊,包括以下幾列:

  • Host:BE節點資訊

  • ScanBytes:已經掃描的數據量,單位Bytes

  • ScanRows:已經掃描的數據行數

  • CPUCostSeconds:已使用的CPU時間。

  • MemUsageBytes:當前占用的記憶體。

  • mysql> show proc '/current_queries/7c56495f-ae8b-11ed-8ebf-00163e00accc/hosts';+--------------------+-----------+-------------+----------------+---------------+| Host | ScanBytes | ScanRows | CpuCostSeconds | MemUsageBytes |+--------------------+-----------+-------------+----------------+---------------+| 172.26.34.185:8060 |11.61 MB | 356252 Rows |52.93 Seconds | 51.14 MB || 172.26.34.186:8060 |14.66 MB | 362646 Rows |52.89 Seconds | 50.44 MB || 172.26.34.187:8060 |11.60 MB | 356871 Rows |52.91 Seconds | 48.95 MB |+--------------------+-----------+-------------+----------------+---------------+3 rows in set (0.00 sec)

    ​​​​

    ​​​​