快捷搜索:  汽车  科技

微服务架构体系讲解(几分钟搞懂微服务)

微服务架构体系讲解(几分钟搞懂微服务)<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.myforever</groupId> <artifactId>zuul-gateway</artifactId> <version>0

现在我们来研究下SpringCloud中Zuul网关的使用,当然之前得说明下为什么要用Zuul网关,毕竟都已经有注册中心中有每个服务的别名了,通过Feign已经完美的调用了,根本不需要Zuul,下面我们就来分析下。

一、为什么要Zuul网关
  • 在微服务中,若是服务暴露出去给外部访问调用,那么因为外部是不可能跟我们的注册中心有关系的,此时用Feign调用就将失效,那么我们能做的就是告诉外部ip、端口、服务请求路径。
  • 在外部调用的时候,我们可能需要进行身份认证,此时我们能做的就是在每个微服务中进行权限认证什么的,每个微服务都一套,这样的话不科学。
  • 并且因为每个都是不同的ip,所以存在跨域请求的问题。
  • 上面随便列举了三个问题,SpringCloud微服务框架中的Zuul技术完美的解决了上面的问题,我们只需要调用同一个ip即可。当然这里需要说明的是,内部服务与服务之间的调用,当然还是通过Feign,虽然说网关也是注册到注册中心的,但是没有必要再加一层,浪费性能。Zuul一般都是用于外部调用我们的微服务。

    二、Zuul网关

    服务网关是微服务架构中一个不可或缺的部分。通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由、均衡负载功能之外,它还具备了权限控制等功能。Spring Cloud Netflix中的Zuul就担任了这样的一个角色,为微服务架构提供了前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,使得服务集群主体能够具备更高的可复用性和可测试性。

    三、实战

    下面我们实现一个例子,两个服务:127.0.0.1:8001/a 和 127.0.0.1:8002/a我们通过网关直接统一访问127.0.0.1/api-a/a 和127.0.0.1/api-b/b 来访问,并且在网关中做登录验证。

    1、环境准备

    建立三个项目:注册中心、服务a、服务b 然后启动。相信这部通过前面的博文三、服务治理SpringCloud Eureka入门实战下面简单的列一下服务a和b的配置:

    服务a

    ###服务提供者启动端口 server: port: 8001 ###服务名称(服务注册到eureka名称) spring: application: name: app-suibibk-zuul-a ###服务注册到eureka地址 eureka: client: service-url: defaultZone: http://localhost:8000/eureka register-with-eureka: true fetch-registry: true

    @RestController public class AController { @Value("${server.port}") private String serverPort; @RequestMapping("/a") public String a() { return "我是a服务" serverPort; } }服务b

    ###服务提供者启动端口 server: port: 8002 ###服务名称(服务注册到eureka名称) spring: application: name: app-suibibk-zuul-b ###服务注册到eureka地址 eureka: client: service-url: defaultZone: http://localhost:8000/eureka register-with-eureka: true fetch-registry: true

    @RestController public class BController { @RequestMapping("/b") public String a() { return "我是b服务"; } }

    浏览器下面两个连接保证服务正常http://127.0.0.1:8001/a 返回:我是a服务8001http://127.0.0.1:8002/b 返回:我是b服务

    2、建立Zuul网关项目

    上面服务已经正常启动了,加入我作为一个外部系统,需要访问调用的话,我应该会用http发起http://127.0.0.1:8001/a 和 http://127.0.0.1:8002/b 请求,但是这样的话,需要知道具体的ip,并且比较难做本地的负载均衡(提醒一下:服务之间的调用用Feign默认开启本地负载均衡的),当然Zuul 默认开启了 Ribbon本地负载均衡功能。如果要进行token验证,也就是参数上是否传递token,那么我们可能需要在服务a和服务b中都进行校验。下面用Zuul解决这些问题,项目结构:

    微服务架构体系讲解(几分钟搞懂微服务)(1)

    其实SpringCloud中建立项目无外乎就是引入依赖,修改配置文件,启动类开启需要的功能什么的。

    a、pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.myforever</groupId> <artifactId>zuul-gateway</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.0.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> </project>

    主要是引入了如下依赖

    <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency>b、application.yml

    ###注册 中心 eureka: client: serviceUrl: defaultZone: http://localhost:8000/eureka/ server: port: 80 ###网关名称 spring: application: name: app-suibibk-zuul-gateway zuul: routes: #这个名字可以顺便取 api-a: ### 以 /api-a/访问转发到a服务 path: /api-a/** serviceId: app-suibibk-zuul-a #这个名字可以顺便取 api-b2: ### 以 /b/访问转发到b服务 path: /api-b/** serviceId: app-suibibk-zuul-b

    这里用80端口,主要是看zuul的配置路由。

  • 上面这段配置表示:/api-ar/开头的url请求,将转发到app-suibibk-zuul-a这个微服务上,/api-b/开头的url请求,将转发到app-suibibk-zuul-b这个微服务上。
  • c、过滤器Myfilter.java

    /** * 拦截用户是否有token,没有token就直接报错 * @author forever * */ @Component public class MyFilter extends ZuulFilter{ @Override public Object run() throws ZuulException { //获取上下文 RequestContext context = RequestContext.getCurrentContext(); HttpServletRequest reqeust = context.getRequest(); //获取token String token =reqeust.getParameter("token"); if(token==null) { context.setSendZuulResponse(false); context.setResponseStatusCode(403); context.setResponseBody("token is null"); //return null; } System.out.println("执行正常逻辑"); return null; } @Override public boolean shouldFilter() { // TODO Auto-generated method stub return true; } @Override public int filterOrder() { // TODO Auto-generated method stub return 0; } @Override public String filterType() { // TODO Auto-generated method stub return "pre"; } }

    主要关注的是如下几个方法

    run()

    这里做权限验证逻辑,只要能执行完就表示通过。若是不通过则用如下代码来提醒用户

    context.setSendZuulResponse(false); context.setResponseStatusCode(403); context.setResponseBody("token is null");shouldFilter()

    返回结果表这个过滤器是否生效,true代表生效,false代表不生效。那么什么情况下使用不生效呢,不生效干嘛还要写这个filter类呢?其实是有用的,有时我们会动态的决定让不让一个filter生效,譬如我们可能根据Request里是否携带某个参数来判断是否需要生效,或者我们需要从上一个filter里接收某个数据来决定,再或者我们希望能手工控制是否生效(使用如Appolo之类的配置中心,来动态设置该字段)。

    filterOrder()

    过滤器的执行顺序。当请求在一个阶段的时候存在多个多个过滤器时,需要根据该方法的返回值依次执行。

    filterType()

    微服务架构体系讲解(几分钟搞懂微服务)(2)

    主要关注 pre、post和error。分别代表前置过滤,后置过滤和异常过滤。

  • 如果你的filter是pre,就是指请求先进入pre的filter类,你可以进行一些权限认证,日志记录,或者额外给Request增加一些属性供后续的filter使用。pre会优先按照order从小到大执行,然后再去执行请求转发到业务服务。
  • 如果你的filter是post,那么就会执行完被路由的业务服务后,再进入post的filter,在post的filter里,一般做一些日志记录,或者额外增加response属性什么的。
  • 如果你的filter是error,如果在上面的任何一个地方出现了异常,就会进入到type为error的filter中
  • d、启动类AppZuulGateway.java

    @SpringBootApplication @EnableEurekaClient @EnableZuulProxy public class AppZuulGateway { //默認開啓ribbon负载均衡 public static void main(String[] args) { SpringApplication.run(AppZuulGateway.class args); } }

    @EnableZuulProxy表示开启Zuul网关代理功能

    3、启动Zuul网关,测试

    当注册中心Eureka,服务a 服务b Zuul网关都启动后,此时我们可以访问如下链接测试1、http://127.0.0.1/api-a/a 和http://127.0.0.1/api-b/b 返回token is null ,表示Zuul网关拦截请求成功。2、http://127.0.0.1/api-a/a?token=123 返回我是a服务80013、http://127.0.0.1/api-b/b?token=123 返回我是b服务到此,搭建zull网关成功。

    四、Nginx与Zuul的区别1、相同点

    Zuul和Nginx都可以实现负载均衡、反向代理(隐藏真实ip地址),过滤请求,实现网关的效果。

    2、不同点

    Nginx--c语言开发 Zuul--java语言开发 Zuul负载均衡实现:采用ribbon eureka实现本地负载均衡 Nginx负载均衡实现:采用服务器实现负载均衡 Nginx相比zuul功能会更加强大,因为Nginx整合一些脚本语言(Nginx lua) Nginx适合于服务器端负载均衡 Zuul适合微服务中实现网关结语

    到此,我们就基本上学会了Zuul网关的使用,当然这里只是入门使用,真正想了解深入的话,还需要继续深入研究。暂时来说会用即可,有时间再去深入研究做笔记。

    猜您喜欢: