版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
【前言】
在上篇博文中《灰度实战(五):SpringCloud灰度(1)》讲解了SpringCloud项目的灰度实战,其中在zuul中拦截到是灰度请求时采用重定向再次请求网关然后分发至灰度服务,在本篇将zuul针对灰度请求分发策略进行优化,由重定向优化为直接转发提高性能。
【SpringCloud灰度实战】
一、项目简介
1、重定向方式的灰度转发策略示意图:
2、直接转发方式的灰度转发策略示意图:
3、对比:
从示意图中不难发现,zuul网关在进行灰度分发时直接转发比重定向少了一次请求,直接分发到业务系统。
二、代码调整
1、增加直接转发拦截器---GrayDirectZuulFilter
/*
* Copyright (c) 2019. [email protected] All Rights Reserved.
* 项目名称:灰度实战
* 类名称:GrayDirectZuulFilter.java
* 创建人:张晗
* 联系方式:[email protected]
* 开源地址: https://github.com/dangnianchuntian/springboot
* 博客地址: https://blog.csdn.net/zhanghan18333611647
*/
package com.zhanghan.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.zhanghan.zuul.bean.GrayBean;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
import org.springframework.util.StreamUtils;
import org.springframework.web.util.UrlPathHelper;
import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.nio.charset.Charset;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.*;
public class GrayDirectZuulFilter extends ZuulFilter {
@Autowired
private GrayBean grayBean;
@Autowired
private RouteLocator routeLocator;
@Autowired
private UrlPathHelper urlPathHelper;
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return grayBean.isEnabled();
}
@Override
public Object run() {
Boolean isGray = shouldBeRedirected();
if (isGray) {
String grayServiceId = getServiceId() + grayBean.getSuffix();
String url = RequestContext.getCurrentContext().getRequest().getRequestURI();
url = replaceUrl(url, grayServiceId);
try {
RequestContext.getCurrentContext().put(REQUEST_URI_KEY, url);
RequestContext.getCurrentContext().put(SERVICE_ID_KEY, grayServiceId);
} catch (Exception e) {
return null;
}
}
return null;
}
/**
* 是否为灰度请求 依据条件同时满足1和2为灰度请求: 1.请求在灰度列表中 2.companyNo为配置的灰度companyNo
*
* @return true灰度 false不灰度
*/
private Boolean shouldBeRedirected() {
HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
if (grayBean.getGraylist().isEmpty()) {
return false;
}
String serviceId = getServiceId();
if (!grayBean.getGraylist().contains(serviceId)) {
return false;
}
Object companyNo = getParment(request, "companyNo");
if (null != companyNo && companyNo.toString().equals(grayBean.getCompanyNo())) {
return true;
}
return false;
}
/**
* 转换为灰度url
*
* @param url 原url
* @param grayServiceId 灰度服务id
* @return
*/
private String replaceUrl(String url, String grayServiceId) {
grayServiceId = grayServiceId.replace(grayBean.getSuffix(), "");
return url.replace("/" + grayServiceId, "");
}
/**
* 获取本次请求的serviceId
*
* @return
*/
private String getServiceId() {
HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
Object object = RequestContext.getCurrentContext().get(SERVICE_ID_KEY);
String serviceId = object == null ? null : object.toString();
if (StringUtils.isEmpty(serviceId)) {
String requestURI = urlPathHelper.getPathWithinApplication(request);
serviceId = routeLocator.getMatchingRoute(requestURI).getLocation();
}
return serviceId;
}
/**
* 获取post请求的body
*
* @param request
* @param parmentKey
* @return
*/
private static Object getParment(HttpServletRequest request, String parmentKey) {
try {
String charset = request.getCharacterEncoding();
InputStream inputStream = request.getInputStream();
String body = StreamUtils.copyToString(inputStream, Charset.forName(charset));
if (StringUtils.isEmpty(body)) {
return null;
}
JSONObject json = JSONObject.fromObject(body);
return json.get(parmentKey);
} catch (Exception e) {
return null;
}
}
}
2、启动类关闭GrayRedirectZuulFilter的注入,启用GrayDirectZuulFilter注入
/*
* Copyright (c) 2019. [email protected] All Rights Reserved.
* 项目名称:灰度实战
* 类名称:ZhZuulApplication.java
* 创建人:张晗
* 联系方式:[email protected]
* 开源地址: https://github.com/dangnianchuntian/springboot
* 博客地址: https://blog.csdn.net/zhanghan18333611647
*/
package com.zhanghan.zuul;
import com.zhanghan.zuul.filter.GrayDirectZuulFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZhZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZhZuulApplication.class, args);
}
/**
* 重定向方式的Filter---性能低
*/
// @Bean
// public GrayRedirectZuulFilter grayRedirectZuulFilter() {
// return new GrayRedirectZuulFilter();
// }
/**
* 直接跳转方式的Filter---性能高建议采用
*
* @return
*/
@Bean
public GrayDirectZuulFilter grayDirectZuulFilter() {
return new GrayDirectZuulFilter();
}
}
3、其他代码
灰度实战:https://github.com/dangnianchuntian/gray
项目模块:gray-cloud
三、演示灰度
效果和上篇博文效果一致,在此不再赘述;
【总结】
1、本节将SpringCloud中利用zuul灰度重定向优化为直接调用至灰度服务。
2、在接下来会为大家演示SpringCloud链式调用情况下如何做灰度。