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: with this amount of objects:
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.