Exceptions in SpringBoot integration with ElasticSearch

1. Abnormal

When using springboot2.2.8+elasticsearch6.8.10, an error is reported during testing:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'elasticsearchClient' defined in class path resource [org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.elasticsearch.client.transport.TransportClient]: Factory method 'elasticsearchClient' threw exception; nested exception is java.lang.IllegalStateException: availableProcessors is already set to [4], rejecting [4]

2. Reason

  • Both Elasticsearch and Redis use Netty at the bottom layer, which will conflict when the project starts.

The classes involved: NettyRuntime, Netty4Util.

  • View the NettyRuntime class, you can see the source code:
public final class NettyRuntime {
    
    
    private static final NettyRuntime.AvailableProcessorsHolder holder = new NettyRuntime.AvailableProcessorsHolder();

    public static void setAvailableProcessors(int availableProcessors) {
    
    
        holder.setAvailableProcessors(availableProcessors);
    }

    public static int availableProcessors() {
    
    
        return holder.availableProcessors();
    }

    private NettyRuntime() {
    
    
    }

    static class AvailableProcessorsHolder {
    
    
        private int availableProcessors;

        AvailableProcessorsHolder() {
    
    
        }

        synchronized void setAvailableProcessors(int availableProcessors) {
    
    
            ObjectUtil.checkPositive(availableProcessors, "availableProcessors");
            // 简单说明:在项目启动时,redis自动设置好Netty处理器(availableProcessors就不为0),而此时elasticsearch也启动,发现Netty处理器已经被设置好了(发现availableProcessors!=0)然后会报异常。无论哪一个先启动,都会有判断去报这样的异常
            if (this.availableProcessors != 0) {
    
    
                // 看到这一句:跟上面报错的格式是一样的
                String message = String.format(Locale.ROOT, "availableProcessors is already set to [%d], rejecting [%d]", this.availableProcessors, availableProcessors);
                throw new IllegalStateException(message);
            } else {
    
    
                this.availableProcessors = availableProcessors;
            }
        }

        @SuppressForbidden(
            reason = "to obtain default number of available processors"
        )
        synchronized int availableProcessors() {
    
    
            if (this.availableProcessors == 0) {
    
    
                int availableProcessors = SystemPropertyUtil.getInt("io.netty.availableProcessors", Runtime.getRuntime().availableProcessors());
                this.setAvailableProcessors(availableProcessors);
            }

            return this.availableProcessors;
        }
    }
}

The bottom layer of Elasticsearch uses Netty4Util. This class calls the NettyRuntime method:

  public static void setAvailableProcessors(final int availableProcessors) {
    
    
        // we set this to false in tests to avoid tests that randomly set processors from stepping on each other
      // 而这里就是解决办法:
        final boolean set = Booleans.parseBoolean(System.getProperty("es.set.netty.runtime.available.processors", "true"));
        if (!set) {
    
    
            return;
        }

        /*
         * This can be invoked twice, once from Netty4Transport and another time from Netty4HttpServerTransport; however,
         * Netty4Runtime#availableProcessors forbids settings the number of processors twice so we prevent double invocation here.
         */
        if (isAvailableProcessorsSet.compareAndSet(false, true)) {
    
    
            // 看着,回去调用NettyRuntime的setAvailableProcessors
            NettyRuntime.setAvailableProcessors(availableProcessors);
        } else if (availableProcessors != NettyRuntime.availableProcessors()) {
    
    
            /*
             * We have previously set the available processors yet either we are trying to set it to a different value now or there is a bug
             * in Netty and our previous value did not take, bail.
             */
            // 看下面的格式跟报错的格式一样
            final String message = String.format(
                    Locale.ROOT,
                    "available processors value [%d] did not match current value [%d]",
                    availableProcessors,
                    NettyRuntime.availableProcessors());
            throw new IllegalStateException(message);
        }
    }

3. Solve

  • As you can see in the Netty4Util source code, setting es.set.netty.runtime.available.processors to false will not check whether the Netty processor is configured.
  • Because you have to resolve the conflict when you have to start it, set it in the startup class
@SpringBootApplication
public class XXXApplication {
    
    

    @PostConstruct
    public void init() {
    
    
        // 解决netty启动冲突的问题(主要体现在启动redis和elasticsearch)
        // 可以看Netty4Util.setAvailableProcessors(..)
        System.setProperty("es.set.netty.runtime.available.processors", "false");
    }

    public static void main(String[] args) {
    
    

        SpringApplication.run(CommunityApplication.class, args);
    }

}
  • It can be configured in the main function, before calling the run method.

This problem caused me for a day. At that time, I copied the System of the Netty4Util class directly. I didn't find that it was getProperty, which caused this exception. I really don't know how to solve it. So see clearly, here is setProperty

4. Other points of attention

Be sure to keep the local ElasticSearch consistent with the version of es integrated with SpringBoot. Otherwise, errors may occur. Especially one uses 6 version and one uses 7 version.

Maven can see the version of es integrated with SpringBoot:

Insert picture description here

If you need to change it right here: in the pom

    <properties>
        <java.version>1.8</java.version>
        <!--定义elasticsearch版本依赖,保证跟本地版本一致,否则可能出错-->
<!--        <elasticsearch.version>7.6.2</elasticsearch.version>-->
    </properties>

Version 7 is not very familiar, and the changes are also great, and I will upgrade when I have time.

Guess you like

Origin blog.csdn.net/weixin_41800884/article/details/107885391