一次压测经历

1.起因

最近在重构公司的画像服务,之前的画像数据存储在cassandra中,性能也很好。但是cassandra,公司没有老司机维护,所以要替换成公司自研的ekv(基于Tidb)存储。既然新的kv存储,当然要进行测试了。

2.方案

测试方案很简单,就是当用户查询数据穿透缓存,全部打到ekv上,该存储能够支撑住,过程如下图:

soa服务代码很简单,就是通过jedis连接ekv,然后查询用户信息:

   public String queryUserProfile(long userId) {

        long start = System.currentTimeMillis();
        Jedis jedis = null;
        try {
            jedis = KvStoreClient.getInstance().getResource();
            String userKey="1:"+userId;
            String profile = jedis.get(userKey);
            return profile;

        } catch (IOException e) {
            LOGGER.error("",e);
        }finally {
            if(jedis!=null) {
                jedis.close();
            }
            LOGGER.info("total time : "+(System.currentTimeMillis()-start));
        }
        return null;
    }

3.第一波jmeter测试

  • 开启10个线程 耗时180s,测试结果,qps大概在3.58k/s。
  • 开启50个线程,耗时180s,测试结果,qps大概在3.06k/s。
  • 开启100个线程,耗时180s,测试结果,qps大概还是维持在3.7k/s。

查看了测试机器和服务器的各项指标,负载都很低,但是qps压不上去了。。。

3.1 排查问题

3.1.1 soa服务排查

首先想到的是代码质量是否有问题,检测了一下jedis的连接池的配置,确认配置上 是没有问题的:

  JedisPoolConfig config = new JedisPoolConfig();
            config.setMinIdle(50);
            config.setMaxIdle(200);
            config.setMaxTotal(500);
            config.setBlockWhenExhausted(false);
            config.setMaxWaitMillis(1000 * 3);
            config.setTestOnBorrow(false);
            config.setTestOnReturn(false);
            config.setTestWhileIdle(false);

再检查了一下SOA的配置是否有限流等配置,发现线程池的连接数默认为50,于是配置到100。重新测试一下,发现qps还是上不去,到此基本上可以确认soa服务,没啥问题,不过最后还是做了一个空接口的qps查询,果然qps能够轻松上万。

3.1.2 ekv是否存在性能瓶颈

经过上一步的排查后,我把问题聚焦在ekv这块,通过granfan上的监控,觉得每次到get操作数据能够达到7-8k/s(这个是有异常的,理论上应该和接口的qps保持一致才对,后来向ekv的开发人员反映后,才知道监控打点配置成了double),是否通过jedis获取这块存在性能瓶颈,于是在代码里面模拟用户查询,代码如下:

 public String stressTest(int threads, long second, long userId) {
        ExecutorService poolExecutor = Executors.newFixedThreadPool(threads);
        for (int i=0;i<threads;i++){
            userId=userId+100000;
            poolExecutor.submit(new TestThread(userId));
        }
        try {
            Thread.sleep(second*1000);
            poolExecutor.shutdownNow();
        } catch (Exception ex) {
           LOGGER.warn("",ex);
        }

        String message="success:"+this.successCount.intValue()
                +",failure:"+this.failureCount.intValue();

        return message;
    }

    private class TestThread implements Runnable{

        private long userId;

        public TestThread(long userId){
            this.userId = userId;
        }

        @Override
        public void run() {
            while (true){
                this.userId++;
                String ret=queryUserProfile(this.userId);
                if (ret==null){
                    failureCount.incrementAndGet();
                }else {
                    successCount.incrementAndGet();
                }
            }
        }
    }

测试后,get的qps查询能够达到100多k,立马懵逼。。。

3.1.3 连接数检测

通过netstat这个工具,查看各个服务器的连接数是否都达到有效值,测试机器开启100个连接数,服务端能够全部监听到,但是到ekv的时候,只有30多,然后怎么也上不去了。 netstat -anp | grep -i est 到此总算找到了点眉目,100个连接,到达ekv只有30多个连接。说明jedis在处理get请求是,30个线程就能处理100个连接,也就是说测试环境和服务之间网络传输有延迟。 soa服务器网络输入1.5Gps,输出只有200Mbps。也就是说单台机器的的性能瓶颈是在网卡输出上。

结合我们的业务场景用户画像服务,每个用户的标签信息有多又少,多的10几k数据,少的小于1k,我们固定用户id,找了个小于1k的返回内容,果然qps突破3k到达6k,然后我把返回内容设置为固定的“aaa”返回信息,qps大概维持在8k左右。后续就再压不上去了,终于找到我们的性能瓶颈。

不过这次测试并没有测试到ekv的性能瓶颈。。。后续会通过集群的方式对ekv进行压测。

4.总结

复盘整个压测过程,我们一开始只考虑到CPU和内存的使用情况,没有仔细查看网络负载情况,主要对网络负载这块不是很了解。若直接将几张监控报表对比一下,应该很快就能发现问题的。排查问题就先从CPU、内存和网路IO这三个方向查看,就能很快定位瓶颈。

results matching ""

    No results matching ""