解密JavaChassis3:易擴充套件的多種註冊中心支援

华为云开发者联盟發表於2024-02-06

本文分享自華為雲社群《JavaChassis3技術解密:易擴充套件的多種註冊中心支援》,作者:liubao68。

Java Chassis 的早期版本依賴於 Service Center,提供了很多差異化的競爭力:

  • 介面級別轉發。 透過註冊中心管理微服務的每個版本的後設資料,特別是契約資料。 結合契約資料,能夠實現版本級別的路由能力。 比如一個微服務存在 v1 和 v2 兩個版本, 其中 v1 版本存在介面 op1, op2, v2 版本存在介面 op1, op2, op3, 在灰度場景, Java Chassis能夠自動將 op3 的訪問轉發到 v2 版本,將 op1, op2 的訪問在 v1, v2版本做負載均衡。
  • 基於 version-rule 的例項選擇。 客戶端能夠配置 version-rule, 比如 last, 2.0+等。 這樣客戶端能夠根據實際情況,篩選例項的版本。

Java Chassis過度依賴 Service Center, 為產品的發展帶來了一些瓶頸。 Java Chassis的生態推廣依賴於 Service Center的生態推廣, 不利於Java Chassis被更多使用者使用。 隨著雲的發展, 越來越多的客戶也期望一套程式碼,能夠在不同的雲環境執行,有些雲產商未提供Service Center執行環境,那麼使用者選擇Java Chassis 就會存在顧慮。

基於上述原因, Java Chassis簡化了註冊發現的依賴,定義了簡單容易實現的介面,並基於 Nacos 提供了實現,未來還會提供 zookeeper 等實現。 Java Chassis 採用了一系列新的設計模式, 保證了在降低註冊中心功能依賴的前提下,不降低應用自身的可靠性。

介面級別轉發的替代方案

依賴於 Service Center, Java Chassis提供了介面級別轉發。 Java Chassis 3 首先做的一個變化是刪除了對於介面級別轉發的支援。 這樣對於註冊中心的依賴複雜度至少可以降低 70%。 然而灰度場景依然對很多業務比較重要, Java Chassis 3使用灰度釋出解決這個問題。 使用灰度釋出的好處是不用依賴註冊中心提供版本後設資料管理能力,只需要每個例項具備版本號等簡單後設資料資訊。

servicecomb:
  # enable router for edge service
  router:
    type: router
  routeRule:
    business: |
      - precedence: 2
        match:
          apiPath:
            prefix: "/business/v2"
        route:
          - weight: 100
            tags:
              version: 2.0.0
      - precedence: 1
        match:
          apiPath:
            prefix: "/business/v1/dec"
        route:
          - weight: 50
            tags:
              version: 1.1.0
          - weight: 50
            tags:
              version: 2.0.0

註冊發現介面及其實現

Java Chassis 3 只需要使用 Discovery 介面就能夠提供新的註冊發現支援。 Java Chassis會呼叫 findServiceInstances 查詢例項,如果後續例項發生變更,註冊中心實現透過 InstanceChangedListener 通知 Java Chassis.

/**
 * This is the core service discovery interface. <br/>
 */
public interface Discovery<D extends DiscoveryInstance> extends SPIEnabled, SPIOrder, LifeCycle {
  interface InstanceChangedListener<D extends DiscoveryInstance> {
    /**
     * Called by Discovery Implementations when instance list changed.
     * @param registryName Name of the calling discovery implementation
     * @param application Microservice application
     * @param serviceName Microservice name
     * @param updatedInstances The latest updated instances.
     */
    void onInstanceChanged(String registryName, String application, String serviceName, List<D> updatedInstances);
  }

  String name();

  /**
   * If this implementation enabled for this microservice.
   */
  boolean enabled(String application, String serviceName);

  /**
   * Find all instances.
   *
   * Life Cycle:This method is called anytime after <code>run</code>.
   *
   * @param application application
   * @param serviceName microservice name
   * @return all instances match the criteria.
   */
  List<D> findServiceInstances(String application, String serviceName);

  /**
   * Discovery can call InstanceChangedListener when instance get changed.
   */
  void setInstanceChangedListener(InstanceChangedListener<D> instanceChangedListener);
}

Java Chassis 3 透過 Registration 來管理註冊, 註冊過程分為 initrundestroy簡單的生命週期, 可以在 init 準備註冊的資料, run 執行註冊, destroy 則在註冊失敗或者系統停止的時候執行。

/**
 * This is the core service registration interface. <br/>
 */
public interface Registration<R extends RegistrationInstance> extends SPIEnabled, SPIOrder, LifeCycle {
  String name();

  /**
   * get MicroserviceInstance </br>
   *
   * Life Cycle:This method is called anytime after <code>run</code>.
   */
  R getMicroserviceInstance();

  /**
   * update MicroserviceInstance status </br>
   *
   * Life Cycle:This method is called anytime after <code>run</code>.
   */
  boolean updateMicroserviceInstanceStatus(MicroserviceInstanceStatus status);

  /**
   * adding schemas to Microservice </br>
   *
   * Life Cycle:This method is called after <code>init</code> and before <code>run</code>.
   */
  void addSchema(String schemaId, String content);

  /**
   * adding endpoints to MicroserviceInstance </br>
   *
   * Life Cycle:This method is called after <code>init</code> and before <code>run</code>.
   */
  void addEndpoint(String endpoint);

  /**
   * adding property to MicroserviceInstance </br>
   *
   * Life Cycle:This method is called after <code>init</code> and before <code>run</code>.
   */
  void addProperty(String key, String value);
}

註冊發現的組合

Java Chassis 3可以獨立實現多個 DiscoveryRegistration, 達到向多個註冊中心註冊和從多個註冊中心發現例項的作用。 每個例項根據例項ID唯一來標識。 如果例項ID相同, 會被認為是同一個例項, 如果不同, 則會認為是不同的例項。 在 Java Chassis 3技術解密:註冊中心分割槽隔離 中聊到了, Java Chassis 要求每次例項註冊(新的程序), 生成唯一的例項ID, 以解決註冊分割槽隔離帶來的例項假下線問題。 DiscoveryRegistration 都包含了 Java Chassis 定義的基礎資訊。

/**
 * Standard information used for microservice instance registration and discovery.
 */
public interface MicroserviceInstance {
  /**
   * Environment(Required): Used for logic separation of microservice instance. Only
   * microservice instance with same environment can discovery each other.
   */
  String getEnvironment();

  /**
   * Application(Required): Used for logic separation of microservice instance. Only
   * microservice instance with same application can discovery each other.
   */
  String getApplication();

  /**
   * Service Name(Required): Unique identifier for microservice.
   */
  String getServiceName();

  /**
   * Service Name Alias(Optional): Unique identifier for microservice.
   *   This alias is used by registry implementation to support rename
   *   of a microservice, e.g. old consumers use old service name can
   *   find a renamed microservice service.
   */
  String getAlias();

  /**
   * Service Version(Required): version of this microservice.
   */
  String getVersion();

  /**
   * Data center info(Optional).
   */
  DataCenterInfo getDataCenterInfo();

  /**
   * Service Description(Optional)
   */
  String getDescription();

  /**
   * Service Properties(Optional)
   */
  Map<String, String> getProperties();

  /**
   * Service Schemas(Optional): Open API information.
   */
  Map<String, String> getSchemas();

  /**
   * Service endpoints(Optional).
   */
  List<String> getEndpoints();

  /**
   * Microservice instance id(Required). This id can be generated when microservice instance is starting
   * or assigned by registry implementation.
   *
   * When microservice instance is restarted, this id should be changed.
   */
  String getInstanceId();

  /**
   * Microservice service id(Optional). This is used for service center, other implementations may not
   * support service id.
   */
  default String getServiceId() {
    return "";
  }
}

在實現註冊發現的時候,需要保證該介面定義的基礎資訊能夠註冊到註冊中心,查詢例項的時候,能夠獲取到這些資訊。

客戶故事:不把雞蛋放到同一個籃子裡面,是技術選型裡面很重要的考量。解決方案的開放性和可替代性、雲服務的可替代性,是很多客戶都關注的問題。對於一個開源的技術框架,Java Chassis早期的版本雖然設計上也支援不同的註冊中心擴充套件,但是實現難度很高,不自覺的把客戶使用其他註冊中心替換 service center的要求變得不可行。提供更加簡化的註冊發現實現,雖然減少了少量有有競爭力的功能特性,但是極大降低了客戶選型的顧慮。

點選關注,第一時間瞭解華為雲新鮮技術~

相關文章