spring Boot 应用程序中堆大小增加的问题(在k8s中运行)

laik7k3q  于 2023-02-04  发布在  Spring
关注(0)|答案(1)|浏览(144)
    • 服务说明:**

该 Spring 引导应用程序本质上是用于充电站的web套接字代理(在web套接字上使用OCPP协议),该充电站作为负载平衡器后面的多个节点运行,以基本上保持/保持连接打开,使得可以重新部署和维护通过rabbitmq连接到该代理的其他微服务(消息的实际消费者)。

    • 堆转储:**

这些设备(成千上万)往往非常频繁地连接和断开。

    • 会话(属性)**在组织中。apache。catalina。会话。标准管理器

不断添加会话(超过700 000),但不删除它们(在7天内)。see picture (StandartManager)
我还调查了

    • 会话(属性)**位于组织中。Apache。Tomcat。Web套接字。服务器。wsServerContainer

其保持websocket会话(在转储时:523),正确答案为see picture (WsServerContainer)
应用程序还将活动会话(每个节点)保存在并发Map中,以用于自己的目的:
Web套接字服务器服务中的会话(属性)
转储时:530(与上述会话相关,不介意小差异,没关系)see picture (WebsocketServerService)
因此,基本上预期所有会话属性将保存几乎相同数量的会话,在这种情况下,大约为530,不超过700 000。

    • 问题:**

是什么原因导致标准会话的不断增加?我不熟悉tomcat的内部工作原理,如果一个websocket连接被一个标准会话"烤"(至少在连接开始的时候),并且没有正确关闭套接字(双方)可能会导致标准会话将停留在一段时间后不被收集。这些只是假设。
可能原因(WIP)的一个版本是我们正在使用标准的WebSecurityConfigurerAdapter

@Configuration
@EnableWebSecurity
@AllArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final WebsocketServerProperties websocketServerProperties;
    private final StationAuthenticationProvider stationAuthenticationProvider;
    private final AuthenticationEntryPoint authEntryPoint;

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(stationAuthenticationProvider);
    }

    @Override
    @SuppressWarnings("squid:S4502")
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .httpBasic()
                .authenticationEntryPoint(authEntryPoint)
                .and()
                .antMatcher(websocketServerProperties.getWebsocketPathVpn() + "/**").anonymous()
                .and()
                .antMatcher(websocketServerProperties.getWebsocketPathInternet() + "/**")
                .authorizeRequests()
                .anyRequest()
                .authenticated();
    }

}

不是这里提到的www.example.comhttps://docs.spring.io/spring-security/reference/servlet/integrations/websocket.html#websocket-configuration
因此,如果工作站连接并且存在错误(例如401),则套接字没有正确关闭,并且会话增加,而没有正确关闭并且没有被GC收集(假设)。
websocket控制器的实现是标准的(至少参考文档是这样):
x一个一个一个一个x一个一个二个x
任何建议,想法可能导致这将不胜感激。
我运行了一些负载测试,看看会话是否在上升,是否与实际状态无关。测试后的堆转储(至少现在)不是很有帮助。还尝试模拟错误,没有可见的结果。

omqzjyyz

omqzjyyz1#

我能够找到原因,所以这里的调查结果:

  • 如果你在一个spring Boot 应用程序中使用WebSocket处理程序的默认配置,它是由tomcat作为底层提供者提供的
  • 我们使用了默认的@EnableWebSecurity =〉,这意味着对于每个WebSocket会话,还创建了一个用于身份验证部分的经典StandardHttpSession
  • 标准HttpSession的默认超时为60秒(server.servlet.session.timeout=60)在tomcat的情况下,这些值总是60的倍数=〉60,120,180....但在生产环境中(在我不知情的情况下)有人将此属性设置为-1 =〉,这意味着会话永不过期(这解决了丢失Web Socket连接的第一个可见问题,但由于负载增加,导致了一年后(现在)看到的一个新问题)
  • 因此,问题的机制是,在StandartHttpSession超时之后,即使是可见通信,“底层”WebSocket会话也被关闭。
  • 问题是WebSocket会话中的“活动”没有传播到上述StandardHttpSession =〉,这意味着http会话超时并关闭底层websocket会话

现在的解决方案(我需要测试它)是以某种方式克服这2个会话星座,或使用不同的提供程序,如jetty,undertow...或黑客将httpsession的引用作为属性传递给WebSocket会话,并在onConnected事件中将超时设置为-1,并在会话关闭后将其设置为60 s =〉,以便在一分钟后会话消失。
修复方法是将会话策略强制为“从不”!

protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
        .and().csrf().disable()

相关问题