思考并回答以下问题:
实践案例:自己动手实现一个网关
API网关最基础的功能是对请求的路由转发,根据配置的转发规则将请求动态地转发到指定的服务实例。动态是指与服务发现结合,如Consul、Zookeeper等组件,本书第6章服务注册与发现中已详细讲解过了。本节将会基于Go语言实现一个简易的API网关。
API网关根据客户端HTTP请求,动态查询注册中心的服务实例,通过反向代理实现对后台服务的调用。
这里我们简单介绍一下正向代理和反向代理。
正向代理是在用户端进行的代理。比如需要访问某些网站,我们可能需要使用代理服务器,代理是在我们的用户浏览器端进行设置的(并不是在远端的服务器设置)。浏览器先访问代理地址,代理服务器转发请求,并在最后将请求结果原路返回。反向代理服务器拿到Request以后,把它们转发给内网的服务器,而那些发送Request给代理的client并不知道这个内网的存在。反向代理可以在任意多个服务器需要被同一个IP同时访问的时候使用,服务网关的代理模式属于反向代理。
API网关会为符合规则的请求转发到对应的后端服务。这里的规则可以有很多种,如HTTP请求的资源路径、请求的方法、请求的头部和请求的参数等等。这里我们以最简单的请求路径方式为例,规则为:/{serviceName}/#
。即:路径第一部分为注册中心服务实例名称,其余部分为服务实例的RESTful路径。如:1
/string-service/op/Diff/abc/bcd
其中:
- string-service为服务名称;
/op/Diff/abc/bcd
为字符串服务提供的接口。
实现思路
我们要实现的网关应该遵循如下的运行流程:
客户端向网关发起请求,网关解析请求资源路径中的信息,根据服务名称查询注册中心的服务实例,然后使用反向代理技术把客户端请求转发至后端真实的服务实例,请求执行完毕后,再把响应信息返回客户端。
图9-3 自定义网关的架构图
我们设计实现的网关需要能做到下面这些事:
(1)HTTP请求的规则遵循:/{serviceName}/#
,否则不予通过。
(2)使用Go提供的反向代理包httputil.ReverseProxy
实现一个简单的反向代理,它能够对请求实现负载均衡,把请求随机地发送给集群中的某一服务实例。
(3)使用Consul客户端API动态查询服务实例。
编写反向代理方法
反向代理需要用到NewReverseProxy方法,我们先创建目录gateway,然后新建main.go。NewReverseProxy方法接受两个参数:Consul客户端对象和日志记录工具,返回反向代理对象。该方法的实现过程如下所述:
(1)获取请求路径,检查是否符合规则,不符合规则直接返回。
(2)解析请求路径,获取服务名称(第一个部分为服务名称)。
(3)使用Consul客户端查询服务实例,若查询到结果,则随机选择一个作为目标实例。
(4)根据选定的目标实例,设置反向代理参数:Schema、Host和Path。
具体实现代码如下所示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42// NewReverseProxy 创建反向代理处理方法
func NewReverseProxy(client *api.Client, logger log.Logger) *httputil.ReverseProxy {
//创建Director
director := func(req *http.Request) {
//查询原始请求路径
reqPath := req.URL.Path
if reqPath == "" {
return
}
//按照分隔符'/'对路径进行分解,获取服务名称serviceName
pathArray := strings.Split(reqPath, "/")
serviceName := pathArray[1]
//调用consul api查询serviceName的服务实例列表
result, _, err := client.Catalog().Service(serviceName, "", nil)
if err != nil {
logger.Log("ReverseProxy failed", "query service instance error", err.Error())
return
}
if len(result) == 0 {
logger.Log("ReverseProxy failed", "no such service instance", serviceName)
return
}
//重新组织请求路径,去掉服务名称部分
destPath := strings.Join(pathArray[2:], "/")
//随机选择一个服务实例
tgt := result[rand.Int()%len(result)]
logger.Log("service id", tgt.ServiceID)
//设置代理服务地址信息
req.URL.Scheme = "http"
req.URL.Host = fmt.Sprintf("%s:%d", tgt.ServiceAddress, tgt.ServicePort)
req.URL.Path = "/" + destPath
}
return &httputil.ReverseProxy{Director: director}
}
在上述代码中,反向转发处理时,我们只是根据请求中的服务名直接转发;如果我们需要对外屏蔽服务名,这样的路由转发规则显然是不够的。我们需要增加路由配置的多样性,可以抽出路由配置层,根据指定的规则进行路由转发,如配置名称、头部的信息、请求的参数和请求的body等转发到指定的服务。
编写入口方法
main方法的主要任务是创建Consul连接对象、创建日志记录对象和开启反向代理HTTP服务。整个过程与前面章节创建字符串服务类似,直接贴代码(为了测试方便,我们直接指定了Consul服务地址信息),具体实现代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61package main
import (
"flag"
"fmt"
"github.com/go-kit/kit/log"
"github.com/hashicorp/consul/api"
"math/rand"
"net/http"
"net/http/httputil"
"os"
"os/signal"
"strings"
"syscall"
)
func main() {
// 创建环境变量
var (
consulHost = flag.String("consul.host", "114.67.98.210", "consul server ip address")
consulPort = flag.String("consul.port", "8500", "consul server port")
)
flag.Parse()
//创建日志组件
var logger log.Logger
{
logger = log.NewLogfmtLogger(os.Stderr)
logger = log.With(logger, "ts", log.DefaultTimestampUTC)
logger = log.With(logger, "caller", log.DefaultCaller)
}
// 创建consul api客户端
consulConfig := api.DefaultConfig()
consulConfig.Address = "http://" + *consulHost + ":" + *consulPort
consulClient, err := api.NewClient(consulConfig)
if err != nil {
logger.Log("err", err)
os.Exit(1)
}
//创建反向代理
proxy := NewReverseProxy(consulClient, logger)
errc := make(chan error)
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
errc <- fmt.Errorf("%s", <-c)
}()
//开始监听
go func() {
logger.Log("transport", "HTTP", "addr", "9090")
errc <- http.ListenAndServe(":9090", proxy)
}()
// 开始运行,等待结束
logger.Log("exit", <-errc)
}
如上的代码实现,为了创建反向代理,需要先创建日志组件和Consul连接对象。反向代理处理器一般使用装饰者模式封装,如增加中间件Hystrix断路器、链路追踪Tracer(Zipkin、Jaeger)组件等。
运行
接下来我们启动字符串服务。为了测试负载均衡效果,我们启动了两个实例。注意需要使用不同的端口。运行代码如下:1
2./string-service/string-service -consul.host localhost -consul.port 8500 -service.host 127.0.0.1 -service.port 8000
./string-service/string-service -consul.host localhost -consul.port 8500 -service.host 127.0.0.1 -service.port 8002
再切换至目录gateway,执行go build
完成编译,然后启动网关服务,命令如下所示:1
2
3> ./gateway -consul.host localhost -consul.port 8500
> ts=2019-02-26T07:49:39.04680582 caller=main.go:54 transport=HTTP addr=9090
测试
在命令行请求String-service服务的字符串操作接口,请求如下:1
同时,在终端可以看到如下输出,说明多次请求访问了不同的服务实例:1
在本案例中,我们使用反向代理技术,结合注册中心Consul实现了简单的API网关。Go提供了反向代理工具包,使得整个实现过程比较简单。实际项目中使用的产品,如Zuul、Nginx等,还会包含限流、请求过滤和身份认证等功能。该网关仅仅实现了请求的代理,功能虽然简单,我们重点是要了解其内部运行过程,加深理解。
高可用服务网关:Kong
Kong是Mashape开源的高性能、高可用API网关和API服务管理层,它是一款基于 Nginx_ Lua模块开发的高可用服务网关,由于Kong是基于Nginx的,所以可以水平扩展.多个Kong服务器。通过前置的负载均衡配置把请求均匀地分发到各个Server,来应对大批量的网络请求,架构如图9-7所示。
图9-7 Kong整体架构图
Kong 主要有以下三个组件:
(1)KongServer:基于Nginx的服务器,用来接收API请求。
(2)Apache Cassandra/PostgreSQL:用来存储操作数据。
(3)Kongdashboard:官方推荐UI管理工具;当然,也可以使用RESTfull方式管理Admin API。
Kong采用插件机制进行功能定制,插件集(可以是0或N个)在API请求响应循环的生命周期中被执行。插件使用Lua语言编写,基础功能包括:HTTP基本认证、密钥认证、CORS (Cross-Origin Resource Sharing,跨域资源共享)、TCP、UDP、文件日志、APF请求限流、请求转发以及Nginx监控等。
我们来总结一下,Kong网关具有以下的特性:
(1)可扩展性:通过简单地添加更多的服务器,可以轻松地进行横向扩展,这意味着平台可以在一个较低负载的情况下处理任何请求。
(2)模块化:可以通过添加新的插件进行扩展,这些插件可以通过RESTfulAdmin API轻松配置。
(3)可运行在任何基础架构上:我们可以在云或内部网络环境中部署Kong,包括单个或多个数据中心设置。
为什么使用Kong
当我们决定对应用进行微服务改造时,应用客户端如何与微服务交互的问题也随之而来,毕竟服务数量的增加会直接导致部署授权、负载均衡、通信管理、分析和改变的难度增加。微服务网关所提供的访问限制、安全、流量控制、分析监控、日志、请求转发、合成和协议转换功能,可以让开发者解放出来,把精力集中在具体逻辑代码的开发上,而不是把时间花费在考虑如何解决应用和其他微服务链接的问题上。
在众多微服务网关框架中,Mashape开源的高性能高可用API网关和API服务管理层一Kong(基于Nginx)特点尤为突出,它可以通过插件扩展已有功能。这些插件(使用Lua编写)在API请求响应循环的生命周期中被执行。除此之外,Kong本身提供包括HTTP基本认证、密钥认证、CORS、TCP、UDP、文件日志、API请求限流、请求转发及Nginx监控等基本功能。
Kong中常用的术语介绍,这些术语会在下面的实践中经常用到,如下表9-2所示。
表9-2
Kong安装实践
【实例9-1】Docker方式安装Kong
docker-compose.yml中定义的镜像、依赖和参数如下所示:1
如上的配置中,docker-compose.yml会启动3个容器服务:Kong、konga和kong-database。这3个容器之间的通信需要增加network段,把容器放在同一个网段内,相关链接修改为容器名称来访问:1
docker network create kong-net
所启动的3个容器服务中除了Kong之外,konga是Kong的Dashboard,基于js的客户端管理工具,对外暴露的端口为8080;kong-database是Kong的数据库服务,存储配置信息,这里使用的是postgres。需要注意的是,在启动Kong容器之前,需要保持数据库的Docker容器为运行状态,并执行如下初始化数据库的操作:1
2
3
4
5docker run - -rm
-network=kong-net\
e "KONG-DATABASE=postgres"
-e. "KONG-PG-HOST=kong-database"
kong:latest kong migrations bootstrap
数据库初始化成功后,再次启动docker-compose.yml服务就可以了。我们看到Kong映射出多个端口,默认情况下,Kong监听的端口如下表9-3所示。
表9-3
本地访问8001端口,返回如上的结果,表示安装正确,可以正常使用 Kong。浏览器输入http://localhost:8080
访问Konga的管理界面(如图9-9所示),第一次登录使用需要创建管理员帐号和密码。
图9-9 Konga的管理界面
更多内容请读者参照官网的安装文档。至此,Kong以及管理工具都已安装完成,下面将会进入API Gateway的具体实践,包括通过创建服务、创建路由、安装插件等讲解。
创建服务
如我们在术语部分的介绍,服务是上游服务的抽象,可以是一个应用,或者具体某个接口。Kong提供了管理接口,我们可以通过请求8001管理接口直接创建,也可以通过安装的管理界面,实现的效果是一样的。
通过请求8001管理接口创建服务的代码如下:
图9-10 Kong Service
创建服务时,还可以设置其中的一些参数,如 Retries(重试次数)、Connect timeout(连接的超时时间)和 Write/Read timeout(读/写超时时间)等。
创建路由
创建好服务之后,我们需要创建具体的API路由。路由是请求的转发规则,根据Hostname和PATH,将请求转发,代码如下:1
2
3
4i-XPOST
urlhttp://localhost:8001/services/aoho-blog/routes
-data'hosts[]=blueskykong.com'\
-data'paths[]=/api/blog
如上,在aoho-blog中创建了一个访问/api/blog的路由,在管理界面可以看到相应的记录,如图9-11所示。
图9-11KongRoute
创建好路由之后,我们就可以访问/api/blog了,如图9-12所示。
图9-12访问Kong的路由接口
Kong默认通过8000端口处理代理的请求。成功的响应意味着Kong将htp//ocalost.800的请求转发到了配置的URL,并将响应返回给了客户端。需要注意的是,如果API暴露的地址与前面Host定义的地址(blueskykong.com)不一致,就需要在请求的Headers里面加入Header,Kong根据上面请求中定义的Header:Host,执行此操作。
创建了服务和路由之后,我们已经能够将客户端的请求转发到对应的服务,微服务网关还承担了很多基础的功能,如安全认证、限流、分析监控等功能,因此还需要应用Kong的插件实现这些功能,下一节我们进入这些插件的讲解。
安装Kong插件
请求到达Kong后,在转发给服务端应用之前,我们可以应用Kong自带的插件对请求进行处理,如合法认证、限流控制、黑白名单校验和日志采集等等。同时,我们也可以按照Kong的教程文档,定制开发属于自己的插件。本小节将会选择其中的三个插件示例应用,其余的插件应用,可以参见:https://docs.konghq.com/hub/
。
跨域身份验证:JWT认证插件
JWT是目前最流行的跨域身份验证解决方案。作为一个开放的标准(RFC7519),JWT定义了一种简洁的、自包含的方法用于通信双方之间以JSON对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的。JWT令牌一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便从资源服务器获取资源,也可以增加一些额外的其他业务逻辑所必须的声明信息。
JWT最大的优点就是能让业务无状态化,让Token作为业务请求的必要信息随着请求一并传输过来,服务端不用再去存储session信息,尤其是在分布式系统中。关于为什么使用JWT,不在本章详细论述,具体可见本书第11章统一认证与授权。Kong提供了JWT认证插件,用以验证包含HS256或RS256签名的JWT请求(如RFC7519中所述)。JWT令牌可以通过请求字符串、cookie或者认证头部传递。Kong将会验证令牌的签名,通过则转发,否则直接丢弃请求。
我们在前面小节配置的路由基础上,先来增加JWT认证插件,代码如下:1
2curl-XPOSThttp://locainost:8001/routes/e33d6aeb-4f35-4219-86c2-a41e879eda36/plugins
--data"name=jwt"
在图9-13中可以看到,插件列表增加了相应的记录。
在增加了JWT插件之后,就没法直接访问/api/blog接口了,直接访问接口会返回:”message”:”Unauthorized”,提示客户端要访问需要提供JWT的认证信息。因此,我们需要先创建用户,代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14curl-i-XPOST\
--urlhttp://localhost:8001/consumers/
--data"username=aoho"
如上代码中创建了一个名为aoho的用户,结果如图9-14所示。
Consumers
+CREATECONSDMER
awrish.
Reestis:25
USERNAME
CUSTOH_ID
CREATEDA
。acho
Jul202019203.54
DELETE
图9-14 KongConsumers
创建好用户之后,需要获取用户JWT凭证,执行如下的调用:
使用key和secret在https:/ljwt.io可以生成JWT凭证信息。在实际的使用过程中,我们通过编码实现,此处为了演示使用了网页工具生成Token;如图9-15所示。
将生成的Token配置到请求的认证头部,再次执行请求,如图9-16所示。
图9-16访问受限的API接口
可以看到,我们能够正常请求相应的API接口。JWT认证插件应用成功。Kong的JWT认证插件使用比较简单,我们在实践过程中,还需要考虑如何与自身的用户认证系统进行结合。
系统监控报警:Prometheus可视化监控插件
Prometheus是一套开源的系统监控报警框架。它的设计思路来源于Google的Borgmon监控系统,由工作在SoundCloud的Google前员工于2012年创建,:作为社区开源项目进行开发,并于2015年正式发布。2016年,Prometheus正式加入CloudNativeComputingFoundation,成为受欢迎程度仅次于Kubernetes的项目。作为新一代的监控框架,Prometheus适用于记录时间序列数据,具有强大的多维度数据模型、灵活而强大的查询语句、易于管理和伸缩等特点。
Kong官方提供的Prometheus插件,可用的metric(指标)如下表9-4所示。
接下来我们在Service中为aoho-blog安装Prometheus插件,代码如下:1
2cur1-XPoshttp///1ocalhost:8001/sefvices/aohob1og/plugins
--data"name-prometheus"
如图9-17所示,可以从管理界面看到,我们已经成功将Prometheus插件绑定到了aoho-blog服务上。
图9-17」KongPrometheus
验证一下,通过访问/metrics接口返回收集度量数据,如下所示:
返回的响应太长,我们作了适当的省略。从响应可以看到Prometheus插件提供的metic都有体现。Prometheus插件导出的度量标准,可以在Grafana(一个跨平台的开源的度量分析和可视化工具,具体参见htps://grafana.com/)中绘制,Prometheus加Grafana的组合是目前较为流行的监控系统。
实时链路数据追踪:Zipkin插件
Zipkin是一款开源的分布式实时数据追踪系统.其主要功能是聚集来自各个异构系统的实时监控数据,用来追踪微服务架构下的系统延时问题。应用系统需要向Zipkin报告数据。Kong的ipkin插件作为zipkinclient,其作用是组装好ipkin需要的数据包,向Zipkin服务端发送数据。Zipkin插件会将请求打上如下标签,并推送到Zipkin服务端:
(1)span.kind(senttoZipkinas“kind”)
(2)http.method
(3)http.status_code
(4)http.url
(5)peer.ipv4
…..,~一”
(6).peer.ipv6
(7)peer.port
(8)peer.hostname
(9)peer.service
本章旨在介绍如何在Kong中使用Zipkin插件追踪所有请求的链路。关于链路追踪和
Zipkin的具体信息,参见本书第12章分布式链路追踪。
我们首先开启Zipkin插件,将插件绑定到路由上(这里可以绑定为全局的插件)。1
2
3curl-XPOSThttp://kong:8001/routes/e33d6aeb-4f35-4219-86c2-a41e879eda36/plugins
data"name=zipkin"
--data"config.sampleratio=1'data"config.http_endpoint=http://localhost:9411/api/v2/spans"
如上配置了ZipkinCollector的地址和采样率,为了效果明显一些,我们设置采样率为100%,但在生产环境请谨慎使用,因为采样率对系统吞吐量有影响。
从图9-18中我们可以看到,Zipkin插件已经应用到指定的路由上。
图9-18 KongZipkin
下面我们将会执行请求/api/blog接口,打开http://localhost:9411
,界面如下图9-19所示。
图9-19 Zipkin监控页面
这时,Zipkin已经将请求记录,我们可以点开查看详细的链路详情,如图9-20所示。
从上图9-20中的链路调用可以知道,请求到达Kong之后,经历了哪些服务和Span,以及每个Span所花费的时间等等信息。
笔者在本章只介绍了三个具有代表性的Kong插件:JWT认证插件、Prometheus可视化监控和链路追踪Zipkin插件。Kong的插件机制是其高可扩展性的根源,Kong可以很方便地为路由和服务提供各种插件。
进阶应用:自定义Kong插件
官方虽然自带了很多插件,但是我们在实际的业务场景中还会有业务的需求,自定义插件能够帮助我们在APIGateway实现我们的业务需求。Kong提供了插件开发包和示例,自定义插件只需要按照提供的步骤即可。
为了方便编写自定义插件,我们使用本地安装的Kong,笔者的环境是macOS,安装较为简单,如下:1
2brewtapkong/kong
brewinstallkong
其次安装Postgres,并下载kong.conf.default配置文件(参见https://raw.githubusercontent.com/Kong/kong/master/kong.conf.default
),执行如下的命令:1
2sudomkdir-p/etc/kong
sudocpkong.conf.default/etc/kong/kong.conf
执行migration:1
kongmigrationsbootstrap-c/etc/kong/kong.conf
随后即可启动Kong:1
kongstart-c/etc/kong/kong.conf
启动之后,可以通过8001管理端口验证是否成功。1
curl-ihttp://localhost:8001/
基于上面安装好的Kong,我们介绍一下如何将自定义的插件加入到Kong的可选插件中,这里以鉴权的token-auth插件为例进行讲解。
【实例9-2】自定义鉴权插件token-auth
Kong官方提供了有关认证的插件有:JWT、OAuth2.0和BasicAuth等,我们在实际业务中,也经常会自建认证和授权服务器,这样就需要我们在API网关处拦截验证请求的合法性。基于此,我们自定义实现一个类似Kong过滤器的插件:token-auth。
Kong自带的插件在/usr/local/share/lua/5.1/kong/plugins/目录下。每个插件文件夹下有如下两个主要文件:
(1)schema.lua:定义的启动插件时的参数检查。
(2)handler.lua:文件定义了各阶段执行的函数,插件的核心。
token-auth是我们定制的插件名。我们需要在/usr/local/share/lua/5.1/kong/plugins下新建token-auth目录。然后进行Plugin的加载和初始化阶段,即Kong.init()在加载插件的时候,会将插件目录中的schema.lua和handler.lua加载,下面我们看下这两个脚本的实现。
1.插件配置定义:schema.lua
Kong中每个插件的配置存放在plugins表中的config字段,是一段JSON文本,token-auth所需的配置定义如下:1
2
3
4return
noconsumer=true,
fields={
authserverurl=(type="url",required=true}
从schema.lua可以看到,启用token-auth插件时,需要检查authserverurl字段为URL类型,且不能为空。
2.插件功能实现:handler.lua
handler.lua实现了插件认证功能,这个插件中定义的方法,会在处理请求和响应的时候被调用。
我们来分析一下上面这段代码,token-auth插件实现了thew和#access两个方法,它们只在access阶段发挥作用。在#acess方法中,首先会提取JWT头部信息,检查token是否存在以及格式是否正确等,随后请求认证服务器验证token的合法性。
3.加载插件
插件开发完成后,首先要在插件目录中新建token-auth-1.2.1-0.rockspec文件,填写新开发的插件,代码如下所示:
然后在kong.conf配置文件中添加新开发的插件:
ETSi/etckong/kongiconf.
P#去掉开头的注释并修改如下
RRiuginsCbund1edtoken-al
上述代码中的bundled属性是指官方提供的插件合集,默认是开启的。这里可以看到,我们增加了自定义的token-auth插件。验证一下,自定义的插件是否成功加载:
可以看到,我们自定义的token-auth插件已经成功加载到了插件列表中。
4,启用插件
接下来在Service上启用token-auth插件,同时需要指定config.auth.server_url的属性:
如果插件有自己的数据库表,或者对数据库表或表中数据有要求,在插件目录中创建migrations目录。根据使用的是Postgres还是Cassandra,创建migrations/postgres.lua或者migrations/cassandra.Iia.
Kong提供了一个数据库抽象层用于存储自定义的实体,也就是dao层。要完成数据访问,需要编写Migration文件,用于数据库DDL操作,在kongmigrationsup时执行;并编写daos.lua,用于映射数据表。token-auth插件没有单独的数据库表,因此不需要创建这个文件。
我们通过该实例了解了插件的结构、可以扩展的内容以及如何发布和安装它们。这个实例插件不涉及数据库以及其他复杂的操作,比较简单。这里不做过多演示,读者可2以结合第.11章统一认证与授权的章节内容,自行尝试。.有关PDK的完整开发,请参阅插件开发套件(https://ocs.konghq.com/1.4.x/plugin-development/
).
小结
在微服务架构之下,服务按领域划分,降低了耦合度的同时也给服务的统一管理增加了难度。API网关致力于实现微服务的统一鉴权、限流、日志、监控等通用的功能,在此基础上提高系统的可扩展性。
本章首先介绍了在微服务架构中API网关具有的基本功能和特性。路由转发和负载均衡是API网关最基本的功能,笔者编写了一个简易的Go语言版本的网关,用以帮助读者深入了解网关实现的原理细节。随后,本章比较了市面上流行的微服务网关,并最终选择了Kong进行实践。Kong在功能、性能和可扩展性方面表现都很优异,在实践部分讲解了如何使用Kong进行转发请求,安装使用几种常用的Kong自带插件,并扩展介绍如何自定义Kong插件:token-auth。Kong官方为插件开发也提供了很方便的扩展点。通过自定义插件,我们可以很轻松地定制需要的功能。