一、本节重点
实战通过高性能Polaris网关访问后端服务,深入理解高性能Polaris网关启动流程、请求路由转发流程和响应结果的流程设计与实现。重点掌握整体调用链路的设计思路和设计方法,并能够将其灵活应用到自身实际项目中。
二、实战场景
本节,通过高性能网关访问后端服务接口主要验证如下几个简单的场景,验证高性能Polaris网关的核心功能:
- 只启动后端服务,直接访问后端服务接口,正确返回hello polaris。
- 启动网关和后端服务,通过网关访问后端服务接口,正确返回hello polaris。
- 停止后端服务,通过网关访问后端服务接口,返回503:后端服务暂时不可用,请稍后再试。
三、服务规划
实战通过高性能Polaris网关访问后端服务的规划如下所示。
四、测试服务实现
1.实现后端服务
用于测试的后端服务的实现比较简单,主要是通过SpringBoot快速实现一个访问接口。
源码详见:polaris-examples-http工程下的io.binghe.polaris.examples.http.controller.HttpController
@RestController
public class HttpController {
@RequestMapping(value = "/http_test")
public String helloPolaris(){
return "hello polaris";
}
}
就是这么简单,实现一个简单的HTTP接口用于测试即可,正常情况下,接口会返回hello polaris。
随后,基于SpringBoot实现后端服务的启动类即可。
源码详见:polaris-examples-http工程下的io.binghe.polaris.examples.http.HttpExampleStarter。
@SpringBootApplication
public class HttpExampleStarter {
public static void main(String[] args) {
SpringApplication.run(HttpExampleStarter.class, args);
}
}
至此,后端服务实现完毕。
2.实现网关启动服务
由于Polaris网关在启动时,需要通过服务发现从注册中心获取后端服务调用器对象,后端服务的定义对象、网关过滤器规则、后端服务实例对象等,将其存放到本地缓存并定期更新。由于目前我们是测试网关访问后端服务的接口,先直接创建对应的实例对象放到本地缓存。
后续我们会通过SPI对接多个注册中心实现服务注册与发现,基于SPI对接多个配置中心,基于SPI实现多种负载均衡算法,实现熔断限流,实现网关热插拔插件,并且为了简化服务对接网关,也会专门设计和开发服务对接网关的SDK等等,妥妥的企业级网关。
好了,开始实现网关的启动服务。
源码详见:polaris-examples-http-gateway工程下的io.binghe.polaris.examples.http.HttpExampleGatewayStarter。
为了大家理解的更加清晰,这里,我对HttpExampleGatewayStarter类的实现方法进行拆解。
(1)实现main()方法
main()方法也是测试网关的启动服务的入口,主要实现如下所示。
public static void main(String[] args) {
// 初始化后端服务相关配置
initServiceConfig();
// 启动网关
startPolaris(args);
}
可以看到,在main()方法的实现中,主要调用了initServiceConfig()方法初始化后端服务配置,随后调用了startPolaris()方法加载网关的核心配置并启动网关。
(2)实现initServiceConfig()方法
initServiceConfig()方法是模拟服务发现加载后端服务配置的核心方法,这里,对initServiceConfig()方法的实现进行拆解。
定义基础变量
定义后端服务的基本信息,例如访问的后端接口path,服务id,版本号、唯一id、规则id、访问协议、目标后端服务地址等,源码如下所示。
// 接口path
String path = "/http_test";
String serviceId = "100001";
String version = "1.0.0";
String uniqueId = serviceId + ":" + version;
String ruleId = "10001";
String protocol = "http";
String targetAddress = "localhost:8080";
这里,需要注意的是通过网关访问后端服务时,请求头中需要携带uniqueId。
创建服务调用器对象
创建服务调用器对象的源码如下所示。
// 创建ServiceInvoker对象
ServiceInvoker serviceInvoker = new HttpServiceInvoker();
serviceInvoker.setInvokerPath(path);
serviceInvoker.setRuleId(ruleId);
serviceInvoker.setTimeout(5000);
可以看到,在serviceInvoker服务调用器对象中,主要封装了调用后端服务的path,规则id和超时时间。
创建服务定义对象
服务定义对象会注册到服务注册中心,是对后端服务的一种描述,会封装后端服务的详情信息,源码如下所示。
// 创建ServiceDefinition对象,后续注册到注册中心
ServiceDefinition serviceDefinition = new ServiceDefinition();
serviceDefinition.setServiceId(serviceId);
serviceDefinition.setVersion(version);
serviceDefinition.setUniqueId(uniqueId);
serviceDefinition.setProtocol(protocol);
serviceDefinition.setPatternPath(path);
serviceDefinition.setEnvType("local");
Map<String, ServiceInvoker> invokerMap = new HashMap<>();
invokerMap.put(path, serviceInvoker);
serviceDefinition.setInvokerMap(invokerMap);
ConfigCacheFactory.getInstance().putServiceDefinition(uniqueId, serviceDefinition);
可以看到,serviceDefinition服务定义对象中主要封装后端服务的定义信息,并切会封装封装后端服务path与服务调用器的关系,最终会将serviceDefinition服务定义对象存储到本地缓存。
实现规则定义
对过滤器的规则进行实现和封装,源码如下所示。
Set<FilterRule> filterRules = new HashSet<>();
FilterRule filterRule = new FilterRule();
filterRule.setId(FilterConstants.LOADBALANCER_FILTER_ID);
filterRule.setConfig("{\"balanceType\" : \"roundRibbonBalance\"}");
filterRules.add(filterRule);
filterRule = new FilterRule();
filterRule.setId(FilterConstants.HTTP_FILTER_ID);
filterRules.add(filterRule);
filterRule = new FilterRule();
filterRule.setId(FilterConstants.ERROR_FILTER_ID);
filterRules.add(filterRule);
Rule rule = new Rule(ruleId, "测试规则", protocol, serviceId, path, Arrays.asList(path), 1, filterRules);
ConfigCacheFactory.getInstance().putRule(ruleId, rule);
可以看到,这里会创建对个过滤器规则,将其封装到一个Set集合中,最终将Set集合封装到总体规则对象Rule中,并存储到本地缓存。
需要注意的是:每个规则的id需要对应过滤器实现类上@Filter注解的id属性的值。
实现服务实例对象
服务实例对象会注册到服务注册中心,这里模拟创建服务实例对象,并将其存储到本地缓存。源码如下所示。
ServiceInstance serviceInstance = new ServiceInstance();
serviceInstance.setInstanceId(targetAddress);
serviceInstance.setUniqueId(uniqueId);
serviceInstance.setAddress(targetAddress);
serviceInstance.setWeight(100);
serviceInstance.setRegisterTime(System.currentTimeMillis());
serviceInstance.setVersion(version);
ConfigCacheFactory.getInstance().addServiceInstance(uniqueId, serviceInstance);
可以看到,服务实例对象中封装了后端服务实例的具体信息,包括服务的目标地址,唯一id、权重、注册时间、版本号等,最终将服务实例存储到本地缓存。
(3)实现startPoalris()方法
startPoalris()方法是启动Poalris网关的核心方法,源码如下所示。
private static void startPolaris(String[] args) {
// 加载配置
PolarisConfig polarisConfig = PolarisConfigLoader.getInstance().loadConfig(args);
// 初始化容器
PolarisContainer container = new PolarisContainer(polarisConfig);
// 启动容器
container.start();
// 优雅关闭
Runtime.getRuntime().addShutdownHook(new Thread(container::shutdown));
}
相信小伙伴们对于startPolaris()方法的实现并不陌生,加载网关核心配置,创建并启动容器来驱动网关的运行,在优雅关闭中停止容器。
至此,高性能Polaris网关的测试程序实现完毕。
五、测试场景验证
接下来,对网关的测试场景进行验证。
场景一: 只启动后端服务,直接访问后端服务接口,正确返回hello polaris。
只启动后端服务后,通过Apifox访问http://localhost:8080/http_test,如下所示。
测试结果符合预期,正确返回了hello polaris字符串。
场景二: 启动网关和后端服务,通过网关访问后端服务接口,正确返回hello polaris。
启动网关和后端服务后,通过Apifox访问http://localhost:10000/http_test,如下所示。
测试结果符合预期,正确返回了hello polaris字符串。
场景三: 停止后端服务,通过网关访问后端服务接口,返回503:后端服务暂时不可用,请稍后再试。
停止后端服务后,通过Apifox访问http://localhost:10000/http_test,如下所示。
测试结果符合预期,正确返回了503:后端服务暂时不可用,请稍后再试。
六、本节总结
本节主要以实现的形式通过高性能Poalris网关访问后端服务接口,对典型的正常和异常场景都进行了验证,结果都符合预期效果。
希望这节内容能够为大家带来实质性的收获,最后,可以在评论区写下你学完本章节的收获,祝大家都能学有所成,我们一起搞定高性能Polaris网关。