OceanBase数据库实践入门——性能测试建议
概述
本文主要分享針對想壓測OceanBase時需要了解的一些技術原理。這些建議可以幫助用戶對OceanBase做一些調優,再結合測試程序快速找到適合業務的最佳性能。由于OceanBase自身參數很多、部署形態也比較靈活,這里并沒有給出具體步驟。
數據庫讀寫特點
壓測的本質就是對一個會話的邏輯設計很高的并發。首先需要了解單個會話在數據庫內部的讀寫邏輯。比如說,業務會話1對數據庫發起一個DML SQL,第一次修改某筆記錄,數據庫會怎么做呢?
為了便于理解OB的行為,我們先看看ORACLE是怎么做的。后面有對比才可以加深理解。
ORACLE 讀寫特點
ORACLE會話第一次修改一行記錄,如果該記錄所在塊(8K大小)不在內存(Buffer Cache)里時會先從磁盤文件里讀入到內存里。這個稱為一次物理讀,為了性能考慮,ORACLE一次會連續讀取相鄰的多個塊。然后就直接在該塊上修改,修改之前會先記錄REDO和UNDO(包括UNDO的REDO)。然后這個數據塊就是臟塊(Dirty Block)。假設事務沒有提交,其他會話又來讀取這個記錄,由于隔離級別是讀已提交(READ COMMITTED),ORACLE會在內存里克隆當前數據塊到新的位置,新塊包含了最新的未提交數據。然后ORACLE在新塊上逆向應用UNDO鏈表中的記錄,將數據塊回滾到讀需要的那個版本(SCN),然后才能讀。這個也稱為一次一致性讀(Consistency Read),這個新塊也稱為CR塊。
即使是修改一條記錄一個字段的幾個字節,整個塊(8K大小)都會是臟塊。隨著業務持續寫入,大量臟塊會消耗數據庫內存。所以ORACLE會有多重機制刷臟塊到磁盤數據文件上。在事務日志切換的時候也會觸發刷臟塊操作。如果業務壓力測試ORACLE,大量的寫導致事務日志切換很頻繁,對應的刷臟操作可能相對慢了,就會阻塞日志切換,也就阻塞了業務寫入。這就是ORACLE的特點。解決辦法就是加大事務日志文件,增加事務日志成員或者用更快的磁盤存放事務日志和數據文件。
ORACLE里一個表就是一個Segment(如果有大對象列還會有獨立的Segment,這個先忽略),Segment由多個不一定連續的extent組成,extent由連續的Block(每個大小默認8K)組成,extent缺點是可能會在后期由于頻繁刪除和插入產生空間碎片。
OceanBase 讀寫特點
OceanBase會話第一次修改一行記錄,如果該記錄所在塊(64K大小)不在內存(Block Cache)里時也會先從磁盤文件里讀入到內存里。這個稱為一次物理讀。然后要修改時跟ORACLE做法不同的是,OceanBase會新申請一小塊內存用于存放修改的內容,并且鏈接到前面Block Cache里該行記錄所在塊的那筆記錄下。如果修改多次,每次修改都跟前面修改以鏈表形式關聯。同樣在修改之前也要先在內存里記錄REDO。每次修改都會記錄一個內部版本號,記錄的每個版本就是一個增量。其他會話讀取的時候會先從Block Cache中該記錄最早讀入的那個版本(稱為基線版本)開始讀,然后疊加應用后面的增量版本直到合適的版本(類似ORACLE中SCN概念)。(隨著版本演進,這里細節邏輯可能會有變化。)
OB的這個讀方式簡單說就是從最早的版本讀起,逐步應用增量(類似REDO,但跟REDO日志無關)。而ORACLE一致性讀是從最新的版本讀起,逐步回滾(應用UNDO)。在OB里,沒有UNDO。當版本鏈路很長時,OB的讀性能會略下降,所以OB也有個checkpoint線程定時將記錄的多個版本合并為少數幾個版本。這個合并稱為小合并(minor compaction)。此外,OB在內存里針對行記錄還有緩存,
從上面過程還可以看出,每次修改幾個字節,在內存里的變臟的塊只有增量版本所在的塊(默認寫滿才會重新申請內存),基線數據塊是一直不變化。所以OB里臟塊產生的速度非常小,臟塊就可以在內存里保存更久的時間。實際上OB的設計就是臟塊默認不刷盤。那如果機器掛了,會不會丟數據呢?
OB跟ORACLE一樣,修改數據塊之前會先記錄REDO,在事務提交的時候,REDO要先寫到磁盤上(REDO同時還會發送往其他兩個副本節點,這個先忽略)。有REDO在,就不怕丟數據。此外,增量部分每天還是會落盤一次。在落盤之前,內存中的基線數據和相關的增量數據會在內存里進行一次合并(稱Merge),最終以SSTable的格式寫回到磁盤。如果說內存里塊內部產生碎片,在合并的那一刻,這個碎片空間基本被消弭掉了。所以說OB的數據文件空間碎片很小,不需要做碎片整理。同時OB的這個設計也極大降低了LSM的寫放大問題。
當業務壓測寫OB時,臟塊的量也會增長,最終達到增量內存限制,這時候業務就無法寫入,需要OB做合并釋放內存。OB的合并比較耗IO、CPU(有參數可以控制合并力度),并且也不會等到內存用盡才合并,實際會設置一個閾值。同時為了規避合并,設計了一個轉儲機制。當增量內存使用率超過閾值后,就開啟轉儲。轉儲就是直接把增量內存寫到磁盤上(不合并)。轉儲對性能的影響很小,可以高峰期發生,并且可以轉儲多次(參數配置)。
OB增量內存就類似一個水池,業務寫是進水管在放水, 轉儲和大合并是出水管。水位就是當前增量內存使用率。當進水的速度快于出水,池子可能就會滿。這時候業務寫入就會報內存不足的錯誤。
這就是OB讀寫的特點,解決方法就是加大OB內存、或者允許OB自動對業務寫入速度限流。
OceanBase部署建議
OB 在commit的時候redo落盤會寫磁盤。讀數據的時候內存未命中的時候會有物理讀,轉儲和大合并的時候落盤會有密集型寫IO。這些都依賴磁盤讀寫性能。所以建議磁盤都是SSD盤,并且建議日志盤和數據盤使用獨立的文件系統。如果是NVME接口的閃存卡或者大容量SSD盤,那日志盤和數據盤放在一起也可以。不要使用LVM對NVME接口的大容量SSD做劃分,那樣瓶頸可能會在LVM自身。
OB的增量通常都在內存里,內存不足的時候會有轉儲,可以轉儲多次。盡管如此,建議測試機器的內存不要太小,防止頻繁的增量轉儲。通常建議192G內存以上。
OB集群的節點數至少要有三個。如果是功能了解,在單機上起3個OB進程模擬三節點是可以的,但是如果是性能測試,那建議還是使用三臺同等規格的物理機比較合適。機器規格不一致時,最小能力的機器可能會制約整個集群的性能。 OceanBase集群的手動部署請參考《OceanBase數據庫實踐入門——手動搭建OceanBase集群》。在部署好OceanBase之后,建議先簡單了解一下OceanBase的使用方法,詳情請參考文章《OceanBase數據庫實踐入門——常用操作SQL》。
如果要驗證OB的彈性縮容、水平擴展能力,建議至少要6節點(部署形態2-2-2)。并且測試租戶(實例)的每個Zone里的資源單元數量至少也要為2個,才可以發揮多機能力。這是因為OB是多租戶設計,對資源的管理比較類似云數據庫思想,所以里面設計有點精妙,詳情請參見《揭秘OceanBase的彈性伸縮和負載均衡原理》。
下面是一個租戶的測試租戶資源初始化建議
- 登錄sys租戶
請注意上面的unit_num=2這個很關鍵。如果unit_num=1,OB會認為這個租戶是個小租戶,后面負載均衡處理時會有個默認規則。
- 登錄業務租戶
sysbench壓測建議
因為測試場景跟業務有關,這里就以常見的sysbench場景舉例分析
sysbench工具可以建幾個結構相同的表,然后執行純讀、純寫、讀寫混合。其中讀又分根據主鍵或者二級索引查詢,等值查詢、IN查詢或范圍查詢幾種。詳細的可以查看官方介紹。
如果用sysbench壓測OB,創建很多表是一種方法。另外一種方法就是創建分區表。OceanBase是分布式數據庫,數據遷移和高可用的最小粒度是分區,分區是數據表的子集。分區表有多個分區,非分區表只有一個分區。分區表的拆分細節是業務可以定義的。OceanBase可以將多個分區分布到不同節點,也可能不會分布到多個節點。這個取決于OB集群和租戶的規劃設計。所以對sysbench創建的表(分區),在性能分析時要分析分區具體的位置。
建表準備
下面是sysbench里分區表示例,修改 oltp_common.lua:
query = string.format([[ CREATE TABLE sbtest%d(id %s,k INTEGER DEFAULT '0' NOT NULL,c CHAR(120) DEFAULT '' NOT NULL,pad CHAR(60) DEFAULT '' NOT NULL,%s (id,k) ) partition by hash(k) partitions %s %s %s]],table_num, id_def, id_index_def, part_num, engine_def, extra_table_options)需要注意用分區表后,主鍵列和唯一索引列需要包含分區鍵。分區表的索引有本地(LOCAL)索引和全局索引兩種。本地索引的存儲跟數據是在一起的,全局索引的存儲是獨立的。全局索引是為了應對查詢條件不是分區鍵的場景,沒有全局索引時,會掃描所有分區的本地索引。這兩種索引的性能優劣沒有定論,以實際業務場景測試為準。此外,傳統數據庫索引對修改操作會有負面影響,分布式數據庫的全局索引對修改操作的影響可能更大,因為一個簡單的DML語句都會因為要同步修改全局索引而產生分布式事務。而本地索引就沒有分布式事務問題。所以對全局索引的使用場景要謹慎評估。這個特性不是OB特有,只要是分布數據庫都會面臨這個問題。
數據分布均衡
本節是說明OB數據分布背后的原理和方法。
OceanBase是分布式數據庫,它通過每個機器上的observer進程將多個機器的資源能力聚合成一個大的資源池,然后再為每個業務分配不同資源規格的租戶(實例)。所以每個業務租戶(實例)的資源能力都只是整個集群能力的子集。業務并不一定能使用到全部機器資源。
OceanBase里的數據都有三份,細到每個分區有三個副本,角色上有1個leader副本2個follower副本。默認只有leader副本提供讀寫服務,leader副本所在的節點才有可能提供服務,有負載。OceanBase調整各個節點負載的方法是通過調整內部leader副本的位置實現的。這個調整可以讓OceanBase自動做,也可以手動控制。
OceanBase自動負載均衡是參數enable_rebalance控制,默認值為True。可以查看確認。修改用alter system語句。
alter system set enable_rebalance=True; show parameters like 'enable_rebalance';查看實際表的分區leader副本位置
##查看分區分布 SELECT t5.tenant_id,t5.tenant_name,t3.database_name, t4.tablegroup_name, t2.table_name, t1.partition_id, concat(t1.svr_ip,':',t1.svr_port) observer, t1.role, t1.data_size,t1.row_count from `gv$partition` t1 join `__all_table` t2 on (t1.tenant_id=t2.tenant_id and t1.table_id=t2.table_id)join `__all_database` t3 on (t2.tenant_id=t3.tenant_id and t2.database_id=t3.database_id)left join `__all_tablegroup` t4 on (t1.tenant_id=t4.tenant_id and t1.tablegroup_id=t4.tablegroup_id)join `__all_tenant` t5 on (t1.tenant_id=t5.tenant_id) where t5.tenant_id = 1020 and role=1 and database_name in ('sysbenchtest') order by t5.tenant_id,t3.database_id,t1.tablegroup_id,t1.partition_id, t1.role;sysbench命令參數
sysbench的機制是壓測過程中如果有錯誤就會報錯退出,所以需要針對一些常見的錯誤進行忽略處理,這樣sysbench會話可以重試繼續運行。比如說主鍵或者唯一鍵沖突、事務被殺等等。
下面的運行命令供參考
- 初始化
- 純讀
- 純寫
- 讀寫混合
測試觀察
在純寫或者讀寫測試中,注意觀察增量增量內存使用進度。如果寫入速度比轉儲和合并速度還快,那會碰到內存不足寫入失敗錯誤。這就是OB租戶資源相對不足了。觀察這個內存使用進度可以通過 dooba腳本。dooba腳本默認在/home/admin/oceanbase/bin/目錄下。
使用示例如下:
python dooba -h11..84.84 -uroot@sys#obdemo -P2883 -p**
OB有個內部視圖gv$sql_audit可以查看執行過所有成功或失敗的SQL,用來分析具體的SQL性能。用法詳情參見官網(oceanbase.alipay.com) 或 文章《阿里數據庫性能診斷的利器——SQL全量日志》。
select /*+ read_consistency(weak) query_timeout(1000000000) */ usec_to_time(request_time) req_time, svr_Ip, trace_id, sid, client_ip, tenant_id,tenant_name,user_name,db_name, query_sql, affected_rows,ret_code, event, state, elapsed_time, execute_time, queue_time, decode_time, get_plan_time, block_cache_hit, bloom_filter_cache_Hit, block_index_cache_hit, disk_reads,retry_cnt,table_scan, memstore_read_row_count, ssstore_read_row_count, round(request_memory_used/1024/1024) req_mem_mb from gv$sql_audit where tenant_id=1012 and user_name in ('demouser') order by request_time desc limit 100;經驗總結
本節是一些測試場景的經驗總結,需要提前了解一些OceanBase的原理特性介紹。
實際測試情形可能會出現由于是三節點部署,所以測試時壓力都打到一臺服務器上,這個建議用六節點測試。還有個辦法就是禁用自動負載均衡手動調整分區位置。調整是OB給業務的手段,業務上有些表會有JOIN,為了性能(避免跨節點請求),業務需要這種干預能力。
還有一種情形是寫入壓力非常大,跑了一段時間后報內存不足的提示,這個就是租戶內存資源相對寫入速度和量不足了(OB的轉儲和合并對內存的回收趕不上寫入對內存的消耗),此時需要擴容或者調整測試需求。OB 2.x版本還有自動對應用寫入限速功能(自我保護),這個會影響測試報告里性能結果。如果數據庫分析sql性能以及分布式調優都做了,那可以認為當前寫入的TPS就是數據庫的寫入峰值了。需要注意的是不同的硬件,不同的租戶規格,不同的測試場景,這個TPS能力都表現不同。
sysbench有個batch insert功能,當表是分區表的時候,默認這個batch insert 很可能會產生分布式事務,性能比單表寫入要慢。需要靠提高客戶端并發數來提升總的吞吐量。此外這個批量的大小不宜太大。由于OB支持SQL執行計劃緩存,SQL文本過大且并發很高時,會在SQL解析環節面臨內存不足問題。數據庫內存的大部分還是主要用于存取數據。JAVA的addBatch方法也同理,建議批量大小設置為100以內。
在查詢驗證數據的時候,可能會碰到超時類錯誤。OB里超時的可能場景有多個:
- SQL語句超時,由租戶變量 ob_query_timeout控制。單位是微秒,默認是10秒。
- 事務空閑超時,由租戶變量 ob_trx_idle_timeout控制。單位是微秒,默認120秒。
- 事務超時,由租戶變量 ob_trx_timeout控制。單位是微秒,默認100秒。
以上超時時間都可以在租戶里根據實際情況修改。
其他
關于使用分布式數據庫測試,不同的做法可以得到不同的結果。即使是同一個OB租戶(實例),不同的人設計的表結構不同,或者SQL不同都有可能取得不同的性能數據。這些不同都是可以從原理上給出解釋。熟知這些原理的更容易發揮OB的分布式數據庫特點。使用越深入會發現這個原理越多且更加有趣。當然環境、場景的不同,還是會遇到一些問題。如果有碰到問題,歡迎公眾號留言討論。
原文鏈接
本文為云棲社區原創內容,未經允許不得轉載。
總結
以上是生活随笔為你收集整理的OceanBase数据库实践入门——性能测试建议的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 直击案发现场!TCP 10倍延迟的真相是
- 下一篇: 离屏渲染在车载导航中的应用