• 如何使用Spring Cloud跨多个云区域运行Java微服务
  • 发布于 2个月前
  • 242 热度
    0 评论
如果用户想在公共云基础设施上运行Java微服务,那么可以利用多个云区域。这是一个好主意,其中有几个原因。首先,由于硬件问题、云服务升级后引入的错误或人为错误,云计算可用区(Availability Zones)和云区域(Regions)经常出现故障。最著名的S3中断之一是因为AWS公司的员工发布了错误的操作命令。

如果一个云区域发生故障,那么该区域的微服务也会发生故障。但是,如果跨多个云区域运行微服务实例,即使美国东部地区出现大面积故障,也可以继续运行。其次,用户可以选择在美国东部部署微服务,但应用程序在大西洋彼岸的欧洲运行。从欧洲用户到美国东部应用程序实例的往返延迟大约为100毫秒,将这个时间与来自美国东部(运行微服务的数据中心附近)的用户流量的5毫秒往返延迟进行比较,当欧洲用户表示应用程序速度较慢时,不要感到惊讶。如果微服务实例部署在美国东部和欧洲西部地区,就不会听到这种负面反馈。

最后,假设一个Java微服务服务于来自欧洲的用户请求,但从美国的数据库实例请求数据。在这种情况下,可能会违反数据驻留法规(如果GDPR法规将请求的数据分类为个人数据)。然而,如果微服务实例在欧洲运行,并从欧洲某个云区域的数据库实例获取个人数据,那么就不会遇到监管机构所关注的问题。以下对本文的主题进行介绍,但希望看到在多个云区域运行Java微服务的一些好处。以下了解如何使用Spring Cloud开发和部署多个云区域微服务。

高层次的概念
以下以一个地理分布式Java Messenger为例,对微服务和Spring Cloud如何在多个云区域环境中发挥作用进行深入了解。

该应用程序(由多个微服务组成)运行在多个云区域:美国西部、美国中部、欧洲西部和亚洲南部。所有应用程序实例都是无状态的。Spring Cloud组件在应用程序实例所在的相同云区域中运行。该应用程序使用Spring Config Server进行配置设置分发,使用Spring Discovery Server进行平滑和容错的服务间通信。

选择YugabyteDB作为分布式数据库,可以轻松地远程运行。另外,只要它是在PostgreSQL源代码上构建的,它就自然地与Spring Data和Spring生态系统的其他组件集成在一起。本文并不会回顾YugabyteDB多区域部署选项。

用户流量通过全局外部云负载均衡器到达微服务实例。简而言之,负载均衡器提供了一个单一的IP地址,可以从地球上的任何地点访问。该IP地址(或转换为该地址的DNS名称)被提供给用户的Web或移动前端,它们使用该IP连接到应用程序后端。负载均衡器自动将用户请求转发到最近的应用程序实例。下面将详细地演示这个云组件。

目标架构
多区域Java Messenger的目标架构如下所示:

整个解决方案运行在谷歌云平台上。用户可能更喜欢另一个云计算提供商提供的云服务,所以可以放心使用。很多用户喜欢使用谷歌云,因为它提供了开发人员体验、丰富且价格合理的基础设施、快速且稳定的网络,以及在本文中提到的其他好处。微服务实例可以根据需要部署在尽可能多的云区域中。

在上图中有两个随机云区域:Region A和Region B。微服务实例可以运行在一个云区域的多个可用性分区中(例如Region A的Zone A和ZoneB),也可以运行在一个云区域内(Region B的Zone A)。每个云区域都有一个Spring Discovery和Config服务器的实例也是合理的,但特意为每个可用区运行每个服务器的实例,以将延迟降至最低。谁决定哪个微服务实例将服务于用户请求?那全局外部负载均衡器就是决策者!

假设一位用户通过手机打开Java Messenger,并发送了一条消息。带有消息的请求将被发送到负载均衡器,它可以通过以下方式转发:
(1)Region A是离用户最近的云区域,并且在请求时处于正常状态(没有中断)。负载均衡器根据这些条件选择该区域。
(2)在这个云区域中,微服务实例在Zone A和Zone B都可用。因此,如果这两个可用区都处于活动状态并且正常运行,负载均衡器可以选择任何一个可用区。假设这个请求发送到Zone B。

以下将解释每个微服务负责什么。到目前为止,只需要知道消息传递微服务将所有应用程序数据(消息、通道、用户配置文件等)存储在一个多区域YugabyteDB部署中。Attachments微服务使用全球分布的谷歌云存储存储用户图片。

微服务和Spring Cloud
以下进一步讨论微服务以及它们如何利用Spring Cloud。

Messenger微服务实现了每个Messenger应用程序必须具备的跨渠道和工作区发送消息的关键功能。Attachments微服务上载图片和其他文件,可以在geo messenger的存储库中查看它们的源代码。

Spring Cloud配置服务器
这两个微服务都是在Spring Boot上构建的。当它们启动时,他们从Spring Cloud Config Server中检索配置设置,如果需要在分布式环境中外部化配置文件,这是一个很好的选项。配置服务器可以托管并从各种后端获取配置,包括Git存储库、Vault和JDBC兼容数据库。在Java geo messenger的情况下,使用Git选项,下面一行来自应用程序。两个微服务请求的属性文件Spring Boot从配置服务器加载设置:
spring.config.import=configserver:http://${CONFIG_SERVER_HOST}:${CONFIG_SERVER_PORT}
Spring Cloud Discovery Server
一旦启动了Messenger和Attachments微服务,它们就会向Spring Cloud Discovery Server(属于Spring Cloud Netflix组件)的区域本地实例注册。
Discovery Server实例的位置在从Config Server实例传输的以下配置设置中定义:
1eureka.client.serviceUrl.defaultZnotallow=http://${DISCOVERY_SERVER_HOST}:${DISCOVERY_SERVER_PORT}/eureka
也可以在浏览器中打开HTTP地址,确认服务已成功注册到Discovery Server:

微服务使用您通过应用程序的spring.application.name设置传递的名称注册到application.properties file。如上图所示,选择了以下名称:
·spring.application.name=messenger for the Messenger microservice
·spring.application.name=attachments for the Attachments service
微服务实例使用这些名称来定位并通过Discovery Server相互发送请求。例如,当用户想要在讨论频道中上传图片时,该请求首先会发送到Messenger服务。然后,Messenger在Discovery Server的帮助下将此任务委托给Attachments微服务。

首先,Messenger服务获得一个附件对应的实例:
 List<ServiceInstance> serviceInstances = discoveryClient.getInstances("ATTACHMENTS");

 ServiceInstance instance;

 if (!serviceInstances.isEmpty()) {
 instance = serviceInstances
    .get(ThreadLocalRandom.current().nextInt(0, serviceInstances.size()));
 }

  System.out.printf("Connected to service %s with URI %s\n", 
       instance.getInstanceId(), instance.getUri());
接下来,Messenger微服务使用附件的实例URI创建一个HTTP客户端,并通过InputStream发送图片:
 HttpClient httpClient = HttpClient.newBuilder().build();

 HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create(instance.getUri() + "/upload?fileName=" + fileName))
  .header("Content-Type", mimeType)
    .POST(HttpRequest.BodyPublishers.ofInputStream(new Supplier<InputStream>() {
        @Override
        public InputStream get() {         
               return inputStream;
        }
  })).build();
Attachments服务通过REST端点接收请求,并最终将图片存储在谷歌云存储中,将图片URL返回给Messenger微服务:
// 堆代码 duidaima.com 
public Optional<String> storeFile(String filePath, String fileName, String contentType) {
  if (client == null) {
  initClient();
   }
 
  String objectName = generateUniqueObjectName(fileName);
 
  BlobId blobId = BlobId.of(bucketName, objectName);
  BlobInfo blobInfo = BlobInfo.newBuilder(blobId).build();

 try {
  client.create(blobInfo, Files.readAllBytes(Paths.get(filePath)));
 } catch (IOException e) {
  System.err.println("Failed to load the file:" + fileName);
  e.printStackTrace();

 return Optional.empty();
  }

  System.out.printf(
  "File %s uploaded to bucket %s as %s %n", filePath, bucketName, objectName);

 String objectFullAddress = "http://storage.googleapis.com/" + bucketName + "/" + objectName;

  System.out.println("Picture public address: " + objectFullAddress);

 return Optional.of(objectFullAddress);
 }
如果想探索微服务的完整实现以及它们如何通过Discovery Server进行通信,可以访问GitHub repo。

在谷歌云平台上部署
现在,在谷歌云平台上跨三个地理位置和五个云区域部署Java geo-messenger:北美('us-west2','us-central1','us-east4'),欧洲('Europe-west3')和亚洲('Asia-east1')。

遵循以下步骤部署:
(1)创建一个谷歌项目。
(2)创建自定义高级网络。
(3)配置谷歌云存储。
(4)为虚拟机创建实例模板。
(5)以应用实例启动虚拟机。
(6)配置全局外部负载均衡器。
将跳过上述步骤的详细说明。与其相反,采用下图来阐明为什么在步骤2中选择高级谷歌网络:

假设一个应用程序实例部署在美国的谷歌云平台上,用户从印度连接到该应用程序。从用户的位置到应用程序有快速路径和慢速路径。如果为这个部署选择了标准网络,则采用慢速路径。在这种情况下,用户请求通过公共互联网传输,在到达美国之前进入和退出许多云计算提供商的网络。最终,在美国,请求到达靠近应用程序实例的谷歌的PoP(存在点),进入谷歌网络,并到达应用程序。

如果部署使用高级网络,则选择快速路径。在这种情况下,用户请求在离用户最近的PoP处进入谷歌网络,并且永远不会离开它。该PoP在印度,请求将通过快速稳定的连接加速到美国的应用程序实例。另外,云外部负载均衡器需要高级层。否则,将无法在最近的PoP处拦截用户请求,并将它们转发到附近的应用程序实例。

测试容错性
一旦微服务部署到全球各大洲,就可以看到云负载均衡器在正常时间和停机期间的工作情况。在浏览器中打开负载均衡器使用的IP地址,并在其中一个讨论通道中发送一些带有照片的消息:

Messenger和Attachments微服务的哪个实例为最后请求提供了服务?这取决于在世界上的位置。在本文的例子中,来自美国东部(ig-us-east)的实例服务于流量:

如果美国东部地区无法使用,导致该地区的所有微服务都无法使用,应用程序将会发生什么?对于多区域部署来说不是问题。负载均衡器将检测美国东部的问题,并将流量转发到另一个最近的位置。在这种情况下,只要住在大西洋附近的美国东海岸,流量就会被转发到欧洲:

为了模拟美国东部地区的停机,连接到该地区的虚拟机并关闭了所有的微服务。负载均衡器检测到该区域的微服务不再响应,并开始将流量转发到欧洲数据中心。现在可以享受开箱即用的容错功能!

测试性能
除了容错之外,如果跨多个云区域部署Java微服务,那么无论用户请求位于何处,应用程序都能够以较低的延迟服务用户请求。为了实现这一点,首先,需要在大多数用户所在的云区域部署微服务实例,并配置全局外部负载均衡器,可以进行路由。这就是在“跨多个云区域自动化Java应用程序部署”一文中讨论的内容。

其次,需要在这些位置正确地排列数据。数据库需要跨多个区域运行,与微服务实例一样。否则,微服务和数据库之间的延迟会很高,整体性能会很差。在讨论的架构中,使用了YugabyteDB,因为它是一个分布式SQL数据库,可以跨多个云区域部署。

结语
如果为公共云环境开发Java应用程序,则应该通过跨多个区域部署应用程序实例来利用全球云计算基础设施。这将使解决方案更具弹性、性能更高,并符合数据监管要求。重要的是要记住,创建跨云区域运行和协调的微服务并不难。Spring生态系统提供了Spring Cloud框架,而像谷歌这样的公共云提供商提供了简化工作所需的基础设施和服务。
用户评论