订单读服务压测记录

1.服务调用架构图

2.硬件规格

client:MacBook pro(13-inch, 2017,Intel Core i5,8 GB 2133 MHz LPDDR3)scala脚本,并发请求

search服务端:4Core 8GB  4台

ES服务端:16Core 32GB 8台

3.压测记录

3.1 50并发 5分钟

3.2 100并发 5分钟

可以看到并发增加的情况下QPS有所下降,且有9个请求出错了。search服务端和ES服务端的负载并没有明显的增加。

可以推测,此时的瓶颈不在于机器的性能,应该有类似连接池的东西限制了QPS。

由于search服务端使用了jestClient,而jestClient是基于http与ES服务端进行通信的,是否是jestClient中维护了一个连接池呢?

在debug时查看jestClient中的数据结构,发现其内部使用了httpclient

 

httpclient通过maxTotal和defaultMaxPerRoute来配置连接池

maxTotal:设置连接池的最大连接数,即整个池子的大小。初始值20

defaultMaxPerRoute:设置每一个路由的最大连接数,这里的路由是指IP+PORT,例如连接池大小(MaxTotal)设置为300,路由连接数设置为200(DefaultMaxPerRoute),对于www.a.comwww.b.com两个路由来说,发起服务的主机连接到每个路由的最大连接数(并发数)不能超过200,两个路由的总连接数不能超过300。初始值2.

在defaultMaxPerRoute小于maxTotal时,主要是defaultMaxPerRoute起作用,因为在我这个例子中只有一个 ip+port

在没有配置httpclient的连接池参数时,默认使用初始值。接下来调整参数继续进行测试。

3.3 maxTotal=100, defaultMaxPerRoute=5, 50并发 5分钟

defaultMaxPerRoute变为原来的2.5倍,QPS变为原来的3倍。此时QPS主要受defaultMaxPerRoute参数影响。

search后端和ES后端的负载均由所增加,search后端的负载比ES后端的压力高约10%

 

3.4 maxTotal=100, defaultMaxPerRoute=5, 100并发 5分钟

线程数增加一倍,QPS只是略有增加,且95线 99线均增加了不少,看起来是defaultMaxPerRoute限制了并且数量。

3.5 maxTotal=100, defaultMaxPerRoute=10, 50并发 5分钟

此时QPS已经到5278,比前次有不少提升。search后端和ES后端的负载均由明显增加。接下来增大并发数。

 

 

3.6 maxTotal=100, defaultMaxPerRoute=10, 100并发 5分钟

从测试结果看,并发数增加了一倍,但是QPS只是略有增加,且95线 99线均由增加,推测是defaultMaxPerRoute限制了并发数。接下来继续调整参数。

 

 

3.7 maxTotal=200, defaultMaxPerRoute=20, 100并发 5分钟

此时QPS已达到8118,且95线 99线均表现良好。

从机器负载监控图看,search后端服务器压力较大,CPU使用率超过60%。ES后端CPU使用率35%左右,压力一般。

 

 

3.8 maxTotal=200, defaultMaxPerRoute=20, 200并发 10分钟

并发数增加一倍,QPS值增加了800。此时search后端服务器CPU使用率在70%左右,ES后端服务器CPU使用率不到40%。加下来继续增加defaultMaxPerRoute

 

 

3.9 maxTotal=200, defaultMaxPerRoute=30, 100并发 5分钟

maxTotal相同、并发数相同,defaultMaxPerRoute由20增加到30,QPS只增加了300。

search后端机器压力仍然较大,CPU负载约66%,略有增加。ES后端机器CPU负载约38%,没有明显增加。

接下来提高并发数。

 

 

3.10 maxTotal=200, defaultMaxPerRoute=30, 200并发 5分钟

maxTotal相同、defaultMaxPerRoute相同,并发数由100增加到200时,QPS增加了1500,突破了10000.

此时search后端服务器CPU负载约75%,ES后端服务器负载约41%。

综合看来,此时search后端服务器已到极限。而ES后端服务器仍有压榨空间。

 

 

4.结论

search后端4台机器(4C8G)、ES后端8台机器(16C32G),jestClient配置maxTotal=200、defaultMaxPerRoute=30的情况下,订单读服务的极限QPS为10000。此时search后端服务器到达极限,ES后端服务器仍有压榨空间。

目前订单读服务日常QPS在200-300,完全能满足未来10倍的增长需求。

5.存在的问题

1.压测时调用服务端接口使用的参数均为热点数据,ES服务端是否存在缓存?

2.没有jestClient连接数的监控,参数设置是否达到最优?

 

附:设置maxTotal和defaultMaxPerRoute的方法

@Slf4j
@Component
public class HttpSettingsCustomizer implements HttpClientConfigBuilderCustomizer {

	//Apollo配置
    @Value("${es.max.total.connection:100}")
    private Integer maxTotalConnection;
    @Value("${es.default.max.total.connection.per.route:5}")
    private Integer defaultMaxTotalConnectionPerRoute;

    @Override
    public void customize(HttpClientConfig.Builder builder) {
        log.info("set maxTotalConnection={}, defaultMaxTotalConnectionPerRoute={}", maxTotalConnection, defaultMaxTotalConnectionPerRoute);
        builder.maxTotalConnection(maxTotalConnection).defaultMaxTotalConnectionPerRoute(defaultMaxTotalConnectionPerRoute);
    }
}

参数设置过程可参考JestAutoConfiguration源码

@Configuration
@ConditionalOnClass(JestClient.class)
@EnableConfigurationProperties(JestProperties.class)
@AutoConfigureAfter(GsonAutoConfiguration.class)
public class JestAutoConfiguration {

   private final JestProperties properties;

   private final ObjectProvider<Gson> gsonProvider;

   private final List<HttpClientConfigBuilderCustomizer> builderCustomizers;

   public JestAutoConfiguration(JestProperties properties, ObjectProvider<Gson> gson,
         ObjectProvider<List<HttpClientConfigBuilderCustomizer>> builderCustomizers) {
      this.properties = properties;
      this.gsonProvider = gson;
      this.builderCustomizers = builderCustomizers.getIfAvailable();
   }

   @Bean(destroyMethod = "shutdownClient")
   @ConditionalOnMissingBean
   public JestClient jestClient() {
      JestClientFactory factory = new JestClientFactory();
      factory.setHttpClientConfig(createHttpClientConfig());
      return factory.getObject();
   }

   protected HttpClientConfig createHttpClientConfig() {
      HttpClientConfig.Builder builder = new HttpClientConfig.Builder(
            this.properties.getUris());
      PropertyMapper map = PropertyMapper.get();
      map.from(this.properties::getUsername).whenHasText().to((username) -> builder
            .defaultCredentials(username, this.properties.getPassword()));
      Proxy proxy = this.properties.getProxy();
      map.from(proxy::getHost).whenHasText().to((host) -> {
         Assert.notNull(proxy.getPort(), "Proxy port must not be null");
         builder.proxy(new HttpHost(host, proxy.getPort()));
      });
      map.from(this.gsonProvider::getIfUnique).whenNonNull().to(builder::gson);
      map.from(this.properties::isMultiThreaded).to(builder::multiThreaded);
      map.from(this.properties::getConnectionTimeout).whenNonNull()
            .asInt(Duration::toMillis).to(builder::connTimeout);
      map.from(this.properties::getReadTimeout).whenNonNull().asInt(Duration::toMillis)
            .to(builder::readTimeout);
      customize(builder);
      return builder.build();
   }

   private void customize(HttpClientConfig.Builder builder) {
      if (this.builderCustomizers != null) {
         for (HttpClientConfigBuilderCustomizer customizer : this.builderCustomizers) {
            customizer.customize(builder);
         }
      }
   }

}

https://docs.spring.io/spring-boot/docs/2.0.3.RELEASE/reference/htmlsingle/#boot-features-elasticsearch

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值