作者 | 申言方
一、背景
随着业务的增长,作为 QA 的我们开发了一系列的测试工具,随着代码量的增加和工具的增多,商业测试平台应运而生。平台的愿景是在平时的工作中提高 QA 测试效率,帮助 RD 实现自测,但是在实际的使用发现了一些问题:
1.测试平台只能加载一个 rpc 服务的配置文件;
2.测试平台加载的 rpc 服务配置文件无法实时变更,做到因人而异;
3.测试平台不能够并发调用不同机器上的 rpc 服务,“各用个的” 互不影响。
以上 3 个问题,究其根本原因就是作为测试平台的 WF 站点,不能根据需要调用指定机器上的 RPC 服务,即 rpcclient 在线下环境不能够动态的调用不同机器上的 RPC 服务。
释疑:转转有完整的测试环境网络隔离,所有测试用机器统一在环境管理平台上管理,大致分为测试环境、稳定环境、沙箱环境等,而这些环境中的 RPC 服务,无法注册并使用线上的服务管理平台。关于环境平台详见转转 QA 公众号前述分享:转转测试环境平台解决方案https://mp.weixin.qq.com/s/iFeKq2ozW3G3m8pe0wt45A。
二、用到的知识点
1.JAVA 类加载机制
主要有 父类优先策略 和 子类优先策略,顾名思义父类优先策略,当前 classloader 加载类时,先委托父类去加载,形成一个类加载的链路。子类优先策略,则是首先当前 classloader 在自己的 classpath 中寻找 class 文件。
2.类加载同名类的处理
在同一个 cloassloader 中,加载 classpath 中靠前的类。
3.JAVA 动态代理
java.lang.reflect.* 系列提供的功能
4.ThreadLocal
java.lang.ThreadLocal
三、测试平台
先来看一下商业测试平台目前的实现方式,以创建商品并投放为例,在提交之前,需要手动选择一下需要调用的 rpc 服务所在机器的 ip,这个下拉列表是调用环境平台的 api,获取当前用户拥有操作权限的所有机器,再加上默认的测试稳定环境、沙箱稳定环境。
在加上其他必填的参数后,点击提交,页面上就会展示本次请求的执行结果
wf 站点的日志中可以看到本次请求所调用到的 rpc 服务所在的 ip
针对背景中提到的 3 个问题,测试平台通过接入公司内网 sso,调用环境平台对应 api,实时获取 ip 列表,并动态生成 rpc 服务配置文件来解决问题 2;问题 1、3 需要修改 rpcclient 来实现。
四、rpcclient 动态调用 RPC 服务
为了实现 “rpcclient 动态调用 RPC 服务” 这一功能,rpcclient 需要实现加载多个 rpc.config,我用两种方式分别针对不同的 rpcclient 版本,实现了这一功能
方案 1
低版本的 rpcclient 调用逻辑见下图,保密性原因省去具体类名称,主要就是使用了 java 的动态代理机制,来反射生成需要调用的 rpc 服务,通过解析默认位置的 rpc 服务配置文件,来确定 rpc 服务所在的机器及端口,通过序列化和反序列化来传递调用参数和返回结果。
需要做的改动
1.配置文件的生成
单独的 api 提供,在测试平台上选择需要更新的 rpc 服务所在的 ip,点击更新后,根据环境平台 api 返回的该 ip 上所有已部署的集群,生成新的配置文件,该操作会会覆盖已有的对应的配置文件。文件名称会以 ip 作为前缀,例如,192.168.187.208_rpc.config
2.配置文件的加载
从 Class1 的 create 方法增加一个入参 ---- 需要调用的 rpc 服务所在机器的 ip,然后一直传递到 Class5 的 get() 方法,get() 通过 ip 来解析对应 rpc 服务配置文件,返回响应的 rpc 服务 ip 和端口等信息。
3.新建工程,把修改后的代码打包成 1.dynamic.client.jar,这样 classloader 在加载时,会优先加载 1.dynamic.client.jar 中的类,就不会再加载 rpcclient.jar 中重名的类。虽然 java 加载 jar 的先后顺序是由操作系统决定,但是在 linux 上每次都全量更新 lib 下的所有 jar 包,目前还没有出现先加载 rpcclient.jar 的情况出现。
这个方案有一些缺点,1.已有代码需要有很大的改动;2.代码依赖比较严重,如果不想使用 rpcclient 动态加载 rpc 服务这一功能,需要再改回原来的代码。3.每个 create 相关的调用都需要改,工作量有些大。
方案 2
新版的 rpcclient 改变了 client 类之间的调用环节,但是最后还是需要 getConfig() 方法来加载和解析 rpc.config,为了一并解决方案 1 中的缺点,本方案使用了 ThreadLocal 来实现,调用过程简略示意图如下
使用该方案,原来的代码不用做太大的改动,直接在拦截器中添加相应的代码就可以,解决了方案 1 的缺陷,并保证了功能的实现。
五、优点
1.实现动态修改 rpc.config,不需要在重启 wf 站点就可以生效
2.每个用户使用自己的 rpc.config,多个用户之间互不干扰
3.不需要在修改本机的 host,解决了平台型工具需要多个机器部署的尴尬,不需要在被测服务的机器上再启动一个测试平台
4.请求用到的 server 的信息可追踪
5.为 RD 自测时,使用 QA 提供的测试代码提供可能
6.为后续的 RPC 服务 diff 提供了可能
7.如有必要 RPC mock 也可以实现