简体   繁体   中英

keycloak spring boot starter memory leak

My backend microservice fall down with OutOfMemory exception in production environment. ////////////////////////////////

UPDATE: look like problem come from embedded tomcat, I found this在此处输入图片说明 It store sessions for each requests. Currently Have no idea how to clean it. I have this config:

server:
  port: 38083
  compression:
    enabled: true
    mime-types: text/html, text/xml, text/plain, text/css, application/javascript, application/json
    min-response-size: 1024


spring:
  session:
    store-type: none
    timeout: 1

////////////////////////

I'm still not sure, but look like problem come from org.keycloak.representations.AccessToken.roles hash map. Currently I reduce microservice to simpliest as it possible, I have only this controller:

@RestController
@RequestMapping("/nurse")
public class NurseController {


  List<NurseDto> cache = null;

  public NurseController() {
    cache = new ArrayList<>();
    int i = 5000;
    while (i-- > 0) {
      NurseDto n = new NurseDto();
      n.setId("123");
      n.setInternalId("234234");
      n.setName("asdfasfasoinasdf");
      n.setType("NURSE");
      cache.add(n);
    }
  }


  @GetMapping
  public ResponseEntity<List<NurseDto>> findAllNurses() {
    return ResponseEntity.ok(cache);
  }
}

and I call this controller from 20 threads without any pause. After couple minutes application fail with memory leak exception. In same time, I have this information from heap dump: 转储1 with this amount of objects: 转储2

Where 99% of hash map nodes refer to org.keycloak.representations.AccessToken.roles and 99% of string refer to privileges from access token. Previously, application work with

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-spring-boot-starter</artifactId>
    <version>6.0.1</version>
</dependency>

but after I update it to 11.0.2 issue remain

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-spring-boot-starter</artifactId>
    <version>11.0.2</version>
</dependency>

Any thoughts why it happen? Is it desired behavior, and I should set something like a "cache" limit?

Here is my security config, may be it can help:

@KeycloakConfiguration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Profile("!test")
public class WebSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

  @Autowired
  public void configure(AuthenticationManagerBuilder auth) {
    auth.authenticationProvider(keycloakAuthenticationProvider());
  }

  @Bean
  public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
    return new KeycloakSpringBootConfigResolver();
  }

  @Bean
  @Override
  protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
    return new NullAuthenticatedSessionStrategy();
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    super.configure(http);
    http.authorizeRequests().anyRequest().permitAll().and().cors().and().csrf().disable();
  }

  @Bean
  public CorsFilter corsFilter() {
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    final CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.setAllowedOrigins(Collections.singletonList("*"));
    config.setAllowedHeaders(Collections.singletonList("*"));
    config.setAllowedMethods(
        Arrays.stream(HttpMethod.values()).map(HttpMethod::name).collect(Collectors.toList()));
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
  }
}

It happen because of tomcat sessions. Tomcat create session for each request, and store them for an hour, after it memory could be cleaned. I found this solution:

http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

For an example, spring security configuration should look like that:

@KeycloakConfiguration
public class WebSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    super.configure(http);
    http.authorizeRequests().anyRequest().permitAll().and().cors().and().csrf().disable();
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
  }
  

Common sense tell that it should be not enough, because session created on the level of tomcat container, and I'm trying to play with servlet configuration, which is started inside of container, but it works perfectly. I also try to set spring properties, something like this:

  servlet:
    session:
      cookie:
        http-only: true
        secure: true
        max-age: 1
      timeout: 1s

Result was similar, but of course it still create sessions for 1 sec. Currently I can't remember how it behave when I set timeouts to 0, but I stop my discovery on

http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

without any other spring configurations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM