记录一次使用sharding-jdbc分库分表下的压力测试过程

背景介绍:

最近我们在竞标一个项目,对方IT有几个压测要求:

   1.系统用户量4亿+;

   2.用户注册场景下TPS达到2000;

   3.用户查询场景下TPS达到8000;

   4.用户抢券秒杀场景下TPS达到8000;

   5.数据库单表数据量均不能超过5000w;

   6.上述所有接口响应时间不超过500ms;

拿到这个需求之后boss就找我,让我一个星期内把这个压测报告提供给对方,废话不多说,开始干活。

解决方法:

在介绍一下我的思路

1.拿到这个需求之后,我首先按照对方要求的单表不超过5000w,用户总量4亿+,决定使用集群+读写分离+分库分表的方式来达到要求。

a.为了提高系统的稳定性和响应速度,我们数据库采用集群模式,集群里面一主多从,数据库直接使用阿里云的云数据库PolarDB,结构如下图;

b. 为了系统的扩展性和尽量减少数据的迁移,我决定把表一次性拆分到位,最终决定拆分成8个数据库,每个库8张表,结构图如下,这样有个好处就是每张表实际只存储700w用户就可以;

   

2.我们的开发语言是java,使用的框架是springcloud,分库分表插件使用 sharding-jdbc(下方是sharding配置)

sharding:
  jdbc:
    datasource:
      names: db0,db1,db2,db3,db4,db5,db6,db7
      db0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://***.rwlb.rds.aliyuncs.com:3306/db0?characterEncoding=utf-8
        username: ***
        password: ***
      db1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://***.rwlb.rds.aliyuncs.com:3306/db1?characterEncoding=utf-8
        username: ***
        password: ***
      db2:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://***.rwlb.rds.aliyuncs.com:3306/db2?characterEncoding=utf-8
        username: ***
        password: ***
      db3:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://***.rwlb.rds.aliyuncs.com:3306/db3?characterEncoding=utf-8
        username: ***
        password: ***
      db4:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://***.rwlb.rds.aliyuncs.com:3306/db4?characterEncoding=utf-8
        username: remote
        password: ***
      db5:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://***.rwlb.rds.aliyuncs.com:3306/db5?characterEncoding=utf-8
        username: ***
        password: ***
      db6:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql:/***.rwlb.rds.aliyuncs.com:3306/db6?characterEncoding=utf-8
        username: ***
        password: ***
      db7:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://***.rwlb.rds.aliyuncs.com:3306/db7?characterEncoding=utf-8
        username: ***
        password: ***
    config:
      sharding:
        default-database-strategy:
          inline:
            sharding-column: id
            algorithm-expression: db$->{id % 8}
        tables:
          member:
            actual-data-nodes: db$->{0..7}.member_$->{0..7}
            table-strategy:
              inline:
                sharding-column: age
                algorithm-expression: member_$->{age % 8}
          key-generator:
            column: id
         
      props:
        sql:
          show: true
mybatis-plus:
  mapper-locations: classpath:/mapper/*Mapper.xml

测试准备:

1.向数据库中插入4亿条用户信息 (下方是多线程写入代码)

private Long save(int size,int batch){
        Long start = System.currentTimeMillis();
        ExecutorService executor = Executors.newFixedThreadPool(50);
        CountDownLatch countDownLatch = new CountDownLatch(size);
        for (int i=0;i<size;i++){
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    Member member = new Member();
                    member.setAge(RandomUtil.randomInt(0,100));
                    member.setName(RandomUtil.randomStringUpper(4));
                    member.setCreateTime(new Date());
                    try {
                        memberService.save(member);
                    }catch (Exception e){
                        e.printStackTrace();
                    }finally {
                        countDownLatch.countDown();
                    }
                }
            });
        }
        try {
            countDownLatch.await();
            executor.shutdown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Long end = System.currentTimeMillis();
        StringBuffer sb = new StringBuffer();
        sb.append(batch+"开始时间:"+start);
        sb.append(batch+"结束时间:"+end);
        sb.append(batch+"总计条数:"+size);
        sb.append(batch+"总计耗时:"+(end-start)+"ms");
        System.out.println(sb.toString());
        return end-start;
    }

2.部署到服务器开始写入数据,等了几个小时终于写入完成(写入期间数据库QPS,和最终写入数据量约4.9亿)

3.写入期间我只用了2台服务器,所以这个应该不是数据库的极限。

    

开始写入测试:

1.使用阿里云的PTS配置测试场景,作为开发人员个人感觉这个很好用,就是有点费钱;

2.先测试写入场景,因为之前有数据写入,我知道数据写入应该是没有问题的,所以我这里就用了一台应用服务器

3.下面4张图分别是PTS的场景配置、施压配置、场景调试、和最终的测试报告

说明一下,这里的并发只有100,因为这个这个资源包里并发只有这么点,接下来测试查询的时候肯定需要重新购买资源包,这个场景会重新测试

场景配置

施压配置

场景调试 (用来测试你的场景,看返回结果是否是你想要的结果)

测试报告

4.通过测试发现单台应用服务器的TPS就可以达到2000,所以说写入场景现在没有问题了

 

开始查询测试:

查询用户的时候,我预计性能会不如之前的写入,因为按照分库分表的策略,写入计算好路由,写入是很快速的,最终一次写入只需要执行一条sql语句;

我们的会员查询接口是按照会员id查询的,所以确定了会员id就知道去那个数据库查找,但是按照目前的分表策略,是没有办法确定去那张表查找,只能全部查找,也就是按照id查询会员信息,要执行8条sql语句;

查询测试准备工作:

因为预估一台应用服务器没有办法达到要求,这里要做负载均衡,直接用户阿里云的ALB,下图是直接用10台服务器,在实际测试过程中是主键递增的,不是一次就用了10台;

 

接下来开始测试写入场景:

1.首先查找到500w个用户的id,导入到cvs里面。

2.配置测试场景,这里把之前cvs压缩传入数据源管理,就可以根据这些id来模拟实际的用户查询了。

3.配置压测具体参数,这次的并发直接设置为2000

4.调试场景,发现场景配置没有问题

5.开始测试, 下图是应用服务器有10台的测试报告

 

6.下图是逐渐增加应用服务器的时候数据库服务器的QPS,从图中应该可以看出,应用服务器增加了4次,从2台->4台->6台->10台。

 

总结

1.在分库分表之前要规划好分库分表策略,要根据业务和实际需求设置合理的策略,例如在本次测试中用户查询的性能之所以不如用户写入就是因为分表策略的设置,写入只需要执行一条SQL,但是查询就需要执行8条SQL;

2.使用负载均衡后性能并不是线性提升,按照预估应用服务器需要8台就可以达到要求,但是实际中使用了10台;

3.现在各种各样的云产品越来越多,可以在合适的场景灵活的使用云产品,例如在本次测试中我使用了 阿里云的 ECS服务器、PolarDB云数据库、负载均衡 SLB、性能测试PTS,使用这些云产品可以大幅度提高工作效率。如果在以往我们需要自己安装数据库,配置nginx,配置各种集群,搭建测试环境,测试完成之后还要写测试报告,现在直接使用即可,测试报告也自动生成,本来一个星期才能完成的事情,现在只需要2天就能完成了,剩余的3天可以再学点新的技术了;

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程简介 随着互联网的发展,软件的规模在逐渐变大,用关系型数据库如何存储和处理大规模的业务数据成为企业面临的挑战, 关系型数据库作为OLTP(联机事务处理过程)系统的首选毋庸置疑,但是关系型数据面对大规模数据的处理有其先天的不足,比如单存储上千万数据时便会出现不同程度的处理速度缓慢问题,如何解决?分库技术就是为了解决由于数据量过大而导致数据库性能降低的问题,将原来独立的数据库拆分成若干数据库组成 ,将数据大拆分成若干数据组成,使得单一数据库、单一数据的数据量变小,从而达到提升数据库性能的目的。本课程将系统的讲解分库技术。 课程价值 分库技术是为解决关系型数据库存储和处理大规模数据的问题,主要应用于OLTP系统,它与应用于OLAP(联机分析处理)的大数据技术有不同的应用场景,本课程本着从解决生产实际问题出发,讲授分库技术的解决方案,包括:垂直分库、垂直分、水平分库、水平分、读写分离,涵盖了分库的各种方案,并且深入讲解Sharding-JDBC框架的原理及使用方法,通过学习本课程可以快速应用到生产实践中。 课程优势 本课程不仅讲解多种有效的分库的解决方案,还深入讲解了Sharding-JDBC框架的原理和使用方法,Sharding-JDBC是一套轻量级的对代码零侵入的框架,在生产中有广泛的使用。本课程从思想原理、技术框架、案例实操三个方面去学习,可以快速的将分库技术应用到生产实践中,解决大数据存储与处理的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值