记一次网关性能测试记录

Posted by pggsnap on June 11, 2018

网关性能测试

测试接口: /dw-service/jres/test,该接口没有业务逻辑,直接返回字符串 jres-test。

涉及服务器: ip | 配置 | 运行服务 —|— |— 10.201.0.28 | 6 核,8G 内存 | gateway -Xmx2048m 10.201.0.29 | 6 核,8G 内存 | ms-auth -Xmx4096m 10.201.0.32 | 6 核,8G 内存 | dw-service -Xmx1024m

测试工具: 10.201.0.41 服务器安装 JMeter。

关闭 OAuth 认证

涉及服务:gateway;dw-service;外部请求访问网关,网关直接转发给 dw-service 微服务。 threads | avg | 99%Line | error | throughtput/sec | receive | send(KB/s) — |— |— |— |— |— |— 10 |3 |7 |0 |3020 |539 |589 50 |10 |35 |0 |4865 |871 |950 100 |20 |151 |0 |4800 |859 |936 200 |41 |520 |0 |4743 |849 |926 500 |157 |2228 |6.3 |3175 |951 |580

当 threads=50 时,dw-service 内存占用超过 1G,达到瓶颈。

当 zuul.semaphore.max-semaphores=100, threads=200 时,报错:java.lang.RuntimeException: could not acquire a semaphore for execution at com.netflix.hystrix.AbstractCommand.handleSemaphoreRejectionViaFallback。 修改 zuul.semaphore.max-semaphores=200 即可。

当 threads=500 时,报错:java.net.BindException: Address already in use: connect at java.net.DualStackPlainSocketImpl.connect0(Native Method)

这是 windows 的 bug,当 JMeter 并发线程数较高时,可能会发生该错误。可以通过更改注册表解决:增大可分配的 tcp 连接端口数,减少处于 TIME_WAIT 状态的连接生存时间。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
新增 DWORD:
MaxUserPort: 65534
TcpTimedWaitDelay: 30

开启 OAuth 认证

涉及服务:gateway;dw-service;ms-auth;外部请求访问网关,网关先通过 feign 调用 OAuth 服务,确认该用户有权限后转发给 dw-service 服务。 threads | avg | 99%Line | error | throughtput | receive | send(KB/s) — |— |— |— |— |— |— 10 |21 |147 |0 |453 |81 |88 50 |20 |72 |0.2 |2447 |439 |478 100 |53 |664 |1.1 |1879 |339 |367

Cannot get Jedis connection

ms-auth 将用户的 token 信息存在 redis 中,jedis 配置如下:

spring.redis.pool:
  max-active: 8
  max-wait: 8
  min-idle: 0
  max-idle: 8

当 threads=10 时,0.2% 的请求报 Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool 错误。

修改 jedis 配置后问题解决。

spring.redis.pool:
    max-active: 100
    max-wait: 100
    min-idle: 1
    max-idle: 12

java.net.ConnectException: 无法指定被请求的地址

当 threads=50 时,0.2% 的请求报错:java.net.ConnectException: 无法指定被请求的地址 (connect failed) at java.net.PlainSocketImpl.socketConnect(Native Method)。 网上搜索了一下,一般这个是因为本地端口被占用完了的缘故。

通过

[root@gateway imf]# cat /proc/sys/net/ipv4/ip_local_port_range
32768	60999

查看本地可用端口为 28232 个(排除系统占用等);

gateway 的主要功能是认证授权,通过之后转发路由。因此涉及到的 http 连接主要包括:10.201.0.29:9999 的 auth 服务,以及 10.201.0.32:8767 的 dw-service 服务。

[root@gateway imf]# netstat -an | grep 10.201.0.28: | wc -l
28570
[root@gateway imf]# netstat -an | grep 10.201.0.29: | wc -l
28184
[root@gateway imf]# netstat -an | grep 10.201.0.32: | wc -l
128
[root@gateway imf]# netstat -an | grep 10.201.0.29:9999
tcp6       0      0 10.201.0.28:54682       10.201.0.29:9999        TIME_WAIT
tcp6       0      0 10.201.0.28:59942       10.201.0.29:9999        TIME_WAIT
tcp6       0      0 10.201.0.28:33243       10.201.0.29:9999        TIME_WAIT
tcp6       0      0 10.201.0.28:54634       10.201.0.29:9999        TIME_WAIT
tcp6       0      0 10.201.0.28:47410       10.201.0.29:9999        TIME_WAIT
tcp6       0      0 10.201.0.28:54770       10.201.0.29:9999        TIME_WAIT

有大量的连接 10.201.0.29:9999 的本地端口,tcp 状态为 TIME_WAIT。

默认 feign 采用 HttpURLConnection,没有使用线程池;可以通过配置线程池优化调用效率,并解决本地端口不够分配的异常。

feign:
  httpclient:
    enabled: true
@Configuration
public class HttpClientPool {
    @Bean
    public HttpClient httpClient() {
        RequestConfig.Builder builder = RequestConfig.custom();
        // 超时时间配置
        builder.setSocketTimeout(10 * 1000);
        builder.setConnectTimeout(3 * 1000);
        RequestConfig defaultRequestConfig = builder.build();
        // 连接池配置
        final PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.MILLISECONDS);
        poolingHttpClientConnectionManager.setMaxTotal(1000);
        poolingHttpClientConnectionManager.setDefaultMaxPerRoute(500);
        // httpclient 配置
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());
        httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
        httpClientBuilder.setDefaultRequestConfig(defaultRequestConfig);
        HttpClient client = httpClientBuilder.build();

        return client;
    }
}

更改后重新测试,threads=100 时,gateway 6 核 CPU 使用率 579%,达到瓶颈。 threads | avg | 99%Line | error | throughtput | receive | send(KB/s) — |— |— |— |— |— |— 10 |7 |13 |0 |1270 |227 |248 50 |17 |40 |0 |2870 |514 |560 100 |32 |142 |0 |3024 |541 |591 200 |65 |520 |0 |3028 |544 |591 500 |162 |686 |0 |3072 |549 |600 1000 |327 |874 |0 |3047 |549 |595

测试服务链路跟踪 sleuth 对性能的影响

spring:
    zipkin:
        base-url: 'http://zipkin-server:9411'
    sleuth:
        sampler:
        percentage: 1
sleuth threads avg 99%Line error throughtput receive send(KB/s)
100%跟踪 100 32 133 0 3070 541 591
1%跟踪 100 24 90 0 4030 722 787