sofastack / sofa-registry

SOFARegistry is a production-level, low-latency, high-availability service registry powered by Ant Financial.
https://www.sofastack.tech/sofa-registry/docs/Home
Apache License 2.0
653 stars 247 forks source link

sofa-registry subscriber 后,会收到空的 push 推送消息 #325

Closed chuntaojun closed 1 year ago

chuntaojun commented 1 year ago

Describe the bug

Screenshot 2023-05-31 at 15 39 50

Expected behavior

Actual behavior

Steps to reproduce

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF 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
 *
 *     http://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 com.alipay.sofa.registry.client;

import java.util.concurrent.CountDownLatch;

import com.alipay.remoting.exception.CodecException;
import com.alipay.sofa.registry.client.api.Publisher;
import com.alipay.sofa.registry.client.api.SubscriberDataObserver;
import com.alipay.sofa.registry.client.api.model.UserData;
import com.alipay.sofa.registry.client.api.registration.PublisherRegistration;
import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration;
import com.alipay.sofa.registry.client.provider.DefaultRegistryClient;
import com.alipay.sofa.registry.client.provider.DefaultRegistryClientConfigBuilder;

public class Main {

    private static String HOST = "127.0.0.1";

    private static int PORT = 9603;

    public static void main(String[] args) throws InterruptedException, CodecException {
        System.out.println("Begin run SOFA Client test");
        tenantOne();
        tenantTwo();
        CountDownLatch latch = new CountDownLatch(1);
        latch.await();
    }

    private static void tenantOne() {
        DefaultRegistryClientConfigBuilder builder = new DefaultRegistryClientConfigBuilder();
        builder.setRegistryEndpoint(HOST);
        builder.setRegistryEndpointPort(PORT);
        DefaultRegistryClient client = new DefaultRegistryClient(builder.build());
        client.init();

        PublisherRegistration publisherRegistration = new PublisherRegistration("DEFAULT_MOCK");
        Publisher publisher = client.register(publisherRegistration, "springcloud://6.2.2.1?",
            "springcloud://6.2.2.2", "springcloud://6.2.2.3");
        SubscriberRegistration subscriberRegistration = new SubscriberRegistration("DEFAULT_MOCK",
            new SubscriberDataObserver() {
                @Override
                public void handleData(String dataId, UserData data) {
                    System.out.println(data);
                }
            });
        client.register(subscriberRegistration);
    }

    private static void tenantTwo() {
        DefaultRegistryClientConfigBuilder builder = new DefaultRegistryClientConfigBuilder();
        builder.setRegistryEndpoint(HOST);
        builder.setRegistryEndpointPort(PORT);
        builder.setInstanceId("SPRINGLIAO");
        DefaultRegistryClient client = new DefaultRegistryClient(builder.build());
        client.init();

        PublisherRegistration publisherRegistration = new PublisherRegistration("SPRINGLIAO_MOCK");
        Publisher publisher = client.register(publisherRegistration, "springcloud://1.1.1.1",
            "springcloud://1.1.1.2", "springcloud://1.1.1.3");
        SubscriberRegistration subscriberRegistration = new SubscriberRegistration("SPRINGLIAO_MOCK",
            new SubscriberDataObserver() {
                @Override
                public void handleData(String dataId, UserData data) {
                    System.out.println(data);
                }
            });
        client.register(subscriberRegistration);
    }
}

Minimal yet complete reproducer code (or GitHub URL to code)

Environment

nocvalight commented 1 year ago
  1. sofa registry作为注册中心,目前是提供的最终一致性,也就是说并非按全局时钟的顺序 保证获取数据的线性一致性;
  2. 具体到上面的case来说,pub register注册完成后,实际在registry中是一个异步的动作;sub发起时有可能pub的数据还没有真正保存到data上,所以这个时候会有一个推送空的动作;但是最后客户端收到的数据是准确的。
chuntaojun commented 1 year ago
  1. sofa registry作为注册中心,目前是提供的最终一致性,也就是说并非按全局时钟的顺序 保证获取数据的线性一致性;
  2. 具体到上面的case来说,pub register注册完成后,实际在registry中是一个异步的动作;sub发起时有可能pub的数据还没有真正保存到data上,所以这个时候会有一个推送空的动作;但是最后客户端收到的数据是准确的。

最终一致性没有问题,但是不应该推送一个空的数据过来吧,最终是会有问题的,因为会出现推空的数据出现

Screenshot 2023-05-31 at 15 58 11
nocvalight commented 1 year ago

可以提供一下完整的 config.client.log 或者 registry.log的client日志看看

chuntaojun commented 1 year ago

我貌似没太找到这个文件,我在 {user.home} 下没有找到 sofa-client 相关的日志

nocvalight commented 1 year ago

image

client的日志在 {user.home} /logs/registry/registry-client.log,没有复现出来你说的现象。

NickNYU commented 1 year ago

我貌似没太找到这个文件,我在 {user.home} 下没有找到 sofa-client 相关的日志

IDE的话,应该是有一个类似于{user.home}的路径在你的项目文件下面