原创作者:田超凡(程序员田宝宝)
版权所有,引用请注明原作者,严禁复制转载
Part 1 理论部分
1 网关类别有哪些?
常见的网关类别有三种:开放API(Open API)网关、微服务网关、API服务管理平台。
1 开放API(Open API)网关:
在开放API(Open API)中,客户需要将自身的数据、能力等作为开放平台对外开放,通常会以REST的方式对外提供,比如阿里云的开放平台、腾讯的QQ开放平台、微信开放平台等等,Open API开放平台必然会涉及到用户的应用接入、API权限管理、调用次数管理等,所以必然会有一个统一的入口来进行管理,这正是开放API(Open API)网关可以发挥作用的时候。
2 微服务网关:
微服务的概念最早是在2012年提出的,在SpringCloud的大力推广下,微服务在2014年后才逐渐得到了大力发展,在微服务架构中,有一个组件必不可少,那就是微服务网关,微服务网关实现了负载均衡、缓存、路由、访问控制、服务代理、监控、日志等功能,API网关在微服务架构中正是以微服务网关的身份存在。
3 API服务管理平台:
上述的微服务架构对一些企业来说可能存在实施上的困难,因为企业有很多遗留系统,如果要将这些遗留系统全部抽取改造成微服务架构的话,会导致改动量大大增加,且需要部署的服务器数量也会增多,这对企业来说成本太高,但是不同的系统之间存在大量的API服务相互调用,所以需要对系统间的服务调用进行管理,可以清晰地看到各系统之间的调用关系,对系统间的调用行为进行监控,API网关可以解决这些问题,如果没有大规模地实施微服务架构,那么对企业来说微服务网关就是企业的API服务管理平台。
2 网关作用是什么?
网关的作用是可以实现负载均衡、路由转发、日志、权限控制、监控等功能。
3 网关和拦截器、过滤器的区别是什么?
网关是拦截所有服务器的请求进行控制
拦截器是拦截某单个服务器的请求进行控制
过滤器是拦截某单个服务器的请求进行过滤,只放行符合过滤条件的请求。
4 如何设计微服务网关?
设计微服务网关包括开放API接口和内网API接口。
开放API接口:
对于Open API使用的API网关来说,一般合作伙伴要以应用的形式接入到Open API开放平台,然后需要到Open API开放平台申请应用,因此在Open API网关之外,需要有一个面向合作伙伴的使用平台,这就要求Open API网关需要提供API给这个用户平台进行访问。
当然如果是在简单的场景下,可能不需要提供一个面向合作伙伴的门户,只需要让公司的运营人员直接添加合作伙伴应用的应用ID/密钥等,这种情况下也就不需要合作伙伴门户子系统。
内网API接口:
对于内网的API网关来说,起到的作用上可以认为是微服务网关,也可以认为是内网的API服务管理平台,当企业将所有的应用都使用微服务架构管理起来的时候,API网关就起到了微服务网关的作用,当企业只是将系统和系统之间的调用使用REST API的方式进行访问时,使用API网关对调用进行管理,API网关就起到了API服务管理平台的作用。
对于公司内部公网应用(如APP、公司网站),如果管理的比较细致,在架构上可以使用单独的API网关来处理这部分内部公网应用,如果想要使用比较简单的方式实现,可以使用面向合作伙伴的API网关,如果使用独立的API网关,有以下几种好处:
1 面向合作伙伴和面向公司主体业务的优先级不一样,不同的API网关可以实现业务影响的隔离。
2 内网API使用的管理流程和面向合作伙伴的管理流程可能不一样。
3 内网API在功能扩展等方面的需求量一般会大于Open API在功能扩展等方面的需求量。
基于以上的分析,如果公司有能力,还是建议分开使用合作伙伴Open API网关和内部公网应用网关。
5 Nginx和Zuul的区别是什么?
Nginx是采用服务器负载均衡进行转发
Zuul依赖于Ribbon和Eureka实现本地负载均衡转发,
Zuul默认已经整合并开启了Ribbon实现的客户端负载均衡的功能,
Nginx功能比Zuul功能更加强大,能够整合其他的语言比如Lua脚本实现强大的功能,同时Nginx还可以更好地抗高并发,Zuul网关适用于一般请求过滤和拦截等。
6 动态网关实现思路是什么?
传统方式是将路由规则配置到配置文件中,如果路由规则发生了改变,需要重启服务器,可以整合SpringCloud Config分布式配置中心,实现动态路由规则网关。
Part 2 实践部分
Zuul网关
zuul是spring cloud的一个推荐组件:https://github.com/Netflix/zuul
使用Zuul实现反向代理
环境搭建
Maven依赖信息
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> </parent> <!-- 管理依赖 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.M7</version> <type>++pom++ </type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-++netflix++ -++zuul++</artifactId> </dependency> <!-- SpringBoot整合++eureka++客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-++netflix++ -++eureka++-client</artifactId> </dependency> </dependencies> <!-- 注意: 这里必须要添加, 否者各种依赖有问题 --> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/libs-milestone\</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> |
application.yml
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ###注册 中心 eureka: client: ++serviceUrl++ : defaultZone: http://localhost:8100/eureka/ server: port: 80 ###网关名称 spring: application: name: service-zuul ### 配置网关反向代理 ++zuul++ : routes: api-a: ### 以 /api-member/访问转发到用户服务 path: /api-member/** serviceId: app-ittcf-member api-b: ### 以 /api-order/访问转发到订单服务 path: /api-order/** serviceId: app-ittcf-order |
使用Zuul整合Ribbon
Zuul 默认开启了 Ribbon本地负载均衡功能。
使用Zuul过滤器
案例:使用过滤器验证客户端是否有登陆。
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| @Component public class TokenFilter extends ZuulFilter { public Object run() throws ZuulException { // 获取上下文 RequestContext currentContext = RequestContext.getCurrentContext(); HttpServletRequest request = currentContext.getRequest(); String userToken = ++request++.getParameter("userToken"); if (StringUtils.isEmpty(userToken)) { currentContext.setSendZuulResponse(false ); currentContext.setResponseStatusCode(401); currentContext.setResponseBody("userToken is null"); return null ; } // 否则正常执行业务逻辑..... return null ; } // 判断过滤器是否生效 public boolean shouldFilter() { return true ; } // 过滤器的执行顺序。当请求在一个阶段的时候存在多个多个过滤器时,需要根据该方法的返回值依次执行 public int filterOrder() { return 0; } // 过滤器类型 ++pre++ 表示在 请求之前进行拦截 public String filterType() { return "pre"; } } |
动态网关
传统方式将路由规则配置在配置文件中,如果路由规则发生了改变,需要重启服务器。这时候我们可以整合SpringCloud Config分布式配置中心,实现动态路由规则。
在git上创建一个文件service-zuul-dev.yml
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ### 配置网关反向代理 zuul: routes: api-a: ### 以 /api-member/访问转发到用户服务 path: /api-member/** serviceId: app-ittcf-member api-b: ### 以 /api-order/访问转发到订单服务 path: /api-order/** serviceId: app-ittcf-order |
Maven依赖信息
新增监控中心依赖信息
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <!-- actuator监控中心 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- ++springcloud++ ++config++ 2.0 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-++config++-client</artifactId> </dependency> |
application.yml
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ###服务注册地址 eureka: client: ++serviceUrl++ : defaultZone: http://localhost:8100/eureka/ ###api网关端口号 server: port: 80 ###网关名称 spring: application: name: service-zuul cloud: config: ####读取后缀 profile: dev ####读取config-server注册地址 discovery: service-id: config-server enabled: true ###默认服务读取eureka注册服务列表 默认间隔30秒 ###开启所有监控中心接口 management: endpoints: web: exposure: include: "*" |
项目启动
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| // ++zuul++配置能够使用++config++实现实时更新 @RefreshScope @ConfigurationProperties("zuul") public ZuulProperties zuulProperties() { return new ZuulProperties(); } |
手动刷新接口
http://127.0.0.1/actuator/refresh
Zuul网关集群
Zuul网关集群使用Nginx反向代理即可,保证每台网关配置数据相同。
nginx.conf配置参考:
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| upstream backServer{ server 127.0.0.1:81; server 127.0.0.1:82; } server { listen 80; server_name wg.ittcf.com; location / { ### 指定上游服务器负载均衡服务器 proxy_pass http://backServer/; index index.html index.htm; } } |
本文部分素材转载自蚂蚁课堂