[翻译]squbs官网之6 Akka HTTP 客户端

概述

squbs-httpclient 项目在保持Akka HTTP API的同时,增加了Akka HTTP主机级别客户端API 操作方面的内容。 下面是它添加的功能列表:

  • 服务发现:允许任何服务发现机制插入,并允许通过字符串标识符 ( 例如 paymentserv ) 解析 HTTP 端点。
  • 客户端单独配置: 让每个客户端单独覆盖application.conf中的默认值。
  • 管道:允许各客户端全局或者各自注册一个BidiAkka Stream流。
  • 指标:为每个客户端提供 Codahale 指标, 而无需 AspectJ。
  • JMX Beans:将每一个客户端的配置暴露为JMX bean。
  • 断路器:基于断路器提供基于流的弹性。

依赖

增加如下依赖到你的build.sbt或者其它scala构建文件:

"org.squbs" %% "squbs-httpclient" % squbsVersion

用法

squbs-httpclient项目坚持Akka HTTP API。唯一的例外是创建主机连接池期间。不是使用Http().cachedHostConnectionPool,它定义了ClientFlow使用一组相同的参数(和一些其它可选的参数)。

类似于Akka HTTP主机级别客户端API例子,使用ClientFlow 如下:

implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
// construct a pool client flow with context type `Int`
val poolClientFlow = ClientFlow[Int]("sample") // Only this line is specific to squbs

val responseFuture: Future[(Try[HttpResponse], Int)] =
  Source.single(HttpRequest(uri = "/") -> 42)
    .via(poolClientFlow)
    .runWith(Sink.head)

可以传递可选的设置(例如HttpsConnectionContextConnectionPoolSettings)给ClientFlow

val clientFlow = ClientFlow("sample", Some(connectionContext), Some(connectionPoolSettings))

HTTP 模型

Below is an HttpRequest creation example in Scala. Please see HTTP Model Scala documentation for more details:
下面是HttpRequest创建的例子。更详细内容请看Akka文档中的HTTP模型

import HttpProtocols._
import MediaTypes._
import HttpCharsets._
val userData = ByteString("abc")
val authorization = headers.Authorization(BasicHttpCredentials("user", "pass"))

HttpRequest(
  PUT,
  uri = "/user",
  entity = HttpEntity(`text/plain` withCharset `UTF-8`, userData),
  headers = List(authorization),
  protocol = `HTTP/1.0`)

服务发现链

squbs-httpclient在客户端池创建的时候不要求主机名/端口组合。相反, 它允许注册服务发现链, 通过运行注册的服务发现机制, 允许通过字符串标识符解析HttpEndpoint。例如,在上面的例子中,“sample”是客户端想要连接的服务逻辑名,配置的服务发现链将它解析到包括主机和端口的HttpEndpoint, 例如, http://akka.io:80

请注意,你仍然可以传递一个有效的http URI作为字符串给ClientFlow ,作为一个默认解析器,作为默认的服务发现链预配置的有效http URI:

ClientFlow[Int]("http://akka.io") 

下面展示了两种不同的注册解析器。闭包风格允许更紧凑、可读的代码。然而,子类具有保持状态并根据此状态做出决策的能力:

注册函数类型(String, Env) => Option[HttpEndpoint]

ResolverRegistry(system).register[HttpEndpoint]("SampleEndpointResolver", { (svcName, env) =>
  svcName match {
    case "sample" => Some(HttpEndpoint("http://akka.io:80"))
    case "google" => Some(HttpEndpoint("http://www.google.com:80"))
    case _ => None
})

注册类继承于Resolver[HttpEndpoint]

class SampleEndpointResolver extends Resolver[HttpEndpoint] {
  override def name: String = "SampleEndpointResolver"

  override def resolve(svcName: String, env: Environment): Option[HttpEndpoint] =
    svcName match {
      case "sample" => Some(Endpoint("http://akka.io:80"))
      case "google" => Some(Endpoint("http://www.google.com:80"))
      case _ => None
    }
}

// Register EndpointResolver
ResolverRegistry(system).register[HttpEndpoint](new SampleEndpointResolver)

你可以注册多个解析器。该链是按相反的注册顺序执行的。如果解析器返回 None, 则表示无法解析它, 并尝试下一个解析器。

如果已解析的端点是安全的, 例如 https, 则可以将SSLContext作为可选参数传递给HttpEndpoint

也可以将一个可选的Config传递给HttpEndpoint覆盖默认的配置。然而,客户端具体的配置始终比传入的配置有更高的优先级。

请看资源解析中关于解析的详细信息。

客户端单独配置

Akka HTTP配置定义了配置的默认值。你可以覆盖application.conf默认值;然而,这将影响所有的客户端。要执行客户端特定的覆盖,Akka HTTP在创建HostConnectionPool流的时候,传入一个ConnectionPoolSettings。这也得到了 squbs 的支持。

In addition to the above, squbs allows a client specific override in application.conf. You just need to specify a configuration section with the client's name that has type = squbs.httpclient. Then, you can specify any client configuration inside the section. For instance, if we would like to override the max-connections setting only for the above "sample" client, but no other client, we can do it as follows:
除此外,squbs允许在application.conf里定义客户端特定的覆盖。你仅需定义一个带有客户端名称的配置节,并带有type = squbs.httpclient。然后,你可以在此节中定义任意客户端配置。例如,如果想要在上面的“sample”客户端覆盖max-connections 设置,而其它的客户端不需要,可以如下操作:

sample {
  type = squbs.httpclient

  akka.http.host-connection-pool {
    max-connections = 10
  }
}

管道

我们通常需要在不同的客户端之间拥有共同的基础结构功能或组织标准。基础结构包括,但不限于,日志、指标收集、请求追踪、认证/授权、 追踪、cookie 管理、A/B测试等。随着 squbs 促进关注的分离, 此类逻辑属于基础结构, 而不是客户端实现。squbs 管道允许基础结构提供组件安装到客户端, 而无需客户自己担心这些方面。请看squbs管道更多细节。

通常讲,管道是一个Bidi Flow,作为squbs客户端和Akka HTTP层间的桥梁。squbs-httpclient允许注册一个Bidi Akka Stream流或者全局地对所有客户端,或者个别客户端。为了注册一个客户端特定管道,设置pipeline配置。可以通过defaultPipeline设置,打开或关闭默认管道(如果没有设置,设为on):

sample {
  type = squbs.httpclient
  pipeline = metricsFlow
  defaultPipeline = on
}

请看squbs管道章节了解如何创建管道和配置默认管道。

指标

squbs带有预建的管道元素用于指标收集,且squbs激活模板设置这些默认值。因此,每个 squbs 的 http 客户端都可以在没有任何代码更改或配置的情况下, 收集现成的Codahale Metrics。请注意,squbs指标收集不需要AspectJ或者其它运行时代码编写。下面指标在JMX可以默认获得:

  • 请求计时器
  • 请求计数器
  • 每个http响应码的计量器:2xx, 3xx, 4xx, 5xx
  • ClientFlow返回的每个异常类型的计量器

可以通过MetricsExtension(system).metrics访问MetricRegistry 。这使您可以创建更多的计量器, 计时器, 直方图等, 或传递给不同类型的指标报表。

JMX Bean

系统配置的可见性在解决问题时非常重要。squbs-httpclient为一个客户端注册一个JMX bean。JMX bean暴露所有的配置,例如端点、主机连接池配置,等等。bean的名称由org.squbs.configuration.${system.name}:type=squbs.httpclient,name=$name设置。所以,如果actor system名称是squbs,客户端名称是sample,那么JMX bean名称为org.squbs.configuration.squbs:type=squbs.httpclient,name=sample

断路器

squbs提供CircuitBreakerBidi Akka Streams GraphStage 来为流提供断路器功能。这是为流实现的通用断路器。请看断路器文档中详细内容。

断路器有可能改变消息的顺序,所以它需要一个可随身携带的Context,像ClientFlow。但是,除此之外,它还需要能够唯一地识别每个元素的内部机制。因此,传递给ClientFlowContext或来自Context的映射需能够唯一地标识每个元素。如果启用了断路器, 并且传递给ClientFlowContext没有唯一标识每个元素, 那么您将遇到意外的行为。请看“断路器”文档中的“上下文到唯一Id映射”节,关于提供唯一id的详细内容。

断路器默认是关闭的。请看下面的内容启动。

一旦启动,任何Failure或者带有400状态码的Success则递增失败计数。CircuitBreakerState的默认实现是AtomicCircuitBreakerState,可以跨物化和跨流共享。 这些可以通过传递CircuitBreakerSettings以编程方式进行定制。

application.conf中的配置

在客户端的具体配置中,您可以添加circuit-breaker并指定要覆盖的配置。 其余的将使用默认设置。 请参见这里的默认断路器配置。

sample {
  type = squbs.httpclient

  circuit-breaker {
    max-failures = 2
    call-timeout = 10 milliseconds
    reset-timeout = 100 seconds
  }
}

编程方式传递CircuitBreakerSettings

你可以编程方式传递一个CircuitBreakerSettings实例。这个API让你传递一个自定义CircuitBreakerState和可选的回调,失败判断和唯一id映射函数。如果编程方式传入一个CircuitBreakerSettings实例,那么断路器在application.conf中的设置将忽略。

在下面的示例中, 通过withFallback提供了回调响应。默认的失败判断是通过withFailureDecider重写,只考虑状态代码>= 500增加断路器的故障计数:

import org.squbs.streams.circuitbreaker.CircuitBreakerSettings

val circuitBreakerSettings =
  CircuitBreakerSettings[HttpRequest, HttpResponse, Int](circuitBreakerState)
    .withFallback( _ => Try(HttpResponse(entity = "Fallback Response")))
    .withFailureDecider(
      response => response.isFailure || response.get.status.intValue() >= StatusCodes.InternalServerError.intValue)

val clientFlow = ClientFlow[Int]("sample", circuitBreakerSettings = Some(circuitBreakerSettings))  

调用其它服务作为回调

断路器使用中一个常见的场景是调用另一个服务作为回调。调用另一个服务需要在回调函数中有一个新的流物化;所以,我们建议用户将失败的快速消息传递到下游,并相应地进行分支。这可以在相同的流中定义回调ClientFlow

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容