This is an automated email from the ASF dual-hosted git repository. liubao pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git
commit 1eb13a139d49ac30508585664b24c656d380b569 Author: liubao <bao....@huawei.com> AuthorDate: Tue May 15 21:07:58 2018 +0800 [SCB-582]Provide a way to protect instance removal --- .../src/main/resources/microservice.yaml | 8 +++- .../api/registry/MicroserviceInstance.java | 13 ++++++ .../config/ServiceRegistryConfig.java | 8 ++++ .../consumer/MicroserviceInstancePing.java | 34 ++++++++++++++++ .../consumer/MicroserviceVersions.java | 32 ++++++++++++--- .../consumer/SimpleMicroserviceInstancePing.java | 47 ++++++++++++++++++++++ ...rviceregistry.consumer.MicroserviceInstancePing | 18 +++++++++ .../api/registry/TestMicroServiceInstance.java | 10 +++++ .../client/LocalServiceRegistryClientImplTest.java | 1 + .../consumer/TestMicroserviceVersions.java | 13 ++++++ .../TestSimpleMicroserviceInstancePing.java | 46 +++++++++++++++++++++ .../transport/TestRestServletInitializer.java | 2 +- 12 files changed, 224 insertions(+), 8 deletions(-) diff --git a/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml b/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml index 7be293d..74d9481 100644 --- a/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml +++ b/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml @@ -23,6 +23,12 @@ servicecomb: service: registry: address: http://127.0.0.1:30100 + instance: + healthCheck: + interval: 2 + watch: false + remove: + protection: true handler: chain: Consumer: @@ -32,4 +38,4 @@ servicecomb: enabled: false loadbalance: strategy: - name: Random + name: Random \ No newline at end of file diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceInstance.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceInstance.java index 293ab48..184aac3 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceInstance.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceInstance.java @@ -139,6 +139,19 @@ public class MicroserviceInstance { return dataCenterInfo; } + @Override + public int hashCode() { + return this.instanceId.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof MicroserviceInstance) { + return this.instanceId.equals(((MicroserviceInstance) obj).instanceId); + } + return false; + } + public void setDataCenterInfo(DataCenterInfo dataCenterInfo) { this.dataCenterInfo = dataCenterInfo; } diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java index e91444f..0d48a8b 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java @@ -224,6 +224,14 @@ public final class ServiceRegistryConfig { return times < 0 ? DEFAULT_CHECK_TIMES : times; } + public boolean isInstanceRemoveProtectionEnabled() { + DynamicBooleanProperty property = + DynamicPropertyFactory.getInstance() + .getBooleanProperty("servicecomb.service.registry.instance.remove.protection", + false); + return property.get(); + } + public boolean isPreferIpAddress() { DynamicBooleanProperty property = DynamicPropertyFactory.getInstance() diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceInstancePing.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceInstancePing.java new file mode 100644 index 0000000..7bbfa8c --- /dev/null +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceInstancePing.java @@ -0,0 +1,34 @@ +/* + * 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 org.apache.servicecomb.serviceregistry.consumer; + +import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; + +/** + * SPI interface to ping microservice instance status in Instance Protection Mode, which means + * protection of instance removal and usually used in scenarios where instances are fixed and changed rarely. + */ +public interface MicroserviceInstancePing { + int getOrder(); + + /** + * check if this instance if valid to use + * @param instance + * @return + */ + boolean ping(MicroserviceInstance instance); +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java index 0b818df..00b5bc3 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java @@ -23,12 +23,15 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.api.Const; import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstanceStatus; +import org.apache.servicecomb.serviceregistry.api.registry.ServiceCenterConfig; import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent; import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; +import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; import org.apache.servicecomb.serviceregistry.task.event.PullMicroserviceVersionsInstancesEvent; import org.slf4j.Logger; @@ -144,12 +147,7 @@ public class MicroserviceVersions { private void setInstances(List<MicroserviceInstance> pulledInstances, String rev) { synchronized (lock) { - instances = pulledInstances - .stream() - .filter(instance -> { - return MicroserviceInstanceStatus.UP.equals(instance.getStatus()); - }) - .collect(Collectors.toList()); + instances = mergeInstances(pulledInstances, instances); for (MicroserviceInstance instance : instances) { // ensure microserviceVersion exists versions.computeIfAbsent(instance.getServiceId(), microserviceId -> { @@ -169,6 +167,28 @@ public class MicroserviceVersions { } } + private List<MicroserviceInstance> mergeInstances(List<MicroserviceInstance> pulledInstances, + List<MicroserviceInstance> inUseInstances) { + List<MicroserviceInstance> upInstances = pulledInstances + .stream() + .filter(instance -> { + return MicroserviceInstanceStatus.UP.equals(instance.getStatus()); + }) + .collect(Collectors.toList()); + if (inUseInstances != null && ServiceRegistryConfig.INSTANCE.isInstanceRemoveProtectionEnabled()) { + MicroserviceInstancePing ping = SPIServiceUtils.getPriorityHighestService(MicroserviceInstancePing.class); + inUseInstances.stream() + .forEach(instance -> { + if (!upInstances.contains(instance)) { + if (ping.ping(instance)) { + upInstances.add(instance); + } + } + }); + } + return upInstances; + } + public MicroserviceVersionRule getOrCreateMicroserviceVersionRule(String versionRule) { // do not use computeIfAbsent MicroserviceVersionRule microserviceVersionRule = versionRules.get(versionRule); diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/SimpleMicroserviceInstancePing.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/SimpleMicroserviceInstancePing.java new file mode 100644 index 0000000..9520e08 --- /dev/null +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/SimpleMicroserviceInstancePing.java @@ -0,0 +1,47 @@ +/* + * 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 org.apache.servicecomb.serviceregistry.consumer; + +import java.io.IOException; +import java.net.Socket; + +import org.apache.servicecomb.foundation.common.net.IpPort; +import org.apache.servicecomb.foundation.common.net.NetUtils; +import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; + +/** + * Simple implementation of .MicroserviceInstancePing using telnet + */ +public class SimpleMicroserviceInstancePing implements MicroserviceInstancePing { + @Override + public int getOrder() { + return 100; + } + + @Override + public boolean ping(MicroserviceInstance instance) { + if (instance.getEndpoints() != null && instance.getEndpoints().size() > 0) { + IpPort ipPort = NetUtils.parseIpPortFromURI(instance.getEndpoints().get(0)); + try (Socket s = new Socket(ipPort.getHostOrIp(), ipPort.getPort())) { + return true; + } catch (IOException e) { + // ignore this error + } + } + return false; + } +} diff --git a/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing b/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing new file mode 100644 index 0000000..ce06621 --- /dev/null +++ b/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing @@ -0,0 +1,18 @@ +# +# 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. +# + +org.apache.servicecomb.serviceregistry.consumer.SimpleMicroserviceInstancePing \ No newline at end of file diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroServiceInstance.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroServiceInstance.java index 4d4ddc6..affcf92 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroServiceInstance.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroServiceInstance.java @@ -97,6 +97,16 @@ public class TestMicroServiceInstance { Assert.assertEquals(MicroserviceInstanceStatus.DOWN, oMicroserviceInstance.getStatus()); Assert.assertEquals("Test", oMicroserviceInstance.getStage()); Assert.assertEquals("china", oMicroserviceInstance.getProperties().get("region")); + + Assert.assertEquals(oMicroserviceInstance, oMicroserviceInstance); + MicroserviceInstance other = new MicroserviceInstance(); + other.setInstanceId("testInstanceIDOther"); + MicroserviceInstance same = new MicroserviceInstance(); + same.setInstanceId("testInstanceID"); + Assert.assertNotEquals(oMicroserviceInstance, other); + Assert.assertNotEquals(oMicroserviceInstance.hashCode(), other.hashCode()); + Assert.assertEquals(oMicroserviceInstance, same); + Assert.assertEquals(oMicroserviceInstance.hashCode(), same.hashCode()); } @SuppressWarnings("deprecation") diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java index 24b566f..88ba8bf 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java @@ -134,6 +134,7 @@ public class LocalServiceRegistryClientImplTest { mockRegisterMicroservice(appId, microserviceName, "2.0.0"); MicroserviceInstance instance = new MicroserviceInstance(); + instance.setInstanceId("testid"); instance.setServiceId(v1.getServiceId()); registryClient.registerMicroserviceInstance(instance); diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersions.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersions.java index b336d88..53e1f38 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersions.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersions.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.api.Const; import org.apache.servicecomb.serviceregistry.api.MicroserviceKey; @@ -77,6 +78,7 @@ public class TestMicroserviceVersions { @After public void tearDown() throws Exception { + ArchaiusUtils.resetConfig(); findInstancesResponse = null; microserviceInstances = null; } @@ -149,6 +151,17 @@ public class TestMicroserviceVersions { } @Test + public void submitPullProtection() { + ArchaiusUtils.setProperty("servicecomb.service.registry.instance.remove.protection", true); + String microserviceId = "1"; + setup(microserviceId); + microserviceVersions.submitPull(); + microserviceVersions.submitPull(); + MicroserviceVersionRule versionRule = microserviceVersions.getOrCreateMicroserviceVersionRule("0+"); + Assert.assertSame(versionRule.getInstances().entrySet().size(), 1); + } + + @Test public void pullInstancesCancel() { new MockUp<RegistryUtils>() { @Mock diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestSimpleMicroserviceInstancePing.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestSimpleMicroserviceInstancePing.java new file mode 100644 index 0000000..f4403d8 --- /dev/null +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestSimpleMicroserviceInstancePing.java @@ -0,0 +1,46 @@ +/* + * 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 org.apache.servicecomb.serviceregistry.consumer; + +import java.io.IOException; +import java.net.ServerSocket; +import java.util.ArrayList; +import java.util.List; + +import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; +import org.junit.Assert; +import org.junit.Test; + +public class TestSimpleMicroserviceInstancePing { + @Test + public void testPing() throws IOException { + SimpleMicroserviceInstancePing ping = new SimpleMicroserviceInstancePing(); + Assert.assertEquals(ping.getOrder(), 100); + MicroserviceInstance instance = new MicroserviceInstance(); + List<String> endpoints = new ArrayList<>(); + ServerSocket ss = new ServerSocket(35677); + + endpoints.add("http://localhost:35677"); + instance.setEndpoints(endpoints); + Assert.assertTrue(ping.ping(instance)); + MicroserviceInstance instance2 = new MicroserviceInstance(); + Assert.assertFalse(ping.ping(instance2)); + ss.close(); + Assert.assertFalse(ping.ping(instance)); + } +} diff --git a/spring-boot-starter/spring-boot-starter-transport/src/test/java/org/apache/servicecomb/springboot/starter/transport/TestRestServletInitializer.java b/spring-boot-starter/spring-boot-starter-transport/src/test/java/org/apache/servicecomb/springboot/starter/transport/TestRestServletInitializer.java index 8952d2b..bb26648 100644 --- a/spring-boot-starter/spring-boot-starter-transport/src/test/java/org/apache/servicecomb/springboot/starter/transport/TestRestServletInitializer.java +++ b/spring-boot-starter/spring-boot-starter-transport/src/test/java/org/apache/servicecomb/springboot/starter/transport/TestRestServletInitializer.java @@ -51,7 +51,7 @@ public class TestRestServletInitializer { private static final String LISTEN_ADDRESS = "127.0.0.1"; - private static final int TEST_PORT = 8080; + private static final int TEST_PORT = 8582; @BeforeClass public static void beforeClass() { -- To stop receiving notification emails like this one, please contact liu...@apache.org.