作者:回雁
我们都知道,对于数据库中基础信息表来说,它的数据变化频率低,数据量小,但由于基础数据本身的特点,大多数相关系统都会对频繁地读取它。即便我们通过对数据调取服务进行服务化包装,通过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支持得多,需要在应用程序中设置连接池,从而满足更高的并发需求。