满足标准:并发大于等于100 ,平均响应时间小于等于3秒
项目在压测过程中并发数只有50,在并发数100的情况下有很多请求链接是失败的
1、首先从压测结果入手,对不满足标准的链接url进行单独压测,并在100并发数的条件下,查看聚合报告显示的当前压测链接的平均响应时间和错误率,并将结果输出本地中以查看有多少链接出现错误,出现的错误是什么,比如:403、401或500 等。
2、拿出日志,并根据具体报错信息,优化你的代码。
基本上到这一步,所有的问题一般都能解决了。
在本次压测中,大部分失败的请求都是500错误,同时错误主要集中在微服务之间的调用逻辑上,还有一部分是代码响应超时上。在并发量较高的情况下,就会出现处理失败的请求。
1、并发较高的情况下,使用shiro获取上下文中的用户信息时有时为空,这时就会导致错误链接,后台会报空指针异常
原因分析:在访问接口时,需要做登录认证,认证时,需要将用户信息存至上下文,存上下文时会负载均衡调用远程feign接口,导致调用失败,熔断。
这种情况目前处理方案
代码中做非空校验,让其返回200。并不能在压测链接中添加响应断言条件。这种是治标不治本,归其原因还是shiro的上下文信息无法处理高并发请求导致获取不到用户信息,导致压测时错误率升高。
2、并发较高的情况下,openfeign产生了服务降级
准确的说是 openfeign整和了ribbon 和hixtry 而 openfeign启用了hixtry后 并添加了fallback 注解,从而出现在服务端超时或报错的情况下出现了服务降级的情况。
深入剖析一下 openfeign中的服务降级和hixtry中的服务降级 有什么区别与联系?
查看日志报错:
2023-09-05 18:36:07.219 [http-nio-0.0.0.0-8982-exec-34] ERROR c.e.p.cloud.base.exception.GlobalExceptionHandler - could not acquire a semaphore for execution com.netflix.hystrix.exception.HystrixRuntimeException: BaseUserRemote#updateSysUser(SysUser) could not acquire a semaphore for execution and no fallback available.
2023-09-05 18:36:07.219 [http-nio-0.0.0.0-8982-exec-34] 错误 c.e.p.cloud.base.exception.GlobalExceptionHandler - 无法获取用于执行的信号量 com.netflix.hystrix.exception.HystrixRuntimeException:BaseUserRemote#updateSysUser(SysUser) 无法获取用于执行的信号量,并且没有可用的后备。
来分析一下错误的原因:
这个异常信息表示您的程序在调用 BaseUserRemote#updateSysUser(SysUser) 方法时无法获取一个信号量(semaphore)。信号量是一种计数器,用来控制同时访问某个特定资源的操作数量。 如果信号量的值为 0,那么没有许可可用,请求获取信号量的线程会被阻塞,直到有其他线程释放信号量。
出现这个异常的可能原因有以下几种:
hystrix为每个依赖提供一个小的线程池(或信号量),如果线程池已满调用将被立即拒绝,加速失败判定时间。hystrix还提供了两种隔离策略,分别是THREAD和SEMAPHORE。THREAD模式下,每个请求在单独的线程上执行,并受到线程池大小的限制;SEMAPHORE模式下,每个请求在调用线程上执行,并受到信号量计数的限制。隔离策略可以通过execution.isolation.strategy参数来设置,默认值是THREAD。
hixtry和ribbon的超时时间设置对压测时总是熔断有什么影响,主要取决于以下几个因素:
一般来说,要避免压测时总是熔断,需要根据实际情况合理地设置hixtry和ribbon的超时时间,保证在压测流量范围内,请求能够及时得到响应或者降级处理,不会因为等待过久或者失败过多而触发熔断器打开
# 设置实例HystrixCommandKey的此属性值,使用信号量策略
hystrix.command.HystrixCommandKey.execution.isolation.strategy=SEMAPHORE
# 设置 Hystrix 信号量隔离策略的最大并发请求数
hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests=100
# 设置 Hystrix 信号量隔离策略的最大并发回退请求数
hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests=50
# 设置 Hystrix 熔断器开关,true 表示开启熔断器
hystrix.command.default.circuitBreaker.enabled=true
# 设置 Hystrix 熔断器的请求阈值,即在一个统计窗口内最少请求数
hystrix.command.default.circuitBreaker.requestVolumeThreshold=20
# 设置 Hystrix 熔断器的错误率阈值,即触发熔断的错误百分比
hystrix.command.default.circuitBreaker.errorThresholdPercentage=50
# 设置 Hystrix 熔断器的休眠时间窗,即熔断后多久尝试恢复,默认为 5 秒
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=5000
高并发一下如何设置 hixtry 和 ribbon的超时时间?
一般来说,hixtry的超时时间包括以下几个方面:
一般来说,ribbon的超时时间包括以下几个方面:
hixtry还有一个fallback机制,当请求失败或者被拒绝时,可以执行一个备选方案,返回一个默认值或者友好提示。fallback也需要一定的资源来执行,所以hixtry也对fallback的并发请求数做了限制
hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests是一个配置参数,它表示每个命令允许的最大并发请求数。如果超过这个数目,请求将被拒绝,并触发降级逻辑
当你使用100并发进行压测时,可能有以下几种情况:
当你设置了hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests=100时,就相当于把fallback的并发请求数限制放宽了,让所有的fallback都能执行成功,不会报信号量阻塞的错误](about:blank#)12。但这并不意味着你解决了压测中出现的问题,只是把错误从信号量阻塞转移到了其他地方(如线程池拒绝、熔断器打开等)](about:blank#)12。
根据上述分析,我们解决此问题 从两点出发:1、设置hixtry 的超时时间 2、设置ribbon的超时时间 3、设置fallback的数量
当在进行压测时,发生了60个请求连接失败并触发了服务降级,这可能是由于服务端在高并发情况下无法处理这些请求而导致的。服务降级是为了保护服务端的稳定运行而进行的一种策略,当服务端无法及时响应请求或出现错误时,Hystrix会触发服务降级来保护服务端资源不过载。这样会导致某些请求被降级,返回默认响应。
要解决这种情况,首先需要确认为什么这60个请求触发了服务降级,而其他请求并没有报错或被降级。可能的原因包括:
服务端资源限制:服务端可能存在资源限制,如线程池容量不足、内存限制或者数据库连接池不够。你可以检查服务端的资源配置,并根据实际情况进行调整和优化。
请求过于频繁:这60个请求可能在短时间内同时发起,导致高并发情况下服务端无法处理这些请求。你可以考虑限制或调整客户端请求的频率,以免过多的请求同时到达服务端。
在OpenFeign和Hystrix的配置方面,你可以采取一些措施来改善这个问题:
调整线程池配置:在Hystrix的配置中,你可以增加线程池的核心线程数、最大线程数等参数来提高服务端的并发处理能力。
调整Hystrix的超时时间:可根据实际情况适当调整Hystrix的超时时间,避免过长的等待时间导致服务降级。
优化服务端性能:通过代码优化、缓存技术等方式提高服务端的性能和并发处理能力,以应对高并发请求。
使用负载均衡:使用负载均衡器对请求进行分流,将请求均匀分配到多个服务实例上,分散负载压力。
需要注意的是,在进行配置调整之前,一定要通过监控和分析来了解系统的瓶颈和性能状况,并找到具体的问题所在。同时,也可以适用开源性能测试工具,如JMeter、Gatling等进行压力测试,用于定位问题和验证配置的效果。
综上所述,通过优化服务端资源和配置OpenFeign和Hystrix的相关参数,可以增加系统的并发处理能力,减少触发服务降级的情况。但并发测试需要综合考虑系统的硬件资源和业务逻辑,建议结合具体场景来进行调整和优化。
在高并发情况下,Hystrix发生服务降级的条件包括:
这些条件可以通过配置Hystrix的参数来控制。使用OpenFeign集成Hystrix时,可以通过在Feign客户端接口的方法上添加@HystrixCommand注解来设置相关参数。
为了满足100个并发数并避免服务降级的情况,你可以根据以下几个方面进行配置:
超时时间:适当增加超时时间,确保服务端有足够的时间进行处理,并保证请求在指定超时时间内得到响应。可以在@HystrixCommand注解的commandProperties属性中设置execution.isolation.thread.timeoutInMilliseconds
参数。
请求阈值和错误比例:根据实际情况,调整请求阈值和错误比例的参数,使得请求超过阈值和错误比例的发生概率较低。可以在@HystrixCommand注解的commandProperties属性中设置circuitBreaker.requestVolumeThreshold
和circuitBreaker.errorThresholdPercentage
参数。
熔断时间:调整熔断器的关闭时间,确保熔断器在一段时间后能够逐渐关闭,允许部分请求通过。可以在@HystrixCommand注解的commandProperties属性中设置circuitBreaker.sleepWindowInMilliseconds
参数。
需要注意的是,并发数受到多个因素的影响,包括服务端的资源和处理能力、网络传输速度等。当高并发情况下,确保系统的可用性和性能需要综合考虑各个环节的优化。除了Hystrix的参数配置,还可以采取负载均衡、集群部署、合理设计数据库访问、缓存策略等措施来提升系统的并发处理能力。
最重要的是根据具体的业务场景进行测试和调优,逐步优化系统的性能和可用性,以满足高并发场景下的需求。
熔断并不是服务报错,而是一种主动的保护机制,用于避免服务因为故障或者延迟而造成的雪崩效应]。雪崩效应是指当一个服务不可用或者响应缓慢时,会导致调用方的资源耗尽,从而影响其他服务的正常运行,最终导致整个系统崩溃。
熔断的原理是通过监控服务的调用情况,当发现服务出现异常或者超时的比例或次数达到一定的阈值时,就会触发熔断器打开,切断对该服务的调用,并返回一个默认的结果或者提示信息 。这样可以保证调用方不会因为等待故障服务而浪费资源,也可以减轻故障服务的压力,让其有机会恢复正常 。
熔断的优势是可以提高系统的可用性和稳定性,因为它可以防止故障服务影响整个系统的运行,也可以让故障服务快速恢复 。熔断并不会影响高并发的需求,反而可以让系统在高并发下更加健壮和鲁棒 。
服务降级是指当服务不可用或者响应缓慢时,为了保证系统的可用性和稳定性,采取一些措施来减少服务的质量或者功能,从而避免系统崩溃或者雪崩效应。
熔断的目的是为了保护系统在高并发下不至于崩溃,而不是为了满足所有用户的数据需求。当系统的处理能力达到极限时,必须采取一些措施来减少负载,否则会导致系统无法正常运行,甚至崩溃 。
熔断的策略是根据服务的重要性和可用性来制定的,一般来说,对于核心业务和关键服务,不会轻易触发熔断,而对于非核心业务和次要服务,可以适当降低服务质量,或者提供一些默认的结果或提示信息 。
熔断的效果是让系统在高并发下更加稳定和可靠,因为它可以防止故障服务影响其他正常服务,并且可以让故障服务快速恢复。虽然熔断会让部分用户无法获取到他们想要的数据,但这是一种权衡和妥协的结果,相比于让整个系统崩溃,熔断是一种更好的选择 。
对于那些降级的服务,会给用户返回一些默认的结果或者提示信息,以便让用户知道服务目前的状态,不再继续等待或者重试.具体的返回内容取决于服务的类型和业务场景,一般有以下几种方式:
举例说明:
综上分析,
1、高并发情况下出现了服务降级无非就是 服务器压力过大,或者超过了熔断的阈值导致了降级。如果服务端还能承受那就调整熔断的阈值。
2、如果不能承受就修改在降级后响应给用户数据,来保证高并发。
在使用 JMeter 进行压测时,错误的请求链接是由于多种原因导致的,比如网络延迟、服务器负载、请求参数、代码逻辑等。当有 100 个请求同时进来时,可能会有以下几种情况发生:
实际上,并发小的情况下,代码并不会报错,这可能是因为以下几个原因:
压测时请求的参数都是一致的,为什么还会出现部分请求成功,部分请求失败的情况,这可能是因为以下几个原因:
压测过程中,如果并发高的情况下,有的请求报 500 错误,有的请求是成功的。如果并发小的情况下 所有的请求都是成功的,这说明了以下几点:
既然有请求成功,为什么还会报 500 错误呢?500 错误是服务器内部错误,表示服务器在处理请求时出现了意料之外的情况,无法完成请求。这可能是由于以下几种原因:
既然是请求成功的为什么还会报代码错误呢?这可能是由于以下几种原因:
对app服务端压测分为两个步骤:
1、使用fildder工具进行抓包
2、根据抓取的信息在jmeter上创建测试计划,并填写抓取信息。(这里可通过fildder 导出jmx脚本供jmeter使用)
Fiddler是一款可以抓取HTTP/HTTPS/FTP请求的工具,它可以通过代理的方式拦截和修改网络流量,从而获取app应用的请求链接和请求头等信息。要使用Fiddler抓取app应用的请求,您需要做以下几个步骤:
具体的操作方法和截图,您可以参考以下链接:
JMeter是一款可以进行性能测试和压力测试的工具,它可以根据Fiddler抓取到的请求信息来模拟用户并发访问app应用。要使用JMeter进行压测,您需要做以下几个步骤:
如果您要抓取的协议是HTTP协议,那么Fiddler的操作方法和上述操作基本一致,只是不需要安装和信任Fiddler的根证书,也不需要设置解密HTTPS请求。您只需要在手机上设置网络代理为电脑的IP地址和Fiddler的端口号(默认为8888),然后在手机上打开app应用,进行操作,就可以在电脑上的Fiddler中查看抓取到的HTTP请求和响应。
JMeter的操作方法也和我之前回答的基本一致,只是不需要在HTTP请求中填写SSL管理器或Keystore配置元件。您只需要在HTTP请求中填写Fiddler抓取到的请求链接、请求方法、请求参数、请求头等信息,然后在线程组中设置线程数、循环次数、启动时间等参数,就可以开始压测。
如果您想要简便的操作方式,您可以尝试使用Fiddler的导出功能,将抓取到的请求导出为JMeter脚本文件(.jmx格式),然后在JMeter中直接打开该文件,就可以看到已经配置好的测试计划。
测试计划-》线程组-》控制器-》Http Request-》(请求头、提取器、响应断言)
View Result Tree ( 结果查看树)、Aggregate Report(聚合报告)、Asserssion Result(断言结果)
聚合报告是一种常用的性能测试结果分析工具,它可以显示每个请求的统计信息,如响应时间、吞吐量、错误率等。
聚合报告的各个参数的含义如下:
这是因为在springboot项目中,内置的tomcat服务器就已经设置了并发的参数。主要有四个参数比较重要,如下是默认配置
server.tomcat.accept-count=100 # 设置请求队列的最大长度 server.tomcat.max-connections=10000 # 设置最大连接数 server.tomcat.max-threads=200 # 设置最大工作线程数 server.tomcat.min-spare-threads=10 # 设置最小空闲线程数
这四个参数是指 Spring Boot 内置 tomcat 的配置参数,分别是:
这四个参数的含义可以用一个生活中的案例来类比,例如:
假设有一个快餐店,它有一个柜台和一个厨房。柜台负责接收顾客的订单,厨房负责制作食物。我们可以把这个快餐店看作是一个 tomcat 服务器,把顾客看作是请求,把柜台和厨房看作是线程。
那么,这四个参数就相当于:
在使用过程中,如何配置这四个参数取决于您的应用程序的性能需求和实际情况。一般来说,您可以参考以下的原则:
机器的配置是影响这四个参数的重要因素,主要包括 CPU、内存、网络等方面。一般来说,机器的配置越高,就可以支持更高的并发数和更快的响应速度。但是,机器的配置并不是唯一的决定因素,还需要考虑应用程序的代码质量、业务逻辑、缓存策略、数据库优化等方面。
也就是说,当100个请求同时进来后,当前配置能处理的最大并发数 = max-threads + accept-count(队列数)
如果在请求响应中超时,那么一般来说就会占用一定的资源,增加了服务器的负载,所以必要的请求超时时间的设置也是必不可少的。
链接服务器的超时时间是指客户端在发送请求后,等待服务器响应的最大时间。如果在这个时间内,客户端没有收到服务器的响应,那么客户端就会认为请求失败,抛出一个超时异常。
链接服务器的超时时间是如何影响并发的呢?一般来说,链接服务器的超时时间越短,就可以支持更高的并发数,但是也会增加请求失败的风险。链接服务器的超时时间越长,就可以降低请求失败的风险,但是也会占用更多的资源,限制并发数。
为什么会这样呢?我们可以用一个生活中的例子来类比,例如:
假设有一个银行,它有一个柜台和一个后台系统。柜台负责接收客户的业务请求,后台系统负责处理业务逻辑。我们可以把这个银行看作是一个客户端,把后台系统看作是一个服务器。
那么,链接服务器的超时时间就相当于柜台等待后台系统响应的最大时间。如果在这个时间内,柜台没有收到后台系统的响应,那么柜台就会认为业务失败,向客户道歉并结束服务。
如果链接服务器的超时时间设置得很短,比如 1 分钟,那么柜台就可以快速地处理每个客户的业务请求,不会占用太多的资源,可以支持更多的客户同时办理业务。但是,如果后台系统处理业务逻辑需要花费较长的时间,或者出现了网络延迟或故障等情况,那么柜台就有可能在 1 分钟内没有收到后台系统的响应,导致业务失败。
如果链接服务器的超时时间设置得很长,比如 10 分钟,那么柜台就可以降低业务失败的风险,即使后台系统处理业务逻辑需要花费较长的时间,或者出现了网络延迟或故障等情况,柜台也可以等待更久地收到后台系统的响应。但是,如果柜台处理每个客户的业务请求需要花费较长的时间,那么柜台就会占用更多的资源,无法支持更多的客户同时办理业务。
因此,在设置链接服务器的超时时间时,需要根据实际情况和需求来进行权衡和调整。一般来说,可以参考以下的原则:
#默认1000
zuul.host.socket-timeout-millis=2000
#默认2000
zuul.host.connect-timeout-millis=4000
ribbon:
OkToRetryOnAllOperations: false #对所有操作请求都进行重试,默认false
ReadTimeout: 5000 #负载均衡超时时间,默认值5000
ConnectTimeout: 3000 #ribbon请求连接的超时时间,默认值2000
MaxAutoRetries: 0 #对当前实例的重试次数,默认0
MaxAutoRetriesNextServer: 1 #对切换实例的重试次数,默认1
hystrix:
command:
default: #default全局有效,service id指定应用有效
execution:
timeout:
#如果enabled设置为false,则请求超时交给ribbon控制,为true,则超时作为熔断根据
enabled: true
isolation:
thread:
timeoutInMilliseconds: 1000 #断路器超时时间,默认1000ms
feign.hystrix.enabled: true
如下合适的配置:
ribbon:
OkToRetryOnAllOperations: false #对所有操作请求都进行重试,默认false
ReadTimeout: 10000 #负载均衡超时时间,默认值5000
ConnectTimeout: 2000 #ribbon请求连接的超时时间,默认值2000
MaxAutoRetries: 0 #对当前实例的重试次数,默认0
MaxAutoRetriesNextServer: 1 #切换实例的次数,默认1
hystrix:
command:
default: #default全局有效,service id指定应用有效
execution:
timeout:
enabled: true
isolation:
thread:
timeoutInMilliseconds: 20000 #断路器超时时间,默认1000ms
application.properties中配置会话超时
最简单的方法是在你的application.properties中加入参数server.servlet.session.timeout。比如说
server.servlet.session.timeout=60s
还要注意的是,Tomcat不允许你将超时时间设置得少于60秒。
@Configuration
public class WebConfiguration {
@Bean
public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setSessionTimeout(2, TimeUnit.MINUTES);
}
};
}
使用Java 8和lambda表达式的捷径写法。
public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer() {
return (ConfigurableEmbeddedServletContainer container) -> {
container.setSessionTimeout(2, TimeUnit.MINUTES);
};
}
在应用程序启动期间,Spring Boot自动配置检测到EmbeddedServletContainerCustomizer,并调用customize(…)方法,传递对Servlet容器的引用。
一、配置文件方式
在配置文件application.properties中加了spring.mvc.async.request-timeout=120000,意思是设置超时时间为120000ms即120s
spring.mvc.async.request-timeout=120000
二、配置Config配置类
还有一种就是在config配置类中加入:
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void configureAsyncSupport(final AsyncSupportConfigurer configurer) {
configurer.setDefaultTimeout(20000);
configurer.registerCallableInterceptors(timeoutInterceptor());
}
@Bean
public TimeoutCallableProcessingInterceptor timeoutInterceptor() {
return new TimeoutCallableProcessingInterceptor();
}
}
如果服务端使用到Nginx做了反向代理转发请求,就需要在Nginx的配置文件nginx.conf中设置超时时间,否则会返回“java.io.IOException: 你的主机中的软件中止了一个已建立的连接”这样的异常提示。
未设置时Nginx响应时间默认60秒,这里将http头部的keepalive_timeout 、client_header_timeout 、client_body_timeout 、send_timeout 、以及server代码块中的proxy_read_timeout 均配置为120秒。
http {
include mime.types;
default_type application/octet-stream;
client_max_body_size 100m;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 120; #连接超时时间,服务器将会在这个时间后关闭连接
send_timeout 120; #发送超时时间
client_header_timeout 120; #请求头的超时时间
client_body_timeout 120; #请求体的读超时时间
#gzip on;
#业务系统的配置
server {
listen 9092;
server_name localhost;
location / {
proxy_pass http://127.0.0.1:8811/mywebsev/;
proxy_read_timeout 120; # 等候后端服务器响应时间 秒
}
}
bytes_sent “KaTeX parse error: Expected 'EOF', got '#' at position 21: …referer" ' #̲ …http_user_agent” “$http_x_forwarded_for”';
```nginx
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 120; #连接超时时间,服务器将会在这个时间后关闭连接
send_timeout 120; #发送超时时间
client_header_timeout 120; #请求头的超时时间
client_body_timeout 120; #请求体的读超时时间
#gzip on;
#业务系统的配置
server {
listen 9092;
server_name localhost;
location / {
proxy_pass http://127.0.0.1:8811/mywebsev/;
proxy_read_timeout 120; # 等候后端服务器响应时间 秒
}
}