未使用网关的微服务请求:
缺点:
Zuul的核心是一系列的过滤器,这些过滤器可以完成以下功能:
1、身份认证与安全:识别每个资源的验证要求,并拒绝那些与要求不符的请求。
2、审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图。
3、动态路由:动态的将请求路由到不同的后端集群。
4、压力测试:逐渐增加指向集群的流量,以了解性能。
5、负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求。
6、静态响应处理:在边缘位置直接建立部分响应,从而避免其转发到内部集群。
7、多区域弹性:跨越AWS Region进行请求路由,皆在实现ELB使用的多样化,以及让系统的边缘更贴近系统的使用者。
新建一个工程:microservice-simple-gateway-zuul
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
<version>2.1.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-zuulartifactId>
<version>2.1.2.RELEASEversion>
dependency>
需要注册到Eureka上。
server:
port: 5031
spring:
application:
name: microservice-simple-gateway-zuul
eureka:
client:
serviceUrl:
defaultZone: http://hht:123456@localhost:8761/eureka/,http://hht:123456@localhost:8762/eureka/
instance:
prefer-ip-address: true
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication
{
public static void main( String[] args )
{
SpringApplication.run(ZuulApplication.class, args);
}
}
原来直接访问movie:http://localhost:8032/movie/user/feign/1
现在可以访问网关:http://localhost:5031/microservice-simple-consumer-movie/movie/user/feign/1
当@EnableZuulProxy与Spring Boot Actuator配合使用时,Zuul会暴露一个路由管理端点“routes”。借助这个端点,可以方便、直观的查看以及管理Zuul的路由。
由于spring-cloud-starter-netflix-zuul已经包含了spring-boot-starter-actuator,所以Zuul已经具备路由管理的能力。
这个时候直接查看路由端点:http://localhost:5031/actuator/routes , 会报错。
重点注意:
添加配置,开启routes端点:
management:
endpoints:
web:
exposure:
include: '*'
详情参考:参考:https://blog.csdn.net/weixin_43439494/article/details/83819814
zuul:
routes:
microservice-provider-user: /user/**
zuul:
ignored-services: microservice-provider-user,microservice-consumer-movie
zuul:
ignored-services: '*' # 使用'*'可忽略所有的微服务
routes:
microservice-provider-user: /user/**
zuul:
routes:
hht-user-route: # 该配置方式中,hht-user-route只是给路由一个名称,可以任意起名
service-id: microservice-provider-user
path: /user/** # service-id对应的路径
注意:使用这种方式配置的路由不会作为HystrixCommand执行,同时也不能使用Ribbon来负载均衡多个URL。例子6可以解决该问题。
zuul:
routes:
hht-user-route: # 该配置方式中,hht-user-route只是给路由一个名称,可以任意起名
url: http://localhost:8000/ # 指定的URL
path: /user/** # url对应的路径
zuul:
routes:
hht-user-route:
path: /user/**
service-id: microservice-provider-user
ribbon:
eureka:
enabled: false # 为Ribbon禁用Eureka
microservice-provider-user:
ribbon:
listOfServices: localhost:8000,localhost:8001
@Bean
public PatternServiceRouteMapper serviceRouteMapper(){
// 调用构造函数PatternServiceRouteMapper(String servicePatern, String routePattern)
// servicePattern: 指定微服务的正则
// routePattern: 指定路由正则
return new PatternServiceRouteMapper("(?^.+)-(?v.+$)" , "${version}/${name}");
}
zuul:
prefix: /api
strip-prefix: false
routes:
microservice-provider-user: /user/**
示例2: 访问Zuul的 /user/1 路径,会被转发到 microservice-provider-user 的 /user/1
zuul:
routes:
microservice-provider-user:
path: /user/**
strip-prefix: false
zuul:
ignoredPatterns: /**/admin/** # 忽略所有包含 /admin 的路径
routes:
microservice-provider-user: /user/**
【自己的demo举2个简单的例子:】
zuul:
routes:
microservice-simple-consumer-movie: /movie/**
#排除某些路由
ignored-services: microservice-simple-provider-user
再查看http://localhost:5031/actuator/routes,发现已经没有了“microservice-simple-provider-user”。
对于小文件(1M以内)上传,无需任何处理,即可正常上传。
对于大文件(10M以上)上传,需要为上传路径添加/zuul前缀。也可以使用zuul.servlet-path来自定义前缀。
Zuul中定义了4种标准的过滤器类型,这些过滤器类型对应于请求的典型生命周期。
除了默认的过滤器类型,Zuul还允许创建自定义的过滤器类型。 例如:可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端的微服务。
要继承ZuulFilter类,并实现以下几个方法:
public class MyPreRequestLogFilter extends ZuulFilter{
private static final Logger logger = LoggerFactory.getLogger(MyPreRequestLogFilter.class);
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
logger.info(String.format("================ send 【%s】 request to 【%s】 .", request.getMethod(), request.getRequestURL().toString()));
return null;
}
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
}
@Bean
public MyPreRequestLogFilter myPreRequestFilter() {
return new MyPreRequestLogFilter();
}
访问:http://localhost:5031/microservice-simple-consumer-movie/movie/user/feign/1, 确认打印了日志。
配置文件: zuul.
例如:禁用上面的自定义过滤器
#禁用ZuulFilter
zuul:
MyPreRequestLogFilter:
pre:
disable: true
可以看到过滤器不起作用了。
可直接访问:http://localhost:5031/hystrix.stream, 查看监控,也可以在仪表盘中直观看图。
由图可知,Zuul的Hystrix监控的粒度是微服务,而不是某个API。同时也说明,所有经过Zuul的请求,都会被Hystrix保护起来。
想要为Zuul添加回退,需要实现FallbackProvider接口。在实现类中,指定为哪个微服务提供回退,并提供一个FallbackProvider作为回退响应。
package com.itmuch.cloud.gateway.zuul.fallback;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
@Component
public class MovieFallbackProvider implements FallbackProvider {
@Override
public String getRoute() {
//表明是为哪个微服务提供回退
return "microservice-simple-consumer-movie";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpHeaders getHeaders() {
// headers设定
HttpHeaders headers = new HttpHeaders();
MediaType mt = new MediaType("application", "json", Charset.forName("UTF-8"));
headers.setContentType(mt);
return headers;
}
@Override
public InputStream getBody() throws IOException {
// 响应体
return new ByteArrayInputStream("用户微服务不可用,请稍后再试。".getBytes());
}
@Override
public String getStatusText() throws IOException {
// 状态文本,本例返回的其实就是OK,详见HttpStatus
return getStatusCode().getReasonPhrase();
}
@Override
public HttpStatus getStatusCode() throws IOException {
// fallback时的状态码
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
// 数字类型的状态码,本例返回的其实就是200, 详见HttpStatus
return this.getStatusCode().value();
}
@Override
public void close() {
// TODO Auto-generated method stub
}
};
}
}
停掉微服务“microservice-simple-consumer-movie”,再访问http://localhost:5031/microservice-simple-consumer-movie/movie/user/feign/1, 效果如下:
Zuul的高可用非常关键,因为外部请求到后端微服务的请求都会经过Zuul。因而在生产环境中一般都需要部署高可用的Zuul以避免单点故障。
这种情况是指客户端也是一个微服务。不通过前面那种直接调用目标的微服务名,而是直接调用microservice-simple-gataway-zuul 。
这种情况下,Zuul高可用非常简单,只需将多个Zuul节点注册到Eureka Server上,即可。
Zuul高可用架构:
复制一个zuul工程:microservice-simple-gataway-zuul-2
本例:
@FeignClient(name = "microservice-simple-gateway-zuul")
public interface ZuulFeignClient {
@GetMapping(value = "/microservice-simple-provider-user/user/{id}")
public UserEntity findByIdFeign(@PathVariable("id") int id);
}
现实中,更多的场景是客户端没有注册到Eureka Server上。 比如,客户端是一个手机APP — 不可能让所有的手机终端都注册到Eureka上。
这种情况下,可借助一个额外的负载均衡器来实现Zuul的高可用,例如:Nginx 、 HAProxy 、 F5等。
在微服务架构中,微服务的配置管理一般有以下需求:
新建一个工程:microservice-simple-config-server
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-config-serverartifactId>
<version>2.1.3.RELEASEversion>
dependency>
server:
port: 6031
spring:
application:
name: microservice-simple-config-server
cloud:
config:
server:
git:
uri: https://github.com/guessagithub/Spring-cloud-config-repo
username: guessagithub
password: 待定
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication
{
public static void main( String[] args )
{
SpringApplication.run(ConfigServerApplication.class, args);
}
}
在git仓库Spring-cloud-config-repo中,新建两个版本:
访问以下url和查看对应结果:
新建一个工程:microservice-simple-config-client
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-config-clientartifactId>
<version>2.1.3.RELEASEversion>
dependency>
server:
port: 6035
spring:
application:
#对应config server所获取的配置文件的{application}
name: microservice-simple-config-client
cloud:
config:
uri: http://localhost:6031/
#profile对应config server所获取的配置文件中的{profile}
profile: dev
#指定GIT仓库的分支,对应config server所获取的配置文件的{label}
label: master
@RestController
@RequestMapping("/configclient")
public class ConfigClientController {
@Value("${address}")
private String address;
@GetMapping("/address")
public String getAddress() {
return address;
}
}
在git上新建文件:
访问URL:http://localhost:6035/configclient/address
前文中,使用【spring.cloud.config.server.git.uri】指定了一个Git仓库,事实上,该属性非常灵活。
Config Server的占位符支持 {application}、{profile}、{label} 。
示例: