This is an automated email from the ASF dual-hosted git repository.

youling1128 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git


The following commit(s) were added to refs/heads/master by this push:
     new 9b7f8e6039 [#5013] Fixing the issue where microservices cannot be 
registered when enabling RBAC authentication in a dual-engine disaster recovery 
scenario. (#5019)
9b7f8e6039 is described below

commit 9b7f8e60390043c5b8888272ef2560ef4316b51e
Author: Alex <[email protected]>
AuthorDate: Mon Nov 24 15:27:17 2025 +0800

    [#5013] Fixing the issue where microservices cannot be registered when 
enabling RBAC authentication in a dual-engine disaster recovery scenario. 
(#5019)
---
 .../center/client/ConfigCenterAddressManager.java  |  5 +-
 .../config/center/client/ConfigCenterClient.java   | 19 ++++-
 .../servicecomb/config/kie/client/KieClient.java   | 19 ++++-
 .../config/kie/client/model/KieAddressManager.java |  4 +-
 .../kie/client/model/KieAddressManagerTest.java    |  4 +-
 .../dashboard/client/DashboardAddressManager.java  |  4 +-
 .../dashboard/client/AddressManagerTest.java       |  4 +-
 .../http/client/common/AbstractAddressManager.java | 86 +++++++++++++++++++--
 .../http/client/common/HttpTransportImpl.java      | 19 ++++-
 .../http/client/event}/OperationEvents.java        | 10 ++-
 .../client/common/AbstractAddressManagerTest.java  | 33 ++++++--
 .../center/client/ServiceCenterAddressManager.java |  5 +-
 .../service/center/client/ServiceCenterClient.java | 36 +--------
 .../center/client/ServiceCenterOperation.java      |  2 +-
 .../center/client/ServiceCenterRawClient.java      | 50 +++++++++----
 .../center/client/ServiceCenterRegistration.java   |  2 +-
 .../service/center/client/ServiceCenterWatch.java  | 15 +++-
 .../client/ServiceCenterAddressManagerTest.java    |  6 +-
 .../center/client/ServiceCenterClientTest.java     |  2 +-
 .../center/client/ServiceCenterRawClientTest.java  |  3 +-
 .../RegistryClientTest.java                        |  4 +-
 .../cc/ConfigCenterDynamicPropertiesSource.java    | 12 +--
 .../config/cc/ConfigCenterAddressManagerTest.java  |  6 +-
 .../ConfigCenterConfigurationSourceImplTest.java   |  8 +-
 .../config/kie/KieDynamicPropertiesSource.java     | 11 ++-
 .../foundation/auth/AuthHeaderProvider.java        | 14 +++-
 .../monitor/DefaultMonitorDataPublisher.java       |  7 +-
 .../servicestage/RBACBootStrapService.java         |  7 +-
 .../servicestage/TokenAuthHeaderProvider.java      |  4 +-
 .../servicestage/TokenCacheManager.java            | 87 ++++++++++------------
 .../servicecomb/registry/sc/SCAddressManager.java  | 35 +++++----
 .../servicecomb/registry/sc/SCClientUtils.java     | 62 +++++++++++++--
 32 files changed, 402 insertions(+), 183 deletions(-)

diff --git 
a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterAddressManager.java
 
b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterAddressManager.java
index 3b346153a0..977c84ef63 100644
--- 
a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterAddressManager.java
+++ 
b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterAddressManager.java
@@ -28,8 +28,9 @@ import com.google.common.eventbus.Subscribe;
 
 public class ConfigCenterAddressManager extends AbstractAddressManager {
 
-  public ConfigCenterAddressManager(String projectName, List<String> 
addresses, EventBus eventBus) {
-    super(projectName, addresses);
+  public ConfigCenterAddressManager(String projectName, List<String> 
addresses, EventBus eventBus, String region,
+      String availableZone) {
+    super(projectName, addresses, region, availableZone);
     eventBus.register(this);
   }
 
diff --git 
a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterClient.java
 
b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterClient.java
index 66d9d154fd..8ed31a5a61 100644
--- 
a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterClient.java
+++ 
b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterClient.java
@@ -32,6 +32,7 @@ import org.apache.servicecomb.http.client.common.HttpRequest;
 import org.apache.servicecomb.http.client.common.HttpResponse;
 import org.apache.servicecomb.http.client.common.HttpTransport;
 import org.apache.servicecomb.http.client.common.HttpUtils;
+import 
org.apache.servicecomb.http.client.event.OperationEvents.UnAuthorizedOperationEvent;
 import 
org.apache.servicecomb.http.client.utils.ServiceCombServiceAvailableUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -61,12 +62,15 @@ public class ConfigCenterClient implements 
ConfigCenterOperation {
 
   private final Map<String, List<String>> dimensionConfigNames = new 
HashMap<>();
 
+  private EventBus eventBus;
+
   public ConfigCenterClient(ConfigCenterAddressManager addressManager, 
HttpTransport httpTransport) {
     this.addressManager = addressManager;
     this.httpTransport = httpTransport;
   }
 
   public void setEventBus(EventBus eventBus) {
+    this.eventBus = eventBus;
     addressManager.setEventBus(eventBus);
   }
 
@@ -88,6 +92,7 @@ public class ConfigCenterClient implements 
ConfigCenterOperation {
           HttpRequest.GET);
 
       HttpResponse httpResponse = httpTransport.doRequest(httpRequest);
+      recordAndSendUnAuthorizedEvent(httpResponse, address);
       if (httpResponse.getStatusCode() == HttpStatus.SC_OK) {
         Map<String, Map<String, Object>> allConfigMap = HttpUtils.deserialize(
             httpResponse.getContent(),
@@ -121,21 +126,17 @@ public class ConfigCenterClient implements 
ConfigCenterOperation {
         }
         queryConfigurationsResponse.setConfigurations(configurations);
         queryConfigurationsResponse.setChanged(true);
-        addressManager.recordSuccessState(address);
         return queryConfigurationsResponse;
       } else if (httpResponse.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
         queryConfigurationsResponse.setChanged(false);
-        addressManager.recordSuccessState(address);
         return queryConfigurationsResponse;
       } else if (httpResponse.getStatusCode() == 
HttpStatus.SC_TOO_MANY_REQUESTS) {
         LOGGER.warn("rate limited, keep the local dimension [{}] configs 
unchanged.", dimensionsInfo);
         queryConfigurationsResponse.setChanged(false);
-        addressManager.recordSuccessState(address);
         return queryConfigurationsResponse;
       } else if (httpResponse.getStatusCode() == HttpStatus.SC_BAD_REQUEST) {
         throw new OperationException("Bad request for query configurations.");
       } else {
-        addressManager.recordFailState(address);
         throw new OperationException(
             "read response failed. status:"
                 + httpResponse.getStatusCode()
@@ -151,6 +152,16 @@ public class ConfigCenterClient implements 
ConfigCenterOperation {
     }
   }
 
+  private void recordAndSendUnAuthorizedEvent(HttpResponse response, String 
address) {
+    if (this.eventBus != null && response.getStatusCode() == 
HttpStatus.SC_UNAUTHORIZED) {
+      LOGGER.warn("query configuration unauthorized from server [{}], message 
[{}]", address, response.getMessage());
+      addressManager.recordFailState(address);
+      this.eventBus.post(new UnAuthorizedOperationEvent(address));
+    } else {
+      addressManager.recordSuccessState(address);
+    }
+  }
+
   /**
    * Only the name of the new configuration item is printed.
    * No log is printed when the configuration content is updated.
diff --git 
a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieClient.java
 
b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieClient.java
index 2ab9325479..b98a7d3b2a 100644
--- 
a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieClient.java
+++ 
b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieClient.java
@@ -46,6 +46,7 @@ import org.apache.servicecomb.http.client.common.HttpRequest;
 import org.apache.servicecomb.http.client.common.HttpResponse;
 import org.apache.servicecomb.http.client.common.HttpTransport;
 import org.apache.servicecomb.http.client.common.HttpUtils;
+import 
org.apache.servicecomb.http.client.event.OperationEvents.UnAuthorizedOperationEvent;
 import 
org.apache.servicecomb.http.client.utils.ServiceCombServiceAvailableUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -71,6 +72,8 @@ public class KieClient implements KieConfigOperation {
 
   private final Map<String, List<String>> dimensionConfigNames = new 
HashMap<>();
 
+  private EventBus eventBus;
+
   public KieClient(KieAddressManager addressManager, HttpTransport 
httpTransport, KieConfiguration kieConfiguration) {
     this.httpTransport = httpTransport;
     this.addressManager = addressManager;
@@ -78,6 +81,7 @@ public class KieClient implements KieConfigOperation {
   }
 
   public void setEventBus(EventBus eventBus) {
+    this.eventBus = eventBus;
     addressManager.setEventBus(eventBus);
   }
 
@@ -91,6 +95,7 @@ public class KieClient implements KieConfigOperation {
 
       HttpRequest httpRequest = new HttpRequest(url, null, null, 
HttpRequest.GET);
       HttpResponse httpResponse = httpTransport.doRequest(httpRequest);
+      recordAndSendUnAuthorizedEvent(httpResponse, address);
       ConfigurationsResponse configurationsResponse = new 
ConfigurationsResponse();
       if (httpResponse.getStatusCode() == HttpStatus.SC_OK) {
         revision = httpResponse.getHeader("X-Kie-Revision");
@@ -100,7 +105,6 @@ public class KieClient implements KieConfigOperation {
         configurationsResponse.setConfigurations(configurations);
         configurationsResponse.setChanged(true);
         configurationsResponse.setRevision(revision);
-        addressManager.recordSuccessState(address);
         return configurationsResponse;
       }
       if (httpResponse.getStatusCode() == HttpStatus.SC_BAD_REQUEST) {
@@ -108,16 +112,13 @@ public class KieClient implements KieConfigOperation {
       }
       if (httpResponse.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
         configurationsResponse.setChanged(false);
-        addressManager.recordSuccessState(address);
         return configurationsResponse;
       }
       if (httpResponse.getStatusCode() == HttpStatus.SC_TOO_MANY_REQUESTS) {
         LOGGER.warn("rate limited, keep the local dimension [{}] configs 
unchanged.", request.getLabelsQuery());
         configurationsResponse.setChanged(false);
-        addressManager.recordSuccessState(address);
         return configurationsResponse;
       }
-      addressManager.recordFailState(address);
       throw new OperationException(
           "read response failed. status:" + httpResponse.getStatusCode() + "; 
message:" +
               httpResponse.getMessage() + "; content:" + 
httpResponse.getContent());
@@ -128,6 +129,16 @@ public class KieClient implements KieConfigOperation {
     }
   }
 
+  private void recordAndSendUnAuthorizedEvent(HttpResponse response, String 
address) {
+    if (this.eventBus != null && response.getStatusCode() == 
HttpStatus.SC_UNAUTHORIZED) {
+      LOGGER.warn("query configuration unauthorized from server [{}], message 
[{}]", address, response.getMessage());
+      addressManager.recordFailState(address);
+      this.eventBus.post(new UnAuthorizedOperationEvent(address));
+    } else {
+      addressManager.recordSuccessState(address);
+    }
+  }
+
   /**
    * Only the name of the new configuration item is printed.
    * No log is printed when the configuration content is updated.
diff --git 
a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieAddressManager.java
 
b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieAddressManager.java
index 0742c11fb1..d8c069ee9b 100644
--- 
a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieAddressManager.java
+++ 
b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieAddressManager.java
@@ -27,8 +27,8 @@ import com.google.common.eventbus.Subscribe;
 
 public class KieAddressManager extends AbstractAddressManager {
 
-  public KieAddressManager(List<String> addresses, EventBus eventBus) {
-    super(addresses);
+  public KieAddressManager(List<String> addresses, EventBus eventBus, String 
region, String availableZone) {
+    super(addresses, region, availableZone);
     eventBus.register(this);
   }
 
diff --git 
a/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/KieAddressManagerTest.java
 
b/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/KieAddressManagerTest.java
index 6533fc60e5..c8bf1f57a2 100644
--- 
a/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/KieAddressManagerTest.java
+++ 
b/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/KieAddressManagerTest.java
@@ -40,7 +40,7 @@ class KieAddressManagerTest {
   public void kieAddressManagerTest() throws NoSuchFieldException, 
IllegalAccessException {
     addresses.add("http://127.0.0.1:30103";);
     addresses.add("https://127.0.0.2:30103";);
-    addressManager1 = new KieAddressManager(addresses, new EventBus());
+    addressManager1 = new KieAddressManager(addresses, new EventBus(), "", "");
     Field addressManagerField = 
addressManager1.getClass().getSuperclass().getDeclaredField("index");
     addressManagerField.setAccessible(true);
     addressManagerField.set(addressManager1, 0);
@@ -64,7 +64,7 @@ class KieAddressManagerTest {
     Map<String, List<String>> zoneAndRegion = new HashMap<>();
     zoneAndRegion.put("sameZone", addressAZ);
     zoneAndRegion.put("sameRegion", addressRG);
-    addressManager1 = new KieAddressManager(addresses, new EventBus());
+    addressManager1 = new KieAddressManager(addresses, new EventBus(), "", "");
     RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, 
"KIE");
     addressManager1.refreshEndpoint(event, "KIE");
 
diff --git 
a/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardAddressManager.java
 
b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardAddressManager.java
index 9dd8c6a344..6897e02acd 100644
--- 
a/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardAddressManager.java
+++ 
b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardAddressManager.java
@@ -29,8 +29,8 @@ import com.google.common.eventbus.Subscribe;
 
 public class DashboardAddressManager extends AbstractAddressManager {
 
-  public DashboardAddressManager(List<String> addresses, EventBus eventBus) {
-    super(addresses);
+  public DashboardAddressManager(List<String> addresses, EventBus eventBus, 
String region, String availableZone) {
+    super(addresses, region, availableZone);
     eventBus.register(this);
   }
 
diff --git 
a/clients/dashboard-client/src/test/java/org/apache/servicecomb/dashboard/client/AddressManagerTest.java
 
b/clients/dashboard-client/src/test/java/org/apache/servicecomb/dashboard/client/AddressManagerTest.java
index 71e5deedaf..fdb7a23922 100644
--- 
a/clients/dashboard-client/src/test/java/org/apache/servicecomb/dashboard/client/AddressManagerTest.java
+++ 
b/clients/dashboard-client/src/test/java/org/apache/servicecomb/dashboard/client/AddressManagerTest.java
@@ -39,7 +39,7 @@ class AddressManagerTest {
   public void kieAddressManagerTest() throws IllegalAccessException, 
NoSuchFieldException {
     addresses.add("http://127.0.0.1:30103";);
     addresses.add("https://127.0.0.2:30103";);
-    addressManager1 = new DashboardAddressManager(addresses, new EventBus());
+    addressManager1 = new DashboardAddressManager(addresses, new EventBus(), 
"", "");
     Field addressManagerField = 
addressManager1.getClass().getSuperclass().getDeclaredField("index");
     addressManagerField.setAccessible(true);
     addressManagerField.set(addressManager1, 0);
@@ -63,7 +63,7 @@ class AddressManagerTest {
     Map<String, List<String>> zoneAndRegion = new HashMap<>();
     zoneAndRegion.put("sameZone", addressAZ);
     zoneAndRegion.put("sameRegion", addressRG);
-    addressManager1 = new DashboardAddressManager(addresses, new EventBus());
+    addressManager1 = new DashboardAddressManager(addresses, new EventBus(), 
"", "");
     RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, 
"CseMonitoring");
     addressManager1.refreshEndpoint(event, "CseMonitoring");
 
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 52db799f90..3c5d6214be 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
@@ -17,6 +17,7 @@
 
 package org.apache.servicecomb.http.client.common;
 
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -29,6 +30,7 @@ import 
org.apache.servicecomb.http.client.event.EngineConnectChangedEvent;
 import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.util.CollectionUtils;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.eventbus.EventBus;
@@ -42,6 +44,10 @@ public class AbstractAddressManager {
 
   private static final String V3_PREFIX = "/v3/";
 
+  private static final String ZONE = "availableZone";
+
+  private static final String REGION = "region";
+
   private static final int ISOLATION_THRESHOLD = 3;
 
   private volatile List<String> addresses = new ArrayList<>();
@@ -74,17 +80,63 @@ public class AbstractAddressManager {
 
   private EventBus eventBus;
 
-  public AbstractAddressManager(List<String> addresses) {
+  public AbstractAddressManager(List<String> addresses, String ownRegion, 
String ownAvailableZone) {
     this.projectName = DEFAULT_PROJECT;
-    this.addresses.addAll(addresses);
-    this.defaultAddress.addAll(addresses);
+    parseAndInitAddresses(addresses, ownRegion, ownAvailableZone, false);
     this.index = !addresses.isEmpty() ? getRandomIndex() : 0;
   }
 
-  public AbstractAddressManager(String projectName, List<String> addresses) {
+  /**
+   * address support config with region/availableZone info, to enable engine 
affinity calls during startup
+   * address may be like:
+   *   https://192.168.20.13:30110?region=region1&availableZone=az
+   *   https://192.168.20.13:30100?region=region1&availableZone=az
+   * When address have no datacenter information, roundRobin using address
+   *
+   * @param addresses engine addresses
+   * @param ownRegion microservice region
+   * @param ownAvailableZone microservice zone
+   * @param isFormat is need format
+   */
+  private void parseAndInitAddresses(List<String> addresses, String ownRegion, 
String ownAvailableZone,
+      boolean isFormat) {
+    if (CollectionUtils.isEmpty(addresses)) {
+      return;
+    }
+    List<String> tempList = new ArrayList<>();
+    addressAutoRefreshed = addresses.stream().anyMatch(addr -> 
addr.contains(ZONE) || addr.contains(REGION));
+    for (String address : addresses) {
+      // Compatible IpPortManager init address is 127.0.0.1:30100
+      if (!address.startsWith("http")) {
+        tempList.add(address);
+        continue;
+      }
+      URLEndPoint endpoint = new URLEndPoint(address);
+      tempList.add(endpoint.toString());
+      buildAffinityAddress(endpoint, ownRegion, ownAvailableZone);
+    }
+    this.addresses.addAll(isFormat ? this.transformAddress(tempList) : 
tempList);
+    this.defaultAddress.addAll(isFormat ? this.transformAddress(tempList) : 
tempList);
+  }
+
+  private void buildAffinityAddress(URLEndPoint endpoint, String ownRegion, 
String ownAvailableZone) {
+    if (addressAutoRefreshed) {
+      if (regionAndAZMatch(ownRegion, ownAvailableZone, 
endpoint.getFirst(REGION), endpoint.getFirst(ZONE))) {
+        availableZone.add(endpoint.toString());
+      } else {
+        availableRegion.add(endpoint.toString());
+      }
+    }
+  }
+
+  private boolean regionAndAZMatch(String ownRegion, String ownAvailableZone, 
String engineRegion,
+      String engineAvailableZone) {
+    return ownRegion.equalsIgnoreCase(engineRegion) && 
ownAvailableZone.equals(engineAvailableZone);
+  }
+
+  public AbstractAddressManager(String projectName, List<String> addresses, 
String ownRegion, String ownAvailableZone) {
     this.projectName = StringUtils.isEmpty(projectName) ? DEFAULT_PROJECT : 
projectName;
-    this.addresses = this.transformAddress(addresses);
-    this.defaultAddress.addAll(addresses);
+    parseAndInitAddresses(addresses, ownRegion, ownAvailableZone, true);
     this.index = !addresses.isEmpty() ? getRandomIndex() : 0;
   }
 
@@ -271,4 +323,26 @@ public class AbstractAddressManager {
     isolationAddresses.addAll(isolationRegionAddress);
     return isolationAddresses;
   }
+
+  public String compareAndGetAddress(String host) {
+    for (String address : defaultAddress) {
+      if (isAddressHostSame(address, host)) {
+        return address;
+      }
+    }
+    return "";
+  }
+
+  private boolean isAddressHostSame(String address, String host) {
+    if (StringUtils.isEmpty(host)) {
+      return false;
+    }
+    try {
+      URI uri = new URI(address);
+      return host.equals(uri.getHost());
+    } catch (Exception e) {
+      LOGGER.warn("Exception occurred while constructing URI using the address 
[{}]", address);
+    }
+    return false;
+  }
 }
diff --git 
a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportImpl.java
 
b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportImpl.java
index da87892929..507d8d1c55 100644
--- 
a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportImpl.java
+++ 
b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportImpl.java
@@ -18,17 +18,21 @@
 package org.apache.servicecomb.http.client.common;
 
 import java.io.IOException;
+import java.net.URI;
 import java.util.Map;
 
 import org.apache.http.client.HttpClient;
 import org.apache.http.util.EntityUtils;
 import org.apache.servicecomb.foundation.auth.SignRequest;
 import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Created by   on 2019/10/16.
  */
 public class HttpTransportImpl implements HttpTransport {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(HttpTransportImpl.class);
 
   private static final String HEADER_CONTENT_TYPE = "Content-Type";
 
@@ -87,7 +91,7 @@ public class HttpTransportImpl implements HttpTransport {
       globalHeaders.forEach(httpRequest::addHeader);
     }
 
-    
httpRequest.getHeaders().putAll(requestAuthHeaderProvider.loadAuthHeader(createSignRequest()));
+    
httpRequest.getHeaders().putAll(requestAuthHeaderProvider.loadAuthHeader(createSignRequest(httpRequest.getUrl())));
 
     //get Http response
     org.apache.http.HttpResponse response = 
httpClient.execute(httpRequest.getRealRequest());
@@ -98,9 +102,16 @@ public class HttpTransportImpl implements HttpTransport {
         response.getAllHeaders());
   }
 
-  private static SignRequest createSignRequest() {
-    // Now the implementations do not process SignRequest, so return null. 
Maybe future will use it.
-    return null;
+  private static SignRequest createSignRequest(String url) {
+    try {
+      URI uri = URI.create(url);
+      SignRequest signRequest = new SignRequest();
+      signRequest.setEndpoint(uri);
+      return signRequest;
+    } catch (Exception e) {
+      LOGGER.error("create signRequest failed!", e);
+      return null;
+    }
   }
 
   @Override
diff --git 
a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/OperationEvents.java
 
b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/OperationEvents.java
similarity index 79%
rename from 
clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/OperationEvents.java
rename to 
clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/OperationEvents.java
index 62274519ea..69896f750e 100644
--- 
a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/OperationEvents.java
+++ 
b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/OperationEvents.java
@@ -15,10 +15,18 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.service.center.client;
+package org.apache.servicecomb.http.client.event;
 
 public abstract class OperationEvents {
   public static class UnAuthorizedOperationEvent extends OperationEvents {
+    private final String address;
 
+    public UnAuthorizedOperationEvent(String address) {
+      this.address = address;
+    }
+
+    public String getAddress() {
+      return address;
+    }
   }
 }
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 b831d03249..b14d6827cb 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
@@ -46,9 +46,9 @@ public class AbstractAddressManagerTest {
   public void setUp() throws NoSuchFieldException, IllegalAccessException {
     addresses.add("http://127.0.0.1:30103";);
     addresses.add("https://127.0.0.2:30103";);
-    addressManager1 = new AbstractAddressManager(addresses);
-    addressManager2 = new AbstractAddressManager("project", addresses);
-    addressManager3 = new AbstractAddressManager(null, addresses);
+    addressManager1 = new AbstractAddressManager(addresses, "", "");
+    addressManager2 = new AbstractAddressManager("project", addresses, "", "");
+    addressManager3 = new AbstractAddressManager(null, addresses, "", "");
     Field addressManagerField = 
addressManager1.getClass().getDeclaredField("index");
     addressManagerField.setAccessible(true);
     addressManagerField.set(addressManager1, 0);
@@ -88,7 +88,7 @@ public class AbstractAddressManagerTest {
     zoneAndRegion.put("sameZone", addressAZ);
     zoneAndRegion.put("sameRegion", addressRG);
     RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, 
"TEST");
-    AbstractAddressManager addressManager = new 
AbstractAddressManager(addresses) {};
+    AbstractAddressManager addressManager = new 
AbstractAddressManager(addresses, "", "") {};
 
     addressManager.refreshEndpoint(event, "TEST");
 
@@ -124,7 +124,7 @@ public class AbstractAddressManagerTest {
   @Test
   public void testMultipleThread() throws Exception {
 
-    AbstractAddressManager addressManager = new 
AbstractAddressManager(addresses);
+    AbstractAddressManager addressManager = new 
AbstractAddressManager(addresses, "", "");
     String address = "http://127.0.0.3:30100";;
 
     CountDownLatch latch = new CountDownLatch(2);
@@ -302,4 +302,27 @@ public class AbstractAddressManagerTest {
     uri = 
addressManager1.normalizeUri("rest://[2008::7:957f:b2d6:1af4:a1f8]:30100");
     Assertions.assertEquals("http://[2008::7:957f:b2d6:1af4:a1f8]:30100";, uri);
   }
+
+  @Test
+  public void compareAndGetAddressTest() {
+    List<String> testAddr = new ArrayList<>();
+    testAddr.add("https://192.168.20.160:30100";);
+    testAddr.add("https://127.0.0.1:30100";);
+    testAddr.add("https://127.0.0.3:30100";);
+    AbstractAddressManager manager = new AbstractAddressManager(testAddr, "", 
"");
+    
Assertions.assertTrue(manager.compareAndGetAddress("192.168.20.16").isEmpty());
+    Assertions.assertEquals("https://192.168.20.160:30100";, 
manager.compareAndGetAddress("192.168.20.160"));
+  }
+
+  @Test
+  public void AddressAffinityTest() {
+    List<String> testAddr = new ArrayList<>();
+    
testAddr.add("https://192.168.20.160:30100?region=region1&availableZone=zone1";);
+    testAddr.add("https://127.0.0.1:30100";);
+    AbstractAddressManager manager = new AbstractAddressManager(testAddr, 
"region1", "zone1");
+    Assertions.assertEquals("https://192.168.20.160:30100";, manager.address());
+
+    AbstractAddressManager manager2 = new AbstractAddressManager("default", 
testAddr, "region1", "zone1");
+    Assertions.assertEquals("https://192.168.20.160:30100";, 
manager2.address());
+  }
 }
diff --git 
a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManager.java
 
b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManager.java
index a5fd128ab1..b19db919e8 100644
--- 
a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManager.java
+++ 
b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManager.java
@@ -26,8 +26,9 @@ import com.google.common.eventbus.EventBus;
 import com.google.common.eventbus.Subscribe;
 
 public class ServiceCenterAddressManager extends AbstractAddressManager {
-  public ServiceCenterAddressManager(String projectName, List<String> 
addresses, EventBus eventBus) {
-    super(projectName, addresses);
+  public ServiceCenterAddressManager(String projectName, List<String> 
addresses, EventBus eventBus, String region,
+      String availableZone) {
+    super(projectName, addresses, region, availableZone);
     eventBus.register(this);
   }
 
diff --git 
a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterClient.java
 
b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterClient.java
index 407fb28ac9..97aeaa9931 100755
--- 
a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterClient.java
+++ 
b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterClient.java
@@ -33,7 +33,6 @@ import org.apache.servicecomb.http.client.common.HttpResponse;
 import org.apache.servicecomb.http.client.common.HttpTransport;
 import org.apache.servicecomb.http.client.common.HttpTransportFactory;
 import org.apache.servicecomb.http.client.common.HttpUtils;
-import 
org.apache.servicecomb.service.center.client.OperationEvents.UnAuthorizedOperationEvent;
 import 
org.apache.servicecomb.service.center.client.exception.OperationException;
 import 
org.apache.servicecomb.service.center.client.model.CreateMicroserviceInstanceRequest;
 import 
org.apache.servicecomb.service.center.client.model.CreateMicroserviceRequest;
@@ -76,8 +75,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
 
   private final ServiceCenterRawClient httpClient;
 
-  private EventBus eventBus;
-
   private final ServiceCenterAddressManager addressManager;
 
   public ServiceCenterClient(ServiceCenterRawClient httpClient, 
ServiceCenterAddressManager addressManager) {
@@ -86,8 +83,8 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
   }
 
   public ServiceCenterClient setEventBus(EventBus eventBus) {
-    this.eventBus = eventBus;
     addressManager.setEventBus(eventBus);
+    this.httpClient.setEventBus(eventBus);
     return this;
   }
 
@@ -126,7 +123,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
       if (response.getStatusCode() == HttpStatus.SC_OK) {
         return HttpUtils.deserialize(response.getContent(), 
MicroserviceInstancesResponse.class);
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "get service-center instances fails, statusCode = " + 
response.getStatusCode() + "; message = " + response
               .getMessage()
@@ -147,7 +143,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
       if (response.getStatusCode() == HttpStatus.SC_OK) {
         return HttpUtils.deserialize(response.getContent(), 
RegisteredMicroserviceResponse.class);
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "register service fails, statusCode = " + response.getStatusCode() + 
"; message = " + response
               .getMessage()
@@ -165,7 +160,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
       if (response.getStatusCode() == HttpStatus.SC_OK) {
         return HttpUtils.deserialize(response.getContent(), 
MicroservicesResponse.class);
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "get service List fails, statusCode = " + response.getStatusCode() + 
"; message = " + response
               .getMessage()
@@ -190,7 +184,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
       if (response.getStatusCode() == HttpStatus.SC_OK) {
         return HttpUtils.deserialize(response.getContent(), 
RegisteredMicroserviceResponse.class);
       }
-      sendUnAuthorizedEvent(response);
       LOGGER.info("Query serviceId fails, statusCode = " + 
response.getStatusCode() + "; message = " + response
           .getMessage()
           + "; content = " + response.getContent());
@@ -213,7 +206,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
             .deserialize(response.getContent(), MicroserviceResponse.class);
         return microserviceResponse.getService();
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "get service message fails, statusCode = " + 
response.getStatusCode() + "; message = " + response
               .getMessage()
@@ -235,7 +227,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
       if (response.getStatusCode() == HttpStatus.SC_OK) {
         return HttpUtils.deserialize(response.getContent(), 
RegisteredMicroserviceInstanceResponse.class);
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "register service instance fails, statusCode = " + 
response.getStatusCode() + "; message = " + response
               .getMessage()
@@ -276,7 +267,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
         result.setModified(false);
         return result;
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "get service instances list fails, statusCode = " + 
response.getStatusCode() + "; message = " + response
               .getMessage()
@@ -295,7 +285,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
       if (response.getStatusCode() == HttpStatus.SC_OK) {
         return HttpUtils.deserialize(response.getContent(), 
MicroserviceInstancesResponse.class);
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "get service instances list fails, statusCode = " + 
response.getStatusCode() + "; message = " + response
               .getMessage()
@@ -316,7 +305,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
             .deserialize(response.getContent(), 
MicroserviceInstanceResponse.class);
         return instanceResponse.getInstance();
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "get service instance message fails, statusCode = " + 
response.getStatusCode() + "; message = " + response
               .getMessage()
@@ -336,7 +324,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
         LOGGER.info("Delete service instance successfully.");
         return;
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "delete service instance fails, statusCode = " + 
response.getStatusCode() + "; message = " + response
               .getMessage()
@@ -356,7 +343,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
       if (response.getStatusCode() == HttpStatus.SC_OK) {
         return true;
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "update service instance status fails, statusCode = " + 
response.getStatusCode() + "; message = " + response
               .getMessage()
@@ -375,7 +361,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
       if (response.getStatusCode() == HttpStatus.SC_OK) {
         return;
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "heartbeats fails, statusCode = " + response.getStatusCode() + "; 
message = " + response.getMessage()
               + "; content = " + response.getContent());
@@ -395,7 +380,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
       if (response.getStatusCode() == HttpStatus.SC_OK) {
         return true;
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "heartbeats fails, statusCode = " + response.getStatusCode() + "; 
message = " + response.getMessage()
               + "; content = " + response.getContent());
@@ -420,7 +404,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
             .deserialize(response.getContent(), GetSchemaListResponse.class);
         return getSchemaResponse.getSchemas();
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "get service schemas list fails, statusCode = " + 
response.getStatusCode() + "; message = " + response
               .getMessage()
@@ -447,7 +430,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
         GetSchemaResponse getSchemaResponse = 
HttpUtils.deserialize(response.getContent(), GetSchemaResponse.class);
         return getSchemaResponse.getSchema();
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "get service schema context fails, statusCode = " + 
response.getStatusCode() + "; message = " + response
               .getMessage()
@@ -467,7 +449,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
       if (response.getStatusCode() == HttpStatus.SC_OK) {
         return true;
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "update service schema fails, statusCode = " + 
response.getStatusCode() + "; message = " + response
               .getMessage()
@@ -490,7 +471,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
       if (response.getStatusCode() == HttpStatus.SC_OK) {
         return true;
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "update service schema fails, statusCode = " + 
response.getStatusCode() + "; message = " + response
               .getMessage()
@@ -510,7 +490,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
       if (response.getStatusCode() == HttpStatus.SC_OK) {
         return true;
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
           "update service schema fails, statusCode = " + 
response.getStatusCode() + "; message = " + response
               .getMessage()
@@ -521,18 +500,12 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
     }
   }
 
-  private void sendUnAuthorizedEvent(HttpResponse response) {
-    if (this.eventBus != null && response.getStatusCode() == 
HttpStatus.SC_UNAUTHORIZED) {
-      this.eventBus.post(new UnAuthorizedOperationEvent());
-    }
-  }
-
   @Override
-  public RbacTokenResponse queryToken(RbacTokenRequest request) {
+  public RbacTokenResponse queryToken(RbacTokenRequest request, String host) {
     try {
+      String queryAddress = addressManager.compareAndGetAddress(host);
       HttpResponse response = httpClient
-          .postHttpRequestAbsoluteUrl("/v4/token", null,
-              HttpUtils.serialize(request));
+          .postHttpRequestAbsoluteUrl("/v4/token", null, 
HttpUtils.serialize(request), queryAddress);
       if (response.getStatusCode() == HttpStatus.SC_OK) {
         RbacTokenResponse result = 
HttpUtils.deserialize(response.getContent(), RbacTokenResponse.class);
         result.setStatusCode(HttpStatus.SC_OK);
@@ -573,7 +546,6 @@ public class ServiceCenterClient implements 
ServiceCenterOperation {
       if (response.getStatusCode() == HttpStatus.SC_OK) {
         return true;
       }
-      sendUnAuthorizedEvent(response);
       throw new OperationException(
               "update service properties fails, statusCode = " + 
response.getStatusCode() + "; message = " + response
                       .getMessage()
diff --git 
a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterOperation.java
 
b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterOperation.java
index c80e4933a0..fd39a4ce96 100644
--- 
a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterOperation.java
+++ 
b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterOperation.java
@@ -184,7 +184,7 @@ public interface ServiceCenterOperation {
    * @return if heartbeat is successful
    * @throws OperationException If some problems happened to contact service 
center or non http 200 returned.
    */
-  RbacTokenResponse queryToken(RbacTokenRequest request);
+  RbacTokenResponse queryToken(RbacTokenRequest request, String host);
 
   /**
    * Update properties of microservice
diff --git 
a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClient.java
 
b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClient.java
index a8dc9963b7..e233f15fb5 100755
--- 
a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClient.java
+++ 
b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClient.java
@@ -21,13 +21,18 @@ import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpStatus;
 import org.apache.servicecomb.http.client.common.HttpRequest;
 import org.apache.servicecomb.http.client.common.HttpResponse;
 import org.apache.servicecomb.http.client.common.HttpTransport;
+import 
org.apache.servicecomb.http.client.event.OperationEvents.UnAuthorizedOperationEvent;
 import 
org.apache.servicecomb.http.client.utils.ServiceCombServiceAvailableUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.eventbus.EventBus;
+
 public class ServiceCenterRawClient {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(ServiceCenterRawClient.class);
 
@@ -41,6 +46,8 @@ public class ServiceCenterRawClient {
 
   private final ServiceCenterAddressManager addressManager;
 
+  private EventBus eventBus;
+
   private ServiceCenterRawClient(String tenantName, HttpTransport 
httpTransport,
       ServiceCenterAddressManager addressManager) {
     this.httpTransport = httpTransport;
@@ -48,37 +55,40 @@ public class ServiceCenterRawClient {
     this.addressManager = addressManager;
   }
 
+  public void setEventBus(EventBus eventBus) {
+    this.eventBus = eventBus;
+  }
+
   public HttpResponse getHttpRequest(String url, Map<String, String> headers, 
String content) throws IOException {
-    return doHttpRequest(url, false, headers, content, HttpRequest.GET);
+    return doHttpRequest(url, false, headers, content, HttpRequest.GET, "");
   }
 
-  public HttpResponse postHttpRequestAbsoluteUrl(String url, Map<String, 
String> headers, String content)
-      throws IOException {
-    return doHttpRequest(url, true, headers, content, HttpRequest.POST);
+  public HttpResponse postHttpRequestAbsoluteUrl(String url, Map<String, 
String> headers, String content,
+      String address) throws IOException {
+    return doHttpRequest(url, true, headers, content, HttpRequest.POST, 
address);
   }
 
   public HttpResponse postHttpRequest(String url, Map<String, String> headers, 
String content) throws IOException {
-    return doHttpRequest(url, false, headers, content, HttpRequest.POST);
+    return doHttpRequest(url, false, headers, content, HttpRequest.POST, "");
   }
 
   public HttpResponse putHttpRequest(String url, Map<String, String> headers, 
String content) throws IOException {
-    return doHttpRequest(url, false, headers, content, HttpRequest.PUT);
+    return doHttpRequest(url, false, headers, content, HttpRequest.PUT, "");
   }
 
   public HttpResponse deleteHttpRequest(String url, Map<String, String> 
headers, String content) throws IOException {
-    return doHttpRequest(url, false, headers, content, HttpRequest.DELETE);
+    return doHttpRequest(url, false, headers, content, HttpRequest.DELETE, "");
   }
 
   private HttpResponse doHttpRequest(String url, boolean absoluteUrl, 
Map<String, String> headers, String content,
-      String method)
-      throws IOException {
-    String address = addressManager.address();
+      String method, String queryAddress) throws IOException {
+    String address = StringUtils.isEmpty(queryAddress) ? 
addressManager.address() : queryAddress;
     String formatUrl = addressManager.formatUrl(url, absoluteUrl, address);
     HttpRequest httpRequest = buildHttpRequest(formatUrl, headers, content, 
method);
-
+    HttpResponse httpResponse;
     try {
-      HttpResponse httpResponse = httpTransport.doRequest(httpRequest);
-      addressManager.recordSuccessState(address);
+      httpResponse = httpTransport.doRequest(httpRequest);
+      recordAndSendUnAuthorizedEvent(httpResponse, address);
       return httpResponse;
     } catch (IOException e) {
       addressManager.recordFailState(address);
@@ -87,7 +97,9 @@ public class ServiceCenterRawClient {
       LOGGER.warn("send request to {} failed and retry to {} once. ", address, 
retryAddress, e);
       httpRequest = new HttpRequest(formatUrl, headers, content, method);
       try {
-        return httpTransport.doRequest(httpRequest);
+        httpResponse = httpTransport.doRequest(httpRequest);
+        recordAndSendUnAuthorizedEvent(httpResponse, retryAddress);
+        return httpResponse;
       } catch (IOException ioException) {
         addressManager.recordFailState(retryAddress);
         LOGGER.warn("retry to {} failed again. ", retryAddress, e);
@@ -96,6 +108,16 @@ public class ServiceCenterRawClient {
     }
   }
 
+  private void recordAndSendUnAuthorizedEvent(HttpResponse response, String 
address) {
+    if (this.eventBus != null && response.getStatusCode() == 
HttpStatus.SC_UNAUTHORIZED) {
+      LOGGER.warn("request unauthorized from server [{}], message [{}]", 
address, response.getMessage());
+      addressManager.recordFailState(address);
+      this.eventBus.post(new UnAuthorizedOperationEvent(address));
+    } else {
+      addressManager.recordSuccessState(address);
+    }
+  }
+
   public void checkAddressAvailable(String address) {
     ServiceCombServiceAvailableUtils.checkAddressAvailable(addressManager, 
address, httpTransport, ADDRESS_CHECK_PATH);
   }
diff --git 
a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRegistration.java
 
b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRegistration.java
index 7f453834b8..93988ea894 100644
--- 
a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRegistration.java
+++ 
b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRegistration.java
@@ -301,7 +301,7 @@ public class ServiceCenterRegistration extends AbstractTask 
{
         if (failedCount == 2) {
           LOGGER.error("send heart failed, and will try again.", e);
         } else {
-          LOGGER.warn("send heart failed, and will try again. message [{}]", 
e.getCause().getMessage());
+          LOGGER.warn("send heart failed, and will try again. message [{}]", 
e.getMessage());
         }
         eventBus.post(new HeartBeatEvent(false, microservice, 
microserviceInstance));
         startTask(new BackOffSleepTask(failedCount + 1, new 
SendHeartBeatTask(failedCount + 1)));
diff --git 
a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterWatch.java
 
b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterWatch.java
index a68a73a49c..9f24a74a55 100644
--- 
a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterWatch.java
+++ 
b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterWatch.java
@@ -17,6 +17,7 @@
 
 package org.apache.servicecomb.service.center.client;
 
+import java.net.URI;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
@@ -24,6 +25,7 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.apache.servicecomb.foundation.auth.SignRequest;
 import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider;
 import 
org.apache.servicecomb.http.client.common.HttpConfiguration.SSLProperties;
 import org.apache.servicecomb.http.client.common.WebSocketListener;
@@ -108,7 +110,7 @@ public class ServiceCenterWatch implements 
WebSocketListener {
         Map<String, String> headers = new HashMap<>();
         headers.put("x-domain-name", this.tenantName);
         headers.putAll(this.extraGlobalHeaders);
-        headers.putAll(this.requestAuthHeaderProvider.loadAuthHeader(null));
+        
headers.putAll(this.requestAuthHeaderProvider.loadAuthHeader(createSignRequest(address)));
         currentServerUri = convertAddress(address);
         LOGGER.info("start watch to address {}", currentServerUri);
         webSocketTransport = new WebSocketTransport(currentServerUri, 
sslProperties,
@@ -122,6 +124,17 @@ public class ServiceCenterWatch implements 
WebSocketListener {
     });
   }
 
+  private SignRequest createSignRequest(String url) {
+    try {
+      URI uri = URI.create(url);
+      SignRequest signRequest = new SignRequest();
+      signRequest.setEndpoint(uri);
+      return signRequest;
+    } catch (Exception e) {
+      return null;
+    }
+  }
+
   private String convertAddress(String address) {
     String url = String.format(WATCH, project, serviceId);
     if (address.startsWith(HTTP)) {
diff --git 
a/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManagerTest.java
 
b/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManagerTest.java
index f5c316cd84..a2888cfad1 100644
--- 
a/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManagerTest.java
+++ 
b/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManagerTest.java
@@ -41,7 +41,7 @@ class ServiceCenterAddressManagerTest {
   @Test
   public void getUrlPrefix() {
     addresses.add("http://127.0.0.1:30103";);
-    addressManager1 = new ServiceCenterAddressManager("project", addresses, 
new EventBus());
+    addressManager1 = new ServiceCenterAddressManager("project", addresses, 
new EventBus(), "", "");
 
     Assertions.assertNotNull(addressManager1);
 
@@ -55,7 +55,7 @@ class ServiceCenterAddressManagerTest {
   @Test
   public void formatUrlTest() {
     addresses.add("http://127.0.0.1:30103";);
-    addressManager1 = new ServiceCenterAddressManager("project", addresses, 
new EventBus());
+    addressManager1 = new ServiceCenterAddressManager("project", addresses, 
new EventBus(), "", "");
     Assertions.assertNotNull(addressManager1);
 
     String address = addressManager1.address();
@@ -76,7 +76,7 @@ class ServiceCenterAddressManagerTest {
     Map<String, List<String>> zoneAndRegion = new HashMap<>();
     zoneAndRegion.put("sameZone", addressAZ);
     zoneAndRegion.put("sameRegion", addressRG);
-    addressManager1 = new ServiceCenterAddressManager("project", addresses, 
new EventBus());
+    addressManager1 = new ServiceCenterAddressManager("project", addresses, 
new EventBus(), "", "");
     RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, 
"SERVICECENTER");
     addressManager1.refreshEndpoint(event, "SERVICECENTER");
 
diff --git 
a/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterClientTest.java
 
b/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterClientTest.java
index 6143953f3d..c486b2bd6c 100755
--- 
a/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterClientTest.java
+++ 
b/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterClientTest.java
@@ -53,7 +53,7 @@ public class ServiceCenterClientTest {
 
   public ServiceCenterClientTest() {
     this.addressManager = new ServiceCenterAddressManager("default", 
Arrays.asList("http://127.0.0.1:30100";),
-        new EventBus());
+        new EventBus(), "", "");
   }
 
   @Test
diff --git 
a/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClientTest.java
 
b/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClientTest.java
index 29337e31a4..48f3bd914c 100755
--- 
a/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClientTest.java
+++ 
b/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClientTest.java
@@ -41,7 +41,8 @@ public class ServiceCenterRawClientTest {
   public void TestDefaultParameter() throws IOException {
 
     HttpTransport httpTransport = Mockito.mock(HttpTransport.class);
-    ServiceCenterAddressManager addressManager = new 
ServiceCenterAddressManager(PROJECT_NAME, 
Arrays.asList("http://127.0.0.1:30100";), new EventBus());
+    ServiceCenterAddressManager addressManager = new 
ServiceCenterAddressManager(PROJECT_NAME,
+        Arrays.asList("http://127.0.0.1:30100";), new EventBus(), "", "");
     ServiceCenterRawClient client = new ServiceCenterRawClient.Builder()
         .setHttpTransport(httpTransport)
         .setAddressManager(addressManager)
diff --git 
a/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/RegistryClientTest.java
 
b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/RegistryClientTest.java
index 50ae96db15..3b11e0582d 100644
--- 
a/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/RegistryClientTest.java
+++ 
b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/RegistryClientTest.java
@@ -69,8 +69,8 @@ public class RegistryClientTest implements 
CategorizedTestCase {
 
   @Override
   public void testRestTransport() throws Exception {
-    ServiceCenterAddressManager addressManager = new 
ServiceCenterAddressManager("default", Arrays.asList("http://127.0.0.1:30100";),
-        new EventBus());
+    ServiceCenterAddressManager addressManager = new 
ServiceCenterAddressManager("default",
+        Arrays.asList("http://127.0.0.1:30100";), new EventBus(), "", "");
     SSLProperties sslProperties = new SSLProperties();
     sslProperties.setEnabled(false);
     ServiceCenterClient serviceCenterClient = new 
ServiceCenterClient(addressManager, sslProperties,
diff --git 
a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterDynamicPropertiesSource.java
 
b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterDynamicPropertiesSource.java
index d1130317ec..23c0a7af19 100644
--- 
a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterDynamicPropertiesSource.java
+++ 
b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterDynamicPropertiesSource.java
@@ -69,7 +69,7 @@ public class ConfigCenterDynamicPropertiesSource implements 
DynamicPropertiesSou
     ConfigCenterConfig configCenterConfig = new 
ConfigCenterConfig(environment);
     configConverter = new ConfigConverter(configCenterConfig.getFileSources());
 
-    ConfigCenterAddressManager configCenterAddressManager = 
configCenterAddressManager(configCenterConfig);
+    ConfigCenterAddressManager configCenterAddressManager = 
configCenterAddressManager(configCenterConfig, environment);
 
     HttpTransport httpTransport = 
createHttpTransport(configCenterAddressManager,
         buildRequestConfig(configCenterConfig), environment, 
configCenterConfig);
@@ -176,16 +176,18 @@ public class ConfigCenterDynamicPropertiesSource 
implements DynamicPropertiesSou
 
   private static RequestAuthHeaderProvider 
getRequestAuthHeaderProvider(List<AuthHeaderProvider> authHeaderProviders) {
     return signRequest -> {
+      String host = signRequest != null && signRequest.getEndpoint() != null ? 
signRequest.getEndpoint().getHost() : "";
       Map<String, String> headers = new HashMap<>();
-      authHeaderProviders.forEach(provider -> 
headers.putAll(provider.authHeaders()));
+      authHeaderProviders.forEach(provider -> 
headers.putAll(provider.authHeaders(host)));
       return headers;
     };
   }
 
-  private ConfigCenterAddressManager 
configCenterAddressManager(ConfigCenterConfig configCenterConfig) {
+  private ConfigCenterAddressManager 
configCenterAddressManager(ConfigCenterConfig configCenterConfig, Environment 
environment) {
+    String region = environment.getProperty("servicecomb.datacenter.region");
+    String availableZone = 
environment.getProperty("servicecomb.datacenter.availableZone");
     return new ConfigCenterAddressManager(configCenterConfig.getDomainName(),
-        configCenterConfig.getServerUri(),
-        EventManager.getEventBus());
+        configCenterConfig.getServerUri(), EventManager.getEventBus(), region, 
availableZone);
   }
 
   @Override
diff --git 
a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/cc/ConfigCenterAddressManagerTest.java
 
b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/cc/ConfigCenterAddressManagerTest.java
index 1642d11ff5..50d39bc19d 100644
--- 
a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/cc/ConfigCenterAddressManagerTest.java
+++ 
b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/cc/ConfigCenterAddressManagerTest.java
@@ -41,8 +41,8 @@ class ConfigCenterAddressManagerTest {
   public void addressManagerTest() throws NoSuchFieldException, 
IllegalAccessException {
     addresses.add("http://127.0.0.1:30103";);
     addresses.add("https://127.0.0.2:30103";);
-    addressManager1 = new ConfigCenterAddressManager("project", addresses, new 
EventBus());
-    addressManager2 = new ConfigCenterAddressManager(null, addresses, new 
EventBus());
+    addressManager1 = new ConfigCenterAddressManager("project", addresses, new 
EventBus(), "", "");
+    addressManager2 = new ConfigCenterAddressManager(null, addresses, new 
EventBus(), "", "");
     Field addressManagerField = 
addressManager1.getClass().getSuperclass().getDeclaredField("index");
     addressManagerField.setAccessible(true);
     addressManagerField.set(addressManager1, 0);
@@ -71,7 +71,7 @@ class ConfigCenterAddressManagerTest {
     Map<String, List<String>> zoneAndRegion = new HashMap<>();
     zoneAndRegion.put("sameZone", addressAZ);
     zoneAndRegion.put("sameRegion", addressRG);
-    addressManager1 = new ConfigCenterAddressManager("project", addresses, new 
EventBus());
+    addressManager1 = new ConfigCenterAddressManager("project", addresses, new 
EventBus(), "", "");
     RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, 
"CseConfigCenter");
     addressManager1.refreshEndpoint(event, "CseConfigCenter");
 
diff --git 
a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/cc/ConfigCenterConfigurationSourceImplTest.java
 
b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/cc/ConfigCenterConfigurationSourceImplTest.java
index f9424c9a2f..3298d95bb1 100644
--- 
a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/cc/ConfigCenterConfigurationSourceImplTest.java
+++ 
b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/cc/ConfigCenterConfigurationSourceImplTest.java
@@ -36,7 +36,8 @@ class ConfigCenterConfigurationSourceImplTest {
     List<String> addresses = new ArrayList<>();
     addresses.add("http://127.0.0.1:30103";);
     addresses.add("http://127.0.0.2:30103";);
-    ConfigCenterAddressManager addressManager = new 
ConfigCenterAddressManager("test", addresses, EventManager.getEventBus());
+    ConfigCenterAddressManager addressManager = new 
ConfigCenterAddressManager("test", addresses,
+        EventManager.getEventBus(), "", "");
     Field addressManagerField = 
addressManager.getClass().getSuperclass().getDeclaredField("index");
     addressManagerField.setAccessible(true);
     addressManagerField.set(addressManager, 0);
@@ -47,7 +48,7 @@ class ConfigCenterConfigurationSourceImplTest {
     address = addressManager.address();
     Assertions.assertEquals("http://127.0.0.1:30103/v3/test";, address);
 
-    addressManager = new ConfigCenterAddressManager(null, addresses, 
EventManager.getEventBus());
+    addressManager = new ConfigCenterAddressManager(null, addresses, 
EventManager.getEventBus(), "", "");
     addressManagerField = 
addressManager.getClass().getSuperclass().getDeclaredField("index");
     addressManagerField.setAccessible(true);
     addressManagerField.set(addressManager, 0);
@@ -65,7 +66,8 @@ class ConfigCenterConfigurationSourceImplTest {
     zoneAndRegion.put("sameZone", addressAZ);
     zoneAndRegion.put("sameRegion", new ArrayList<>());
     RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, 
"CseConfigCenter");
-    ConfigCenterAddressManager addressManager = new 
ConfigCenterAddressManager("test", addresses, EventManager.getEventBus());
+    ConfigCenterAddressManager addressManager = new 
ConfigCenterAddressManager("test", addresses,
+        EventManager.getEventBus(), "", "");
     addressManager.onRefreshEndpointEvent(event);
 
     List<String> availableAZ = addressManager.getAvailableZone();
diff --git 
a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/KieDynamicPropertiesSource.java
 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/KieDynamicPropertiesSource.java
index e9819f6746..6683b84fb0 100644
--- 
a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/KieDynamicPropertiesSource.java
+++ 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/KieDynamicPropertiesSource.java
@@ -71,7 +71,7 @@ public class KieDynamicPropertiesSource implements 
DynamicPropertiesSource {
   private void init(Environment environment) {
     KieConfig kieConfig = new KieConfig(environment);
     configConverter = new ConfigConverter(kieConfig.getFileSources());
-    KieAddressManager kieAddressManager = configKieAddressManager(kieConfig);
+    KieAddressManager kieAddressManager = configKieAddressManager(kieConfig, 
environment);
 
     RequestConfig.Builder requestBuilder = 
buildRequestConfigBuilder(kieConfig);
     if (kieConfig.enableLongPolling()
@@ -161,15 +161,18 @@ public class KieDynamicPropertiesSource implements 
DynamicPropertiesSource {
 
   private static RequestAuthHeaderProvider 
getRequestAuthHeaderProvider(List<AuthHeaderProvider> authHeaderProviders) {
     return signRequest -> {
+      String host = signRequest != null && signRequest.getEndpoint() != null ? 
signRequest.getEndpoint().getHost() : "";
       Map<String, String> headers = new HashMap<>();
-      authHeaderProviders.forEach(provider -> 
headers.putAll(provider.authHeaders()));
+      authHeaderProviders.forEach(provider -> 
headers.putAll(provider.authHeaders(host)));
       return headers;
     };
   }
 
-  private KieAddressManager configKieAddressManager(KieConfig kieConfig) {
+  private KieAddressManager configKieAddressManager(KieConfig kieConfig, 
Environment environment) {
+    String region = environment.getProperty("servicecomb.datacenter.region");
+    String availableZone = 
environment.getProperty("servicecomb.datacenter.availableZone");
     return new KieAddressManager(
-        Arrays.asList(kieConfig.getServerUri().split(",")), 
EventManager.getEventBus());
+        Arrays.asList(kieConfig.getServerUri().split(",")), 
EventManager.getEventBus(), region, availableZone);
   }
 
   @Override
diff --git 
a/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/auth/AuthHeaderProvider.java
 
b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/auth/AuthHeaderProvider.java
index 313c19ee5b..0e036e21a5 100644
--- 
a/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/auth/AuthHeaderProvider.java
+++ 
b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/auth/AuthHeaderProvider.java
@@ -21,11 +21,21 @@ import java.util.HashMap;
 import java.util.Map;
 
 public interface AuthHeaderProvider {
-  default Map<String, String> authHeaders() {
+  /**
+   * Obtain RBAC authentication request header, host is the key of cache
+   *
+   * @param host engine address ip
+   * @return auth headers
+   */
+  default Map<String, String> authHeaders(String host) {
     return new HashMap<>(0);
   }
 
   default Map<String, String> getSignAuthHeaders(SignRequest request) {
-    return authHeaders();
+    String host = "";
+    if (request != null && request.getEndpoint() != null) {
+      host = request.getEndpoint().getHost();
+    }
+    return authHeaders(host);
   }
 }
diff --git 
a/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/DefaultMonitorDataPublisher.java
 
b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/DefaultMonitorDataPublisher.java
index cd7d2fc10f..1209d9d853 100644
--- 
a/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/DefaultMonitorDataPublisher.java
+++ 
b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/DefaultMonitorDataPublisher.java
@@ -84,8 +84,10 @@ public class DefaultMonitorDataPublisher implements 
MonitorDataPublisher {
     if (addresses.isEmpty()) {
       throw new IllegalStateException("dashboard address is not configured.");
     }
+    String region = environment.getProperty("servicecomb.datacenter.region");
+    String availableZone = 
environment.getProperty("servicecomb.datacenter.availableZone");
 
-    return new DashboardAddressManager(addresses, EventManager.getEventBus());
+    return new DashboardAddressManager(addresses, EventManager.getEventBus(), 
region, availableZone);
   }
 
   private HttpTransport createHttpTransport(DashboardAddressManager 
addressManager, RequestConfig requestConfig,
@@ -120,8 +122,9 @@ public class DefaultMonitorDataPublisher implements 
MonitorDataPublisher {
 
   private static RequestAuthHeaderProvider 
getRequestAuthHeaderProvider(List<AuthHeaderProvider> authHeaderProviders) {
     return signRequest -> {
+      String host = signRequest != null && signRequest.getEndpoint() != null ? 
signRequest.getEndpoint().getHost() : "";
       Map<String, String> headers = new HashMap<>();
-      authHeaderProviders.forEach(provider -> 
headers.putAll(provider.authHeaders()));
+      authHeaderProviders.forEach(provider -> 
headers.putAll(provider.authHeaders(host)));
       return headers;
     };
   }
diff --git 
a/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/RBACBootStrapService.java
 
b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/RBACBootStrapService.java
index 7f18cbb612..007e3e56c9 100644
--- 
a/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/RBACBootStrapService.java
+++ 
b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/RBACBootStrapService.java
@@ -42,6 +42,7 @@ import 
org.apache.servicecomb.http.client.auth.DefaultRequestAuthHeaderProvider;
 import 
org.apache.servicecomb.http.client.common.HttpConfiguration.SSLProperties;
 import org.apache.servicecomb.http.client.common.HttpTransport;
 import org.apache.servicecomb.http.client.common.HttpTransportFactory;
+import org.apache.servicecomb.registry.sc.SCClientUtils;
 import 
org.apache.servicecomb.service.center.client.ServiceCenterAddressManager;
 import org.apache.servicecomb.service.center.client.ServiceCenterClient;
 import org.apache.servicecomb.service.center.client.ServiceCenterRawClient;
@@ -128,8 +129,8 @@ public class RBACBootStrapService implements 
BootStrapService {
   }
 
   private ServiceCenterAddressManager createAddressManager(Environment 
environment) {
-    return new ServiceCenterAddressManager(getProjectName(environment),
-        getRBACAddressList(environment), EventManager.getEventBus());
+    return SCClientUtils.createAddressManager(getProjectName(environment), 
getRBACAddressList(environment),
+        environment);
   }
 
   private SSLProperties createSSLProperties(Environment environment) {
@@ -233,7 +234,7 @@ public class RBACBootStrapService implements 
BootStrapService {
   }
 
   private List<String> getRBACAddressList(Environment environment) {
-    String address = environment.getProperty(RBAC_ADDRESS, 
"http://127.0.0.1:30100)");
+    String address = environment.getProperty(RBAC_ADDRESS, 
"http://127.0.0.1:30100";);
     return Arrays.asList(address.split(","));
   }
 
diff --git 
a/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/TokenAuthHeaderProvider.java
 
b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/TokenAuthHeaderProvider.java
index 6698f99f83..19bd550602 100644
--- 
a/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/TokenAuthHeaderProvider.java
+++ 
b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/TokenAuthHeaderProvider.java
@@ -26,8 +26,8 @@ import 
org.apache.servicecomb.foundation.auth.AuthHeaderProvider;
 
 public class TokenAuthHeaderProvider implements AuthHeaderProvider {
   @Override
-  public Map<String, String> authHeaders() {
-    String token = 
TokenCacheManager.getInstance().getToken(RBACBootStrapService.DEFAULT_REGISTRY_NAME);
+  public Map<String, String> authHeaders(String host) {
+    String token = TokenCacheManager.getInstance().getToken(host);
     if (StringUtils.isEmpty(token)) {
       return new HashMap<>();
     }
diff --git 
a/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/TokenCacheManager.java
 
b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/TokenCacheManager.java
index 205f373816..b4510bb423 100644
--- 
a/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/TokenCacheManager.java
+++ 
b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/TokenCacheManager.java
@@ -17,19 +17,16 @@
 
 package org.apache.servicecomb.huaweicloud.servicestage;
 
+import java.net.URI;
 import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.servicecomb.foundation.auth.Cipher;
-import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
 import org.apache.servicecomb.foundation.common.event.EventManager;
-import org.apache.servicecomb.http.client.event.EngineConnectChangedEvent;
-import org.apache.servicecomb.service.center.client.OperationEvents;
+import org.apache.servicecomb.http.client.event.OperationEvents;
 import org.apache.servicecomb.service.center.client.ServiceCenterClient;
 import org.apache.servicecomb.service.center.client.model.RbacTokenRequest;
 import org.apache.servicecomb.service.center.client.model.RbacTokenResponse;
@@ -55,17 +52,15 @@ public final class TokenCacheManager {
 
   private static final TokenCacheManager INSTANCE = new TokenCacheManager();
 
-
-  private final Map<String, TokenCache> tokenCacheMap;
-
   private Map<String, ServiceCenterClient> serviceCenterClients;
 
+  private TokenCache tokenCache;
+
   public static TokenCacheManager getInstance() {
     return INSTANCE;
   }
 
   private TokenCacheManager() {
-    tokenCacheMap = new ConcurrentHashMapEx<>();
   }
 
   public void setServiceCenterClients(Map<String, ServiceCenterClient> 
serviceCenterClients) {
@@ -73,24 +68,17 @@ public final class TokenCacheManager {
   }
 
   public void addTokenCache(String registryName, String accountName, String 
password, Cipher cipher) {
-    Objects.requireNonNull(registryName, "registryName should not be null!");
-    if (tokenCacheMap.containsKey(registryName)) {
-      LOGGER.warn("duplicate token cache registration for 
serviceRegistry[{}]", registryName);
-      return;
-    }
-
-    tokenCacheMap.put(registryName, new TokenCache(registryName, accountName, 
password, cipher));
+    tokenCache = new TokenCache(registryName, accountName, password, cipher);
   }
 
-  public String getToken(String registryName) {
-    return Optional.ofNullable(tokenCacheMap.get(registryName))
-        .map(TokenCache::getToken)
-        .orElse(null);
+  public String getToken(String host) {
+    if (tokenCache == null) {
+      return null;
+    }
+    return tokenCache.getToken(host);
   }
 
   public class TokenCache {
-    private static final String UN_AUTHORIZED_CODE_HALF_OPEN = "401302";
-
     private static final long TOKEN_REFRESH_TIME_IN_SECONDS = 20 * 60 * 1000;
 
     private final String registryName;
@@ -105,10 +93,6 @@ public final class TokenCacheManager {
 
     private final Cipher cipher;
 
-    private int lastStatusCode;
-
-    private String lastErrorCode;
-
     public TokenCache(String registryName, String accountName, String password,
         Cipher cipher) {
       this.registryName = registryName;
@@ -128,17 +112,17 @@ public final class TokenCacheManager {
           }
         });
         cache = CacheBuilder.newBuilder()
-            .maximumSize(1)
+            .maximumSize(10)
             .refreshAfterWrite(refreshTime(), TimeUnit.MILLISECONDS)
             .build(new CacheLoader<String, String>() {
               @Override
               public String load(String key) throws Exception {
-                return createHeaders();
+                return createHeaders(key);
               }
 
               @Override
               public ListenableFuture<String> reload(String key, String 
oldValue) throws Exception {
-                return Futures.submit(() -> createHeaders(), executorService);
+                return Futures.submit(() -> createHeaders(key), 
executorService);
               }
             });
         EventManager.getEventBus().register(this);
@@ -147,21 +131,22 @@ public final class TokenCacheManager {
 
     @Subscribe
     public void onNotPermittedEvent(OperationEvents.UnAuthorizedOperationEvent 
event) {
-      this.executorService.submit(() -> {
-        if (lastStatusCode == Status.UNAUTHORIZED.getStatusCode() && 
UN_AUTHORIZED_CODE_HALF_OPEN
-            .equals(lastErrorCode)) {
-          cache.refresh(registryName);
-        }
-      });
+      LOGGER.warn("address {} unAuthorized, refresh cache token!", 
event.getAddress());
+      cache.refresh(getHostByAddress(event.getAddress()));
     }
 
-    @Subscribe
-    public void onEngineConnectChangedEvent(EngineConnectChangedEvent event) {
-      cache.refresh(registryName);
+    private String getHostByAddress(String address) {
+      try {
+        URI uri = URI.create(address);
+        return uri.getHost();
+      } catch (Exception e) {
+        LOGGER.error("get host by address [{}] error!", address, e);
+        return registryName;
+      }
     }
 
-    private String createHeaders() {
-      LOGGER.info("start to create RBAC headers");
+    private String createHeaders(String host) {
+      LOGGER.info("start to create RBAC headers for host: {}", host);
 
       ServiceCenterClient serviceCenterClient = 
serviceCenterClients.get(this.registryName);
 
@@ -169,10 +154,7 @@ public final class TokenCacheManager {
       request.setName(accountName);
       request.setPassword(new String(cipher.decrypt(password.toCharArray())));
 
-      RbacTokenResponse rbacTokenResponse = 
serviceCenterClient.queryToken(request);
-
-      this.lastStatusCode = rbacTokenResponse.getStatusCode();
-      this.lastErrorCode = rbacTokenResponse.getErrorCode();
+      RbacTokenResponse rbacTokenResponse = 
serviceCenterClient.queryToken(request, host);
 
       if (Status.UNAUTHORIZED.getStatusCode() == 
rbacTokenResponse.getStatusCode()
           || Status.FORBIDDEN.getStatusCode() == 
rbacTokenResponse.getStatusCode()) {
@@ -185,8 +167,14 @@ public final class TokenCacheManager {
         LOGGER.warn("service center do not support RBAC token, you should not 
config account info");
         return INVALID_TOKEN;
       }
+      if (Status.INTERNAL_SERVER_ERROR.getStatusCode() == 
rbacTokenResponse.getStatusCode()) {
+        // return null for server_error, so the token information can be 
re-fetched on the next call.
+        // It will prompt 'CacheLoader returned null for key xxx'
+        LOGGER.warn("service center query RBAC token error!");
+        return null;
+      }
 
-      LOGGER.info("refresh token successfully {}", 
rbacTokenResponse.getStatusCode());
+      LOGGER.info("refresh host [{}] token successfully {}", host, 
rbacTokenResponse.getStatusCode());
       return rbacTokenResponse.getToken();
     }
 
@@ -194,13 +182,16 @@ public final class TokenCacheManager {
       return TOKEN_REFRESH_TIME_IN_SECONDS;
     }
 
-    public String getToken() {
+    public String getToken(String host) {
       if (!enabled()) {
         return null;
       }
-
+      String address = host;
+      if (StringUtils.isEmpty(address)) {
+        address = registryName;
+      }
       try {
-        return cache.get(registryName);
+        return cache.get(address);
       } catch (Exception e) {
         LOGGER.error("failed to create token", e);
         return null;
diff --git 
a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCAddressManager.java
 
b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCAddressManager.java
index c650d068bc..1c8ec27c8a 100644
--- 
a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCAddressManager.java
+++ 
b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCAddressManager.java
@@ -49,14 +49,14 @@ public class SCAddressManager {
 
   private static final Logger LOGGER = 
LoggerFactory.getLogger(SCAddressManager.class);
 
-  private boolean initialized = false;
-
   private final ServiceCenterClient serviceCenterClient;
 
   private final SCRegistration scRegistration;
 
   private final SCConfigurationProperties configurationProperties;
 
+  private final Map<String, HashSet<String>> lastEngineEndpointsCache = new 
HashMap<>();
+
   public SCAddressManager(SCConfigurationProperties configurationProperties,
       ServiceCenterClient serviceCenterClient,
       SCRegistration scRegistration) {
@@ -68,9 +68,6 @@ public class SCAddressManager {
 
   @Subscribe
   public void onHeartBeatEvent(HeartBeatEvent event) {
-    if (initialized) {
-      return;
-    }
     if (event.isSuccess() && configurationProperties.isAutoDiscovery()) {
       for (Type type : Type.values()) {
         initEndPort(type.name());
@@ -79,19 +76,30 @@ public class SCAddressManager {
   }
 
   private void initEndPort(String key) {
-    List<MicroserviceInstance> instances = findServiceInstance("default",
-        key, "0+");
-    if ("SERVICECENTER".equals(key) && !instances.isEmpty()) {
-      initialized = true;
-    }
-    Map<String, List<String>> zoneAndRegion = 
generateZoneAndRegionAddress(instances);
+    List<MicroserviceInstance> instances = findServiceInstance("default", key, 
"0+");
+    HashSet<String> currentEngineEndpoints = new HashSet<>();
+    Map<String, List<String>> zoneAndRegion = 
generateZoneAndRegionAddress(instances, currentEngineEndpoints);
     if (zoneAndRegion == null) {
       return;
     }
-    EventManager.post(new RefreshEndpointEvent(zoneAndRegion, key));
+    if (isEngineEndpointsChanged(lastEngineEndpointsCache.get(key), 
currentEngineEndpoints)) {
+      LOGGER.info("auto discovery service [{}] addresses: [{}]", key, 
zoneAndRegion);
+      lastEngineEndpointsCache.put(key, currentEngineEndpoints);
+      EventManager.post(new RefreshEndpointEvent(zoneAndRegion, key));
+    }
+  }
+
+  private boolean isEngineEndpointsChanged(Set<String> lastEngineEndpoints, 
Set<String> currentEngineEndpoints) {
+    if (lastEngineEndpoints == null || lastEngineEndpoints.isEmpty()) {
+      return true;
+    }
+    HashSet<String> compareTemp = new HashSet<>(lastEngineEndpoints);
+    compareTemp.removeAll(currentEngineEndpoints);
+    return !compareTemp.isEmpty() || lastEngineEndpoints.size() != 
currentEngineEndpoints.size();
   }
 
-  private Map<String, List<String>> 
generateZoneAndRegionAddress(List<MicroserviceInstance> instances) {
+  private Map<String, List<String>> 
generateZoneAndRegionAddress(List<MicroserviceInstance> instances,
+      HashSet<String> currentEngineEndpoints) {
     if (instances.isEmpty()) {
       return null;
     }
@@ -107,6 +115,7 @@ public class SCAddressManager {
       } else {
         sameRegion.addAll(microserviceInstance.getEndpoints());
       }
+      currentEngineEndpoints.addAll(microserviceInstance.getEndpoints());
     }
     zoneAndRegion.put("sameZone", new ArrayList<>(sameZone));
     zoneAndRegion.put("sameRegion", new ArrayList<>(sameRegion));
diff --git 
a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCClientUtils.java
 
b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCClientUtils.java
index 4d29de05a2..f9371926a1 100644
--- 
a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCClientUtils.java
+++ 
b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCClientUtils.java
@@ -17,9 +17,12 @@
 
 package org.apache.servicecomb.registry.sc;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.http.HttpHost;
 import org.apache.http.auth.AuthScope;
@@ -50,16 +53,62 @@ import org.springframework.core.env.Environment;
 public class SCClientUtils {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(SCClientUtils.class);
 
-  public static ServiceCenterAddressManager 
createAddressManager(SCConfigurationProperties discoveryProperties) {
+  // Compatible chassis multi-registration center
+  private static final Map<String, ServiceCenterAddressManager> 
serviceAddressManagers = new ConcurrentHashMap<>();
+
+  public static ServiceCenterAddressManager 
createAddressManager(SCConfigurationProperties discoveryProperties,
+      Environment environment) {
     List<String> addresses = 
ConfigUtil.parseArrayValue(discoveryProperties.getAddress());
-    LOGGER.info("initialize discovery server={}", addresses);
-    return new ServiceCenterAddressManager("default", addresses, 
EventManager.getEventBus());
+    return createAddressManager("default", addresses, environment);
+  }
+
+  /**
+   * Ensure that the ServiceCenterAddressManager in the client created for 
RBAC authentication and registry discovery
+   * is the same. This ensures that when an error is reported due to the 
registry center address being unavailable,
+   * the authentication and registry discovery remain consistent.
+   *
+   * @param projectName projectName
+   * @param addresses   engine address
+   * @param environment environment
+   * @return Service Center Address Manager
+   */
+  public static ServiceCenterAddressManager createAddressManager(String 
projectName, List<String> addresses,
+      Environment environment) {
+    if (getServiceCenterAddressManager(addresses) == null) {
+      synchronized (SCClientUtils.class) {
+        if (getServiceCenterAddressManager(addresses) == null) {
+          String key = String.join(",", addresses);
+          LOGGER.info("initialize discovery server={}", addresses);
+          String region = 
environment.getProperty("servicecomb.datacenter.region");
+          String availableZone = 
environment.getProperty("servicecomb.datacenter.availableZone");
+          ServiceCenterAddressManager addressManager = new 
ServiceCenterAddressManager(projectName, addresses,
+              EventManager.getEventBus(), region, availableZone);
+          serviceAddressManagers.put(key, addressManager);
+          return addressManager;
+        }
+      }
+    }
+    return getServiceCenterAddressManager(addresses);
+  }
+
+  private static ServiceCenterAddressManager 
getServiceCenterAddressManager(List<String> addresses) {
+    String forwardKey = String.join(",", addresses);
+    List<String> tempAddr = new ArrayList<>(addresses);
+    Collections.reverse(tempAddr);
+    String reverseKey = String.join(",", tempAddr);
+    if (serviceAddressManagers.get(forwardKey) != null) {
+      return serviceAddressManagers.get(forwardKey);
+    }
+    if (serviceAddressManagers.get(reverseKey) != null) {
+      return serviceAddressManagers.get(reverseKey);
+    }
+    return null;
   }
 
   // add other headers needed for registration by new ServiceCenterClient(...)
   public static ServiceCenterClient 
serviceCenterClient(SCConfigurationProperties discoveryProperties,
       Environment environment) {
-    ServiceCenterAddressManager addressManager = 
createAddressManager(discoveryProperties);
+    ServiceCenterAddressManager addressManager = 
createAddressManager(discoveryProperties, environment);
 
     SSLProperties sslProperties = buildSslProperties(addressManager, 
environment);
 
@@ -135,7 +184,7 @@ public class SCClientUtils {
 
   public static ServiceCenterWatch 
serviceCenterWatch(SCConfigurationProperties discoveryProperties,
       List<AuthHeaderProvider> authHeaderProviders, Environment environment) {
-    ServiceCenterAddressManager addressManager = 
createAddressManager(discoveryProperties);
+    ServiceCenterAddressManager addressManager = 
createAddressManager(discoveryProperties, environment);
     SSLProperties sslProperties = buildSslProperties(addressManager, 
environment);
     return new ServiceCenterWatch(addressManager, sslProperties, 
getRequestAuthHeaderProvider(authHeaderProviders),
         "default", new HashMap<>(), EventManager.getEventBus());
@@ -143,8 +192,9 @@ public class SCClientUtils {
 
   private static RequestAuthHeaderProvider 
getRequestAuthHeaderProvider(List<AuthHeaderProvider> authHeaderProviders) {
     return signRequest -> {
+      String host = signRequest != null && signRequest.getEndpoint() != null ? 
signRequest.getEndpoint().getHost() : "";
       Map<String, String> headers = new HashMap<>();
-      authHeaderProviders.forEach(provider -> 
headers.putAll(provider.authHeaders()));
+      authHeaderProviders.forEach(provider -> 
headers.putAll(provider.authHeaders(host)));
       return headers;
     };
   }


Reply via email to