介绍
网关是介于客户端(外部调用方比如app,h5)和微服务的中间层。
在微服务的中有多个模块,为了让用户或者前端有一个同一的入口。网关是对外服务的窗口,进行服务内外隔离。一般微服务都在内网,不做安全验证。
Zuul是Netflix开源的微服务网关,核心是一系列过滤器。这些过滤器可以完成以下功能。
- 是所有微服务入口,进行分发。
- 身份认证与安全,识别合法的请求,拦截不合法的请求。
- 监控:在入口处监控,更全面。
- 动态路由:动态将请求分发到不同的后端集群。
- 压力测试:可以逐渐增加对后端服务的流量,进行测试。
- 负载均衡:也是用ribbon。
- 限流:比如我每秒只要1000次,10001次就不让访问了
使用
网关会将服务名转换成具体服务的ip和端口,实际进行访问
http://localhost/服务名称/alive
http://localhost/consumer/alive
1.负载均衡
一个服务集群启动两台api-provide-9001, api-provide-9002。
访问地址http://localhost:9100/api-provide/test/hello,会看到返回结果中,端口一直轮询在变。说明负载均衡生效了,默认是轮询。
更改负载均衡策略
api-driver:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #随机策略
2.路由端点
zuul的配置
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
##默认是never
show-details: ALWAYS
enabled: true
routes:
enabled: true
访问http://localhost:9100/actuator/routes,可以看到路由地址有哪些
{
/gate-way/sms/**: "service-sms",
/api-driver/**: "api-driver"
}
3.配置指定微服务的访问路径
- 通过服务名配置(虚拟主机名)
zuul:
routes:
api-driver: /zuul-api-driver/**
配置前先访问,然后做对比。
这样访问
http://localhost:9100/zuul-api-driver/test/hello
- 自定义命名配置
zuul:
routes:
custom-zuul-name: #此处名字随便取
path: /zuul-custom-name/**
url: http://localhost:9002/
访问前 看结果,做对比。
访问:http://localhost:9100/zuul-custom-name/test/hello
这样 ribbon和hystrix 就都失效了。
3. 基于2,恢复ribbon+hystrix
zuul:
routes:
#此处名字随便取
custom-zuul-name:
path: /zuul-custom-name/**
service-id: no-eureka-api-driver
no-eureka-api-driver:
ribbon:
listOfServers: localhost:9003,localhost:9002
ribbon:
eureka:
enabled: false
访问:http://localhost:9100/zuul-custom-name/test/hello
ribbon之前讲过类似这种配置。
- 指定serviceId
zuul:
routes:
#此处名字随便取
custom-zuul-name:
path: /zuul-custom-name/**
service-id: api-driver
访问:http://localhost:9100/zuul-custom-name/test/hello
4.忽略微服务
原来访问:
http://localhost:9100/api-driver/test/hello
http://localhost:9100/zuul-api-driver/test/hello(基于基础的例子的)
好使。
- 忽略微服务数组
增加如下配置
zuul:
routes:
api-driver: /zuul-api-driver/**
ignored-services:
- api-driver
再访问:
http://localhost:9100/api-driver/test/hello , 不好使
http://localhost:9100/zuul-api-driver/test/hello, 好使
不好使。只能访问:
现在只有api-driver不好使。api-passenger还是好使的。
http://localhost:9100/api-passenger/test/hello , 好使
http://localhost:9100/zuul-api-passenger/test/hello , 好使
- 忽略正则
# 忽略正则,不能通过 zuul-api-driver 和 api-driver访问。
# ignored-patterns:
# - /*-driver/**
可以测试一下。
测试点:
http://localhost:9100/zuul-api-driver/test/hello,不好使,
http://localhost:9100/api-driver/test/hello ,不好使。
- 忽略全部,下去实验。
访问:http://localhost:9100/api-passenger/test/hello
发现api-passenger也不好使。
只能走routes的配置。
5.前缀
接口一般命名:/api/v1/xxxx
zuul:
prefix: /api
# 是否移除前缀
strip-prefix: true
访问时带上前缀,实际 请求会将前缀去掉。
比如访问:http://localhost:9100/api/zuul-api-driver/test/hello
实际:http://localhost:9002/test/hello
注意全局的移除,和自定义名字下面的移除。
6.过滤器
Zuul的大部分功能都是有过滤器实现的。
4种过滤器
PRE: 在请求被路由之前调用,可利用这种过滤器实现身份验证。选择微服务,记录日志。
ROUTING:在将请求路由到微服务调用,用于构建发送给微服务的请求,并用http clinet(或者ribbon)请求微服务。
POST:在调用微服务执行后。可用于添加header,记录日志,将响应发给客户端。
ERROR:在其他阶段发生错误是,走此过滤器。
自定义过滤器
PreFilter看代码,注意下面4点。
filterType:pre,routing,post,error
filterOrder:执行顺序,在谁前,在谁后,可以+1,-1
shouldFilter:此过滤器是否执行,true false,可以写过滤器是否执行的判断条件。
run:具体执行逻辑。
访问:yapi中 网关token
pre来源uri:/api-driver/test/token
pre拦截
pre 业务逻辑 token:msb coolie
说一下AuthFilter。利用filter实现了 鉴权。看代码。(实际用jwt)
测试一下,
// 测试路径
// if(uri.contains("api-driver")) {
// return true;
// }
7.接口容错
@Component
public class MsbFallback implements FallbackProvider{
/**
* 表明为哪个微服务提供回退
* 服务Id ,若需要所有服务调用都支持回退,返回null 或者 * 即可
*/
@Override
public String getRoute() {
// TODO Auto-generated method stub
return "*";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
if (cause instanceof HystrixTimeoutException) {
return response(HttpStatus.GATEWAY_TIMEOUT);
} else {
return response(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
private ClientHttpResponse response(final HttpStatus status) {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
//return status;
return HttpStatus.BAD_REQUEST;
}
@Override
public int getRawStatusCode() throws IOException {
//return status.value();
return HttpStatus.BAD_REQUEST.value();
}
@Override
public String getStatusText() throws IOException {
//return status.getReasonPhrase();
//return HttpStatus.BAD_REQUEST.name();
return HttpStatus.BAD_REQUEST.getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
String msg = "{\"msg\":\"服务故障\"}";
return new ByteArrayInputStream(msg.getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}
8.限流
保护自己,用ratelimit。
令牌桶
令牌桶可以看作是一个存放一定数量令牌的容器。系统按设定的速度向桶中放置令牌。当桶中令牌满时,多出的令牌溢出,桶中令牌不再增加。在使用令牌桶对流量规格进行评估时,是以令牌桶中的令牌数量是否足够满足报文的转发为依据的。每个需要被转发的报文,都要从令牌桶中领取一定数量的令牌(具体数量视报文大小而定),才可以被正常转发。如果桶中存在足够的令牌可以用来转发报文,称流量遵守或符合约定值,否则称为不符合或超标。
- 启动jmeter,双击:jmeter.bat
- 右击TestPlan,add ,Threads,Thread Group
- 右击测试令牌桶线程组,add,sampler, http request。
- 在线程组:
1、Number of Threads(users):用户个数
2、Ramp-up Period(in seconds):在多长时间内,加载指定的用户个数,单位为s。
假如需加载100个用户,在5s中之内加载完成,那么平均每秒钟加载20个用户。
3、Loop Count(循环次数):用户执行操作的循环次数,如果选择forever,则永远循环下去。
测试点:启动eureka,api-driver,online-taxi-zuul。
令牌桶设置成2,jemter 用10个并发。可以看到控制台输出结果。