詳解Java Chassis 3與Spring Cloud的互操作

本文分享自華爲雲社區《Java Chassis 3技術解密:與Spring Cloud的互操作》,作者: liubao68。

Java Chassis 3一個很重要的設計原則:利用架構的韌性設計來解決兼容性問題。

比如通過引入微服務網關,來解決不同語言、不同框架、遺留系統之間的互操作問題。 本文在這個架構原則基礎上,討論一個更加細粒度的互操作問題,並藉此解密Java Chassis3在運行時設計依賴上的技術細節。

首先,我們描述一個互操作的場景和假設。

  • Spring Cloud和Java Chassis應用同時註冊到註冊中心。引入了Spring Cloud Gateway作爲網關,網關也註冊到註冊中心。
  • Spring Cloud微服務和Java Chassis微服務相互調用。它們彼此作爲消費者的時候,不需要感知對方是不同的框架,做到透明調用。

從技術原理上梳理下上述互操作需要滿足的條件:

  • Spring Cloud和Java Chassis需要有相互認識的註冊信息。核心包括:應用名稱、服務名稱、地址信息和格式等。 需要的共同註冊中心越少,越容易對註冊中心和客戶端進行選型。 在本例子中,我們選擇 Service Center 或者 Nacos 作爲註冊中心,並選擇Spring Cloud Huawei實現Spring Cloud註冊。
  • Spring Cloud訪問Java Chassis,只需要一個地址信息,依賴較少。 Java Chassis訪問Spring Cloud,需要知道Spring Cloud應用提供的契約信息。

Java Chassis區別於Spring Cloud的REST調用的部分,就是契約依賴。 Spring Cloud通過FeignClient來聲明客戶端契約,客戶端都需要在FeignClient中重複書寫REST標籤;Java Chassis有兩種模式發現契約:從註冊中心發現和從Provider實例發現。 Java Chassis3默認採用從Provider實例發現, Java Chassis2採用從註冊中心發現。 從Provider發現的好處是可以降低對於註冊中心元數據管理能力的要求,本例既可以採用 Service Center 作爲註冊中心,也可以選擇 Nacos 作爲註冊中心。

從Provider發現,要求Provider實現如下接口:

/**
 * Java Chassis internal management apis.
 */
@Path("/scb/management")
public interface ManagementEndpoint {
  String NAME = "scb-management";

  /**
   * Health of this instance. If the instanceId match this instance, and this service is ready
   * to service return true. Otherwise, return false.
   *
   * This api is for internal instance status usage. Load balancer will call this api to check if
   * the target instance is alive.
   */
  @GET
  @Path("/health")
  boolean health(@QueryParam("instanceId") String instanceId, @QueryParam("registryName") String registryName);

  /**
   * Schemas of this instance.
   *
   * This api is for internal schema loading usage.
   */
  @POST
  @Path("/schema/contents")
  Map<String, String> schemaContents();
}

它包含一個健康檢查接口和一個查詢契約的接口。 當Spring Cloud應用實現上述接口以後,它就具備了Java Chassis微服務需要的基礎特徵,這樣Java Chassis就可以像訪問本框架的微服務一樣訪問Spring Cloud框架開發的微服務應用。 爲了簡化,在Spring Cloud簡單實現了該接口,該實現接口從 export 目錄加載契約信息,只需要將Spring Cloud需要對外暴露的 REST 接口的符合 Open API 3.0規範的契約文件放到這個目錄下面 。

@RestController
@RequestMapping(("/scb/management"))
public class JavaChassisManagementEndpoint {
  private static final Logger LOGGER = LoggerFactory.getLogger(JavaChassisManagementEndpoint.class);

  @Autowired
  private Registration registration;

  @GetMapping(path = "/health")
  public boolean health(@RequestParam("instanceId") String instanceId,
      @RequestParam("registryName") String registryName) {
    return "sc-registry".equals(registryName) && registration.getInstanceId().equals(instanceId);
  }

  @PostMapping(path = "/schema/contents")
  public Map<String, String> schemaContents() {
    try {
      List<URI> resourceUris = ResourceUtil.findResourcesBySuffix("export", ".yaml");
      Map<String, String> result = new HashMap<>(resourceUris.size());
      for (URI uri : resourceUris) {
        String path = uri.toURL().getPath();
        String[] segments = path.split("/");
        if (segments.length < 2 || !"export".equals(segments[segments.length - 2])) {
          continue;
        }
        result.put(segments[segments.length - 1].substring(0, segments[segments.length - 1].indexOf(".yaml")),
            IOUtils.toString(uri, StandardCharsets.UTF_8));
      }
      return result;
    } catch (IOException | URISyntaxException e) {
      LOGGER.error("Load schema ids failed from microservices. {}.", e.getMessage());
      return Collections.emptyMap();
    }
  }
}

Java Chassis與Spring Cloud互操作的例子放到了ServiceComb Samples , 這個例子也提供了使用 Nacos 作爲註冊中心和配置中心的實現, 只需要將 Profile 設置爲 Nacos 即可。

客戶故事:在架構選型變化的時候,解決功能遷移和兼容性問題是最大的挑戰。一些客戶將Spring Cloud應用改造爲Java Chassis的過程中,發現一些功能不支持,比如SseEmitter、WebSocket等。 如果選擇支持這些能力,Java Chassis需要實現很多Servlet能力,這些能力規劃會和微服務技術架構存在衝突。 對於這些場景,我們選擇通過架構韌性來保留這些功能,比如將提供SseEmitter、WebSocket功能的獨立出微服務,採用Spring Boot開發,這些應用可以通過調用Java Chassis微服務的REST接口來實現其特殊功能。通過這種架構韌性的理念,降低了技術持續演進的包袱,爲敏捷迭代,持續創新奠定了方向,減少了兼容性問題的爭論。

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章