有奖捉虫:行业应用 & 管理与支持文档专题 HOT

操作场景

TSF 支持使用单元化功能以达到让不同的业务流量根据一定的单元化规则分发到指定的单元里,不同单元之间通过微服务网关实现跨单元调用,当某个单元内的服务器实例出现问题时也不会影响到其他单元业务的使用,使得业务受影响粒度达到最小,同时单元化也为业务容灾高可用提供了强有力的保障。
说明
单元化网关支持跨命名空间调用,单元化配置仅支持部署在全局命名空间下的网关。
从1.28.0版本开始,TSF 微服务网关 SDK 支持提供基于 Zuul / Scg 的单元化功能。
微服务网关要么是单元化网关,要么是非单元化网关,开启了单元化的功能,该网关就是单元化网关,否则就是非单元化网关。

前提条件

开始实践单元化功能前,请确保已完成了 下载 Maven,同时请确保 SDK 版本高于1.28

操作步骤

先暴露 Provider 服务接口,然后将单元化规则配置在调用方 Consumer 工程或微服务网关工程里面。

步骤1:配置工程

微服务网关工程

开始实践微服务网关单元化功能之前,请确保您已完成 微服务网关开发
向自定义网关过滤器 Filter 类中添加 tag 标签:
Zuul 网关实例
Scg 网关实例
// 下面省略了无关的代码
import com.tencent.tsf.gateway.core.annotation.TsfGatewayFilter;
import com.tencent.tsf.gateway.core.constant.TsfGatewayFilterOrderConstants;
import com.tencent.tsf.unit.TsfUnitContext;
import org.springframework.tsf.core.entity.Tag;

@TsfGatewayFilter
public class TestFilter extends TsfGatewayZuulFilter {

private Logger logger = LoggerFactory.getLogger(TestFilter.class);

@Override
public String filterType() {
return PRE_TYPE;
}

@Override
public int filterOrder() {
// 注:设置 putTag 的filter的order必须在ZUUL_UNIT_ORDER之前
return TsfGatewayFilterOrderConstants.ZUUL_UNIT_ORDER - 1;
}

@Override
public boolean shouldFilter() {
return true;
}

@Override
public Object run() throws ZuulException {
// 单元化场景的putTag操作
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String userId = request.getHeader("userId");

if(StringUtils.isNotBlank(userId)) {
logger.info("put unit tag userId:{}", userId);
// 针对 “网关 -> A -> B ...” 的长链路场景,标签 Tag 需使用 TRANSITIVE 传递下去
TsfUnitContext.putTag("userId", userId, Tag.ControlFlag.TRANSITIVE);
}

System.out.println("hello world");
logger.info("hello world");
return null;
}
}
// 下面省略了无关的代码
import com.tencent.tsf.gateway.core.annotation.TsfGatewayFilter;
import com.tencent.tsf.gateway.core.constant.TsfGatewayFilterOrderConstants;
import com.tencent.tsf.gateway.scg.AbstractTsfGlobalFilter;
import com.tencent.tsf.unit.TsfUnitContext;

@TsfGatewayFilter
public class TestFilter extends AbstractTsfGlobalFilter {

private static final Logger logger = LoggerFactory.getLogger(TestFilter.class);

@Override
public int getOrder() {
// 注:设置 putTag 的filter的order必须在SCG_UNIT_ORDER之前
return TsfGatewayFilterOrderConstants.SCG_UNIT_ORDER - 1;
}

@Override
public boolean shouldFilter(ServerWebExchange exchange, GatewayFilterChain chain) {
return true;
}

@Override
public Mono<Void> doFilter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 单元化场景的putTag操作
ServerHttpRequest request = exchange.getRequest();
String userId = request.getHeaders().getFirst("userId");

if(StringUtils.isNotBlank(userId)) {
logger.info("put unit tag userId:{}", userId);
// 针对 “网关 -> A -> B ...” 的长链路场景,标签 Tag 需使用 TRANSITIVE 传递下去
TsfUnitContext.putTag("userId", userId, Tag.ControlFlag.TRANSITIVE);
}
System.out.println("hello world");
logger.info("hello world");
return chain.filter(exchange);
}
}
使用包 com.tencent.tsf.unit 下的类 TsfUnitContext 的方法 putTag 来设置单元化标签。
自定义设置 putTag 的 Filter 的 order 顺序必须在 TsfGatewayFilterOrderConstants.ZUUL_UNIT_ORDER 或 TsfGatewayFilterOrderConstants.SCG_UNIT_ORDER 之前。

Consumer 工程

1. 向 Consumer 工程中添加依赖
pom.xml 中添加以下代码:
<dependency>
<groupId>com.tencent.tsf</groupId>
<artifactId>spring-cloud-tsf-starter</artifactId>
<version><!-- 调整为 SDK 最新版本号 --></version>
</dependency>
2. 向 Application 类中添加注解 @EnableTsf@ComponentScan
// 下面省略了无关的代码
@SpringBootApplication
@EnableTsf
@EnableFeignClients // 使用Feign微服务调用时请启用
@ComponentScan(basePackages="com.tsf.demo.consumer.*") // 需要扫描单元化@TsfUnitRule注解所在的包
public class ConsumerApplication {
public static void main(String[] args) throws InterruptedException {
SpringApplication.run(ConsumerApplication.class, args);
}
}
3. 配置单元化规则
Feign 调用:
1.1 使用 @TsfUnitRule 配置单元化规则。
@FeignClient(name = "provider-demo")
public interface ProviderDemoService {

@TsfUnitRule(ruleGenerator = "com.tsf.demo.consumer.util.UserIdGenerator")
@RequestMapping(value = "/echo/unit/{str}", method = RequestMethod.GET)
String echoUnit(@PathVariable("str") String str);
}
1.2 在代码中编写单元化规则。 需要编写一个类实现接口 TsfUnitRuleGenerator 的方法 generateRule,计算出单元化规则的 tag 标签值,该类就是步骤3中 @TsfUnitRule 的 ruleGenerator 属性指定的类。
// 下面省略了无关的代码
public class UserIdGenerator implements TsfUnitRuleGenerator {

@Override
public Map<String, String> generateRule(Method method, Object[] args) {
String userId = (String)args[0];
Map<String, String> ruleMap = new HashMap<>();
// 添加单元化规则的tag key
ruleMap.put("userId", userId);
return ruleMap;
}

}
可以看到,TSF 的单元化功能针对Feign调用只需在需要单元化的类或方法上增加一个注解并添加对应的单元化规则即可(需要该 Bean 类被 Spring 所管理)。
说明
注解@TsfUnitRule支持配置在类上,也支持配置在方法上。如果是配置在类上,则单元化规则对该类所有的方法都生效。
RestTemplate 调用: 在 Consumer 中设置 tag ,使用 com.tencent.tsf.unit 包中的 TsfUnitContext 类,设置单元化 Tag 的方法:
@RequestMapping(value = "/echo-rest-unit/{str}", method = RequestMethod.GET)
public String restUnit(@PathVariable String str,
@RequestParam(required = false) String tagName,
@RequestParam(required = false) String tagValue) {
if (!StringUtils.isEmpty(tagName)) {
// 添加单元化规则tag key和value
TsfUnitContext.putTag(tagName, tagValue);
}
return restTemplate.getForObject("http://provider-demo/echo/unit/" + str, String.class);
}
说明
设置单元化规则的 tag 类是 com.tencent.tsf.unit.TsfUnitContext,不是 org.springframework.tsf.core.TsfContext。

步骤2:开启单元化功能并创建单元化规则

在 TSF 控制台开启单元化功能并创建单元化规则,详细操作参见 单元化部署