通过前几篇介绍,已经可以构建一个简单的微服务架构了,如下图:
通过eureka实现服务注册中心以及服务注册发现,通过ribbon或feign实现服务的消费以及负载均衡,通过spring cloud config实现了应用多环境的外部配置以及版本管理。为了集群更为健壮使用了Hystrix的隔断机制来避免微服务架构中个别服务出现异常而引起的雪崩。
在该架构中,我们的服务集群包含内部服务Service A和Service B,他们都会注册到eureka server,而open service 是一个对外的服务,通过负载均衡公开到服务调用方。
这样的架构存在的不足:
首先,破坏了服务无状态特点,为了保证对外服务的安全性,我们需要实现对服务访问的权限控制,而开放服务的权限控制机制将会贯穿并污染整个开放服务的业务逻辑,者会带来最直接的问题是,破坏了服务集群中REST API无状态的特点。从具体开发和测试的角度来说,在工作中除了要考虑实际的业务之外,还需要额外可续对接口访问的控制处理。
其次,无法直接复用既有接口,当我们需要对一个既有的集群内访问接口,实现外部服务访问时,我们不得不通过在原有接口上增加校验逻辑,或增加一个代理调用来实现权限控制,无法直接复用原有接口。
为了解决上面这些问题,我们需要将权限控制这样的东西从我们的服务单元中抽离出去,而适合这些逻辑的地方就是处于对外访问最前端的地方,我们需要一个更强大一些的负载均衡器->服务网关。
服务网关
服务网关是微服务架构中不可或缺的一部分。通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由、负载均衡功能外,还具备了权限控制等功能。Spring Cloud Netflix中的Zuul就担任了这样的一个角色,为微服务架构提供了前门保护的作用,同事还将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,使得服务集群主体能够具备更高的可复用性和可测试性。
构建服务网关
创建一个基础的Spring Boot项目,命名为david-gateway,并在pom.xml中引入依赖:
<?xml version="1.0" encoding="UTF-8"?> <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>com.david</groupId> <artifactId>gateway</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>gateway</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Edgware.SR2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
在启动类中使用@EnableZuulProxy开启网关功能
@EnableZuulProxy @SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } }
编辑配置文件application.yml
spring: application: name: david-gateway server: port: 8769 eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/
启动eureka、feign、gateway 输入网址:http://localhost:8769/david-feign/test
发现已经可以执行了 feign中的test方法了。
当我们gateway应用启动并注册到eureka之后,服务网关发现我们启动的feign服务,这时候Zuul就会创建一个路由规则,每个路由规则包含两部分,一部分是外部请求的匹配规则,另一部分是路由的服务ID,
转发到feign服务的请求规则为 : /david-feign/**