微服务近⼏年⾮常⽕,围绕微服务的技术⽣态也⽐较多,⽐如微服务⽹关、Docker、 Kubernetes等,最近也在了解这块,所以写了这篇文章记录下。
API网关简图:
![1d825ce0ca89100a6cfa5b462d21f84a.jpeg](https://i-blog.csdnimg.cn/blog_migrate/a1da9f98debaa138e881f14a3f1823ea.jpeg)
一:API⽹关基础
1.1 什么是API⽹关
API⽹关是⼀个服务器,是系统的唯⼀⼊⼝。 从⾯向对象设计的⻆度看,它与外观模式类似。
API⽹关封装了系统内部架构,为每个客户端提供⼀个定制的API。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、协议转换、限流熔断、静态响应处理。
API⽹关⽅式的核⼼要点是,所有的客户端和消费端都通过统⼀的⽹关接⼊微服务,在⽹关层处理所有的⾮业务功 能。通常,⽹关也是提供REST/HTTP的访问API。
1.2 ⽹关的主要功能
微服务⽹关作为微服务后端服务的统⼀⼊⼝,它可以统筹管理后端服务,主要分为数据平⾯和控制平⾯:
数据平⾯主要功能是接⼊⽤户的HTTP请求和微服务被拆分后的聚合。使⽤微服务⽹关统⼀对外暴露后端服务 的API和契约,路由和过滤功能正是⽹关的核⼼能⼒模块。另外,微服务⽹关可以实现拦截机制和专注跨横切 ⾯的功能,包括协议转换、安全认证、熔断限流、灰度发布、⽇志管理、流量监控等。
控制平⾯主要功能是对后端服务做统⼀的管控和配置管理。例如,可以控制⽹关的弹性伸缩;可以统⼀下发配 置;可以对⽹关服务添加标签;可以在微服务⽹关上通过配置Swagger功能统⼀将后端服务的API契约暴露给 使⽤⽅,完成⽂档服务,提⾼⼯作效率和降低沟通成本。
![e87e8650587360869215e35b46d95caa.jpeg](https://i-blog.csdnimg.cn/blog_migrate/d9f082eb2521a4fb07158d2bffefab76.jpeg)
路由功能:路由是微服务⽹关的核⼼能⼒。通过路由功能微服务⽹关可以将请求转发到⽬标微服务。在微服务 架构中,⽹关可以结合注册中⼼的动态服务发现,实现对后端服务的发现,调⽤⽅只需要知道⽹关对外暴露的 服务API就可以透明地访问后端微服务。
负载均衡:API⽹关结合负载均衡技术,利⽤Eureka或者Consul等服务发现⼯具,通过轮询、指定权重、IP地 址哈希等机制实现下游服务的负载均衡。
统⼀鉴权:⼀般⽽⾔,⽆论对内⽹还是外⽹的接⼝都需要做⽤户身份认证,⽽⽤户认证在⼀些规模较⼤的系统 中都会采⽤统⼀的单点登录(Single Sign On)系统,如果每个微服务都要对接单点登录系统,那么显然⽐较 浪费资源且开发效率低。API⽹关是统⼀管理安全性的绝佳场所,可以将认证的部分抽取到⽹关层,微服务系 统⽆须关注认证的逻辑,只关注⾃身业务即可。
协议转换:API⽹关的⼀⼤作⽤在于构建异构系统,API⽹关作为单⼀⼊⼝,通过协议转换整合后台基于 REST、AMQP、Dubbo等不同⻛格和实现技术的微服务,⾯向Web Mobile、开放平台等特定客户端提供统⼀ 服务。
指标监控:⽹关可以统计后端服务的请求次数,并且可以实时地更新当前的流量健康状态,可以对URL粒度的 服务进⾏延迟统计,也可以使⽤Hystrix Dashboard查看后端服务的流量状态及是否有熔断发⽣。
限流熔断:在某些场景下需要控制客户端的访问次数和访问频率,⼀些⾼并发系统有时还会有限流的需求。在 ⽹关上可以配置⼀个阈值,当请求数超过阈值时就直接返回错误⽽不继续访问后台服务。当出现流量洪峰或者 后端服务出现延迟或故障时,⽹关能够主动进⾏熔断,保护后端服务,并保持前端⽤户体验良好。
⿊⽩名单:微服务⽹关可以使⽤系统⿊名单,过滤HTTP请求特征,拦截异常客户端的请求,例如DDoS攻击 等侵蚀带宽或资源迫使服务中断等⾏为,可以在⽹关层⾯进⾏拦截过滤。⽐较常⻅的拦截策略是根据IP地址增 加⿊名单。在存在鉴权管理的路由服务中可以通过设置⽩名单跳过鉴权管理⽽直接访问后端服务资源。
灰度发布:微服务⽹关可以根据HTTP请求中的特殊标记和后端服务列表元数据标识进⾏流量控制,实现在⽤ 户⽆感知的情况下完成灰度发布。
流量染⾊:和灰度发布的原理相似,⽹关可以根据HTTP请求的Host、Head、Agent等标识对请求进⾏染⾊, 有了⽹关的流量染⾊功能,我们可以对服务后续的调⽤链路进⾏跟踪,对服务延迟及服务运⾏状况进⾏进⼀步 的链路分析。
⽂档中⼼:⽹关结合Swagger,可以将后端的微服务暴露给⽹关,⽹关作为统⼀的⼊⼝给接⼝的使⽤⽅提供查 看后端服务的API规范,不需要知道每⼀个后端微服务的Swagger地址,这样⽹关起到了对后端API聚合的效 果。
⽇志审计:微服务⽹关可以作为统⼀的⽇志记录和收集器,对服务URL粒度的⽇志请求信息和响应信息进⾏拦 截。
二:API⽹关选型
2.1 常⽤API⽹关
先简单看⼀下市⾯上常⽤的API⽹关:
![5958b805ba187f5b7a1c3a84655d3871.jpeg](https://i-blog.csdnimg.cn/blog_migrate/5462d2677340a31c0144e429f11f13bb.jpeg)
2.2 Nginx
Nginx是⼀个⾼性能的HTTP和反向代理服务器。Nginx⼀⽅⾯可以做反向代理,另外⼀⽅⾯可以做静态资源服务 器,接⼝使⽤Lua动态语⾔可以完成灵活的定制功能。
Nginx 在启动后,会有⼀个 Master 进程和多个 Worker 进程,Master 进程和 Worker 进程之间是通过进程间通信 进⾏交互的,如图所示。Worker ⼯作进程的阻塞点是在像 select()、epoll_wait() 等这样的 I/O 多路复⽤函数调⽤ 处,以等待发⽣数据可读 / 写事件。Nginx 采⽤了异步⾮阻塞的⽅式来处理请求,也就是说,Nginx 是可以同时处 理成千上万个请求的。
2.3 Zuul
Zuul 是 Netflix 开源的⼀个API⽹关组件,它可以和 Eureka、Ribbon、Hystrix 等组件配合使⽤。社区活跃,融合 于 SpringCloud 完整⽣态,是构建微服务体系前置⽹关服务的最佳选型之⼀。
Zuul 的核⼼是⼀系列的过滤器,这些过滤器可以完成以下功能:
统⼀鉴权 + 动态路由 + 负载均衡 + 压⼒测试
审查与监控:与边缘位置追踪有意义的数据和统计结果,从⽽带来精确的⽣产视图。
多区域弹性:跨越 AWS Region 进⾏请求路由,旨在实现 ELB(Elastic Load Balancing,弹性负载均衡)使 ⽤的多样化,以及让系统的边缘更贴近系统的使⽤者。
Zuul ⽬前有两个⼤的版本:Zuul1 和 Zuul2
Zuul1 是基于 Servlet 框架构建,如图所示,采⽤的是阻塞和多线程⽅式,即⼀个线程处理⼀次连接请求,这种⽅ 式在内部延迟严重、设备故障较多情况下会引起存活的连接增多和线程增加的情况发⽣。
![5753d46e294af3fab1daedc830dd582c.jpeg](https://i-blog.csdnimg.cn/blog_migrate/6f7b430ff5decd8fbabd98e12064a0b6.jpeg)
Netflix 发布的 Zuul2 有重⼤的更新,它运⾏在异步和⽆阻塞框架上,每个 CPU 核⼀个线程,处理所有的请求和响 应,请求和响应的⽣命周期是通过事件和回调来处理的,这种⽅式减少了线程数量,因此开销较⼩。
![ec77947e698cdffab7e2e6a27d61c1b8.jpeg](https://i-blog.csdnimg.cn/blog_migrate/0296f779c53492784e61f8a2d28eddd4.jpeg)
2.4 Spring Cloud GetWay
Spring Cloud Gateway 是Spring Cloud的⼀个全新的API⽹关项⽬,⽬的是为了替换掉Zuul1,它基于Spring5.0 + SpringBoot2.0 + WebFlux(基于⾼性能的Reactor模式响应式通信框架Netty,异步⾮阻塞模型)等技术开发,性 能⾼于Zuul,官⽅测试,Spring Cloud GateWay是Zuul的1.6倍,旨在为微服务架构提供⼀种简单有效的统⼀的 API路由管理⽅式。
Spring Cloud Gateway可以与Spring Cloud Discovery Client(如Eureka)、Ribbon、Hystrix等组件配合使⽤, 实现路由转发、负载均衡、熔断、鉴权、路径重写、⽇志监控等,并且Gateway还内置了限流过滤器,实现了限 流的功能。
![67152263359f553e811b1d6a7169acb9.jpeg](https://i-blog.csdnimg.cn/blog_migrate/5a5d9929b5b818aee54a541cb0c6b01e.jpeg)
2.5 Kong
Kong是⼀款基于OpenResty(Nginx + Lua模块)编写的⾼可⽤、易扩展的,由Mashape公司开源的API Gateway 项⽬。Kong是基于NGINX和Apache Cassandra或PostgreSQL构建的,能提供易于使⽤的RESTful API来操作和 配置API管理系统,所以它可以⽔平扩展多个Kong服务器,通过前置的负载均衡配置把请求均匀地分发到各个 Server,来应对⼤批量的⽹络请求。
![1fdeb3f7f251fee40c916fb3aad1b385.jpeg](https://i-blog.csdnimg.cn/blog_migrate/0df36c99ddfd613de10ebbeb07a82060.jpeg)
2.5.1 Kong主要有三个组件:
Kong Server :基于Nginx的服务器,⽤来接收API请求。
Apache Cassandra/PostgreSQL :⽤来存储操作数据。
Kong dashboard:官⽅推荐UI管理⼯具,也可以使⽤ restfull ⽅式管理admin api。
Kong采⽤插件机制进⾏功能定制,插件集(可以是0或N个)在API请求响应循环的⽣命周期中被执⾏。插件使⽤ Lua编写,⽬前已有⼏个基础功能:HTTP基本认证、密钥认证、CORS(Cross-Origin Resource Sharing,跨域 资源共享)、TCP、UDP、⽂件⽇志、API请求限流、请求转发以及Nginx监控。
![d14ff48480dd4ecd084d6589fd17e5c9.jpeg](https://i-blog.csdnimg.cn/blog_migrate/cb442e09ab03e4591df7e2f297fa1fd5.jpeg)
2.5.2 Kong⽹关具有以下的特性:
可扩展性: 通过简单地添加更多的服务器,可以轻松地进⾏横向扩展,这意味着您的平台可以在⼀个较低负载的情况下处理任何请求; 模块化: 可以通过添加新的插件进⾏扩展,这些插件可以通过RESTful Admin API轻松配置;
在任何基础架构上运⾏: Kong⽹关可以在任何地⽅都能运⾏。您可以在云或内部⽹络环境中部署Kong,包括 单个或多个数据中⼼设置,以及public,private 或invite-only APIs。
2.6 Traefik
Traefɪk 是⼀个为了让部署微服务更加便捷⽽诞⽣的现代HTTP反向代理、负载均衡⼯具。 它⽀持多种后台 (Docker, Swarm, Kubernetes, Marathon, Mesos, Consul, Etcd, Zookeeper, BoltDB, Rest API, file…) 来⾃动化、动态的应 ⽤它的配置⽂件设置。
![f22ef5bb41dd189374e1d2d8ee446756.jpeg](https://i-blog.csdnimg.cn/blog_migrate/9a1d45c8b4e31ba3e2df7f6ee03c032e.jpeg)
重要特性:
它⾮常快,⽆需安装其他依赖,通过Go语⾔编写的单⼀可执⾏⽂件;
多种后台⽀持:Docker, Swarm, Kubernetes, Marathon, Mesos, Consul, Etcd;
⽀持⽀持Rest API、Websocket、HTTP/2、Docker镜像;
监听后台变化进⽽⾃动化应⽤新的配置⽂件设置;
配置⽂件热更新,⽆需重启进程; 后端断路器、负载均衡、容错机制;
清爽的前端⻚⾯,可监控服务指标。
三:API⽹关对⽐
上⾯是⽹关对⽐截图,偷个懒,⼤家主要关注Kong、Traefik和Zuul即可:
从开源社区活跃度来看,⽆疑是Kong和Traefik较好;
从成熟度来看,较好的是Kong、Tyk、Traefik;
从性能来看,Kong要⽐其他⼏个领先⼀些;
从架构优势的扩展性来看,Kong、Tyk有丰富的插件,Ambassador也有插件但不多,⽽Zuul是完全需要⾃ 研,但Zuul由于与Spring Cloud深度集成,使⽤度也很⾼,近年来Istio服务⽹格的流⾏,Ambassador因为能 够和Istio⽆缝集成也是相当⼤的优势。
下⾯是其它⽹友的思考结论,可供参考:
性能:Nginx+Lua形式必然是⾼于Java语⾔实现的⽹关的,Java技术栈⾥⾯Zuul1.0是基于Servlet实现的,剩 下都是基于webflux实现,性能是⾼于基于Servlet实现的。在性能⽅⾯我觉得选择⽹关可能不算那么重要,多 加⼏台机器就可以搞定。
可维护性和扩展性:Nginx+Lua这个组合掌握的⼈不算多,如果团队有⼤神,⼤佬们就随意了,当没看到这段 话,对于⼀般团队来说的话,选择⾃⼰团队擅⻓的语⾔更重要。Java技术栈下的3种⽹关,对于Zuul和Spring Cloud Getway需要或多或少要搞⼀些集成和配置⻚⾯来维护,但是对于Soul我就⽆脑看看⽂章,需要哪个搬 哪个好了,尤其是可以⽆脑对接Dubbo美滋滋,此外Soul2.0以后版本可以摆脱ZK,在我⼼⾥再⽆诟病,我就 喜欢⽆脑操作。
⾼可⽤:对于⽹关⾼可⽤基本都是统⼀的策略都是采⽤多机器部署的⽅式,前⾯挂⼀个负载,对于⽽外需要⽤ 的⼀些组件⼤家注意⼀下。
三:基于Traefik⾃研的微服务⽹关
3.1 技术栈选型
Traefik:⼀款开源的反向代理与负载均衡⼯具,它最⼤的优点是能够与常⻅的微服务系统直接整合,可以实 现⾃动化动态配置。traefik较为轻量,⾮常易于使⽤和设置,性能⽐较好,已在全球范围内⽤于⽣产环境。
Etcd:⼀个Go⾔编写的分布式、⾼可⽤的⼀致性键值存储系统,⽤于提供可靠的分布式键值存储、配置共享 和服务发现等功能。(更多内容可以查看⽂章 肝了⼀个⽉的ETCD,从Raft原理到实践 )
Go:并发能⼒强,性能媲美C,处理能⼒是PHP的4倍,效率⾼,语法简单,易上⼿,开发效率接近PHP。
![e2db6e8217721b2530c38fe639f3d351.jpeg](https://i-blog.csdnimg.cn/blog_migrate/633eda60ae46001390954184c36848e7.jpeg)
3.2 ⽹关框架
整个⽹关框架分为3块:
⽹关后台(hal-fe和hal-admin):⽤于应⽤、服务和插件的配置,然后将配置信息发布到ETCD;
Traefik:读取ETCD配置,根据配置信息对请求进⾏路由分发,如果需要鉴权,会直接通过hal-agent模块进 ⾏统⼀鉴权。鉴权完毕后,如果是Http请求,直接打到下游服务,如果是Grpc和Thrift协议,会通过halproxy模块进⾏协议转换。
协议转换模块:读取ETCD配置,对Traefik分发过来的请求,进⾏Grpc和Thrift协议转换(更多内容可以查看 ⽂章 RPC框架:从原理到选型,⼀⽂带你搞懂RPC),并通过服务发现机制,获取服务下游机器,并通过负载 均衡,将转换后的数据打到下游服务机器
![309cb2ea462b4f7e6271931de92211c6.jpeg](https://i-blog.csdnimg.cn/blog_migrate/7cceb74953fc75be32195fdab4ce514c.jpeg)
3.3 ⽹关后台
主要由3⼤模块组成:
应⽤:主要包括应⽤名、域名、路径前缀、所属组、状态等,⽐如印度海外商城、印度社区;
服务:主要包括服务名、注册⽅式、协议类型、所属组、状态等,⽐如评论服务、地址服务、搜索服务。
插件:主要包括插件名称、插件类型、插件属性配置等,⽐如路径前缀替换插件、鉴权插件。
![225f7a37c176e61715aa44ed41004c76.jpeg](https://i-blog.csdnimg.cn/blog_migrate/915b254b1924be6c96e03236491442ec.jpeg)
⼀个应⽤只能绑定⼀个服务,但是可以绑定多个插件。 通过后台完成⽹关配置后,将这些配置信息⽣成Config⽂ 件,发布到ETCD中,Config⽂件需要遵循严格的数据格式,⽐如Traefix配置需要遵循官⽅的⽂件配置格式,才能 被Traefik识别。
![65554b47b7dab1ec237321530f4ccd63.jpeg](https://i-blog.csdnimg.cn/blog_migrate/02e87c2baa144ba4b055c8c81aae2daa.jpeg)
3.4 协议转换模块
hal-proxy模块是整个微服务⽹关最复杂,也是技术含量最⾼的模块,所以给⼤家详细讲解⼀下。
3.4.1 问题引⼊
在讲这个模块前,我们先看下⾯⼏个问题:
当请求从上游的trafik过来时,需要知道访问下游的机器IP和端⼝,才能将请求发送给下游,这些机器如何获 取呢?
有了机器后,我们需要和下游机器建⽴连接,如果连接⽤⼀次就直接释放,肯定对服务会造成很⼤的压⼒,这 就需要引⼊Client缓存池,那这个Client缓存池我们⼜该如何实现呢?
最后就是需要对协议进⾏转换,因为不同的下游服务,⽀持的协议类型是不⼀样的,这个⽹关⼜是如何动态⽀ 持的呢?
![99c5ab8eee35e157ddeb420956a0a9dd.jpeg](https://i-blog.csdnimg.cn/blog_migrate/a6b49735372e5c12bdcecc14a6db2791.jpeg)
3.4.2 实现原理
![69bef3fcf0a2ddb02fdccd1f6a4af201.jpeg](https://i-blog.csdnimg.cn/blog_migrate/48fb9dde7671745e45d7c4173e707e77.jpeg)
我们还是先看⼀下hal-proxy内部有哪些模块,⾸先是Resolver模块,这个模块的是什么作⽤呢?这⾥我简单介绍 ⼀下,⽬前公司内部通过服务获取到机器列表的⽅式有多种,⽐如MIS平台、服务树等,也就是有的是通过平台配 置的,有的是直接挂在服务树下,⽆论哪种⽅式,我们都通过服务名,通过⼀定的⽅式,找到该服务下⾯所有的主 机。
所以Resolver模块的作⽤,其实就是通过服务名,找到该服务下的所有机器的IP和服务端⼝,然后持久化到内存 中,并定时更新。
协议模块就是⽀持不同的协议转换,每个协议类型的转换,都需要单独实现,这些协议转换,⽆⾮就是先通过机器 IP和端⼝初始化Client,然后再将数据进⾏转换后,直接发送到下游的机器。
最后就是连接池,之前我们其实也⽤到go⾃带的pool来做,但是当对pool数据进⾏更新时,需要加锁,所以性能⼀ 直起不来,后来改成了环形队列,然后对数据的操作全部通过原⼦操作⽅式,就实现了⽆锁操作,⼤⼤提⾼的并发 性能。
3.4.3 实现逻辑
这个是hal-proxy的逻辑实现图,包含所有核⼼对象的交互⽅式.
![6af7edcce3e74d2095b85eb8bbd40f3f.jpeg](https://i-blog.csdnimg.cn/blog_migrate/96daadc9b3f2c147353ba36fbce829cd.jpeg)
作者:小蚂蚁技术
链接:https://juejin.cn/post/7203266679600676922
4.手把手教新人调优
5.上班摸鱼学习法
6.阻塞队列yyds
7.线程与锁