[SCB-2386] Optimiza AZ affinity logic (#2721)

diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/AddressManager.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/AddressManager.java
index b939657..1f4b24c 100644
--- a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/AddressManager.java
+++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/AddressManager.java
@@ -20,6 +20,7 @@
 import java.util.List;
 
 import org.apache.servicecomb.http.client.common.AbstractAddressManager;
+import org.apache.servicecomb.http.client.common.URLEndPoint;
 import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
 
 import com.google.common.eventbus.EventBus;
@@ -33,7 +34,8 @@
   }
 
   @Override
-  public String joinProject(String address) {
+  protected String normalizeUri(String endpoint) {
+    String address = new URLEndPoint(endpoint).toString();
     return formatAddress(address);
   }
 
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/AbstractAddressManager.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/AbstractAddressManager.java
index f8fb59a..61ee576 100644
--- a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/AbstractAddressManager.java
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/AbstractAddressManager.java
@@ -90,12 +90,13 @@
 
   public AbstractAddressManager(List<String> addresses) {
     this.addresses.addAll(addresses);
+    this.defaultAddress.addAll(addresses);
   }
 
   public AbstractAddressManager(String projectName, List<String> addresses) {
     this.projectName = StringUtils.isEmpty(projectName) ? DEFAULT_PROJECT : projectName;
     this.addresses = this.transformAddress(addresses);
-    this.defaultAddress = this.addresses;
+    this.defaultAddress.addAll(this.addresses);
   }
 
   @VisibleForTesting
@@ -154,7 +155,7 @@
   private String getAvailableZoneAddress() {
     List<String> addresses = getAvailableZoneIpPorts();
     if (!addresses.isEmpty()) {
-      return joinProject(getCurrentAddress(addresses));
+      return getCurrentAddress(addresses);
     }
     return getInitAddress();
   }
@@ -177,10 +178,6 @@
     }
   }
 
-  protected String joinProject(String address) {
-    return address;
-  }
-
   private List<String> getAvailableZoneIpPorts() {
     List<String> results = new ArrayList<>();
     if (!availableZone.isEmpty()) {
@@ -214,11 +211,11 @@
   }
 
   public void recordFailState(String address) {
-    if (!recodeStatus.containsKey(address)) {
-      recodeStatus.put(address, 1);
-      return;
-    }
     synchronized (lock) {
+      if (!recodeStatus.containsKey(address)) {
+        recodeStatus.put(address, 1);
+        return;
+      }
       int number = recodeStatus.get(address) + 1;
       if (number < ISOLATION_THRESHOLD) {
         recodeStatus.put(address, number);
@@ -251,7 +248,7 @@
     }
   }
 
-  private boolean telnetTest(String address) {
+  protected boolean telnetTest(String address) {
     URI ipPort = parseIpPortFromURI(address);
     try (Socket s = new Socket()) {
       s.connect(new InetSocketAddress(ipPort.getHost(), ipPort.getPort()), 3000);
diff --git a/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/AbstractAddressManagerTest.java b/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/AbstractAddressManagerTest.java
index 3bfa3bc..d2005a5 100644
--- a/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/AbstractAddressManagerTest.java
+++ b/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/AbstractAddressManagerTest.java
@@ -298,7 +298,7 @@
   }
 
   @Test
-  void normalizeUri() {
+  public void normalizeIPV4Test() {
     String uri = addressManager1.normalizeUri("rest://127.0.0.1:30100?sslEnabled=true");
     Assert.assertEquals("https://127.0.0.1:30100", uri);
 
@@ -308,4 +308,13 @@
     uri = addressManager1.normalizeUri("rest://127.0.0.1:30100");
     Assert.assertEquals("http://127.0.0.1:30100", uri);
   }
+
+  @Test
+  public void normalizeIPV6Test() {
+    String uri = addressManager1.normalizeUri("rest://[2008::7:957f:b2d6:1af4:a1f8]:30100?sslEnabled=true");
+    Assert.assertEquals("https://[2008::7:957f:b2d6:1af4:a1f8]:30100", uri);
+
+    uri = addressManager1.normalizeUri("rest://[2008::7:957f:b2d6:1af4:a1f8]:30100");
+    Assert.assertEquals("http://[2008::7:957f:b2d6:1af4:a1f8]:30100", uri);
+  }
 }
\ No newline at end of file
diff --git a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/ConfigCenterConfigurationSourceImplTest.java b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/ConfigCenterConfigurationSourceImplTest.java
index c53d41d..40dbec8 100644
--- a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/ConfigCenterConfigurationSourceImplTest.java
+++ b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/ConfigCenterConfigurationSourceImplTest.java
@@ -19,17 +19,22 @@
 
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.servicecomb.config.center.client.AddressManager;
 import org.apache.servicecomb.foundation.common.event.EventManager;
+import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
 import org.junit.Assert;
 import org.junit.jupiter.api.Test;
 
+import mockit.Deencapsulation;
+
 class ConfigCenterConfigurationSourceImplTest {
 
   @Test
-  void configKieAddressManagerTest() {
+  void configAddressManagerTest() {
     List<String> addresses = new ArrayList<>();
     addresses.add("http://127.0.0.1:30103");
     addresses.add("http://127.0.0.2:30103");
@@ -37,12 +42,29 @@
     Assert.assertNotNull(addressManager);
 
     String address = addressManager.address();
-    Assert.assertEquals("http://127.0.0.2:30103/v3/test",address);
+    Assert.assertEquals("http://127.0.0.2:30103/v3/test", address);
     address = addressManager.address();
-    Assert.assertEquals("http://127.0.0.1:30103/v3/test",address);
+    Assert.assertEquals("http://127.0.0.1:30103/v3/test", address);
 
     addressManager = new AddressManager(null, addresses, EventManager.getEventBus());
     address = addressManager.address();
-    Assert.assertEquals("http://127.0.0.2:30103/v3/default",address);
+    Assert.assertEquals("http://127.0.0.2:30103/v3/default", address);
+  }
+
+  @Test
+  void onRefreshEndpointEventTest() {
+    List<String> addresses = new ArrayList<>();
+    addresses.add("http://127.0.0.1:30103");
+    List<String> addressAZ = new ArrayList<>();
+    addressAZ.add("rest://127.0.0.1:30100?sslEnabled=true");
+    Map<String, List<String>> zoneAndRegion = new HashMap<>();
+    zoneAndRegion.put("sameZone", addressAZ);
+    zoneAndRegion.put("sameRegion", new ArrayList<>());
+    RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "CseConfigCenter");
+    AddressManager addressManager = new AddressManager("test", addresses, EventManager.getEventBus());
+    addressManager.onRefreshEndpointEvent(event);
+
+    List<String> availableAZ = Deencapsulation.getField(addressManager, "availableZone");
+    Assert.assertEquals("https://127.0.0.1:30100/v3/test", availableAZ.get(0));
   }
 }
\ No newline at end of file
diff --git a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/center/client/AddressManagerTest.java b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/center/client/AddressManagerTest.java
index a0c4228..cda67d3 100644
--- a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/center/client/AddressManagerTest.java
+++ b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/center/client/AddressManagerTest.java
@@ -70,9 +70,11 @@
     addressManager1.refreshEndpoint(event, "CseConfigCenter");
 
     List<String> availableZone = Deencapsulation.getField(addressManager1, "availableZone");
-    Assert.assertEquals("http://127.0.0.3:30100", availableZone.get(0));
+    Assert.assertEquals("http://127.0.0.3:30100/v3/project", availableZone.get(0));
 
     List<String> availableRegion = Deencapsulation.getField(addressManager1, "availableRegion");
-    Assert.assertEquals("http://127.0.0.4:30100", availableRegion.get(0));
+    Assert.assertEquals("http://127.0.0.4:30100/v3/project", availableRegion.get(0));
+
+    Assert.assertEquals("http://127.0.0.3:30100/v3/project", addressManager1.address());
   }
 }
\ No newline at end of file
diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
index 2afec72..4e5b3a8 100644
--- a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
+++ b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
@@ -95,6 +95,8 @@
 
   private boolean registryAutoDiscovery;
 
+  private boolean registryAutoRefresh;
+
   private int resendHeartBeatTimes;
 
   private boolean alwaysOverrideSchema;
@@ -281,6 +283,15 @@
     return this;
   }
 
+  public boolean isRegistryAutoRefresh() {
+    return registryAutoRefresh;
+  }
+
+  public ServiceRegistryConfig setRegistryAutoRefresh(boolean registryAutoRefresh) {
+    this.registryAutoRefresh = registryAutoRefresh;
+    return this;
+  }
+
   public int getResendHeartBeatTimes() {
     return resendHeartBeatTimes;
   }
diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfigBuilder.java b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfigBuilder.java
index e996c43..1ebb721 100644
--- a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfigBuilder.java
+++ b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfigBuilder.java
@@ -62,6 +62,7 @@
         .setHeartbeatInterval(getHeartbeatInterval())
         .setInstancePullInterval(getInstancePullInterval())
         .setRegistryAutoDiscovery(isRegistryAutoDiscovery())
+        .setRegistryAutoRefresh(isRegistryAutoRefresh())
         .setResendHeartBeatTimes(getResendHeartBeatTimes())
         .setAlwaysOverrideSchema(isAlwaysOverrideSchema())
         .setIgnoreSwaggerDifference(isIgnoreSwaggerDifference())
@@ -153,9 +154,9 @@
   public int getIdleWatchTimeout() {
     // watch idle timeout based on SC PING/PONG interval. SC default value is 30.
     DynamicIntProperty property =
-            DynamicPropertyFactory.getInstance()
-                    .getIntProperty("servicecomb.service.registry.client.timeout.watch",
-                            ServiceRegistryConfig.DEFAULT_TIMEOUT_IN_SECONDS * 2);
+        DynamicPropertyFactory.getInstance()
+            .getIntProperty("servicecomb.service.registry.client.timeout.watch",
+                ServiceRegistryConfig.DEFAULT_TIMEOUT_IN_SECONDS * 2);
     int timeout = property.get();
     return timeout < 1 ? ServiceRegistryConfig.DEFAULT_TIMEOUT_IN_SECONDS * 2 : timeout;
   }
@@ -205,6 +206,14 @@
     return property.get();
   }
 
+  public boolean isRegistryAutoRefresh() {
+    DynamicBooleanProperty property =
+        DynamicPropertyFactory.getInstance()
+            .getBooleanProperty("servicecomb.service.registry.autoRefresh",
+                false);
+    return property.get();
+  }
+
   public int getResendHeartBeatTimes() {
     DynamicIntProperty property =
         DynamicPropertyFactory.getInstance()
diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/refresh/AddressManager.java b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/refresh/AddressManager.java
index fd1ce16..8851c95 100644
--- a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/refresh/AddressManager.java
+++ b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/refresh/AddressManager.java
@@ -17,6 +17,9 @@
 
 package org.apache.servicecomb.serviceregistry.refresh;
 
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
 import java.util.List;
 
 import org.apache.commons.lang3.StringUtils;
@@ -24,11 +27,14 @@
 import org.apache.servicecomb.foundation.common.net.URIEndpointObject;
 import org.apache.servicecomb.http.client.common.AbstractAddressManager;
 import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.eventbus.EventBus;
 import com.google.common.eventbus.Subscribe;
 
 public class AddressManager extends AbstractAddressManager {
+  private static final Logger LOGGER = LoggerFactory.getLogger(AddressManager.class);
 
   private static final String URI_SPLIT = ":";
 
@@ -46,6 +52,18 @@
     return new URIEndpointObject(endpoint).toString();
   }
 
+  @Override
+  protected boolean telnetTest(String address) {
+    IpPort ipPort = transformIpPort(address);
+    try (Socket s = new Socket()) {
+      s.connect(new InetSocketAddress(ipPort.getHostOrIp(), ipPort.getPort()), 3000);
+      return true;
+    } catch (IOException e) {
+      LOGGER.warn("ping endpoint {} failed, It will be quarantined again.", address);
+    }
+    return false;
+  }
+
   private IpPort transformIpPort(String address) {
     String[] result = StringUtils.split(address, URI_SPLIT);
     return new IpPort(result[0], Integer.valueOf(result[1]));
diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/refresh/ClassificationAddress.java b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/refresh/ClassificationAddress.java
index 80af0f7..1b7666f 100644
--- a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/refresh/ClassificationAddress.java
+++ b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/refresh/ClassificationAddress.java
@@ -59,6 +59,8 @@
 
   private String defaultTransport = "rest";
 
+  private boolean isAutoRefresh;
+
   private DataCenterInfo dataCenterInfo;
 
   InstanceCacheManager instanceCacheManager;
@@ -70,6 +72,7 @@
   public ClassificationAddress(ServiceRegistryConfig serviceRegistryConfig, InstanceCacheManager instanceCacheManager) {
     this.defaultTransport = serviceRegistryConfig.getTransport();
     this.defaultIpPort = serviceRegistryConfig.getIpPort();
+    this.isAutoRefresh = serviceRegistryConfig.isRegistryAutoRefresh();
     this.instanceCacheManager = instanceCacheManager;
     this.maxRetryTimes = defaultIpPort.size();
     ServiceCenterEventBus.getEventBus().register(this);
@@ -85,6 +88,11 @@
 
   @Subscribe
   public void onMicroserviceCacheRefreshed(MicroserviceCacheRefreshedEvent event) {
+    //if isAutoRefresh is false, it will not be refresh.
+    if (!isAutoRefresh) {
+      return;
+    }
+
     List<MicroserviceCache> microserviceCaches = event.getMicroserviceCaches();
     if (null == microserviceCaches || microserviceCaches.isEmpty()) {
       return;