合理配置线程池参数
线程池是微服务的主要业务处理单元,合理的规划线程池不仅可以最大限度提升系统性能,还能防止异常情况导致系统无法给正常用户提供服务。线程池优化和业务自身的性能有很大关系,不同的场景参数设置不同,需要具体分析。下面分两种场景介绍。开始之前需要对业务的性能做一些基本的摸底,对常见的接口进行测试,查看时延。
- 业务性能很好的情况。
业务性能很好的时候,为了让业务系统具备更好的可预测性,防止JVM垃圾回收、网络波动、突发流量等对系统的稳定性造成冲击,需要能够快速丢弃请求,并配合重试等措施,以保障波动情况下系统性能可预测,同时不会出现偶然的业务失败,影响体验。
- 连接数和超时设置
# 服务端verticle实例数,保持默认值即可。建议配置为8~10。 servicecomb.rest.server.verticle-count: 10 # 最大连接数限制。默认值为 Integer.MAX_VALUE。可以结合实际情况估算最大值,使系统具备更好的韧性。 servicecomb.rest.server.connection-limit: 20000 # 连接闲置时间。默认值60秒,一般不需要修改 servicecomb.rest.server.connection.idleTimeoutInSeconds: 60 # 客户端verticle实例数,保持默认值即可。建议配置为8~10。 servicecomb.rest.client.verticle-count: 0 # 一个客户端与服务器建立的最大连接数为 verticle-count * maxPoolSize,不要超过线程数。 # 这里是 10*50=500. 实例非常多的场景,要减小单个实例的连接数。 servicecomb.rest.client.connection.maxPoolSize: 50 # 连接闲置时间。默认值30 秒,一般不需要修改,要小于服务端的连接闲置时间。 servicecomb.rest.client.connection.idleTimeoutInSeconds
- 业务线程池配置
# 线程池组数,建议 2~4 servicecomb.executor.default.group: 2 # 建议 50~200 servicecomb.executor.default.thread-per-group: 100 # 线程池排队队列大小,默认值为Integer.MAX_VALUE。高性能场景不要使用默认值,以快速丢弃请求 servicecomb.executor.default.maxQueueSize-per-group: 10000 # 队列最大等待时间,如果超过,理解丢弃请求的处理并返回。默认值为0。 # 高性能场景配置小的排队超时时间,快速丢弃请求 servicecomb.rest.server.requestWaitInPoolTimeout: 100 # 设置比较短的超时时间,快速丢弃请求, 但是不建议这个值小于1秒,可能导致很多问题。 servicecomb.request.timeout=5000
- 连接数和超时设置
- 业务性能不那么好的情况。
即非并发场景,接口的平均时延大于100ms。时延高通常是由于业务代码存在IO、资源等等待,CPU利用率上不去导致的。如果是由于计算复杂导致的,调优会变得复杂。
当业务性能不太好的时候,下面几个参数值需要调大,否则业务会大量阻塞。业务性能不好,通过调大参数能够保证系统的吞吐量,应对突发流量来临时带来的业务失败。不过这个是以牺牲用户体验为代价的。
# 服务端连接闲置时间。 servicecomb.rest.server.connection.idleTimeoutInSeconds: 120000 # 客户端连接闲置时间。 servicecomb.rest.client.connection.idleTimeoutInSeconds: 90000 # 线程池组数。 servicecomb.executor.default.group: 4 # 线程池大小。 servicecomb.executor.default.thread-per-group: 200 # 线程池排队队列大小,性能不好的情况下需要排队 servicecomb.executor.default.maxQueueSize-per-group: 100000 # 配置较大的超时时间 servicecomb.rest.server.requestWaitInPoolTimeout: 10000 servicecomb.request.timeout=30000