# 《高性能Polaris网关》牛刀小试-第01节:实战通过高性能Polaris网关访问后端服务

作者:冰河
星球:http://m6z.cn/6aeFbs (opens new window)
博客:https://binghe.gitcode.host (opens new window)
文章汇总:https://binghe.gitcode.host/md/all/all.html (opens new window)
源码获取地址:https://t.zsxq.com/0dhvFs5oR (opens new window)

沉淀,成长,突破,帮助他人,成就自我。

  • 本节难度:★★★☆☆
  • 本节重点:实战通过高性能Polaris网关访问后端服务,深入理解高性能Polaris网关启动流程、请求路由转发流程和响应结果的流程设计与实现。重点掌握整体调用链路的设计思路和设计方法,并能够将其灵活应用到自身实际项目中。

截止到目前,我们已经实现了网关的最基础与最核心的功能,主要包括:需求设计、总体架构设计、环境搭建、通用模型设计与实现、基于自定义SPI设计与实现通用过滤器、高性能BatchEvent模式与MPMC模式缓冲队列通用处理器的设计与实现、HTTP核心处理器的设计与实现和网关核心启动容器的设计与实现。

专栏已上线,点击学习:https://binghe.gitcode.host/md/project/gateway/start/2024-05-19-start.html (opens new window)

期间,也设计和实现了众多的网关组件。那如何检验我们自己手搓的高性能网关的功能是否满足需求呢?最好的方式就是实际通过网关访问后端服务的接口验证下网关的功能是否符合我们的预期。

# 一、背景

截止到目前,我们完成了《高性能Polaris网关》的八大篇章的设计与实现,也对代码进行了深度的设计与封装实现,代码结构如下图所示。


在需求设计篇章: 详细设计了高性能Polaris网关的需求,对网关要实现的功能和性能进行了明确的定义和设计。

在总体架构设计篇章: 详细设计了网关的总体方案目标、架构设计和网关的数据模型。

在环境搭建篇章: 详细搭建了网关的基础环境与研发环境、搭建了项目总体框架与工程结构并详细搭建了Maven私服仓库用来开发高性能Polaris网关。

在通用模型设计篇章: 完成了整个通用模型的设计,为整个Polaris网关后续的设计和研发奠定了坚实的基础。相信小伙伴们对网关已经并不陌生,一个网关本质上最基础和最核心的功能就是接收客户端请求,根据一定的策略将请求转发至后端服务,随后接收后端服务的响应结果,再将结果响应给客户端。在此基础上,网关可以实现各种策略功能,例如:限流、熔断、降级、重试、负载均衡、流控、灰度、蓝绿发布等等一系列的功能。

在通用过滤器设计篇章: 对网关的顶级核心过滤器接口进行了设计和实现,也进一步封装了请求和响应的模型,对网关过滤器的两大顶级抽象类和整体过滤器链进行了设计和实现。基于自定义SPI实现了负载均衡过滤器、超时配置过滤器、HTTP过滤器、RPC过滤器、指标分析过滤器、Mock过滤器、灰度过滤器、错误处理过滤器。

注意:网关通过SPI内置了各种过滤器的实现,如果网关内置的过滤器不满足需求,大家也可以通过SPI扩展自己特定场景的过滤器。

在通用处理器篇章: 在网关的处理器设计中,我们重点设计和实现了通用处理器接口,基于Netty实现了核心处理器的功能,并且基于BatchEvent和MPMC两种模式实现了缓冲队列。在此基础上,基于自定义SPI扩展实现了BatchEvent模式处理器和MPMC模式处理器。在实现缓冲队列时,重点参考了JDK的队列实现,并且在JDK队列实现的基础上,做了进一步优化。所以,各位小伙伴们在学习自定义缓冲队列时,可以结合JDK的Queue接口及其实现类等深入学习和理解。

在HTTP处理器篇章: 对HTTP处理器的核心接口、服务端核心处理器与连接管理器进行了设计与实现,并且基于Netty对网关的服务端和客户端进行了设计与实现。其他服务或者客户端可以通过HTTP协议、RPC协议和WebSocket协议访问网关。

在核心启动流程篇章: 对网关的核心启动容器与核心启动加载流程进行了设计与实现。

# 二、本节重点

实战通过高性能Polaris网关访问后端服务,深入理解高性能Polaris网关启动流程、请求路由转发流程和响应结果的流程设计与实现。重点掌握整体调用链路的设计思路和设计方法,并能够将其灵活应用到自身实际项目中。

# 三、实战场景

本节,通过高性能网关访问后端服务接口主要验证如下几个简单的场景,验证高性能Polaris网关的核心功能:

  • 只启动后端服务,直接访问后端服务接口,正确返回hello polaris。
  • 启动网关和后端服务,通过网关访问后端服务接口,正确返回hello polaris。
  • 停止后端服务,通过网关访问后端服务接口,返回503:后端服务暂时不可用,请稍后再试。

# 四、服务规划

实战通过高性能Polaris网关访问后端服务的规划如下所示。

服务名 服务说明 端口 接口
polaris-examples-http 后端服务 8080 /http_test
polaris-examples-http-gateway 网关服务 10000 访问polaris-examples-http的接口用来测试

# 五、测试服务实现

# 5.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";
    }
}
1
2
3
4
5
6
7

就是这么简单,实现一个简单的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);
    }
}
1
2
3
4
5
6

至此,后端服务实现完毕。

# 5.2 实现网关启动服务

由于Polaris网关在启动时,需要通过服务发现从注册中心获取后端服务调用器对象,后端服务的定义对象、网关过滤器规则、后端服务实例对象等,将其存放到本地缓存并定期更新。由于目前我们是测试网关访问后端服务的接口,先直接创建对应的实例对象放到本地缓存。

后续我们会通过SPI对接多个注册中心实现服务注册与发现,基于SPI对接多个配置中心,基于SPI实现多种负载均衡算法,实现熔断限流,实现网关热插拔插件,并且为了简化服务对接网关,也会专门设计和开发服务对接网关的SDK等等,妥妥的企业级网关。

好了,开始实现网关的启动服务。

源码详见:polaris-examples-http-gateway工程下的io.binghe.polaris.examples.http.HttpExampleGatewayStarter。

为了大家理解的更加清晰,这里,我对HttpExampleGatewayStarter类的实现方法进行拆解。

# 5.2.1 实现main()方法

main()方法也是测试网关的启动服务的入口,主要实现如下所示。

public static void main(String[] args) {
    // 初始化后端服务相关配置
    initServiceConfig();
    // 启动网关
    startPolaris(args);
}
1
2
3
4
5
6

可以看到,在main()方法的实现中,主要调用了initServiceConfig()方法初始化后端服务配置,随后调用了startPolaris()方法加载网关的核心配置并启动网关。

# 5.2.2 实现initServiceConfig()方法

initServiceConfig()方法是模拟服务发现加载后端服务配置的核心方法,这里,对initServiceConfig()方法的实现进行拆解。

(1)定义基础变量

定义后端服务的基本信息,例如访问的后端接口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";
1
2
3
4
5
6
7
8

这里,需要注意的是通过网关访问后端服务时,请求头中需要携带uniqueId。

(2)创建服务调用器对象

创建服务调用器对象的源码如下所示。

// 创建ServiceInvoker对象
ServiceInvoker serviceInvoker = new HttpServiceInvoker();
serviceInvoker.setInvokerPath(path);
serviceInvoker.setRuleId(ruleId);
serviceInvoker.setTimeout(5000);
1
2
3
4
5

可以看到,在serviceInvoker服务调用器对象中,主要封装了调用后端服务的path,规则id和超时时间。

(3)创建服务定义对象

服务定义对象会注册到服务注册中心,是对后端服务的一种描述,会封装后端服务的详情信息,源码如下所示。

// 创建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);
1
2
3
4
5
6
7
8
9
10
11
12

可以看到,serviceDefinition服务定义对象中主要封装后端服务的定义信息,并切会封装封装后端服务path与服务调用器的关系,最终会将serviceDefinition服务定义对象存储到本地缓存。

(4)实现规则定义

对过滤器的规则进行实现和封装,源码如下所示。

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);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

可以看到,这里会创建对个过滤器规则,将其封装到一个Set集合中,最终将Set集合封装到总体规则对象Rule中,并存储到本地缓存。

需要注意的是:每个规则的id需要对应过滤器实现类上@Filter注解的id属性的值。

(5)实现服务实例对象

服务实例对象会注册到服务注册中心,这里模拟创建服务实例对象,并将其存储到本地缓存。源码如下所示。

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);
1
2
3
4
5
6
7
8

可以看到,服务实例对象中封装了后端服务实例的具体信息,包括服务的目标地址,唯一id、权重、注册时间、版本号等,最终将服务实例存储到本地缓存。

5.2.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));
}
1
2
3
4
5
6
7
8
9
10

相信小伙伴们对于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网关。

# 写在最后

在冰河的知识星球除了目前正在热更的高性能网关和RPC视频外,还有其他9个项目,像DeepSeek大模型、手写高性能熔断组件、手写通用指标上报组件、手写高性能数据库路由组件、分布式IM即时通讯系统、Sekill分布式秒杀系统、手写RPC、简易商城系统等等,这些项目的需求、方案、架构、落地等均来自互联网真实业务场景,让你真正学到互联网大厂的业务与技术落地方案,并将其有效转化为自己的知识储备。

值得一提的是:冰河自研的Polaris高性能网关比某些开源网关项目性能更高,并且冰河也正在为企业级高性能RPC框架录制视频,全程带你分析原理和手撸代码。 你还在等啥?不少小伙伴经过星球硬核技术和项目的历练,早已成功跳槽加薪,实现薪资翻倍,而你,还在原地踏步,抱怨大环境不好。抛弃焦虑和抱怨,我们一起塌下心来沉淀硬核技术和项目,让自己的薪资更上一层楼。


目前,领券加入星球就可以跟冰河一起学习《DeepSeek大模型》、《手写高性能通用熔断组件项目》、《手写高性能通用监控指标上报组件》、《手写高性能数据库路由组件项目》、《手写简易商城脚手架项目》、《手写高性能RPC项目》和《Spring6核心技术与源码解析》、《实战高并发设计模式》、《分布式Seckill秒杀系统》、《分布式IM即时通讯系统》和《手写高性能Polaris网关》,从零开始介绍原理、设计架构、手撸代码。

花很少的钱就能学这么多硬核技术、中间件项目和大厂秒杀系统与分布式IM即时通讯系统,比其他培训机构不知便宜多少倍,硬核多少倍,如果是我,我会买他个十年!

加入要趁早,后续还会随着项目和加入的人数涨价,而且只会涨,不会降,先加入的小伙伴就是赚到。

另外,还有一个限时福利,邀请一个小伙伴加入,冰河就会给一笔 分享有奖 ,有些小伙伴都邀请了50+人,早就回本了!

# 九、其他方式加入星球

  • 链接 :打开链接 http://m6z.cn/6aeFbs 加入星球。
  • 回复 :在公众号 冰河技术 回复 星球 领取优惠券加入星球。

特别提醒: 苹果用户进圈或续费,请加微信 hacker_binghe 扫二维码,或者去公众号 冰河技术 回复 星球 扫二维码加入星球。

好了,今天就到这儿吧,我是冰河,我们下期见~~