【问题分析】解决java中epoll依赖缺失问题

【问题分析】解决java中epoll依赖缺失问题

一、前言

在学习使用lettuce框架实现UNIX域套接字unix domain socket连接redis时,遇到了一个问题,提示java.lang.IllegalStateException: A unix domain socket connection requires epoll or kqueue and neither is available
针对这个问题的解决,我们做一个总结

二、问题描述

1、关键业务代码

RedisURI uri = RedisURI.create("redis-socket:///tmp/redis.sock");
        uri.setDatabase(0);
        uri.setTimeout(Duration.of(100, ChronoUnit.SECONDS));
        uri.setPassword("******");

        RedisClient redisClient = RedisClient.create(uri);
        StatefulRedisConnection<String, String> connection = redisClient.connect();
        log.info("---------------11111111-------------------");
        connection.setAutoFlushCommands(true);
        RedisCommands<String, String> jedis = connection.sync();

2、报错异常详情

22:17:05.175 [http-nio-8098-exec-1] ERROR org.apache.juli.logging.DirectJDKLog.log(DirectJDKLog.java:175) - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: A unix domain socket connection requires epoll or kqueue and neither is available] with root cause
java.lang.IllegalStateException: A unix domain socket connection requires epoll or kqueue and neither is available
        at io.lettuce.core.internal.LettuceAssert.assertState(LettuceAssert.java:236) ~[lettuce-core-6.2.1.RELEASE.jar!/:6.2.1.RELEASE]
        at io.lettuce.core.resource.Transports$NativeTransports.assertDomainSocketAvailable(Transports.java:124) ~[lettuce-core-6.2.1.RELEASE.jar!/:6.2.1.RELEASE]
        at io.lettuce.core.ConnectionBuilder.configureBootstrap(ConnectionBuilder.java:250) ~[lettuce-core-6.2.1.RELEASE.jar!/:6.2.1.RELEASE]
        at io.lettuce.core.AbstractRedisClient.connectionBuilder(AbstractRedisClient.java:293) ~[lettuce-core-6.2.1.RELEASE.jar!/:6.2.1.RELEASE]
        at io.lettuce.core.RedisClient.connectStatefulAsync(RedisClient.java:322) ~[lettuce-core-6.2.1.RELEASE.jar!/:6.2.1.RELEASE]
        at io.lettuce.core.RedisClient.connectStandaloneAsync(RedisClient.java:287) ~[lettuce-core-6.2.1.RELEASE.jar!/:6.2.1.RELEASE]
        at io.lettuce.core.RedisClient.connect(RedisClient.java:216) ~[lettuce-core-6.2.1.RELEASE.jar!/:6.2.1.RELEASE]
        at io.lettuce.core.RedisClient.connect(RedisClient.java:201) ~[lettuce-core-6.2.1.RELEASE.jar!/:6.2.1.RELEASE]
        at com.sk.init.MyClient05.start(MyClient05.java:31) ~[classes!/:0.0.1-SNAPSHOT]
        at com.sk.action.TestAction.test(TestAction.java:68) ~[classes!/:0.0.1-SNAPSHOT]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_352]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_352]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_352]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_352]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.24.jar!/:5.3.24]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.24.jar!/:5.3.24]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.24.jar!/:5.3.24]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.24.jar!/:5.3.24]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.24.jar!/:5.3.24]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.24.jar!/:5.3.24]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071) ~[spring-webmvc-5.3.24.jar!/:5.3.24]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964) ~[spring-webmvc-5.3.24.jar!/:5.3.24]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.24.jar!/:5.3.24]
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.24.jar!/:5.3.24]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:670) ~[tomcat-embed-core-9.0.70.jar!/:?]
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.24.jar!/:5.3.24]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:779) ~[tomcat-embed-core-9.0.70.jar!/:?]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.70.jar!/:?]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.70.jar!/:?]
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.70.jar!/:?]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.70.jar!/:?]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.70.jar!/:?]

三、问题分析

首先分析源码异常信息A unix domain socket connection requires epoll or kqueue and neither is available是哪里报出来的

1、异常信息

在这里插入图片描述
由于kqueueFreeBSD系统上的多路复用技术,epoll是linux上的多路复用技术,所以异常是来自于EpollProvider.isAvailable()

2、EpollProvider.isAvailable()

在这里插入图片描述

由源码可知,由可能availability = Epoll.isAvailable();值为false导致的,Epoll.java源码如下:

/*
 * Copyright 2014 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package io.netty.channel.epoll;

import io.netty.channel.ChannelOption;
import io.netty.channel.unix.FileDescriptor;
import io.netty.util.internal.SystemPropertyUtil;

/**
 * Tells if <a href="https://netty.io/wiki/native-transports.html">{@code netty-transport-native-epoll}</a> is
 * supported.
 */
public final class Epoll {
    
    

    private static final Throwable UNAVAILABILITY_CAUSE;

    static {
    
    
        Throwable cause = null;

        if (SystemPropertyUtil.getBoolean("io.netty.transport.noNative", false)) {
    
    
            cause = new UnsupportedOperationException(
                    "Native transport was explicit disabled with -Dio.netty.transport.noNative=true");
        } else {
    
    
            FileDescriptor epollFd = null;
            FileDescriptor eventFd = null;
            try {
    
    
                epollFd = Native.newEpollCreate();
                eventFd = Native.newEventFd();
            } catch (Throwable t) {
    
    
                cause = t;
            } finally {
    
    
                if (epollFd != null) {
    
    
                    try {
    
    
                        epollFd.close();
                    } catch (Exception ignore) {
    
    
                        // ignore
                    }
                }
                if (eventFd != null) {
    
    
                    try {
    
    
                        eventFd.close();
                    } catch (Exception ignore) {
    
    
                        // ignore
                    }
                }
            }
        }

        UNAVAILABILITY_CAUSE = cause;
    }

    /**
     * Returns {@code true} if and only if the <a href="https://netty.io/wiki/native-transports.html">{@code
     * netty-transport-native-epoll}</a> is available.
     */
    public static boolean isAvailable() {
    
    
        return UNAVAILABILITY_CAUSE == null;
    }

    /**
     * Ensure that <a href="https://netty.io/wiki/native-transports.html">{@code netty-transport-native-epoll}</a> is
     * available.
     *
     * @throws UnsatisfiedLinkError if unavailable
     */
    public static void ensureAvailability() {
    
    
        if (UNAVAILABILITY_CAUSE != null) {
    
    
            throw (Error) new UnsatisfiedLinkError(
                    "failed to load the required native library").initCause(UNAVAILABILITY_CAUSE);
        }
    }

    /**
     * Returns the cause of unavailability of <a href="https://netty.io/wiki/native-transports.html">
     * {@code netty-transport-native-epoll}</a>.
     *
     * @return the cause if unavailable. {@code null} if available.
     */
    public static Throwable unavailabilityCause() {
    
    
        return UNAVAILABILITY_CAUSE;
    }

    /**
     * Returns {@code true} if the epoll native transport is both {@linkplain #isAvailable() available} and supports
     * {@linkplain ChannelOption#TCP_FASTOPEN_CONNECT client-side TCP FastOpen}.
     *
     * @return {@code true} if it's possible to use client-side TCP FastOpen via epoll, otherwise {@code false}.
     */
    public static boolean isTcpFastOpenClientSideAvailable() {
    
    
        return isAvailable() && Native.IS_SUPPORTING_TCP_FASTOPEN_CLIENT;
    }

    /**
     * Returns {@code true} if the epoll native transport is both {@linkplain #isAvailable() available} and supports
     * {@linkplain ChannelOption#TCP_FASTOPEN server-side TCP FastOpen}.
     *
     * @return {@code true} if it's possible to use server-side TCP FastOpen via epoll, otherwise {@code false}.
     */
    public static boolean isTcpFastOpenServerSideAvailable() {
    
    
        return isAvailable() && Native.IS_SUPPORTING_TCP_FASTOPEN_SERVER;
    }

    private Epoll() {
    
    
    }
}

3、验证Epoll.isAvailable()方法返回值

@Slf4j
@RestController
@RequiredArgsConstructor
public class TestAction {
    
    


    private static final Throwable UNAVAILABILITY_CAUSE;

    static {
    
    
        Throwable cause = null;

        if (SystemPropertyUtil.getBoolean("io.netty.transport.noNative", false)) {
    
    
            cause = new UnsupportedOperationException(
                    "Native transport was explicit disabled with -Dio.netty.transport.noNative=true");
        } else {
    
    
            FileDescriptor epollFd = null;
            FileDescriptor eventFd = null;
            try {
    
    
                epollFd = Native.newEpollCreate();
                eventFd = Native.newEventFd();
            } catch (Throwable t) {
    
    
                cause = t;
            } finally {
    
    
                if (epollFd != null) {
    
    
                    try {
    
    
                        epollFd.close();
                    } catch (Exception ignore) {
    
    
                        // ignore
                    }
                }
                if (eventFd != null) {
    
    
                    try {
    
    
                        eventFd.close();
                    } catch (Exception ignore) {
    
    
                        // ignore
                    }
                }
            }
        }

        UNAVAILABILITY_CAUSE = cause;
    }



    private final MyClient05 myClient05;

    //private final RedisConfig redisConfig;

    @GetMapping("/test")
    public void test(){
    
    

        log.error("-----:{}",UNAVAILABILITY_CAUSE);

        log.info("================Epoll:{}",Epoll.isAvailable());


        myClient05.start();
      
    }

}

执行结果:

19:26:54.428 [http-nio-8098-exec-1] ERROR com.sk.action.TestAction.test(TestAction.java:65) - -----:{
    
    }
java.lang.UnsatisfiedLinkError: could not load a native library: netty_transport_native_epoll_x86_64
        at io.netty.util.internal.NativeLibraryLoader.load(NativeLibraryLoader.java:239) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
        at io.netty.channel.epoll.Native.loadNativeLibrary(Native.java:323) ~[netty-transport-classes-epoll-4.1.86.Final.jar!/:4.1.86.Final]
        at io.netty.channel.epoll.Native.<clinit>(Native.java:85) ~[netty-transport-classes-epoll-4.1.86.Final.jar!/:4.1.86.Final]
        at com.sk.action.TestAction.<clinit>(TestAction.java:31) ~[classes!/:0.0.1-SNAPSHOT]
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:1.8.0_352]
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[?:1.8.0_352]
.
.
.
19:26:54.447 [http-nio-8098-exec-1] INFO  com.sk.action.TestAction.test(TestAction.java:67) - ================Epoll:false
19:26:54.758 [http-nio-8098-exec-1] ERROR org.apache.juli.logging.DirectJDKLog.log(DirectJDKLog.java:175) - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: A unix domain socket connection requires epoll or kqueue and neither is available] with root cause
java.lang.IllegalStateException: A unix domain socket connection requires epoll or kqueue and neither is available
        at io.lettuce.core.internal.LettuceAssert.assertState(LettuceAssert.java:236) ~[lettuce-core-6.1.5.RELEASE.jar!/:6.1.5.RELEASE]
        at io.lettuce.core.resource.Transports$NativeTransports.assertDomainSocketAvailable(Transports.java:124) ~[lettuce-core-6.1.5.RELEASE.jar!/:6.1.5.RELEASE]
        at io.lettuce.core.ConnectionBuilder.configureBootstrap(ConnectionBuilder.java:250) ~[lettuce-core-6.1.5.RELEASE.jar!/:6.1.5.RELEASE]
        at io.lettuce.core.AbstractRedisClient.connectionBuilder(AbstractRedisClient.java:274) ~[lettuce-core-6.1.5.RELEASE.jar!/:6.1.5.RELEASE]

通过上述异常信息可知netty_transport_native_epoll_x86_64文件加载异常

四、解决方法

关于netty_transport_native_epoll_x86_64文件引起的异常的原因有多种,所以只能针对不同的原因进行分析和验证;

首先想到的有两种,一种是缺少这个依赖第二种就是这个依赖有冲突

针对第一种,引入epoll相关的java依赖

<dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-transport-native-epoll</artifactId>
            <classifier>linux-x86_64</classifier>
        </dependency>

没想到第一种方式就解决了问题

代码执行结果:

19:37:11.550 [http-nio-8098-exec-1] ERROR com.sk.action.TestAction.test(TestAction.java:65) - -----:{
    
    }
19:37:11.553 [http-nio-8098-exec-1] INFO  com.sk.action.TestAction.test(TestAction.java:67) - ================Epoll:true

执行结果没有异常产生

五、总结

有一些问题相对比较偏门,网上的资料也比较少,只能通过分析源码,才能更精准的定位问题,所以经常性的分析源码对我们解决问题也比较有利的。

猜你喜欢

转载自blog.csdn.net/weixin_37598243/article/details/128432074