发现

Akka 发现(Discovery)提供了一个围绕各种定位服务方式的接口。内置方法有:

  • DNS
  • 配置
  • 聚合

此外,「Akka Management」包括以下方法:

  • Kubernetes API
  • AWS
  • Consul
  • Marathon API

Discovery曾是 Akka 管理的一部分,但从 Akka 的2.5.19版和 Akka 管理的1.0.0版开始,它已成为 Akka 的模块。如果你还将 Akka 管理用于其他服务发现方法或加载程序,请确保你至少使用了 Akka 管理(Management)的1.0.0版本。

依赖

为了使用 Akka 发现,你需要将以下依赖添加到你的项目中:

  1. <!-- Maven -->
  2. <dependency>
  3. <groupId>com.typesafe.akka</groupId>
  4. <artifactId>akka-discovery_2.12</artifactId>
  5. <version>2.5.22</version>
  6. </dependency>
  7. <!-- Gradle -->
  8. dependencies {
  9. compile group: 'com.typesafe.akka', name: 'akka-discovery_2.12', version: '2.5.22'
  10. }
  11. <!-- sbt -->
  12. libraryDependencies += "com.typesafe.akka" %% "akka-discovery" % "2.5.22"

它是如何工作的?

加载扩展:

  1. ActorSystem as = ActorSystem.create();
  2. ServiceDiscovery serviceDiscovery = Discovery.get(as).discovery();

Lookup包含一个必需的serviceName和一个可选的portNameprotocol。如何解释这些内容取决于发现方法,例如,如果缺少任何字段,DNS 会执行 A/AAAA 记录查询,并执行 SRV 查询以进行完整查找:

  1. serviceDiscovery.lookup(Lookup.create("akka.io"), Duration.ofSeconds(1));
  2. // convenience for a Lookup with only a serviceName
  3. serviceDiscovery.lookup("akka.io", Duration.ofSeconds(1));

portNameprotocol是可选的,其含义由方法解释。

  1. CompletionStage<ServiceDiscovery.Resolved> lookup =
  2. serviceDiscovery.lookup(
  3. Lookup.create("akka.io").withPortName("remoting").withProtocol("tcp"),
  4. Duration.ofSeconds(1));

当服务打开多个端口(如 HTTP 端口和 Akka 远程处理端口)时,可以使用port

发现方法:DNS

DNS 发现映射Lookup查询如下:

  • serviceNameportNameprotocol:SRV 查询,格式为_port._protocol._name,其中_是需要添加的名称。
  • 任何缺少任何字段的查询都将映射到serviceName的 A/AAAA 查询。

Akka 服务发现术语和 SRV 术语之间的映射:

  • SRV service = port
  • SRV name = serviceName
  • SRV protocol = protocol

application.conf中将akka-dns配置为发现的实现:

  1. akka {
  2. discovery {
  3. method = akka-dns
  4. }
  5. }

从那时起,你就可以使用通用 API 来隐藏调用以下方法所使用的发现方法的事实:

  1. import akka.discovery.ServiceDiscovery;
  2. ActorSystem system = ActorSystem.create("Example");
  3. // ...
  4. SimpleServiceDiscovery discovery = ServiceDiscovery.get(system).discovery();
  5. Future<SimpleServiceDiscovery.Resolved> result = discovery.lookup("service-name", Duration.create("500 millis"));

它是如何工作的?

根据发出的是Simple查找还是Full查找,DNS 发现将使用 A/AAAA 记录或 SRV 记录。SRV 记录的优点是它们可以包含一个端口。

SRV 记录

设置了所有字段的查找将成为 SRV 查询。例如:

  1. dig srv _service._tcp.akka.test
  2. ; <<>> DiG 9.11.3-RedHat-9.11.3-6.fc28 <<>> srv service.tcp.akka.test
  3. ;; global options: +cmd
  4. ;; Got answer:
  5. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60023
  6. ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 1, ADDITIONAL: 5
  7. ;; OPT PSEUDOSECTION:
  8. ; EDNS: version: 0, flags:; udp: 4096
  9. ; COOKIE: 5ab8dd4622e632f6190f54de5b28bb8fb1b930a5333c3862 (good)
  10. ;; QUESTION SECTION:
  11. ;service.tcp.akka.test. IN SRV
  12. ;; ANSWER SECTION:
  13. _service._tcp.akka.test. 86400 IN SRV 10 60 5060 a-single.akka.test.
  14. _service._tcp.akka.test. 86400 IN SRV 10 40 5070 a-double.akka.test.

在这种情况下,service.tcp.akka.test解析为端口5060上的a-double.akka.test和端口5070上的a-double.akka.test 。当前发现不支持权重。

A/AAAA 记录

缺少任何字段的查找将成为 A/AAAA 记录查询。例如:

  1. dig a-double.akka.test
  2. ; <<>> DiG 9.11.3-RedHat-9.11.3-6.fc28 <<>> a-double.akka.test
  3. ;; global options: +cmd
  4. ;; Got answer:
  5. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 11983
  6. ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 1, ADDITIONAL: 2
  7. ;; OPT PSEUDOSECTION:
  8. ; EDNS: version: 0, flags:; udp: 4096
  9. ; COOKIE: 16e9815d9ca2514d2f3879265b28bad05ff7b4a82721edd0 (good)
  10. ;; QUESTION SECTION:
  11. ;a-double.akka.test. IN A
  12. ;; ANSWER SECTION:
  13. a-double.akka.test. 86400 IN A 192.168.1.21
  14. a-double.akka.test. 86400 IN A 192.168.1.22

在这种情况下,a-double.akka.test将解析为192.168.1.21192.168.1.22

发现方法:配置

配置(Configuration)当前忽略服务名称以外的所有字段。

对于简单的用例,可以使用配置来发现服务。将 Akka Discovery 与配置一起使用而不是与你自己的配置值一起使用的好处是,可以将应用程序迁移到更复杂的发现方法,而无需更改任何代码。

application.conf中将其配置为发现方法:

  1. akka {
  2. discovery.method = config
  3. }

默认情况下,可发现的服务在akka.discovery.config.services中定义,格式如下:

  1. akka.discovery.config.services = {
  2. service1 = {
  3. endpoints = [
  4. {
  5. host = "cat"
  6. port = 1233
  7. },
  8. {
  9. host = "dog"
  10. port = 1234
  11. }
  12. ]
  13. },
  14. service2 = {
  15. endpoints = []
  16. }
  17. }

上面的块定义了两个服务,service1service2。每个服务可以有多个endpoints

发现方法:聚合多个发现方法

聚合(Aggregate)发现允许聚合多个发现方法,例如,尝试通过 DNS 解析并返回到配置。

若要使用聚合发现,请添加其依赖项以及要聚合的所有发现。

aggregate配置为akka.discovery.method,并尝试使用哪些发现方法,以及按何种顺序执行。

  1. akka {
  2. discovery {
  3. method = aggregate
  4. aggregate {
  5. discovery-methods = ["akka-dns", "config"]
  6. }
  7. config {
  8. services {
  9. service1 {
  10. endpoints [
  11. {
  12. host = "host1"
  13. port = 1233
  14. },
  15. {
  16. host = "host2"
  17. port = 1234
  18. }
  19. ]
  20. }
  21. }
  22. }
  23. }
  24. }

上述配置将导致首先检查akka-dns,如果它失败或没有返回给定服务名称的目标,那么将查询config,如上配置了一个名为service1的服务,其中两个主机为host1host2

从 Akka Management Discovery 迁移

Akka Discovery 与旧版本的 Akka Management Discovery 不兼容。如果还使用 Akka Discovery,则应至少使用任何 Akka Management 模块的1.0.0版本。

迁移步骤:

  • 任何自定义发现方法现在都应实现akka.discovery.ServiceDiscovery
  • discovery-method现在必须是akka.discovery下的一个配置位置,至少要有一个属性class,指定akka.discovery.ServiceDiscovery实现的完全限定名。以前的版本允许它是类名或完全限定的配置位置,例如akka.discovery.kubernetes-api,而不仅仅是kubernetes-api

英文原文链接Discovery.