New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
dubbo service repeat register to registry #7124
Comments
4213 , 这个并没有解决问题,或者说, 我理解错了 |
4213, 问题回复: 近期,关于升级到2.7.1版本后注册中心(多数是zookeeper)出现重复URL地址数据无法删除的情况,我们持续收到来自社区的issue报告。以下issue是几个典型的异常现象:#3785 #3770 #3920 #4013 经过问题排查我们定位到了问题的原因:在2.7.1版本中URL地址在zookeeper中被注册为持久persistent节点(2.7.0及之前注册的是临时emperal节点),这样当server进程异常终止无法进入正常优雅下线流程时,如进程崩溃、强行kill -9等,导致zookeeper已失效持久节点无法清空,最终导致脏数据的出现。 解决及规避方法: 上下线过程避免强行终止进程,保证让Dubbo进入优雅停机流程 到2.7.8了,依然没有解决? |
从zookeeper的官方临时节点生命周期,及官方文档来看Nodes+and+ephemeral+nodes ,显然不止Dynamic的问题 ZooKeeper also has the notion of ephemeral nodes. These znodes exists as long as the session that created the znode is active. When the session ends the znode is deleted. Ephemeral nodes are useful when you want to implement [tbd]. 会话结束后,临时节点应该删除呀。 |
测试临时节点没有问题 @Slf4j
public class CuratorZookeeperClientTest {
private static CuratorZookeeperClient zookeeperClient = null;
/**
*
*/
@BeforeClass
public static void initClient(){
URL url = new URL("zookeeper","127.0.0.1", 2181);
zookeeperClient = new CuratorZookeeperClient(url);
log.info("zookeeperClient init done");
}
/**
*
*/
@AfterClass
public static void closeClient(){
if(!ObjectUtils.isEmpty(zookeeperClient)){
zookeeperClient.close();
log.info("zookeeperClient close done");
}
}
/**
* https://zookeeper.apache.org/doc/r3.2.2/zookeeperOver.html#Nodes+and+ephemeral+nodes
*/
@Test
public void testEphemeral(){
zookeeperClient.createEphemeral("/cherry");
log.info("zookeeperClient createEphemeral /cherry");
}
} |
是不是没有优雅关机,我是在Idea启动服务,然后关闭。 |
damn!graceful shutdow, is ok, the problem is slove:
how grace shutodow refer to : https://www.baeldung.com/spring-boot-shutdown; but use the dubbo-spring-boot-starter:0.1.0, not care the point. |
why use the dubbo-spring-boot-starter:0.1.0, not care the point. |
This comment has been minimized.
This comment has been minimized.
wait to solve? |
能提供一个稳定重现的例子不? |
现在有3个版本的,你需要哪一个版本? 2.7.8, 2.6.9, 2.5.x, 2.5.x没有问题,其他两个版本要优雅方式关闭,方可避免同ip重复注册 |
麻烦提供一个 2.7.8 的 demo |
springboot 版本:2.3.0.RELEASE 属性配置
pom <!-- dubbo 2.7.8 start-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- dubbo 2.7.8 end --> dubbo 服务
Application
dubbo config
服务AccountRemoteServiceImpl实现这一块,你可以置空,试一下 |
好的,我这边看下 |
TK |
请教下,你这边启动后还做了啥操作没?我这边测试是一个节点。 |
服务非优雅停机临时节点不会马上删除,要等zookeeper心跳超时才会删除这个节点。在zookeeper删除无效节点之前你再去注册就会有两个一模一样的节点(timestamp会不一样),这个不影响服务调用的。 |
一个节点启动即可,启动,观察zk的服务注册节点,什么也不做,然后使用idea stop 关闭应用,再重启,观察zk的服务注册节点 |
结果重复注册 |
|
好的 |
#7124 (comment) |
默认60s: protected int DEFAULT_SESSION_TIMEOUT_MS = 60 * 1000;
public CuratorZookeeperClient(URL url) {
super(url);
try {
int timeout = url.getParameter(TIMEOUT_KEY, DEFAULT_CONNECTION_TIMEOUT_MS);
int sessionExpireMs = url.getParameter(ZK_SESSION_EXPIRE_KEY, DEFAULT_SESSION_TIMEOUT_MS);
CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder()
.connectString(url.getBackupAddress())
.retryPolicy(new RetryNTimes(1, 1000))
.connectionTimeoutMs(timeout)
.sessionTimeoutMs(sessionExpireMs);
String authority = url.getAuthority();
if (authority != null && authority.length() > 0) {
builder = builder.authorization("digest", authority.getBytes());
}
client = builder.build();
client.getConnectionStateListenable().addListener(new CuratorConnectionStateListener(url));
client.start();
boolean connected = client.blockUntilConnected(timeout, TimeUnit.MILLISECONDS);
if (!connected) {
throw new IllegalStateException("zookeeper not connected");
}
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
} |
zk会话追踪器SessionTrackerImpl,检查客户端会话超时时,会关闭会话, 同时清理会话临时节点(不可能两天都没有清掉),会话的超时时间,是客户端设置的60s. //org.apache.zookeeper.server.DataTree#killSession /**
* 清除会话临时节点
* @param session
* @param zxid
*/
void killSession(long session, long zxid) {
// the list is already removed from the ephemerals
// so we do not have to worry about synchronizing on
// the list. This is only called from FinalRequestProcessor
// so there is no need for synchronization. The list is not
// changed here. Only create and delete change the list which
// are again called from FinalRequestProcessor in sequence.
Set<String> list = ephemerals.remove(session);
if (list != null) {
for (String path : list) {
try {
deleteNode(path, zxid);
if (LOG.isDebugEnabled()) {
LOG
.debug("Deleting ephemeral node " + path
+ " for session 0x"
+ Long.toHexString(session));
}
} catch (NoNodeException e) {
LOG.warn("Ignoring NoNodeException for path " + path
+ " while removing ephemeral for dead session 0x"
+ Long.toHexString(session));
}
}
}
} |
你把你的 zk 的配置文件贴出来看下 |
今天突然发现Zk启动的最大和最小超时会话id为-1:想看一下是不是这个问题: zk超时会话设置 int sessionTimeout = connReq.getTimeOut();
byte passwd[] = connReq.getPasswd();
int minSessionTimeout = getMinSessionTimeout();
if (sessionTimeout < minSessionTimeout) {
sessionTimeout = minSessionTimeout;
}
int maxSessionTimeout = getMaxSessionTimeout();
if (sessionTimeout > maxSessionTimeout) {
sessionTimeout = maxSessionTimeout;
}
cnxn.setSessionTimeout(sessionTimeout); 根据配置和连接会话的超时时间,取客户端的sessionTimeout ,zk配置的minSessionTimeout,maxSessionTimeout, 那我就吧zk配置minSessionTimeout,maxSessionTimeout设置为60s;
客户端关闭应该超过60s了还没有关闭 查看zk的关于会话超时的说明 跟zk无关。 |
The number of milliseconds of each ticktickTime=20000000 这个会导致 dubbo 配置的 sessionTimeout 失效。 dubbo 中配置的 sessionTimeout 必须在 2 * tick ~ 20 * tick 这个范围。 |
这个我好想在那看到过,我试一下先 |
One of the parameters to the ZooKeeper client library call to create a ZooKeeper session is the session timeout in milliseconds. The client sends a requested timeout, the server responds with the timeout that it can give the client. The current implementation requires that the timeout be a minimum of 2 times the tickTime (as set in the server configuration) and a maximum of 20 times the tickTime. The ZooKeeper client API allows access to the negotiated timeout. |
确实这个问题:会话追踪器中的过期check时间为tickTime. public SessionTrackerImpl(SessionExpirer expirer,
ConcurrentMap<Long, Integer> sessionsWithTimeout, int tickTime,
long serverId, ZooKeeperServerListener listener)
{
super("SessionTracker", listener);
this.expirer = expirer;
//过期会话的check的时间间隔为tickTime
this.sessionExpiryQueue = new ExpiryQueue<SessionImpl>(tickTime);
this.sessionsWithTimeout = sessionsWithTimeout;
this.nextSessionId.set(initializeNextSession(serverId));
for (Entry<Long, Integer> e : sessionsWithTimeout.entrySet()) {
addSession(e.getKey(), e.getValue());
}
}
tickTime过大,导致过期会话检查时间没有到,没有移除过期会话。 |
@xiaoheng1 , 你复现过是什么原因? 在注册之前最后check一下或以IP管理,避免重复注册;虽然是TickTime设置太大导致,Zk工作是正常的,如果能避免这个问题,更好。可以容忍,外部因素(····)。 |
我当时为了复现你说的这个问题时发现的,当时注册到 zk 上的节点,40s 左右就过期来,这个是不正常的。 |
临时文件存储?这种方式也可以,减少对现有目录结构的变更。第一种方式:注册信息在两个地方维护;第二种只在ZK上维护,便于管理,都可以的; |
1.临时文件存储优点:减少对现有目录结构的变更; 2.增加IP节点优点:注册信息统一有ZK维护,更清晰,直观; 从大局观上讲,选择1;从整体、维护的角度及后期的发展来看,选择2; 看如何权衡,取舍吧。 |
关闭应用后,40s左后,会话就过期,同时注册的临时节点消失? |
@xiaoheng1 |
默认的 zk 配置,tick 为 2s,那么 minSessionTime 为 4s,maxSessionTime 为 40s. dubbo 默认配置 sessionTime 为 60s,默认取 40s,和我观察到的差不多40s 左右消失是一致的(注册到zk 的临时节点)。 |
能详细描述下这个问题是如何产生的吗?能列下复现的步骤就更好了。 |
在一个非provider的应用实现通过zk registry更新provider,这样这个provider(zk ephemeral)的emhemeralOwer 属于这个非真实provider的会话,导致真实的provider非正常关闭(kill -9)时,zk不会去清理ephemeral node。。。 |
也就是说你用一个第三方的应用,写了一段代码,连上了 zk,然后修改了 zk provider 节点的属性,导致真实 provider 非正常关闭的时候没有清理 ephemeral node? zk 的配置麻烦贴下,还有就是这个 ephemeral node 节点后来一直没有被清掉吗? |
是的,第三方应用连接zk获取操作provider,update之后provider的ephemeral node被第三方应用的连接会话把持,这个是我使用上的问题;zk配置没问题的 tickTime=2000 minSessionTimeout=30000 maxSessionTimeout=60000 |
明白了 |
2.7.8 使用 nacos 也有这个问题 |
@Donaldhan @lin-mt 在2.7.14版本中是否存在该问题? |
No feedback for a long time, please close the issue temporarily. If there is still a problem, you can reopen it. |
Environment
information
服务重复注册,用的是dububo:2.7.8, spring-boot:2.3.0.RELEASE,我的pom
dubbo服务
查看zk服务的节点信息,
ip地址一样;
从4213来看,同样存在这样的问题?说是dynamic的问题,默认false,则持久路径,true为临时路径,2.7.8为true还是没用。
DubboService
···java
/**
* Whether the service is dynamic, default value is true
*/
boolean dynamic() default true;
···
调试结果:
临时节点,在连接断开后,zk会自动删除, 这不应该呀!
我们dubbo版本为2.6.9,dubbo-boot:0.2.1.RELEASE,spring-boot:2.1..RELEASE 存在同样的问题,重复注册?
pom
dubbo 服务
然而注解service为false
dynamic 为false还是有;
从这两个例子来看,跟dynamic 无关。
这是一个问题,另外我想问一下,服务节点路径的timestamp 是做什么用了
去掉timestamp,是不是,就保持一个节点了, 但这不是根本问题。
The text was updated successfully, but these errors were encountered: