[alibaba/nacos]压测 Nacos 2.2.0 3个节点的集群,每个节点中的服务列表信息不一致

2025-10-30 813 views
2

新搭建了一个3节点的2.2.0版本的Nacos集群,准备压测一波比较下性能提升。 使用800个并发,1W8的TPS只往节点1中注册服务。 脚本执行5分钟之后,最终节点1显示注册了7385个服务,节点2显示注册了3011个服务,节点3显示注册了3007个服务。 本来以为是不是同步服务阻塞了,等到脚本停止之后一直保持这个数据。

回答

3

这你需要自己看下问题了, 信息太少了,比如客户端版本, 服务的打散规模,有无报错等都缺失,应该没人帮的了你。

3

服务端客户端全部是2.2.0的release,3节点集群,内存设置Xmx8g,Xms8g,Xmn4g,机器配置8c16g 1个线程 一致: 2W个服务,每个服务1个节点 不一致: 3W个服务,每个服务1个节点

10个线程 一致: 每个线程3K个服务,每个服务1个节点,总计3W个节点 不一致:4K个服务,每个服务1个节点,总计4W个节点

测试了很多次,基本上会存在一个临界值,然后就必现,注册只往1个nacos节点注册。这个节点的控制台最终的服务数量是正确的,其它2个nacos节点的控制台上查看服务数量可以直接看出来服务数量不一致。

观察日志是有 Sync data change failed .但是看了源码 失败之后会进行重试,根据目前观察最终结果初步分析可能是重试并未执行或者还是失败了。本来猜想会有个延迟的重推达到最终一致。然而并没有,nacos各节点上的服务数量很稳定,放了一个晚上基本上每个nacos节点上面显示的服务数量都是不变的,所以并没有补偿同步数据。

以下是单机模拟的程序:

public class NamingTest_2_x {

    public static ExecutorService service=Executors.newCachedThreadPool();

    private static NamingService naming;

    static {
        Properties properties = new Properties();
        properties.setProperty("serverAddr", System.getProperty("serverAddr", "10.130.20.60:8848"));
        properties.setProperty("namespace", System.getProperty("namespace", "public"));

        try {
            naming = NamingFactory.createNamingService(properties);
        } catch (NacosException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) throws Exception{
        //并发执行的线程数
        int thread_count=1;
        //注册的服务数
        int serviceCount=20000;
        //每个服务的节点数
        int instanceCount=5;

        AtomicInteger successCnt=new AtomicInteger(0);
        for (int k = 0; k < thread_count; k++) {
            service.execute(()->{
                try {
                    register(serviceCount,Thread.currentThread().getName(),instanceCount);
                    successCnt.incrementAndGet();
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println(Thread.currentThread().getName()+":注册失败");
                }
            });
        }
        new CountDownLatch(1).await();
    }

    public static void register(int serviceCount,String tName,int instanceCount) throws Exception{

        for (int i = 0; i < serviceCount; i++) {
            String serviceName = "nacos2.x-"+tName+"-"+i+"-ms";

            List<Instance> instanceList=new ArrayList<>();
            for (int j = 1; j <=instanceCount;  j++) {
                String instanceIp = "20.20.20." + j;
                int port = 8880 + j;
                Instance instance = new Instance();
                instance.setEphemeral(true);
                instance.setIp(instanceIp);
                instance.setPort(port);
                instance.setWeight(1d);
                instance.setClusterName("DEFAULT");
                instance.setEnabled(true);
                instance.setEphemeral(true);
                instanceList.add(instance);
            }
            try {
                naming.batchRegisterInstance(serviceName, "DEFAULT_GROUP", instanceList);
            }catch (Exception e){
                e.printStackTrace();
                throw e;
            }
        }

    }
}
0

@KomachiSion 有空的话可以试下^_^

2

补充: 当前写入的nacos节点中的protect-distro.log 中的报错信息(其它2个targetServer节点的ip都存在)

INFO [DISTRO-START] DistroSyncChangeTask for DistroKey{resourceKey='1679360984778_172.16.0.67_62401', resourceType='Nacos:Naming:v2:ClientData', targetServer='10.130.20.100:8848'}

WARN [DISTRO] Sync data change failed. key: DistroKey{resourceKey='1679360984778_172.16.0.67_62401', resourceType='Nacos:Naming:v2:ClientData', targetServer='10.130.20.100:8848'}

io.grpc.StatusRuntimeException: CANCELLED: HTTP/2 error code: CANCEL
Received Rst Stream
        at io.grpc.Status.asRuntimeException(Status.java:533)
        at io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:515)
        at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:426)
        at io.grpc.internal.ClientCallImpl.access$500(ClientCallImpl.java:66)
        at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.close(ClientCallImpl.java:689)
        at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.access$900(ClientCallImpl.java:577)
        at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:751)
        at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:740)
        at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
        at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.
1

每3秒出现1次,同步失败,重试,又失败,继续重试。。。

1

这个报错看起来是网络有问题, 集群间的grpc链接被reset了, 可能是压力导致连接的pingpong断了。也可能是网络本身出问题导致连接被reset了。

2

GrpcServerConstants DEFAULT_GRPC_MAX_INBOUND_MSG_SIZE = 10 1024 1024; 大概已经接近找到原因了,nacos服务端的启动脚本里面调大之后可以支持更多的实例数量了 -Dnacos.remote.server.grpc.maxinbound.message.size=

9

另外我看了下测试用例, 发现是同一个连接上注册了非常多服务, 这可能导致单个client的同步压力过大。实际使用的时候应该创建多个namingService来进行分散注册来模拟。

5

是的 实际使用肯定是多个client,因为使用一个client在数量小的时候都没问题,稍微大一点就出现了上述问题,所以才有本次的反馈。 又经过几轮测试,通过调节这个参数的大小,起到了明显的效果,之前测出来的几个数据 都提升了,所以看起来更像是集群之间通讯的grpc的一个消息大小限制被解除了。

9

一般一个连接注册服务不会太多, 即使是dubbo2这种场景, 1个连接注册几百个接口也已经算是很大了, 我看你的用例一个连接注册了几万个服务, 这肯定会导致同步的时候,单个client数据内容过大,触发grpc的单次请求大小, 调高是能缓解,但是继续增加依旧会影响处理速度和带宽压力等等问题。

建议还是按照较真实场景来压测,否则没什么意义。

8

@KomachiSion 请问官方有没有压测的脚本 能提供一下呢 想看看官方的性能是通过怎样的场景测出来的

1

目前没有benchmark项目, 以前好像有人提过,不过最后没有社区同学接手也就放弃了。

之前2.0刚发布的时候压测过一段时间, 大致就是每台机器启动n个线程,每个线程new 一个NamingService,然后每个线程再注册X个服务。

n根据施压机规格在50~200不等, X根据情况从5~500不等。