1

DreamMesh抛砖引玉(9)-API Gateway

 2 years ago
source link: https://skyao.io/post/201803-dreammesh-brainstorm-gateway/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

service mesh解决的是东西向服务间通讯的问题,我们来审视一下API gateway到微服务之间的南北向通讯: 服务发现,负载均衡,路由,灰度,安全,认证,加密,限流,熔断……几乎大部分的主要功能,在这两个方向上都高度重叠。

因此,是否该考虑提供一个统一的解决方案来处理?

在Service Mesh之前

在Service Mesh出来之前,这个问题就已经存在,而且也已经有了解决方案。

对于API Gateway的产品,有两种不同的实现方式:

  1. 基于微服务体系

    典型如Zuul/Spring Cloud Gateway,这类API Gateway的产品和微服务体系一脉相承,在实现将请求转发到内部服务时,API Gateway等同于一个普通的微服务客户端。

    因此,可以复用微服务体系客户端的几乎所有功能,比如Zuul/Spring Cloud Gateway都是和Spring Cloud的普通客户端一样,用Feign做client,Ribbon做负载均衡,用Eureka或者其他ServiceDiscovery实现做服务发现,Hystrix做熔断……

    gateway-1_hu8db9845740bd15d389dc67f63082b958_44780_ebc62a4114f87ee2cd4bf354449b2696.png
  2. 独立于微服务体系

    对于独立的API Gateway产品,典型如kong,因为和微服务体系不是一体,因此无法直接复用微服务体系的客户端,需要自行通过其他方式解决。

    最基本的,是需要解决服务发现的问题。

    请教了一下熟悉kong的朋友,kong是通过DNS的方式来进行服务发现的。也就是说,需要实现DNS和服务注册机制的协同,典型的做法是使用consul这种支持DNS的服务注册机制。也可以通过插件的方式实现服务发现的客户端。

    gateway-2_hua6547528b5dfa582efe039847447fd49_47922_0ce45bc9a41015987a8a61d2c1114878.png

两种实现方式的根本差别:在于能否复用微服务体系的客户端机制。

在Service Mesh之后

当我们将侵入式的微服务框架替换为Service Mesh,这个问题会发生一些微妙的变化,因为:

Service Mesh是基于Sidecar的

而Sidecar的特点是:独立进程,运行于客户端进程之外;通过远程访问来接收和转发请求。

按照上面的思路,我们需要考虑如何在API Gateway中复用Service Mesh体系的客户端机制,也就是复用sidecar。有个简单而直白的方案,就是将sidecar"竖"起来,添加到南北向的流量中,如图所示:

gateway-3_huaaa2b3ba21e6d5a7ca4341a31f198aac_69220_faef79260d8d477fa6be9b438a8a23f9.png

上述方案如果成功实现,则带来以下好处:

  • 统一了微服务和API Gateway两套体系,大量节约学习/开发/维护的成本
  • API Gateway体系可以从Service Mesh方案中得到同样的各种好处,可以使用各种高级特性
  • 通过Service Mesh的控制平面,可以控制的范围从微服务体系扩展到了API Gateway体系

非常美好的想法,那关键来了:该如何实现?

宏观上看,实现应该不难,起码思路很清晰:

将API Gateway纳入Service Mesh体系

理由:要让API Gateway可以使用sidecar,要让这个和API Gateway一起部署的siecar可以工作于Service Mesh体系,那么最简单的办法,就是将API Gateway连同它的sidecar,一起融入Service Mesh体系:

gateway-4_hua89d7b6e5f4128b724dda44ee60b9968_47456_b24cbdbab942760b63a7bacc0f301af7.png

此时,API Gateway扮演一个普通服务的角色,运行于Service Mesh体系内,自然可以复用Service Mesh的所有功能。

k8s带来的影响

考虑到如果Service Mesh是运行在k8s上时,典型如Istio/Conduit,那么事情会稍微复杂一点:因为k8s下会有个外部流量如何进入k8s的问题。我们需要为此引入类似Ingress的组件:

gateway-5_hua0b4b878a6fc2a73e78eb261a335949a_53020_922cc93c3d310840c4fecd789d918bbf.png

k8s下的另类方式

仔细想了一下,理论上还存在另外一种的方式,貌似有些另类:

  • API Gateway体系继续独立于Service Mesh体系之外
  • 在Service Mesh体系内为API Gateway部署特殊的sidecar,专门用于转发南北向流量

如下图所示:

gateway-6_huf3875207f15630f1849985d277d4c690_48209_24ee7ab38f3afc19cfbfc3cefb4e267a.png

此时的sidecar,不再和使用者在一起,也就是不是"local"。部署模型上和正规的sidecar差别很大。

追求极致性能的方式

如果特别介意Sidecar引入之后造成的性能下降,也可以考虑下面的方式:

gateway-7_hu590fdb4678d196f44e79b31d28050516_51813_0bc0398c5a48877eeb0a9180906d4fff.png
  • 直接在Sidecar的基础上做开发和扩展
  • 目标是将Gateway的功能和Sidecar的功能合二为一
  • 这样可以减少一次gateway和sidecar之间的远程调用

这个方式个人不建议,因为基本又退回侵入式框架的模式,除非对性能有非常高甚至堪称极致的需求(比如单机超过10万/20万QPS),否则感觉没有必要。

权衡各个方案,个人意见,下面这个方案比较均衡:

gateway-5_hua0b4b878a6fc2a73e78eb261a335949a_53020_922cc93c3d310840c4fecd789d918bbf.png

主要考虑如下:

  1. 可以直接重用sidecar

    • 开发工作量少很多
    • Gateway职责清晰
  2. 编程语言的考虑

    • 目前Istio中的sidecar是Envoy,基于c++,Conduit中的是Rust语言
    • 这两个语言开发难度,尤其是客户二次开发或者扩展的难度都非常大
    • gateway最好还是用Golang或者Java开发会比较合适
    • 尤其是Java,普通用户的接受度应该会更高

这个gateway可以全新编写,或者找个现成的gateway产品修改。考虑到gateway的工作模式主要是请求转发,最适合响应式编程,这里有很多发挥的空间。

讨论和反馈

TBD:等收集后整理更新

有兴趣的朋友,请联系我的微信,加入DreamMesh内部讨论群。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK