javaspring-bootcassandracassandra-driver

failed to create a child event loop/failed to open a new selector/Too many open files


I am getting errors like "failed to create a child event loop/failed to open a new selector/Too many open files" when there are 30 or more concurrent requests...How to solve the above errors? Am I doing anything wrong? I am using Spring boot and Java cassandra driver. Below is the connection file:

public class Connection {

public static Session getConnection() {

    final Cluster cluster = Cluster.builder().addContactPoint(ConnectionBean.getCASSANDRA_DB_IP())
            .withQueryOptions(new QueryOptions().setConsistencyLevel(ConsistencyLevel.LOCAL_ONE))
            .withCredentials(ConnectionBean.getCASSANDRA_USER(), ConnectionBean.getCASSANDRA_PASSWORD())
            .withPoolingOptions(poolingOptions)
            .build();
    final Session session = cluster.connect(ConnectionBean.getCASSANDRA_DB_NAME());
    return session;
}

}

Below is the ConnectionBean file which I used in Connection file:

public  class ConnectionBean {

public static   String CASSANDRA_DB_IP;
public static String CASSANDRA_DB_NAME;
public static  String CASSANDRA_USER;
public static String CASSANDRA_PASSWORD;

public ConnectionBean() {

}
public ConnectionBean(String CASSANDRA_DB_IP,String CASSANDRA_DB_NAME,String CASSANDRA_USER,String CASSANDRA_PASSWORD) {
this.CASSANDRA_DB_IP=CASSANDRA_DB_IP;
this.CASSANDRA_DB_NAME=CASSANDRA_DB_NAME;
this.CASSANDRA_USER=CASSANDRA_USER;
this.CASSANDRA_PASSWORD=CASSANDRA_PASSWORD;
}

public static String getCASSANDRA_DB_IP() {
    return CASSANDRA_DB_IP;
}
public static void setCASSANDRA_DB_IP(String cASSANDRA_DB_IP) {
    CASSANDRA_DB_IP = cASSANDRA_DB_IP;
}
public static String getCASSANDRA_DB_NAME() {
    return CASSANDRA_DB_NAME;
}
public static void setCASSANDRA_DB_NAME(String cASSANDRA_DB_NAME) {
    CASSANDRA_DB_NAME = cASSANDRA_DB_NAME;
}
public static String getCASSANDRA_USER() {
    return CASSANDRA_USER;
}
public static void setCASSANDRA_USER(String cASSANDRA_USER) {
    CASSANDRA_USER = cASSANDRA_USER;
}
public static String getCASSANDRA_PASSWORD() {
    return CASSANDRA_PASSWORD;
}
public static void setCASSANDRA_PASSWORD(String cASSANDRA_PASSWORD) {
    CASSANDRA_PASSWORD = cASSANDRA_PASSWORD;
}   

}

Below is the class from where ConnectionBean variables are initialized :

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private static final String LOGIN_PROCESSING_URL = "/login";
private static final String LOGIN_FAILURE_URL = "/login?error";
private static final String LOGIN_URL = "/login";

@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;

@Autowired
private DataSource dataSource;

@Value("${spring.queries.users-query}")
private String usersQuery;

@Value("${spring.queries.roles-query}")
private String rolesQuery;

@Value("${CASSANDRA_DB_IP}")
public String CASSANDRA_DB_IP;

@Value("${CASSANDRA_DB_NAME}")
public String CASSANDRA_DB_NAME;

@Value("${CASSANDRA_USER}")
public String CASSANDRA_USER;

@Value("${CASSANDRA_PASSWORD}")
public String CASSANDRA_PASSWORD;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    ConnectionBean cb = new ConnectionBean(CASSANDRA_DB_IP, CASSANDRA_DB_NAME, CASSANDRA_USER, CASSANDRA_PASSWORD);

    auth.jdbcAuthentication().usersByUsernameQuery(usersQuery).authoritiesByUsernameQuery(rolesQuery)
            .dataSource(dataSource).passwordEncoder(bCryptPasswordEncoder);
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    // Not using Spring CSRF here to be able to use plain HTML for the login page

    http.csrf().disable()

            // Register our CustomRequestCache, that saves unauthorized access attempts, so
            // the user is redirected after login.
            .requestCache().requestCache(new CustomRequestCache())

            // Restrict access to our application.
            .and().authorizeRequests()

            // Allow all flow internal requests.
            .requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll()

            // Allow all requests by logged in users.
            .anyRequest().authenticated()

            // Configure the login page.
            .and().formLogin().loginPage(LOGIN_URL).permitAll().loginProcessingUrl(LOGIN_PROCESSING_URL)
            .failureUrl(LOGIN_FAILURE_URL)

            // Register the success handler that redirects users to the page they last tried
            // to access
            .successHandler(new SavedRequestAwareAuthenticationSuccessHandler())

            // Configure logout
            .and().logout().logoutSuccessUrl(LOGOUT_SUCCESS_URL);
}

/**
 * Allows access to static resources, bypassing Spring security.
 */
@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers(
            // Vaadin Flow static resources
            "/VAADIN/**",

            // the standard favicon URI
            "/favicon.ico",

            // web application manifest
            "/manifest.json", "/sw.js", "/offline-page.html",

            // icons and images
            "/icons/**", "/images/**",

            // (development mode) static resources
            "/frontend/**",

            // (development mode) webjars
            "/webjars/**",

            // (development mode) H2 debugging console
            "/h2-console/**",

            // (production mode) static resources
            "/frontend-es5/**", "/frontend-es6/**");
}

}

And finally, below is the class through which I am querying cassandra data:

public class getData {
Session session;

public getData(){
    session = Connection.getConnection();
    getDataTable();
}

private void getDataTable() {
    try {
        String query = "SELECT * FROM tableName";
        ResultSet rs = session.execute(query);
        for (Row row : rs) {
            /*Do some stuff here using row*/
        }

    } catch (Exception e) {
        e.printStackTrace();
    }
}

}


Solution

  • If getConnection() is being invoked for every request, you are creating a new Cluster instance each time.

    This is discouraged because one connection is created between your client and a C* node for each Cluster instance, and for each Session a connection pool of at least one connection is created for each C* node.

    If you are not closing your Cluster instances after a request completes, these connections will remain open. After a number of requests, you'll have so many connections open that you will run out of file descriptors in your OS.

    To resolve this issue, create only one Cluster and Session instance and reuse it between requests. This strategy is outlined in 4 simple rules when using the DataStax drivers for Cassandra:

    1. Use one Cluster instance per (physical) cluster (per application lifetime)
    2. Use at most one Session per keyspace, or use a single Session and explicitely specify the keyspace in your queries