作者:回雁
我們都知道,對於數據庫中基礎信息表來說,它的數據變化頻率低,數據量小,但由於基礎數據本身的特點,大多數相關係統都會對頻繁地讀取它。即便我們通過對數據調取服務進行服務化包裝,通過HSF服務的方式對外暴露,以減少多個系統直接操作數據庫帶來的問題,但數據本身的讀取頻率和併發度都非常高,QPS可以輕易達到10萬以上。通常,使用普通的關係型數據庫,比如RDS很難滿足這樣的場景,業內普遍的做法是在數據庫前加一層數據庫緩存服務,比如redis或memcache來存放基礎信息,以此承載海量的高併發訪問請求。但是也會存在問題,當緩存服務發生故障,或者由於某種異常被擊穿,大量的訪問請求迅速會打到後端的數據庫上,數據庫能不能在關鍵時候扛住壓力,為運維人員爭取時間,快速修復緩存服務,顯得至關重要。
是的,這個時候,阿里雲RDS和DRDS都提供了只讀實例,從原理上來說,RDS只讀實例使用的 MySQL主備複製,一個主庫最多支持5個備庫,備庫提供只讀訪問,用戶程序訪問備庫時使用與主庫不同的地址。而DRDS只讀實例(讀寫分離)其實底層依賴的就是RDS的只讀實例,但是DRDS作為數據庫中間件,為1個主實例和多個只讀實例提供了統一的訪問入口,當DRDS設置了讀寫分離時,對用戶程序是透明的,用戶只需要在DRDS控制檯上自由調整隻讀實例的讀比例即可。在比較新的版本中,RDS也支持了讀寫分離,但是在專有云v2版本中暫時還沒有支持。
那麼,RDS的只讀實例和DRDS的讀寫分離在性能上是否存在差異,我們在阿里雲專有云的環境做一個測試,來驗證這個問題。
一.準備環境
1.1 資源清單
資源類型 | 規格 | 數量 |
---|---|---|
RDS主實例 | 48G內存,磁盤100GB | 1 |
RDS只讀實例 | 48G內存,磁盤100GB | 5 |
DRDS實例 | 8節點,64Core CPU,128GB內存 | 1 |
測試壓力機ECS | 16Core CPU,64GB內存 | 3 |
1.2 創建測試表
在DRDS建立非分庫分表的測試表:
1.3 在DRDS中導入測試數據
mysql -u用戶名 -p密碼 -hDRDSIP -P3306 DRDS庫名< bic_base_org_insert.sql
1.4 查看錶大小
mysql> select count(*) from bic_base_org;
+----------+
| count(*) |
+----------+
| 191087 |
+----------+
1 row in set (0.03 sec)
1.5 執行計劃
mysql> explain select id,inst_id,code,name_cn,aic_register_name,postcode,administrative_division,province_code,city_code,status,business_unit,org_level,org_category,manage_level,parent_org_code,erp_parent_org_code from bic_base_org where id=170000;
+------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+
| GROUP_NAME | SQL | PARAMS |
+------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+
| DRDS_XNCS_BIC_CS_1513840820139DMOXDRDS_XNCS_BIC_CS_CJWT_0000_RDS | select id,inst_id,code,name_cn,aic_register_name,postcode,administrative_division,province_code,city_code,status,business_unit,org_level,org_category,manage_level,parent_org_code,erp_parent_org_code from bic_base_org where id=170000 | {} |
+------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+
1 row in set (0.00 sec)
mysql> explain execute select id,inst_id,code,name_cn,aic_register_name,postcode,administrative_division,province_code,city_code,status,business_unit,org_level,org_category,manage_level,parent_org_code,erp_parent_org_code from bic_base_org where id=170000;
+----+-------------+--------------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------+-------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | bic_base_org | const | PRIMARY | PRIMARY | 8 | const | 1 | NULL |
+----+-------------+--------------+-------+---------------+---------+---------+-------+------+-------+
1 row in set (0.01 sec)
可以看到 ,SQL在DRDS0號分庫上執行,並且執行計劃是主鍵查詢,這是最快的方式。
二.測試語句
2.1 測試語句:
vi select.sql
select id,inst_id,code,name_cn,aic_register_name,postcode,administrative_division,province_code,city_code,status,business_unit,org_level,org_category,manage_level,parent_org_code,erp_parent_org_code from bic_base_org where id=170000;
這個語句非常簡單,只是針對單表基於索引字段id查詢一條記錄的某些字段,我們重點考察的是大併發下只讀實例的性能表現。
2.2 測試工具:
mysqlslap
三.測試過程
測試分為兩大組:
第一組併發100,對比RDS,RDS只讀實例,DRDS 1個只讀實例和DRDS 5個只讀實例的性能表現。3.1-3.4是第一組測試數據。
第二組將增加併發,進行摸高測試,觀察資源的瓶頸和系統的極限。3.5-3.9是第二組測試數據。
3.1 RDS主實例測試(100併發)
測試說明:100併發,總共跑1千萬條相同的主鍵查詢:
mysqlslap --query=/select.sql --concurrency=100 --number-of-queries=10000000 --iterations=1 --create-schema=drds_xncs_bic_cs_trou_0000 --engine=innodb -hRDSIP地址 -u用戶名 -p密碼
Benchmark
Running for engine innodb
Average number of seconds to run all queries: 154.738 seconds
Minimum number of seconds to run all queries: 154.738 seconds
Maximum number of seconds to run all queries: 154.738 seconds
Number of clients running queries: 100
Average number of queries per client: 100000
QPS=10000000/154.738=64625,該場景下,資源沒有瓶頸。
注:後面每個測試案例的命令與本案例相似,所以略去測試命令,只展示測試結果。
3.2 RDS只讀實例測試(100併發)
測試說明:100併發,總共跑 1千萬條相同的主鍵查詢:
Benchmark
Running for engine innodb
Average number of seconds to run all queries: 150.370 seconds
Minimum number of seconds to run all queries: 150.370 seconds
Maximum number of seconds to run all queries: 150.370 seconds
Number of clients running queries: 100
Average number of queries per client: 100000
QPS=10000000/150.370=66502,該場景下,資源沒有瓶頸。
3.3 DRDS測試(1個只讀實例,100併發)
測試說明:(把其中一個slave庫讀比例設100% 測drds下一個備庫 ) 100併發,共跑 1千萬條相同的主鍵查詢:
Benchmark
Running for engine innodb
Average number of seconds to run all queries: 235.556 seconds
Minimum number of seconds to run all queries: 235.556 seconds
Maximum number of seconds to run all queries: 235.556 seconds
Number of clients running queries: 100
Average number of queries per client: 100000
QPS=10000000/235.556=42453,該場景下,資源沒有瓶頸。
3.4 DRDS測試(5個只讀實例,100併發)
測試說明:5個只讀每個開20%,100併發,總共跑1千萬條相同的主鍵查詢:
Benchmark
Running for engine innodb
Average number of seconds to run all queries: 216.412 seconds
Minimum number of seconds to run all queries: 216.412 seconds
Maximum number of seconds to run all queries: 216.412 seconds
Number of clients running queries: 100
Average number of queries per client: 100000
QPS=10000000/216.412=46208,該場景下,資源沒有瓶頸。
第一組測試結束,低壓力(100併發)下,RDS主實例和只讀實例性能大致相同,DRDS 1個只讀實例和5個只讀實例的配置對比,性能也基本相似,且不如RDS的性能,這是符合預期的,因為在沒有達到性能極限前,DRDS會比RDS多一層開銷。第二組測試中,數據考慮到單臺ECS性能併發量的侷限性,於是採用多臺ECS併發測試,通過DRDS和RDS控制檯觀察數據,重點關注整體吞吐能力和極限。
3.5 RDS主實例測試(1500併發)
測試說明:共1500併發,兩個ECS執行分別1000,500併發,總共跑 20億條相同的主鍵查詢:
RDS連接數:75%(1500),RDS最大連接數為2000
RDSQPS:接近70000
RDS CPU:接近100%,出現瓶頸
SQL的執行時間:幾百-幾萬微秒
3.6 RDS主實例測試(1900併發)
測試說明:共1900併發,三個ECS執行分別1000,500,400 併發,總共跑 30億條相同的主鍵查詢。
RDS連接數:1900,達到瓶頸
RDS QPS:接近70000
RDS CPU:接近100%,達到瓶頸
SQL的執行時間:幾百-幾萬微秒
3.7 DRDS(5個只讀實例,1000併發)
測試說明:5個只讀每個開20%,1000併發,總共跑1億條相同的主鍵查詢:
Benchmark
Running for engine innodb
Average number of seconds to run all queries: 1790.584 seconds
Minimum number of seconds to run all queries: 1790.584 seconds
Maximum number of seconds to run all queries: 1790.584 seconds
Number of clients running queries: 1000
Average number of queries per client: 100000
QPS=100000000/1790=55866,該場景下,資源沒有瓶頸。
3.8 DRDS(5個只讀實例,10000併發)
測試說明:(5個只讀每個開20%) 共10000併發,兩個ECS執行分別5000 總共跑 20億條相同的主鍵查詢:
物理RT:1.1ms左右
QPS:大約125000左右
RDS SQL執行時間:100微秒左右
客戶端ECS千兆網卡打滿,出現瓶頸
3.9 DRDS(5個只讀實例,15000併發)
測試說明:(5個只讀每個開20%) 共15000併發,三個ECS執行分別5000 總共跑 30億條相同的主鍵查詢。
DRDS QPS:大約210000左右
RDS上SQL的執行時間:100微秒左右
物理RT:2.1ms左右
客戶端ECS網卡被打滿,出現瓶頸
四.測試總結:
數據庫 | 連接數 | QPS | RT/SQL執行時間 | 瓶頸分析 |
---|---|---|---|---|
RDS主實例 | 100 | 64625 | 15.4us | 沒有瓶頸 |
RDS只讀實例 | 100 | 66502 | 15.0us | 沒有瓶頸 |
DRDS(1主+1只讀) | 100 | 42453 | 23.6us | 沒有瓶頸 |
DRDS(1主+5只讀) | 100 | 46208 | 21.6us | 沒有瓶頸 |
RDS主實例 | 1500 | 69980 | 幾百~幾萬us | RDS CPU打滿 |
RDS主實例 | 1900 | 69000 | 幾百~幾萬us | RDS CPU、連接數打滿 |
DRDS(1主+5只讀) | 1000 | 55866 | 17.9us | 沒有瓶頸 |
DRDS(1主+5只讀) | 10000 | 125000 | 1.9ms(DRDS)100us(RDS) | 加壓ECS網卡打滿 |
DRDS(1主+5只讀) | 15000 | 210000 | 11.2ms(DRDS)100us(DRDS) | 加壓ECS網卡打滿 |
4.1 單臺ECS客戶端低壓力測試
RDS主實例和只讀實例性能基本相同;
只有1個只讀實例的DRDS耗時比單RDS主實例或單RDS只讀實例相差較大,大約損失35%的性能;
開滿5個只讀實例的DRDS耗時比單RDS主實例或者單RDS只讀實例相差較大,大約損失29%的性能;
低壓力下測試場景,平均RT在幾十微秒這個數量級。
4.2 多臺ECS客戶端大壓力極限測試
RDS單個主實例配置2000最大併發數,選用1900併發,QPS達到69000,響應時間在毫秒級。此時連接數和CPU都已經接近極限;
DRDS開滿5個只讀實例,三臺ECS到達15000的併發,DRDS的QPS可以達到210000左右,響應時間達到毫秒級。此時除客戶端ECS達到極限外,RDS和DRDS均有資源剩餘可用;
因為DRDS是數據庫中間件,同時有內置連接池,所以從單個連接的SQL性能來說,DRDS不如RDS,但差異只體現在微秒這個數量級;而正因為DRDS有內置連接池,大規模大量連接高併發場景下,DRDS體現出優勢,且響應時間還保持在毫秒級別,可以接受;
RDS讀寫分離由於專有云還不支持,所以沒有進行測試,預期會比單實例RDS性能稍差。從數據庫連接數來看,也不如DRDS支持得多,需要在應用程序中設置連接池,從而滿足更高的併發需求。