作者:回雁
我們都知道,對于資料庫中基礎資訊表來說,它的資料變化頻率低,資料量小,但由于基礎資料本身的特點,大多數相關系統都會對頻繁地讀取它。即便我們通過對資料調取服務進行服務化包裝,通過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隻讀執行個體 | 5 | |
DRDS執行個體 | 8節點,64Core CPU,128GB記憶體 | |
測試壓力機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%,達到瓶頸
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執行時間 | 瓶頸分析 |
---|---|---|---|---|
100 | 64625 | 15.4us | 沒有瓶頸 | |
66502 | 15.0us | |||
DRDS(1主+1隻讀) | 42453 | 23.6us | ||
DRDS(1主+5隻讀) | 46208 | 21.6us | ||
1500 | 69980 | 幾百~幾萬us | RDS CPU打滿 | |
1900 | 69000 | RDS CPU、連接配接數打滿 | ||
1000 | 55866 | 17.9us | ||
10000 | 125000 | 1.9ms(DRDS)100us(RDS) | 加壓ECS網卡打滿 | |
15000 | 210000 | 11.2ms(DRDS)100us(DRDS) |
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支援得多,需要在應用程式中設定連接配接池,進而滿足更高的并發需求。