通信、高可用性和微服务

Communication, High Availability and microservices

我对微服务的理解是,您可以根据需要"just"启动同一服务的多个实例。

我的问题是,如果你有 x 个微服务实例,分布在 y 个服务器上,那么在微服务上调用 API 的任何东西如何知道在哪里可以找到它?

我见过的一种方法是使用某种发现服务(可以路由到实例的固定 IP 地址,如负载平衡器);但可以肯定的是,这只会将问题推回一层 - 发现服务然后需要知道一切在哪里/何时失败等等?发现服务的高可用性又如何(如果您有多个实例,您将再次不知道任何东西在哪里)

另一种方法可能是使用 pub/sub 消息传递,但您仍然需要知道队列管理器的位置(具有高可用性等);所以你基本上仍然遇到同样的问题 - 并且使用这种方法对查询的响应更加棘手。

另一个相关问题是,如果您有一个从 STOMP 提要中提取的微服务,您将如何实现 HA?你不能只拥有该服务的 x 个实例,否则你将订阅和读取数据 x 次,这意味着你最终会在数据传递到下游系统时复制数据。所以你会想要某种 active/passive 的方法,对吧?这意味着您需要一些东西来管理故障转移,这又会导致单点故障?

您可以有一个服务注册中心,服务在启动时注册自己。注册表可能会监听其他服务对注册事件的广播,因此注册表的位置不需要固定在服务中的某个地方。

然后所有其他服务都可以使用此注册表通过查询注册表来查找可用实例。注册表还可以充当 DNS 解析器,因此您的服务可以使用 DNS 按名称解析其他服务,并自动在多个主机之间进行负载平衡。

另一种方法可能是颠倒责任,想要联系其他服务的服务广播请求,其他服务用所需信息回答这些请求(这基本上是 DNS 所做的)。

一个现成的解决方案是 Consul by Hashi Corp。查看它提供的功能,这些功能可能会有用,例如健康检查。

我所做的是:

我让每个服务在启动时生成一个 Table 的内容,可以作为根资源访问 (.../{service}/)。 在此 ToC 中,所有端点都作为 Map。

Key是一个(well-known)EndpointId,一个Value总是由

组成
  • title
  • href
  • type(媒体类型)

所以,基本上是常规 Link。

魔法在于 href,其中 public 主机 (DNS) 可配置为环境变量(例如 Config Map)。由于使用 DNS,LoadBalancing 等不在等式中。但是您也可以将这种方法用于内部 IP。

这是提到的好做法 here

A REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types that are appropriate for the intended audience (i.e., expected to be understood by any client that might use the API). From that point on, all application state transitions must be driven by client selection of server-provided choices that are present in the received representations or implied by the user’s manipulation of those representations. The transitions may be determined (or limited by) the client’s knowledge of media types and resource communication mechanisms, both of which may be improved on-the-fly (e.g., code-on-demand). [Failure here implies that out-of-band information is driving interaction instead of hypertext.]

因此每个服务都有一个包含 Link 到所有端点(有时是模板化)的根资源。

这个完全相同的 ToC 通过将它发布到一个名为 "endpoints" 的 Kafka-Topic 得到重用,其中 key 是一个 (well-known) ServiceId ("fooService"或 "fooService:1.2.3") 并且 value 是其目录。

每个服务还具有对主题 (GlobalKTable) 的读取权限,因此当它想要向 FooService 生成 Link 时,他会在 GlobalK[=59] 中查找其目录=],通过其 Id 查找端点,用实际值替换模板变量并完成,它不会改变 type,因为它被认为是正确的。

这里很酷的事情是(由于 Kafkas GlobalKTable 和 QueryableKeyStores),当 FooService 改变它的端点时(仅以非中断方式)所有其他服务自动生成新链接。 DNS 更改或重命名路径段将起作用。参数的重命名显然不是。