[ISSUES #9001]spi instanceIdGenerator and snowFlakeInstanceIdGenerator (#11561)

* spi instanceIdGenerator and snowFlakeInstanceIdGenerator

* Test fix

* fix InstanceId set

* Copyright fix
This commit is contained in:
hth 2024-01-05 17:53:56 +08:00 committed by GitHub
parent 2296125d41
commit ea94095f74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 336 additions and 50 deletions

View File

@ -16,17 +16,27 @@
package com.alibaba.nacos.api.naming.spi.generator;
import com.alibaba.nacos.api.naming.pojo.Instance;
/**
* Generator SPI for Instance Id.
*
* @author xiweng.yy
*/
public interface IdGenerator {
public interface InstanceIdGenerator {
/**
* Generate instance id.
*
* @param instance instance
* @return instance id
*/
String generateInstanceId();
String generateInstanceId(Instance instance);
/**
* Generator type.
*
* @return type
*/
String type();
}

View File

@ -23,7 +23,7 @@ import org.springframework.core.env.StandardEnvironment;
import java.util.stream.IntStream;
public class SnowFlowerIdGeneratorTest {
public class SnowFlowerInstanceIdGeneratorTest {
@Test
public void nextId() {

View File

@ -19,7 +19,7 @@ package com.alibaba.nacos.core.model.vo;
import org.junit.Assert;
import org.junit.Test;
public class IdGeneratorVOTest {
public class InstanceIdGeneratorVOTest {
@Test
public void test() {

View File

@ -84,12 +84,7 @@ public class BeatInfoInstanceBuilder {
actualBuilder.setEphemeral(beatInfo.isEphemeral());
}
/**
* TODO use spi and metadata info to generate instanceId.
*/
private void setInstanceId(Instance instance) {
DefaultInstanceIdGenerator idGenerator = new DefaultInstanceIdGenerator(instance.getServiceName(),
instance.getClusterName(), instance.getIp(), instance.getPort());
instance.setInstanceId(idGenerator.generateInstanceId());
instance.setInstanceId(InstanceIdGeneratorManager.generateInstanceId(instance));
}
}

View File

@ -16,34 +16,29 @@
package com.alibaba.nacos.naming.pojo.instance;
import com.alibaba.nacos.api.naming.spi.generator.IdGenerator;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.spi.generator.InstanceIdGenerator;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_INSTANCE_ID_GENERATOR;
import static com.alibaba.nacos.api.common.Constants.NAMING_INSTANCE_ID_SPLITTER;
/**
* Default instance id generator.
*
* @author xiweng.yy
*/
public class DefaultInstanceIdGenerator implements IdGenerator {
public class DefaultInstanceIdGenerator implements InstanceIdGenerator {
public static final String ID_DELIMITER = "#";
private final String serviceName;
private final String clusterName;
private final String ip;
private final int port;
public DefaultInstanceIdGenerator(String serviceName, String clusterName, String ip, int port) {
this.serviceName = serviceName;
this.clusterName = clusterName;
this.ip = ip;
this.port = port;
@Override
public String generateInstanceId(Instance instance) {
return instance.getIp() + NAMING_INSTANCE_ID_SPLITTER
+ instance.getPort() + NAMING_INSTANCE_ID_SPLITTER
+ instance.getClusterName() + NAMING_INSTANCE_ID_SPLITTER
+ instance.getServiceName();
}
@Override
public String generateInstanceId() {
return ip + ID_DELIMITER + port + ID_DELIMITER + clusterName + ID_DELIMITER + serviceName;
public String type() {
return DEFAULT_INSTANCE_ID_GENERATOR;
}
}

View File

@ -138,12 +138,7 @@ public class HttpRequestInstanceBuilder {
}
}
/**
* TODO use spi and metadata info to generate instanceId.
*/
private void setInstanceId(Instance instance) {
DefaultInstanceIdGenerator idGenerator = new DefaultInstanceIdGenerator(instance.getServiceName(),
instance.getClusterName(), instance.getIp(), instance.getPort());
instance.setInstanceId(idGenerator.generateInstanceId());
instance.setInstanceId(InstanceIdGeneratorManager.generateInstanceId(instance));
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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.alibaba.nacos.naming.pojo.instance;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.spi.generator.InstanceIdGenerator;
import com.alibaba.nacos.api.utils.StringUtils;
import com.alibaba.nacos.common.spi.NacosServiceLoader;
import java.util.Collection;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentHashMap;
/**
* InstanceIdGeneratorManager.
*
* @author : huangtianhui
*/
public class InstanceIdGeneratorManager {
private static final InstanceIdGeneratorManager INSTANCE = new InstanceIdGeneratorManager();
private final Map<String, InstanceIdGenerator> generatorMap = new ConcurrentHashMap<>();
public InstanceIdGeneratorManager() {
init();
}
private void init() {
Collection<InstanceIdGenerator> instanceIdGenerators = NacosServiceLoader.load(InstanceIdGenerator.class);
for (InstanceIdGenerator instanceIdGenerator : instanceIdGenerators) {
generatorMap.put(instanceIdGenerator.type(), instanceIdGenerator);
}
}
private InstanceIdGenerator getInstanceIdGenerator(String type) {
if (generatorMap.containsKey(type)) {
return generatorMap.get(type);
}
throw new NoSuchElementException("The InstanceIdGenerator type is not found ");
}
/**
* spi generateInstanceId.
*
* @param instance instance
* @return InstanceId
*/
public static String generateInstanceId(Instance instance) {
String instanceIdGeneratorType = instance.getInstanceIdGenerator();
if (StringUtils.isBlank(instanceIdGeneratorType)) {
instanceIdGeneratorType = Constants.DEFAULT_INSTANCE_ID_GENERATOR;
}
return INSTANCE.getInstanceIdGenerator(instanceIdGeneratorType).generateInstanceId(instance);
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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.alibaba.nacos.naming.pojo.instance;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.spi.generator.InstanceIdGenerator;
import com.alibaba.nacos.core.distributed.id.SnowFlowerIdGenerator;
import static com.alibaba.nacos.api.common.Constants.NAMING_INSTANCE_ID_SPLITTER;
import static com.alibaba.nacos.api.common.Constants.SNOWFLAKE_INSTANCE_ID_GENERATOR;
/**
* SnowFlake InstanceId Generator..
*
* @author : huangtianhui
*/
public class SnowFlakeInstanceIdGenerator implements InstanceIdGenerator {
private static final SnowFlowerIdGenerator SNOW_FLOWER_ID_GENERATOR = new SnowFlowerIdGenerator();
static {
SNOW_FLOWER_ID_GENERATOR.init();
}
@Override
public String generateInstanceId(Instance instance) {
return SNOW_FLOWER_ID_GENERATOR.nextId() + NAMING_INSTANCE_ID_SPLITTER
+ instance.getClusterName() + NAMING_INSTANCE_ID_SPLITTER
+ instance.getServiceName();
}
@Override
public String type() {
return SNOWFLAKE_INSTANCE_ID_GENERATOR;
}
}

View File

@ -23,7 +23,7 @@ import com.alibaba.nacos.naming.constants.Constants;
import com.alibaba.nacos.naming.core.v2.metadata.InstanceMetadata;
import com.alibaba.nacos.naming.core.v2.pojo.InstancePublishInfo;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import com.alibaba.nacos.naming.pojo.instance.DefaultInstanceIdGenerator;
import com.alibaba.nacos.naming.pojo.instance.InstanceIdGeneratorManager;
import java.util.HashMap;
import java.util.List;
@ -87,7 +87,7 @@ public final class InstanceUtil {
/**
* Deepcopy one instance.
*
*
* @param source instance to be deepcopy
*/
public static Instance deepCopy(Instance source) {
@ -113,9 +113,10 @@ public final class InstanceUtil {
*/
public static void setInstanceIdIfEmpty(Instance instance, String groupedServiceName) {
if (null != instance && StringUtils.isEmpty(instance.getInstanceId())) {
DefaultInstanceIdGenerator idGenerator = new DefaultInstanceIdGenerator(groupedServiceName,
instance.getClusterName(), instance.getIp(), instance.getPort());
instance.setInstanceId(idGenerator.generateInstanceId());
if (StringUtils.isBlank(instance.getServiceName())) {
instance.setServiceName(groupedServiceName);
}
instance.setInstanceId(InstanceIdGeneratorManager.generateInstanceId(instance));
}
}

View File

@ -0,0 +1,18 @@
#
# Copyright 1999-2023 Alibaba Group Holding Ltd.
#
# Licensed 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.
#
com.alibaba.nacos.naming.pojo.instance.DefaultInstanceIdGenerator
com.alibaba.nacos.naming.pojo.instance.SnowFlakeInstanceIdGenerator

View File

@ -16,16 +16,22 @@
package com.alibaba.nacos.naming.pojo.instance;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
public class DefaultInstanceIdGeneratorTest {
public class DefaultInstanceInstanceIdGeneratorTest {
@Test
public void testGenerateInstanceId() {
DefaultInstanceIdGenerator idGenerator = new DefaultInstanceIdGenerator("service", "cluster", "1.1.1.1", 1000);
assertThat(idGenerator.generateInstanceId(), is("1.1.1.1#1000#cluster#service"));
final DefaultInstanceIdGenerator instanceIdGenerator = new DefaultInstanceIdGenerator();
Instance instance = new Instance();
instance.setServiceName("service");
instance.setClusterName("cluster");
instance.setIp("1.1.1.1");
instance.setPort(1000);
assertThat(instanceIdGenerator.generateInstanceId(instance), is("1.1.1.1#1000#cluster#service"));
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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.alibaba.nacos.naming.pojo.instance;
import com.alibaba.nacos.api.naming.PreservedMetadataKeys;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.sys.env.EnvUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.mock.env.MockEnvironment;
import java.util.HashMap;
import java.util.Map;
import static com.alibaba.nacos.api.common.Constants.SNOWFLAKE_INSTANCE_ID_GENERATOR;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@RunWith(MockitoJUnitRunner.class)
public class InstanceIdGeneratorManagerTest {
static {
MockEnvironment environment = new MockEnvironment();
environment.setProperty("nacos.core.snowflake.worker-id", "-1");
EnvUtil.setEnvironment(environment);
}
@Test
public void testGenerateSnowFlakeInstanceId() {
Instance instance = new Instance();
Map<String, String> metaData = new HashMap<>(1);
metaData.put(PreservedMetadataKeys.INSTANCE_ID_GENERATOR, SNOWFLAKE_INSTANCE_ID_GENERATOR);
instance.setMetadata(metaData);
instance.setServiceName("service");
instance.setClusterName("cluster");
instance.setIp("1.1.1.1");
instance.setPort(1000);
String instanceId = InstanceIdGeneratorManager.generateInstanceId(instance);
assertTrue(instanceId.endsWith("#cluster#service"));
}
@Test
public void testGenerateInstanceId() {
Instance instance = new Instance();
instance.setServiceName("service");
instance.setClusterName("cluster");
instance.setIp("1.1.1.1");
instance.setPort(1000);
assertThat(InstanceIdGeneratorManager.generateInstanceId(instance), is("1.1.1.1#1000#cluster#service"));
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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.alibaba.nacos.naming.pojo.instance;
import com.alibaba.nacos.api.naming.PreservedMetadataKeys;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.sys.env.EnvUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.mock.env.MockEnvironment;
import java.util.HashMap;
import java.util.Map;
import static com.alibaba.nacos.api.common.Constants.SNOWFLAKE_INSTANCE_ID_GENERATOR;
import static org.junit.Assert.assertTrue;
@RunWith(MockitoJUnitRunner.class)
public class SnowFlakeInstanceIdGeneratorTest {
static {
MockEnvironment environment = new MockEnvironment();
environment.setProperty("nacos.core.snowflake.worker-id", "-1");
EnvUtil.setEnvironment(environment);
}
@Test
public void testGenerateInstanceId() {
final SnowFlakeInstanceIdGenerator instanceIdGenerator = new SnowFlakeInstanceIdGenerator();
Instance instance = new Instance();
Map<String, String> metaData = new HashMap<>(1);
metaData.put(PreservedMetadataKeys.INSTANCE_ID_GENERATOR, SNOWFLAKE_INSTANCE_ID_GENERATOR);
instance.setMetadata(metaData);
instance.setServiceName("service");
instance.setClusterName("cluster");
instance.setIp("1.1.1.1");
instance.setPort(1000);
String instanceId = instanceIdGenerator.generateInstanceId(instance);
assertTrue(instanceId.endsWith("#cluster#service"));
}
}

View File

@ -20,7 +20,7 @@ import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.naming.core.v2.metadata.InstanceMetadata;
import com.alibaba.nacos.naming.core.v2.pojo.InstancePublishInfo;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import com.alibaba.nacos.naming.pojo.instance.DefaultInstanceIdGenerator;
import com.alibaba.nacos.naming.pojo.instance.InstanceIdGeneratorManager;
import org.junit.Before;
import org.junit.Test;
@ -93,11 +93,10 @@ public class InstanceUtilTest {
instance.setIp("1.1.1.1");
instance.setPort(8890);
String groupedServiceName = "test";
instance.setClusterName("testCluster");
InstanceUtil.setInstanceIdIfEmpty(instance, groupedServiceName);
assertNotNull(instance.getInstanceId());
DefaultInstanceIdGenerator idGenerator = new DefaultInstanceIdGenerator(groupedServiceName,
instance.getClusterName(), instance.getIp(), instance.getPort());
assertEquals(instance.getInstanceId(), idGenerator.generateInstanceId());
assertEquals(instance.getInstanceId(), InstanceIdGeneratorManager.generateInstanceId(instance));
String customInsId = "customInstanceId_1";
Instance instance1 = new Instance();
instance1.setInstanceId(customInsId);
@ -107,15 +106,17 @@ public class InstanceUtilTest {
@Test
public void testBatchSetInstanceIdIfEmpty() {
List<Instance> instances = new ArrayList<>();
final List<Instance> instances = new ArrayList<>();
Instance instance1 = new Instance();
instance1.setServiceName("test");
Instance instance2 = new Instance();
instance2.setServiceName("test");
Instance instance3 = new Instance();
instance3.setServiceName("test");
instances.add(instance1);
instances.add(instance2);
instances.add(instance3);
String groupedServiceName = "test";
InstanceUtil.batchSetInstanceIdIfEmpty(instances, groupedServiceName);
InstanceUtil.batchSetInstanceIdIfEmpty(instances, "test");
assertNotNull(instance1.getInstanceId());
assertNotNull(instance2.getInstanceId());
assertNotNull(instance3.getInstanceId());

View File

@ -0,0 +1,18 @@
#
# Copyright 1999-2023 Alibaba Group Holding Ltd.
#
# Licensed 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.
#
com.alibaba.nacos.naming.pojo.instance.DefaultInstanceIdGenerator
com.alibaba.nacos.naming.pojo.instance.SnowFlakeInstanceIdGenerator