Spring Boot MQTT Too many publishes in progress错误的解决方案
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot MQTT Too many publishes in progress错误的解决方案相关的知识,希望对你有一定的参考价值。
参考技术A最近项目中需要与andorid端进行交互,采用了MQTT消息进行通信,生产环境中偶尔会出现Too many publishesin progress(32202)的错误,严重的影响了正常功能的使用。
项目中采用的是Spring Boot2.0集成的MQTT引入的版本为1.2.0,消息发送用的是MessagingGateway的方式实现
出现此问题的原因跟MQTT的Qos的设置有关,所以需要简单的介绍下Qos相关值的含义
发布者发送消息到服务器,没有确认消息,也不知道对方是否收到。
发布者发布消息保存消息,服务器(broker)接收到消息,服务器(broker)发送消息到订阅者,服务器(broker)回一个PUBACK信息到发布者让删除消息,然后订阅者接收消息后PUBACK给服务器让删除消息。如果失败了,在一段时间确认信息没有收到,发送方都会将消息头的DUP设置为1,然后再次发送消息,消息最少一次到达服务。例如网络延迟等问题,发布者重复发送消息,订阅者多次订阅会产生重复消息.
Qos为2只是在1的基础上做了改进,在发布者发送到服务器之后多了消息的确认以及多了消息msgID的缓存,重复信息的去重。在服务器发送到订阅者之后也多了消息的确认。
项目中使用了MQTT发送消息的地方比较多,且一般都是以Qos为0,那么为什么Qos为0,在并发量比较大的情况下就会出现Too many publishesin progress(32202)的错误,报错的内容的源码如下:
当actualInFlight超出设置的maxInflight最大值时就会报此错误,那么具体是什么原因导致的呢?我们需要通过源码来分析此问题的原因。
关于源码的阅读我们需要整理主线思路,MQTT发送消息主线分为消息push到缓存中和异步发送两部分。
说明:checkConection检查连接后,在发送消息。
MqttPublish消息类型,继承了父类MqttWireMessage,而在MqttWireMessage的构造方法中将消息id设置为0
SaveToken的源码实现如下:
通过前面这几步的操作,消息已经放入到HashTable缓存中,准备异步发送。
说明:MqttAsyncClient的connect为客户端建立连接,兴趣的可以看下源码。
在高并发的场景下,pendingMessage可能会添加多条数据,Qos设置为0的时候,存入tokens(Hashtable)中的key一直是0,当执行tokenStore.getToken在发送方法之后会remove所有数据,由于tokenStore中已经不存在值,因为已经被上一次已经全部remove了,当再次getToken的消息时获取会为空,不在发送信息,使得actualInFlight没有递减,所以才经过一段时间后actualInFlight就会超出设置最大值,从而报错。
此方案虽然可以解决此问题,但存在如下的缺点:
此方案虽然修改比较简单,但是并没有从根本上解决问题,只是缓解了出现错误的时间,如果项目中并发量比较低,可以采用此方案解决。
由于mqttMessageHandler只会引用一个paho客户端,所以才会想到增加客户端模式来提高并发量.需要重写MqttPahoMessageHandler类的相关方法。虽然可以解决此问题,如果对MQTT的源码不是很了解,不建议采用此方案,不利于后续的版本升级。
在1.2.1的版本中官方已经进行了相关的修改,当qos=0已经不存入tokenStore了,每次发送完之后就会删除掉token以及释放id,所以就不会出现Too many publishes in progress的问题。
引入1.2.1的版本会带来https验证问题,因为在Mqtt的1.2.1版本中,增加了https的验证需要添加相关配置,否则启动时会报安全认证错误。
解决方案:如果项目中没有开启https认证,需要设置HttpsHostnameVerificationEnabled为false即可。
本文通过定位MQTT错误,详细的讲解了MQtt消息的发送流程,解决的方案虽然有多种,我们需要结合实际的业务情况来解决问题
Spring Boot OAuth2,使用 Tomcat 和 nginx 验证后出现错误 ERR_TOO_MANY_REDIRECTS
【中文标题】Spring Boot OAuth2,使用 Tomcat 和 nginx 验证后出现错误 ERR_TOO_MANY_REDIRECTS【英文标题】:Spring Boot OAuth2, with Tomcat and nginx get error ERR_TOO_MANY_REDIRECTS after authenticate 【发布时间】:2021-04-24 01:16:36 【问题描述】:我有一个 Spring Boot 应用程序,它使用来自 WSO2 Identity Server 的 OAuth2 身份验证。 当我在 Spring Tool Suit 上运行应用程序时,它可以工作,所以我可以唱歌并使用我的网站。 但是当我在 Tomcat(9.0) 上运行我的应用程序时,我尝试访问一个页面,并重定向到登录页面,当我尝试登录时,我收到错误 ERR_TOO_MANY_REDIRECTS
错误示例:当我的 Spring Boot 应用在 Tomcat 上运行时,我尝试访问 html 页面:https://domain/chat/example.html
如果用户未通过身份验证, 重定向到登录页面 WSO2 身份服务器: https://domain/is/authenticationendpoint/login.do
登录后页面重定向到下面的url,并没有重定向到url(https://domain/chat/example.html)
-
https://domain/is/oauth2/authorize
https://domain/chat/oauth2/authorization/wso2
https://domain/chat/login/oauth2/code/wso2
https://domain/chat/login
这些页面返回错误ERR_TOO_MANY_REDIRECTS。
用户可以进行身份验证,但应用程序重定向并进入导致错误的循环,该循环位于 url 1、2、3、4 之间。
Tomcat 日志
Spring Boot 配置:
LoginController.java
@Controller
public class LoginController
@GetMapping("/oauth-login")
public String getLoginPage(Model model)
return "redirect:/oauth2/authorization/wso2";
ConfigSecurity.java
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)//abilitar seguranca nos metodos
public class ConfigSecurity extends WebSecurityConfigurerAdapter
protected void configure(HttpSecurity http) throws Exception
http.authorizeRequests()
.antMatchers("/oauth-login")
.permitAll()
.anyRequest()
.authenticated()
.and()
.oauth2Login().loginPage("/oauth-login")
.and()
.logout().logoutUrl("/applogout");
application.properties
server.port=8443
spring.security.oauth2.client.registration.wso2.client-name=WSO2 Identity Server
spring.security.oauth2.client.registration.wso2.client-id=asdasd
spring.security.oauth2.client.registration.wso2.client-secret=asdasd
spring.security.oauth2.client.registration.wso2.redirect-uri=https://domain/chat/login/oauth2/code/wso2
spring.security.oauth2.client.registration.wso2.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.wso2.scope=openid
#Identity Server Properties
spring.security.oauth2.client.provider.wso2.authorization-uri=https://domain/is/oauth2/authorize
spring.security.oauth2.client.provider.wso2.token-uri=https://domain/is/oauth2/token
spring.security.oauth2.client.provider.wso2.user-info-uri=https://domain/is/oauth2/userinfo
spring.security.oauth2.client.provider.wso2.jwk-set-uri=https://domain/is/oauth2/jwks
这是我的 git:https://github.com/Mingato/Root2
我按照教程:https://medium.com/@piraveenaparalogarajah/secure-your-spring-boot-application-with-wso2-identity-server-8140af8aa30b
当我运行 .jar 文件时它可以工作,但是当我在 tomcat 上运行 .war 文件时它不起作用。
【问题讨论】:
【参考方案1】:经过多次研究,我发现了我的错误。我的配置是正确的,但是当我在 Tomcat 上运行我的 Spring boot 应用程序时,我必须配置我的应用程序以在其上运行,但是还有另一种方法,我以最简单的方式运行我的应用程序,我生成 .jat 并执行下面的命令
java -jar myapp.jar
所以我删除了 Tomcat 服务器来部署我的 Spring Boot 应用程序。
【讨论】:
以上是关于Spring Boot MQTT Too many publishes in progress错误的解决方案的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot OAuth2,使用 Tomcat 和 nginx 验证后出现错误 ERR_TOO_MANY_REDIRECTS
使用 jOOQ 和 Spring Boot 进行集成测试时出现“PSQLException: FATAL: sorry, too many clients already”错误
Grails - Spring Security REST - 302 响应网络::ERR_TOO_MANY_REDIRECTS
Spring Cloud Feign - 报错:Method has too many Body parameters 说明 #解决方法