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

【JRaft RheaKV】客户端使用rheaKVStore,最佳实践是随用随释放,还是进程启动后初始化一次?以及客户端在主切换时应如何处理? #1131

Closed en-hui closed 1 month ago

en-hui commented 1 month ago

Your question

Describe your question clearly

1、使用jraft-rheakv的时候,客户端的这个rheaKVStore,是初始化一次,保持内存中唯一就行,还是随用随释放?那种是最佳实践。

Your scenes

Describe your use scenes (why need this feature)

Your advice

Describe the advice or solution you'd like

Environment

fengjiachun commented 1 month ago

Rheakv client 推荐保持单例使用

en-hui commented 1 month ago

好的,感谢解答。

en-hui commented 1 month ago

@fengjiachun 大佬,我又遇到了一个问题,我模拟以下一种场景: 服务端启动了六台服务作为一个集群,三台普通节点,三台learner节点 客户端while(true) 调用rheaKVStore.bPutIfAbsent,每次间隔一秒钟。 我将leader挂掉,集群可以正常选择另外两台普通节点中的一个作为新的主,但客户端已经抛出异常,且看样子需要手动捕获并处理。

请问rheaKVStore作为客户端,不具备识别主切换的能力吗?我在while true里面不停重试,依然一直报错,看样子需要手动调用某些api才能解决。

我应该如何处理呢?

fengjiachun commented 1 month ago

重试的逻辑看这里吧:

https://github.com/sofastack/sofa-jraft/blob/373c087824cba920cc87c67592c3bb7ec1d866f1/jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/client/failover/impl/FailoverClosureImpl.java#L62

简单说,遇到一些指定错误,会发起重试(retries 上限是配置的),重试的时候,会强制刷新最新的 leader:

https://github.com/sofastack/sofa-jraft/blob/2d0495524d80210e0982c6fb4b0f3de5f17dc6ae/jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/client/DefaultRheaKVRpcService.java#L100

重点:

重试次数有上限

次重点

文档确实少了点,先说抱歉,得需要你稍微看下代码,代码里面无秘密 :)

en-hui commented 1 month ago

我再次尝试并简单看了一下逻辑,发现当主动停掉leader的时候,客户端未刷新元数据时,获取到的leader地址还是旧的。 然后在请求时会抛出com.alipay.remoting.exception.RemotingException: Create connection failed. The address is 127.0.0.1:8183异常,而此异常不会触发重试和刷新集群元数据。

这算是bug吗

看着逻辑像是只有请求通leader的一些异常情况才会触发刷新,如果leader直接挂了,请求不通的时候,没有重试机制?

en-hui commented 1 month ago

是不是我可以这样调用,主动去刷新缓存中的元数据: store.getPlacementDriverClient().getLeader(-1, true, 5000)

fengjiachun commented 1 month ago

我再次尝试并简单看了一下逻辑,发现当主动停掉leader的时候,客户端未刷新元数据时,获取到的leader地址还是旧的。 然后在请求时会抛出com.alipay.remoting.exception.RemotingException: Create connection failed. The address is 127.0.0.1:8183异常,而此异常不会触发重试和刷新集群元数据。

这算是bug吗

看着逻辑像是只有请求通leader的一些异常情况才会触发刷新,如果leader直接挂了,请求不通的时候,没有重试机制?

感谢指出,是有这么个问题,我来看看处理下

fengjiachun commented 1 month ago

是不是我可以这样调用,主动去刷新缓存中的元数据: store.getPlacementDriverClient().getLeader(-1, true, 5000)

嗯,是可以先这么处理

en-hui commented 1 month ago

好的,您现在维护版本包括哪些,此问题会修复哪些版本? 我们用的是1.3.12版本

需要我提一个新的issue吗?

fengjiachun commented 1 month ago

最近会发一个版本(1.3.15)来解决,不用新提 issue,这个 issue 不要关闭就行

en-hui commented 1 month ago

分布式锁续约,如果遇到这种情况,直接把续约取消了?

那业务应该如何用锁,来避免这种情况呢。遇到主切换,岂不是会导致锁可能失效

en-hui commented 1 month ago

使用store.getPlacementDriverClient().getLeader(-1, true, 5000)刷新后,确实在用store put get都可以成功了,但后台一直刷异常,是有什么后台任务也需要刷新url吗?应该如何刷,您帮忙看看

2024-07-29 14:41:23,013 [Bolt-heal-connection-thread] WARN com.alipay.sofa.common.log - reconnect target: Origin url [127.0.0.1:8181], Unique key [127.0.0.1:8181]. failed. java.lang.RuntimeException: com.alipay.remoting.exception.RemotingException: Create connection failed. The address is 127.0.0.1:8181 at com.alipay.remoting.ReconnectManager$ReconnectTask.run(ReconnectManager.java:187) at com.alipay.remoting.ReconnectManager$HealConnectionRunner.run(ReconnectManager.java:155) at java.lang.Thread.run(Thread.java:748) Caused by: com.alipay.remoting.exception.RemotingException: Create connection failed. The address is 127.0.0.1:8181 at com.alipay.remoting.DefaultConnectionManager.create(DefaultConnectionManager.java:478) at com.alipay.remoting.DefaultConnectionManager.doCreate(DefaultConnectionManager.java:781) at com.alipay.remoting.DefaultConnectionManager.access$000(DefaultConnectionManager.java:51) at com.alipay.remoting.DefaultConnectionManager$ConnectionPoolCall.call(DefaultConnectionManager.java:709) at com.alipay.remoting.DefaultConnectionManager$ConnectionPoolCall.call(DefaultConnectionManager.java:675) at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) at java.util.concurrent.FutureTask.run(FutureTask.java) at com.alipay.remoting.util.RunStateRecordedFutureTask.run(RunStateRecordedFutureTask.java:39) at com.alipay.remoting.DefaultConnectionManager.getConnectionPoolAndCreateIfAbsent(DefaultConnectionManager.java:567) at com.alipay.remoting.DefaultConnectionManager.createConnectionAndHealIfNeed(DefaultConnectionManager.java:459) at com.alipay.remoting.ReconnectManager$ReconnectTask.run(ReconnectManager.java:185) ... 2 more Caused by: java.lang.Exception: Create connection to 127.0.0.1:8181 error! at com.alipay.remoting.connection.AbstractConnectionFactory.doCreateConnection(AbstractConnectionFactory.java:329) at com.alipay.remoting.connection.AbstractConnectionFactory.createConnection(AbstractConnectionFactory.java:185) at com.alipay.remoting.DefaultConnectionManager.create(DefaultConnectionManager.java:475) ... 12 more Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /127.0.0.1:8181 Caused by: java.net.ConnectException: Connection refused at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method) at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:715) at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:327) at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:334) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:688) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:635) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:552) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:514) at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1044) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at java.lang.Thread.run(Thread.java:748)

fengjiachun commented 1 month ago

看日志,不是 jraft 的,是 bolt rpc 有个健康监测在打印日志

en-hui commented 1 month ago

看日志,不是 jraft 的,是 bolt rpc 有个健康监测在打印日志

那应该怎么做呢,一直刷屏日志。还有上面问的那个锁的问题

en-hui commented 1 month ago

看日志,不是 jraft 的,是 bolt rpc 有个健康监测在打印日志

在jraft-core的BoltRpcClient.java的init(RpcOptions opts) 方法中,使用了this.rpcClient.enableReconnectSwitch(); 这个会开启你说的那个重试,但是我还没找到如何关这个,且关了会有什么影响呢

fengjiachun commented 1 month ago

分布式锁续约,如果遇到这种情况,直接把续约取消了?

keep lease 本就无法保证一定成功,但凡涉及到网络,任何操作都无法保证成功,如果续租失败,那么 lease timeout 超过后锁就不再生效

fengjiachun commented 1 month ago

看日志,不是 jraft 的,是 bolt rpc 有个健康监测在打印日志

那应该怎么做呢,一直刷屏日志。还有上面问的那个锁的问题

bolt 的日志不是打在单独的文件里么

fengjiachun commented 1 month ago

这个会开启你说的那个重试,但是我还没找到如何关这个,且关了会有什么影响呢

bolt 在创建连接的时候,如果网路有问题,有可能被 block 住最多一秒,所以需要它自动 reconnect,目前不支持修改 reconnect 的配置

en-hui commented 1 month ago

这个会开启你说的那个重试,但是我还没找到如何关这个,且关了会有什么影响呢

bolt 在创建连接的时候,如果网路有问题,有可能被 block 住最多一秒,所以需要它自动 reconnect,目前不支持修改 reconnect 的配置

那这个无用的连接也不会取消,因为我已经刷新元数据了,获取到新的leader,对于原leader的连接我应该取消,让他不在reconnect,这个有方法吗

en-hui commented 1 month ago

分布式锁续约,如果遇到这种情况,直接把续约取消了?

keep lease 本就无法保证一定成功,但凡涉及到网络,任何操作都无法保证成功,如果续租失败,那么 lease timeout 超过后锁就不再生效

感觉可以优化一下,对于一些连接问题,应该参照rheaKvStore,也有重试机制,尝试去新的leader进行续约。这个能优化吗。 不然这个续约功能,等于没有,不敢用这个功能

fengjiachun commented 1 month ago

TODO:

fengjiachun commented 1 month ago

分布式锁续约,如果遇到这种情况,直接把续约取消了?

keep lease 本就无法保证一定成功,但凡涉及到网络,任何操作都无法保证成功,如果续租失败,那么 lease timeout 超过后锁就不再生效

感觉可以优化一下,对于一些连接问题,应该参照rheaKvStore,也有重试机制,尝试去新的leader进行续约。这个能优化吗。 不然这个续约功能,等于没有,不敢用这个功能

都一样的,只要完成网络异常重试就可以了

en-hui commented 1 month ago

异常重试当前好像是出错了立马重试? 是不是加一点缓冲时间比较好呢?加一个可配置化的重试间隔时间

fengjiachun commented 1 month ago

异常重试当前好像是出错了立马重试? 是不是加一点缓冲时间比较好呢?加一个可配置化的重试间隔时间

不需要,跟你说的这个没关系,是刷新 leader 再重试,都不一定请求的同一个节点,间隔啥

en-hui commented 1 month ago

异常重试当前好像是出错了立马重试? 是不是加一点缓冲时间比较好呢?加一个可配置化的重试间隔时间

不需要,跟你说的这个没关系,是刷新 leader 再重试,都不一定请求的同一个节点,间隔啥

好的,这个问题预计发版时间是啥时候呢,我可以参照pr先本地改一下先用着

fengjiachun commented 1 month ago

应该这周会提一个 PR 来修复(最近较忙,我会尽快),发版预计再推迟一周

fengjiachun commented 1 month ago

最新版本正准备发布,请关注 #1137

fengjiachun commented 1 month ago

已发布 1.3.15,这个 issue 就关闭了