kong

Kong很好玩,很好

View project on GitHub

使用Kong在生产环境替代Eureka+Zuul+Hystrix

在《基于kong的微服务解决方案》里边,提到了Eureka和Zuul的替代处理方案,建峰建议我把这部分写的细一些。

虽然众所周知,不过我还是先简单的把这几个spring cloud的组件简单说一下,主要是为了明确讨论范围和后文指代明确。

  • Eureka

Eureka提供了“服务注册”和“服务发现”两个核心功能。服务注册,就是当有一个服务的实例启动时候,比如order.jar它实现了/order/*下边的各种REST端点(endpoint)。这里我避免使用“服务”这个字眼,因为在不同的环境和语境里,它有不同的具体指代,容易产生混淆。我用“部署单元”指一个具体可执行jar文件;用“端点”指具体的一个REST服务。当实例启动的时候,实例需要让它的调用方知道它的存在,所以它发一个请求给Eureka,说“我提供对所有/order/和它下边路径的服务,我的访问地址是http://xx.xx.xx.xx:port/order” 。Eureka记录了这个信息,然后在调用方需要一个可以提供/order/*的服务的时候,就返回一个服务提供者的路径。这个逻辑很简单清晰,也是被广泛接受的。Eureka实现的是服务注册与发现微服务模式

这里我们看下Eureka具体的实现,首先,它定义了一组REST,用于实例和它通信。可以参考这里。这里,除了“注册”之外,还有“注销”操作;另外,为了维护信息的有效性,还有心跳请求,以及增删改查等。

Eureka的存在,使得服务之间互相调用时候,可以通过服务名称来直接获取服务提供者(provider)。本质上是名字服务,就像dns。

  • Zuul

Zuul主要提供服务代理(gateway)和过滤器(filter)的功能。简单的说,有两个服务A和B,当A访问B的时候,有些功能是非业务功能(比如路由,根据/order/list或者/order/search把服务转向不同的服务提供者),这个时候,加入一个网关,功能在网关上实现,就会很好的分离控制逻辑和业务逻辑。我认可和尊崇微服务网关模式的内容。

过滤器,是在HTTP请求处理过程中,做一些非业务逻辑的处理,一个简单的例子是:需要把来源IP,翻译成具体物理的地址,GEOIP,这个时候就可以写个过滤器。过滤器很像AOP编程,通过拦截调用,插入一些代码。

  • Hystrix

Hystrix主要是提供“熔断”服务。Hystrix实现了熔断微服务设计模式。简单的例子是如果一个服务开始大量出错,这个时候调用方的请求应该不再发送或者被拦截,避免更多的错误产生和传递。


这个时候,两个服务之间访问,A访问B,过程就从A->B变成了:

  1. B到Eureka注册
  2. A去Eureka查询B的实例
  3. A把请求发送给网关GW
  4. GW经过一些过滤器,把请求转发给B
  5. 如果这个时候B出现需要熔断的场景(比如大量报错),A应该主动停止访问,或者GW拦截A对B的访问

回头来看eureka/zuul/hystrix的设计和实现,他们虽然实现了不同的设计模式,但是在功能上,他们本应该相辅相成的。当一个服务注册到eureka的时候,eureka除了记录这个服务提供者,还应该在zuul里边添加路由。另外在服务需要熔断的时候,首先需要判断什么符合熔断条件,然后处理如何熔断的问题。而条件的判断,和熔断的方式,应该是运行时候决定的。比如预制了“如果出现大量503错误,就停止发送请求”,但是实际中出现了很多500错误,熔断的方式可以是“降低服务访问速率”。而降低速率的实现,应该是在GW上。从相辅相成这个角度看,这三者多数时候应该搭配使用。不是很理解spring cloud在开始时候,为什么把这些分开实现,也许是为了“不同的微服务模式用不同的组件”吧,但是这样带来的实际使用中的繁琐。

如果这些还勉强可以接受的话,那么当spring cloud的这几大组件都用在kubernetes上的时候,冲突就更严重了。kubernetes重新界定了这些微服务模式“应该的样子”:)。个人觉得,因为kubernetes更好的从资源角度管理服务所用的资源(其实是用容器做的),而且支持多种编程语言,所以kubernetes被更多人接受了。这两个微服务领域的领军者各有套路,结果就是“在kubernetes上使用spring cloud”的人异常纠结:)进一步的纠结来自,一些springboot的东西,需要运行在非kubernetes的环境,但是有时候需要和kubernetes上的服务互相访问。

具体的几个话题:

  • 服务注册。springboot的应用,用“服务名”来标识服务。这个名字是写在spring的配置文件里。然后通过服务注册,比如注册到Eureka,然后后续访问,通过这个服务名来获取服务实例的信息。k8s也是用“服务名”来标示服务,注意这里k8s的服务和spring的服务相似但不尽相同。这个服务名也是写在k8s的部署描述文件里的。k8s是在创建实例的时候,修改service IP和docker IP,以及内部dns注册,来完成服务注册的。相应的,服务发现是通过访问service IP或者域名来处理。实践当中, 用域名访问要好一些。
  • 服务发现。spring是用服务名来查询服务实例的地址。k8s是通过内部域名来来发现服务提供者的。
  • 负载均衡。spring通过Eureka每次返回给调用方不同的服务提供方地址,来实现“客户端负载均衡”。k8s使用DNS轮询做负载均衡。
  • 路由。spring cloud用zuul,通过配置文件和过滤器实现路由的处理。k8s在集群内,通过上层的istio服务来实现服务间路由;通过ingress和egress实现进出集群的路由。
  • 灰度发布,蓝绿发布,精细路由,都是路由的具体功能,通过zuul和istio实现。
  • 熔断。spring用hystrix处理熔断;k8s还是借助上层的istio来实现。
  • 服务质量管理。这里我把服务质量管理具体一些,服务质量包括平均响应时间,错误类型和错误率,服务稳定度(上边两个指标是否均匀分布)。实际上,spring并没有很具体的处理这些指标,虽然在hystrix里有些涉及。k8s还是借助上层的istio来处理这些,而且这些的处理还很含糊…

这里多说一点,看起来,spring cloud在起步的时候,没有太考虑非java实现的服务的处理,这个情况现在成了他的最明显短板;但是超大量的java开发者,以及spring的影响力,使得使用spring cloud的人还是相当的可观,无论是互联网还是企业里。而k8s,初期这东西的定位是“容器部署”,是个调度软件;后来可能发现这个东西最适合的就是“微服务”,所以想把概念扭成“k8s是最好的微服务运行平台”,但是实际上在没有istio的时候,k8s的“服务”概念的抽象和“服务管理”的支持,是很含糊和底气不足的。所以后期赶快补了一个项目,istio,而且抽象出了service mesh的概念。我十分认可service mesh的这层抽象和其中的核心概念。但是看起来k8s初期没有想这么多…如果想了,也就直接一起做出来了。service mesh还是IBM先明确提出来,然后k8s社区快速跟进。这样导致实际是k8s+istio是k8s社区的完整的微服务解决方案。

因为“在kubernetes上使用spring cloud”和“混合使用非容器的spring cloud及容器平台”的使用者不是一个小的数目,我也一直在寻求比较简单、合理、有效、直观的解决方案。直到我发现了kong。


简单介绍一下kong。kong是个开源的API网关,可能是最流行的同类型开源产品,在github上有17K多的star。技术上,kong是基于openresty的。而openresty可以简单认为是nginx+lua。所以大家可以认为,kong就是可编程的nginx,编程的方法是用lua。

kong使用了非常简单的一个模型,其实就是nginx的proxy模型,主要是引入了插件和DAO。插件容易理解,kong把一个http请求处理的过程包装成一系列插件的链式调用。DAO也很清晰,就是所有的配置,都是存在数据库里边的;但是实际访问,都是访问内存里的内容,这个内存到数据库的映射,就是DAO。这个概念就像hibernate。

需要强调的是,kong有几个优点:

  • 基于nginx,底层非常可靠;而且性能是有目共睹的好。可以说性能和可靠性德才兼备。
  • 插件,简单,但是带来了非常好的灵活性
  • DAO层,其实包括其他的一些代码实现(kong的代码质量很好),以及lua的高性能,为kong带来了非常好的性能。性能有多好呢?我们落地的项目,一般要求是网关的延迟都在10ms以内,这样一个10次微服务的调用,整体网关性能损耗也不过100ms。

kong在核心功能上很简单,但是插件可以实现强大的扩展性和很复杂的功能。


回到主题上,我的目标是解决“在kubernetes上使用spring cloud”和“混合使用非容器的spring cloud及容器平台”里边的服务注册、发现、路由、质量管理、熔断、蓝绿分布、精细路由等核心微服务治理的功能;另外也希望可以提升服务可视化程度。这个方案应该直接、简单;容易理解,容易实施;可以支撑大规模生产使用;对于已有的程序应该零改造,对于使用环境应该全兼容(容器、虚拟机、物理机)。对于网络,应该是只要3层通就能用。

在使用kong做这个方案的时候,需要提前介绍一个概念,“服务”,在这个方案里,服务不同于spring cloud的服务,也不同于k8s的服务,也不同于kong的service。一句话说,一个REST请求的路径部分,就是一个服务。所以如果部署了一个order.jar,他里边实现了/order和/order/car和/order/bike,那么这里是3个服务,我们叫做order, order-car, order-bike。之所以这样,我给出几个理由:

  • 服务的定义不再依赖配置文件的描述性名字,而就是路径本身。REST本身就强调路径和操作的自然语义功能,无论是用application.proporties还是用yaml定义k8s的service,我觉得都不够直接;这种不直接导致为了自然语义和代码的关联,有时候需要用强制性的命名规则和管理手段实现。
  • 服务的管理粒度。每个uri都对应一个服务,可以实现细粒度的服务管理,包括质量管理,以及可视化等
  • 服务和路由的关联更简单直接。每个服务可以有多个路由,也包括动态路由。一个uri加上特定的信息,比如http header的user-agent,就可以形成一个路由。比如“firefox访问/order/car”

最后介绍一下如何实现的,很简单:

  • 所有的请求都通过代理网关。这样,服务的访问就不用再关心域名/IP和端口了,只要给出要访问的uri就可以。从一个uri路由到具体的哪个服务提供实例,这个事情网关来判断。换言之,服务发现是通过网关实现的
  • 服务注册的同时,实现路由的设定。比如“IP xx.xx.xx.xx提供对/order/car的服务”,那么添加一个服务,添加一个路由,添加一个upstream+target。这个过程就像手工修改nginx配置一样;其实实现上也是差不多的
  • 对于一个部署单元里多个endpoint,每个都是一个服务,这些子服务,是自动发现和注册的。比如服务注册时候,注册了“xx.xx.xx.xx提供/order/*服务“,那么当一个请求/order/car到来的时候,自动创建这个“xx.xx.xx.xx提供/order/car”这个服务
  • Eureka的注册如上。注销则是不必要的,因为负载均衡器会判断后端是否有效,无效之后自动从集群里删除;心跳也不用了,负载均衡和后端有定期的探测决定后端是否有效
  • Zuul的基本功能,Kong都有实现;都是编程,所以功能没有什么做不到的。基本功能而言,Kong比Zuul丰富得多。kong的已有插件,可以自己搜索,很多很实用的。另外kong比zuul的性能和可靠性都有不小的提升。毕竟一个是nginx,一个是Java。流量稍微大一些,Zuul和Nginx就天壤之别了
  • Hystrix的各种熔断,kong都有对等的。而且kong支持REST修改配置,搭配使用promethus,可以实现非常好的服务质量管理。比如“当连续出现平均访问时长超过200ms的情况2分钟,那么限制后端的访问速度降低50%”
  • 把网关布置在非容器环境和容器网络之间,可以实现他们之间服务的互访
  • 通过kong的promethus插件,实现服务质量的监控,并且通过alert rule实现服务质量的管理(熔断)
  • 通过kong的syslog和elasticsearch/kibana集成,实现全网数据的汇总和分析;通过kibana插件实现了服务间流量可视化
  • 通过kong的opentracing插件和zipkin/jaeger集成,实现服务间调用链的记录

而所有这些,都不用修改已有程序的代码。针对于dubbo的poc正在进行,逻辑上和实际上,跟springboot基本一样。

可能的几个常见问题的问与答:

  • 这个部署是不是sidecar?实际上这取决于kong网关的部署位置,每个服务实例一个网关,还是每个主机一个网关,还是多个主机一个网关,这个事情最主要的是性能。在性能可接受情况下,我认同越少网关越少。
  • 这是service mesh么?从功能描述上看,是的。
  • 需要修改程序代码适应这个方案么?不需要,服务走代理这个事情,不用改代码
  • 还兼容原来的基于服务名或者域名的服务路由么?兼容
  • 蓝绿发布、金丝雀发布这些,有开箱即用的么?有
  • 访问控制都支持哪些认证方式?常用的都有插件可以直接用
  • 支持容器化部署么?支持,无差别
  • 除了支持k8s/虚拟机/物理机,还支持其他的容器平台比如就是用docker本身?支持,这个方案唯一的依赖是3层网络可达;即使网络不可达,只要网关可以部署在跨两个网络的位置,也是可以的
  • 支持非k8s的非java部署么,比如虚拟机运行nodejs?支持,但是需要代码或者启动脚本实现服务注册接口,其实就是启动时候发送给网关一个REST请求,描述“xx.xx.xx.xx地址提供针对某个uri的服务”

先写这么多,感兴趣的可以扫二维码加我然后一起讨论。konghq.png