sofastack / sofa-jraft

A production-grade java implementation of RAFT consensus algorithm.
https://www.sofastack.tech/projects/sofa-jraft/
Apache License 2.0
3.57k stars 1.14k forks source link

同样的代码--springboot项目调用node.shutdown(),方法,再次调用start,启动报错;但是如果不用springboot项目,通过main方法启动就不会出现这个问题,出现端口占用,端口没有关闭。 #718

Closed SpringLin97 closed 2 years ago

SpringLin97 commented 2 years ago

Springboot---------

关闭的方法

1636946720(1)

开启方法

image

报错

[11:19:25:389] [ERROR] - com.alipay.sofa.jraft.storage.impl.RocksDBLogStorage.init(RocksDBLogStorage.java:207) - Fail to init RocksDBLogStorage, path=/tmp/jraft/cluster/data2\log.

org.rocksdb.RocksDBException: Failed to create lock file: /tmp/jraft/cluster/data2\log/LOCK: Áíһ¸ö³ÌÐòÕýÔÚʹÓôËÎļþ£¬½ø³ÌÎ at org.rocksdb.RocksDB.open(Native Method) ~[rocksdbjni-5.18.4.jar:?] at org.rocksdb.RocksDB.open(RocksDB.java:286) ~[rocksdbjni-5.18.4.jar:?] at com.alipay.sofa.jraft.storage.impl.RocksDBLogStorage.openDB(RocksDBLogStorage.java:308) ~[jraft-core-1.3.8.jar:?] at com.alipay.sofa.jraft.storage.impl.RocksDBLogStorage.initAndLoad(RocksDBLogStorage.java:226) ~[jraft-core-1.3.8.jar:?] at com.alipay.sofa.jraft.storage.impl.RocksDBLogStorage.init(RocksDBLogStorage.java:205) ~[jraft-core-1.3.8.jar:?] at com.alipay.sofa.jraft.storage.impl.RocksDBLogStorage.init(RocksDBLogStorage.java:70) ~[jraft-core-1.3.8.jar:?] at com.alipay.sofa.jraft.storage.impl.LogManagerImpl.init(LogManagerImpl.java:184) ~[jraft-core-1.3.8.jar:?] at com.alipay.sofa.jraft.storage.impl.LogManagerImpl.init(LogManagerImpl.java:77) ~[jraft-core-1.3.8.jar:?] at com.alipay.sofa.jraft.core.NodeImpl.initLogStorage(NodeImpl.java:589) ~[jraft-core-1.3.8.jar:?] at com.alipay.sofa.jraft.core.NodeImpl.init(NodeImpl.java:999) ~[jraft-core-1.3.8.jar:?] at com.alipay.sofa.jraft.core.NodeImpl.init(NodeImpl.java:139) ~[jraft-core-1.3.8.jar:?] at com.alipay.sofa.jraft.RaftServiceFactory.createAndInitRaftNode(RaftServiceFactory.java:47) ~[jraft-core-1.3.8.jar:?] at com.alipay.sofa.jraft.RaftGroupService.start(RaftGroupService.java:129) ~[jraft-core-1.3.8.jar:?] at com.alipay.sofa.jraft.RaftGroupService.start(RaftGroupService.java:107) ~[jraft-core-1.3.8.jar:?] at com.visec.platform.webstarter.cluster.core.jraft.server.RaftServer.(RaftServer.java:71) ~[classes/:?] at com.visec.platform.webstarter.cluster.core.jraft.server.RaftServer.start(RaftServer.java:128) ~[classes/:?] at com.visec.platform.webstarter.cluster.core.jraft.RaftHandle.startServer(RaftHandle.java:47) ~[classes/:?] at com.visec.platform.webstarter.cluster.web.service.RaftService.operateRaftServer(RaftService.java:351) ~[classes/:?] at com.visec.platform.webstarter.cluster.web.service.RaftService$$FastClassBySpringCGLIB$$a2eb3f1c.invoke() ~[classes/:?] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367) [spring-tx-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118) [spring-tx-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) [spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) [spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691) [spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE] at com.visec.platform.webstarter.cluster.web.service.RaftService$$EnhancerBySpringCGLIB$$42be83e5.operateRaftServer() [classes/:?] at com.visec.platform.webstarter.cluster.web.controller.RaftController.operateRaftServer(RaftController.java:146) [classes/:?] at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?] at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?] at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?] at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) [spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) [spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) [spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879) [spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) [spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) [spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) [spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) [spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:920) [spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:663) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) [spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) [tomcat-embed-websocket-9.0.36.jar:9.0.36] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61) [shiro-web-1.5.3.jar:1.5.3] at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108) [shiro-web-1.5.3.jar:1.5.3] at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137) [shiro-web-1.5.3.jar:1.5.3] at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) [shiro-web-1.5.3.jar:1.5.3] at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66) [shiro-web-1.5.3.jar:1.5.3] at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449) [shiro-web-1.5.3.jar:1.5.3] at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365) [shiro-web-1.5.3.jar:1.5.3] at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90) [shiro-core-1.5.3.jar:1.5.3] at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83) [shiro-core-1.5.3.jar:1.5.3] at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:387) [shiro-core-1.5.3.jar:1.5.3] at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362) [shiro-web-1.5.3.jar:1.5.3] at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) [shiro-web-1.5.3.jar:1.5.3] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92) [spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) [spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) [spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) [spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590) [tomcat-embed-core-9.0.36.jar:9.0.36] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.36.jar:9.0.36] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.36.jar:9.0.36] at java.lang.Thread.run(Thread.java:834) [?:?] [11:19:25:392] [ERROR] - com.alipay.sofa.jraft.storage.impl.LogManagerImpl.init(LogManagerImpl.java:185) - Fail to init logStorage [11:19:25:392] [ERROR] - com.alipay.sofa.jraft.core.NodeImpl.init(NodeImpl.java:1000) - Node <TEST/192.168.5.201:8082> initLogStorage failed. [11:19:25:411] [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: Fail to init node, please see the logs to find the reason.] with root cause

Springboot---------end

main方法启动报错

1636946856(1)

killme2008 commented 2 years ago

这跟用什么框架没关系,确保你的代码里把所有服务都关闭就可以重新启动,因为 jraft 自己单测的也是不停地重复创建和启动节点。

注意的一点是 node 的 shutdown 是一个异步方法,要等待所有过程结束可以在 shutdown 后调用 node.join() 同步等待。异步版本是 shutdown(closure) 可以传入一个闭包,当所有服务关闭的时候会回调这个闭包通知。

SpringLin97 commented 2 years ago

这跟用什么框架没关系,确保你的代码里把所有服务都关闭就可以重新启动,因为 jraft 自己单测的也是不停地重复创建和启动节点。

  • RPC server/client
  • node

注意的一点是 node 的 shutdown 是一个异步方法,要等待所有过程结束可以在 shutdown 后调用 node.join() 同步等待。异步版本是 shutdown(closure) 可以传入一个闭包,当所有服务关闭的时候会回调这个闭包通知。

能出一个文档,如何正确的关闭node节点吗

double-7 commented 2 years ago

这跟用什么框架没关系,确保你的代码里把所有服务都关闭就可以重新启动,因为 jraft 自己单测的也是不停地重复创建和启动节点。

  • RPC server/client
  • node

注意的一点是 node 的 shutdown 是一个异步方法,要等待所有过程结束可以在 shutdown 后调用 node.join() 同步等待。异步版本是 shutdown(closure) 可以传入一个闭包,当所有服务关闭的时候会回调这个闭包通知。

我这边也碰到类似问题, 版本: jraft-core-1.3.8 例子:com.alipay.sofa.jraft.example.counter 测试: 1:raft 线程启动后 2:运行10S后使用 RaftGroupService.shutdown()(该段源码会一并关闭RPC,node) 3:通过java VisualVM查看线程仍有Jraft-Closuere-Executor线程常驻 4:这些线程不会销毁,且会持有对应raft 服务文件的lock ,导致无法创建新的raft服务 5:这时候哪怕等1个小时,重新创建一个新的jraft服务,任然会锁住相应文件无法创建服务 6:只有所有非守护线程退出最终程序退出时,这些Jraft 线程才会完全退出 总结:jraft 创建的服务子线程,无法通过 RaftGroupService.shutdown() 进行关闭,只有整个程序退出时才会销毁这些子线程 所以:有哪些方法可以关闭其创建的子线程,还是其他原因导致无法销毁其子线程 image

killme2008 commented 2 years ago

前面提过了,调用下 join 就可以了。 RaftGroupService 也有 join 方法。

这里我们加个文档说明,除了调用 shutdown 之外,还需要额外调用 join

double-7 commented 2 years ago

前面提过了,调用下 join 就可以了。 RaftGroupService 也有 join 方法。

这里我们加个文档说明,除了调用 shutdown 之外,还需要额外调用 join

new Thread(() -> { try { String[] as = {"./run/counter/server1", "counter", "127.0.0.1:8081", "127.0.0.1:8081,127.0.0.1:8082,127.0.0.1:8083"}; CounterServer server = parse(as); Thread.sleep(10 * 1000); server.RaftGroupService().shutdown(); server.getNode().join(); System.out.println("shutdown"); } catch (Exception e) { e.printStackTrace(); } }).start();

double-7 commented 2 years ago

前面提过了,调用下 join 就可以了。 RaftGroupService 也有 join 方法。 这里我们加个文档说明,除了调用 shutdown 之外,还需要额外调用 join

new Thread(() -> { try { String[] as = {"./run/counter/server1", "counter", "127.0.0.1:8081", "127.0.0.1:8081,127.0.0.1:8082,127.0.0.1:8083"}; CounterServer server = parse(as); Thread.sleep(10 * 1000); server.RaftGroupService().shutdown(); server.getNode().join(); System.out.println("shutdown"); } catch (Exception e) { e.printStackTrace(); } }).start();

这样吗,其子线程还是不会被销毁哦

killme2008 commented 2 years ago

Jraft-Closuere-Executor 以及 bolt 线程池这些不会销毁,因为他们是全局共享的, shutdown + join 会关闭节点特有的资源,然后就可以重复创建 raft group/node,虽然我不知道除了测试还有什么场景需要这么做。

killme2008 commented 2 years ago

现在的问题其实是 join 方法是必须要调用的,原来设计初衷是可选的,这个问题我们会修复下。

killme2008 commented 2 years ago

这跟用什么框架没关系,确保你的代码里把所有服务都关闭就可以重新启动,因为 jraft 自己单测的也是不停地重复创建和启动节点。

  • RPC server/client
  • node

注意的一点是 node 的 shutdown 是一个异步方法,要等待所有过程结束可以在 shutdown 后调用 node.join() 同步等待。异步版本是 shutdown(closure) 可以传入一个闭包,当所有服务关闭的时候会回调这个闭包通知。

能出一个文档,如何正确的关闭node节点吗

简而言之,如果你是使用 RaftGroupService 帮你管理节点,你可以直接这样来关闭:

RaftGroupService service ...
service.shutdown();
service.join();

他会调用到底层的 Node#shutdownNode#join 等方法,确保该节点的资源释放。

如果你不是使用 RaftGroupService,那你要确保你自己打开的服务关闭,如果是 Node ,除了 shutdown 之外,还需要额外调用 join 方法。这个不是设计初衷,我们会修正这个问题,join 是为了同步等待关闭,现在变成了需要强制调用一次。

double-7 commented 2 years ago

这跟用什么框架没关系,确保你的代码里把所有服务都关闭就可以重新启动,因为 jraft 自己单测的也是不停地重复创建和启动节点。

  • RPC server/client
  • node

注意的一点是 node 的 shutdown 是一个异步方法,要等待所有过程结束可以在 shutdown 后调用 node.join() 同步等待。异步版本是 shutdown(closure) 可以传入一个闭包,当所有服务关闭的时候会回调这个闭包通知。

能出一个文档,如何正确的关闭node节点吗

简而言之,如果你是使用 RaftGroupService 帮你管理节点,你可以直接这样来关闭:

RaftGroupService service ...
service.shutdown();
service.join();

他会调用到底层的 Node#shutdownNode#join 等方法,确保该节点的资源释放。

如果你不是使用 RaftGroupService,那你要确保你自己打开的服务关闭,如果是 Node ,除了 shutdown 之外,还需要额外调用 join 方法。这个不是设计初衷,我们会修正这个问题,join 是为了同步等待关闭,现在变成了需要强制调用一次。

谢谢,已经可以正常重复启动node了。 目前业务场景可能会重复关闭启动node。 且关闭停止间隔时间长,关闭的时候如果把共享线程给销毁了,占用资源会小LIB相对更加干净。 希望可以提全部的销毁方法,不会因为调用了一次该服务就会创建永久驻留的共享线程。