背景介绍
在信也科技公司内部,存在着各种类型版本的系统,如SpringBoot1.5.*、SpringBoot2.0.*、Sofa等系统,远程调用方式有Feign、RestTemplate、OkHttpClient、Apache HttpClient,还有自研的HttpClient等调用方式。应用与应用之间的调用是通过Nginx域名的方式调用。这种方式存在如下一些问题:
- 无法进行精细化流量调控。
- 无法支持多环境。
- 缺少统一的监控。
- 缺少统一的熔断限流。
- 缺少模拟测试功能。
- 缺少应用和接口的拓扑信息。
微能力架构设计
在将项目进行微服务改造之前,我们在思考微服务的核心是什么?
经过深入的思考与调研,发现熔断限流、流量调节、监控是微服务系统中最重要的功能。
那如何实现在存量应用不改代码的情况下,让应用平滑升级到现代微服务架构上来呢?经过研究,我们发现可以采用一种拦截器的方式来实现,具体架构图如下:
具体实现步骤如下:
- 提供方启动的时候,会将当前应用的域名,IP和端口等信息向注册中心注册,注册成功后,会定时向注册中心发送心跳来保活。
- 当提供方启动、退出或者元数据信息发生变更的时候,注册中心会将提供方的信息推送到消费方。
- 当消费方在发起请求的时候,通过拦截消费方的请求,将域名替换成IP和端口,如果此时提供方未注册到注册中心,客户端会采用传统的域名方式进行调用。在拦截的时候,可以添加一些监控埋点,方便监控远程调用情况,也可以在请求的信息头中添加一些透传信息,方便实现多环境等功能。
- 当提供方收到请求时,拦截器会拦截入口请求。此时在拦截器中,可以添加一些监控埋点,也可以采集上下游接口信息生成拓扑关系。
拦截器方式的优点,对于上下游升级没有先后依赖顺序,通过开关配置也可以很方便的回退到传统的基于Nginx域名方式进行调用。
原理与实现
注意下文所说的应用是基于SpringBoot Web这种类型的应用。
下面会简单介绍一下拦截器的原理与实现:
拦截器分两种,一种是服务提供方拦截器,一种是消费方拦截器。
服务提供方拦截器是指SpringBoot应用中的各种filter。Spring应用中的filter会拦截所有的入口请求。通过此filter可以实现上述所说的相关功能,不在此详加描述。
消费方拦截器是指各种发起方在进行远程调用时的Intercetpor。对于Java应用程序来说,我们常见的远程调用方式分为四种,OkHttp、 Apache HttpClient、RestTemplate、Feign。而RestTemplate和Feign 底层依赖于 OkHttp、Apache HttpClient 或者Java JDK自带的HttpClient。总结来说消费方调用方式只有三种:OkHttp、Apache HttpClient、Java JDK自带的HttpClient,下面会分别介绍这几种类型。
1.OkHttp,当消费方发起远程调用的时候会调用一系列的Interceptor, 我们只需要在OkHttp创建的时候注入自定义的Interceptor,就可以拦截所有消费方的请求,比如域名替换,监控,信息透传等功能。
2.Apache HttpClient,Apache HttpClient 实例在执行的过程中,最后都会调用InternalHttpClient的doExecute方法,我们只需要修改一下InternalHttpClient源码,在InternalHttpClient 的doExecute方法中加入自己的逻辑即可。
3.RestTemplate,RestTemplate的底层会调用OkHttp、Apache HttpClient或者JDK HttpClient,如果是OkHttp、Apache HttpClient, 前面的介绍已经支持;如果是JDK HttpClient ,只需要在RestTemplate添加 ClientHttpRequestInterceptor 即可。
4.最后一种是Feign,Feign的底层实现同RestTemplate类似, 最终也是调用OkHttp、Apache HttpClient或者JKD HttpClient,如果是 OkHttp、Apache HttpClient, 前面的介绍已经支持;如果是原始的JDK HttpClient 只需要继承Client.Default,覆盖调用excute方法即可。
总结
综上所述,拦截器的本质是拦截应用的“入口”和“出口”来实现微服务的各种功能。
通过上面的介绍,我们再回过头看开始提出的几个问题:
- 无法进行精细化流量调控。我们通过在后台控制页面上,设置应用相关实例的权重,然后注册中心将这些权重信息下发到消费端,在将域名替换成IP的时候,根据这些权重规则,选择相应的IP实例,即可实现精细化流量管控。
- 无法支持多环境。应用实例注册的时候,会将IP,端口,环境信息注册到注册中心,消费方发起调用在域名替换的时候,优先选择相同环境的实例,同时会将起始的环境信息通过header往下游传递,以此来实现多环境的功能。
- 缺少统一的监控。服务的提供方和消费方统一监控埋点。
- 缺少统一的熔断限流。可以在服务提供方加上一个统一的熔断限流filter,来实现统一的熔断限流功能。
- 缺少模拟测试功能。在真实的测试环境中,有时候会遇到一些参数难以模拟的情况,此时就可以通过服务提供方的参数采集功能来实现。服务提供方的filter会抽样采集接口的请求入参,header,地址等信息,用户可以通过后台界面对某个接口对指定的IP重新发起请求,来模拟测试真实的调用。
- 缺少应用和接口的拓扑信息。服务提供方的拦截器,可以通过记录上游的appid,当前的appid,接口地址,来生成对应的拓扑关系。
本文来自拍码场,经授权后发布,本文观点不代表信也智慧金融研究院立场,转载请联系原作者。