转转技术团队对测试环境治理的高效能实践(下)

发表于:2023-2-02 09:25

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:王建新    来源:转转技术

  4. 转转测试环境V2-基于自动IP标签的流量路由
  随着转转公司业务的飞速发展,服务数量迅速增加,每个动态环境部署的服务数量增至30-60个,搭建测试环境的成本越来越高。为了解决该问题,转转架构部、运维部、工程效率部推出了流量路由解决方案。该解决方案在此前的公众号文章转转测试环境的服务治理实践中已有详细讲解,本文仅做简要介绍。
  该版本的流量路由技术称为基于自动IP标签的流量路由,之所以选择IP为标签是因为基于现有使用习惯发现所有被测服务部署在同一台虚拟机上,IP地址一样,并且IP易获取,用户无感知;“自动”则体现在无需用户对服务及流量进行打标,打标是完全自动化进行的。
  基于自动IP标签的流量路由将测试环境的搭建时间从数小时-数天减少至30分钟-1小时,每环境部署的服务数量从30-60个服务下降至个位数,并且完全兼容没有流量路由时的使用习惯。但是仍然存在申请虚拟机耗时长,kvm内存无法扩容的问题。
  5. 转转测试环境V3-基于手动标签的流量路由
  基于自动IP标签的流量路由解决了转转测试环境存在的大部分问题,使测试环境的搭建时间从数小时-数天下降至30分钟-1小时,但是仍然存在申请环境耗时长,kvm内存无法扩容的问题,本着精益求精,用户至上的原则,我们开发了基于手动标签的流量路由。
  5.1 docker化
  为了解决申请环境耗时长,kvm内存无法扩容的问题,我们决定将服务部署在docker容器内,无需提前申请资源,理论上无内存限制。但是docker化以后,基于IP为标签的流量路由显然无法工作了,因为不同的服务部署在不同的docker pod内,IP也是不一样的。
  5.2 服务及流量打标
  此时就需要手动为服务及流量指定标签,我们称为基于手动标签的流量路由。为服务打标是自动化完成的,在环境平台申请环境时指定标签,在该环境内部署服务时,由环境平台自动添加jvm参数-Dtag=xxx。而为流量打标则通过http header进行,在发起请求时添加header tag=xxx。
申请环境
自动添加jvm参数
请求添加http header
  并非所有请求都是通过http发起的,有些由进程内部(如定时任务)直接发起的调用则自动携带当前节点的标签。
  5.3 目标形态
  基于手动打标的流量路由目标形态如下图所示,标签为yyy的动态环境,本次需求修改了服务B及服务D,只需要在该动态环境内部署B和D,真正实现修改什么就部署什么。
标签路由使用目标
  5.4 RPC调用实现
  5.4.1 服务注册、发现及调用
  以下图服务A调用服务B为例,服务B有3个节点,稳定环境的B,动态环境的B'(标签为yyy)及B''(标签为xxx)。B'和B''在启动时会将标签参数注册到注册中心,服务A在启动时会从注册中心发现B、B'、B'',同时获取它们的标签参数。
RPC标签路由
  以红色的链路为例,流量标签为zzz,A在调用时发现并没有动态环境的服务B拥有标签zzz,于是调用稳定环境的B节点。
  橙色链路的标签为xxx,A在调用时发现B''的标签为xxx,且为动态环境,则调用B''。
  5.4.2 标签的传递
  转转使用的RPC为自研RPC框架,在调用时除了传递请求方法及参数等信息之外,还可以通过attachement功能传递额外的参数,而路由标签就是通过该功能在RPC调用时实现传递。
  5.5 MQ消息实现
  5.5.1 消费原理
  若想实现消息可以在动态环境与稳定环境之间路由,通过不同的的topic前缀实现动态环境和稳定环境的物理隔离显然已经行不通。此时的解决方案为动态环境和稳定环境拥有相同的topic,但是不同的消费group,不同的消费group就对应不同的消费offset。动态环境的group添加${tag}前缀,而稳定环境的group添加test_前缀,添加前缀的过程由MQ客户端自动完成,对用户透明。
  如下图所示服务B有稳定环境及动态环境(B')节点各一个,B'的标签为xxx。图中通过不同的颜色表示不同的标签,其中绿色表示没有标签。
MQ标签路由
  B节点在消费时,首先判断是否有和消息中标签对应的消费组注册到broker上,如果有则过滤掉,否则消费。其中消息1、3、5、7的标签和B'匹配,消息2没有标签,而消息4、6的标签所对应的消费者没有注册到broker上,所以B节点消费了消息2、4、6。
  B'节点在消费时,只消费消息中标签和自身标签前缀一致的消息,即消息1、3、5。
  5.5.2 存在的问题
  假如此时B'下线了,我们发现消息7没有被消费者消费,该消息丢了。这是因为稳定环境消费组和动态环境消费组offset不一致导致的,稳定环境消费组offset大于动态环境消费组offset,解决方案就是B'下线时将其与稳定环境offset之间的消息重新投递。重新投递后假如B'又上线了呢,就带来了消息的重复消费,但是我们认为重复消费是没有问题的,因为mq本身的消费语义就是至少一次,而不是仅仅一次,重复消费幂等性应该由业务逻辑来保证。
  另一个问题是批量消费如何解决,mq客户端有批量消费功能,一批消息所携带的标签可能是不一样的。对于这个问题,只需要将消息按标签分组后再执行消费逻辑即可。
  5.5.3 标签的传递
  转转使用的是RocketMQ,并进行了二次开发,RocketMQ提供了可扩展的header可以用来传递路由标签。
  5.6 进程内标签的传递
  跨进程的标签传递相对来讲比较容易解决,而进程内标签的传递难度更高。
  5.6.1 通过方法参数传递
  通过为每一个方法调用添加tag参数可以实现标签的的进程内传递,但是显然这不现实,需要全公司所有的代码配合改动。
  5.6.2 通过ThreadLocal传递
  jdk内置有ThreadLocal及InheritableThreadLocal可以实现标签的隐式传递,但是ThreadLocal无法实现new Thread及跨线程池传递,而InheritableThreadLocal可以实现new Thread传递却仍然无法实现跨线程池传递。虽然可以通过对Callable和Runnable进行包装实现跨线程池传递,但这仍然要求修改现有的业务代码,成本较高。
  5.6.3 通过TransmittableThreadLocal传递
  TransmittableThreadLocal是阿里巴巴开源的,通过java agent技术实现的可以跨线程/跨线程池传递的ThreadLocal,对用户透明,只需要在jvm启动参数中加入对应的java agent参数即可,最终我们采用了该方案。
TransmittableThreadLocal Agent
  5.6 上线收益
  下图为转转公司动态环境平均部署服务数量曲线,在2022年5月之前平均每环境约部署7-8个服务,在2022年5月之后标签路由开始推广,至2022年7月每环境约部署3-4个服务。虽然从原理上看基于手动标签的流量路由每环境仅比基于自动IP标签的流量路由仅少部署一个服务(Entry),但是由于kvm无法扩容,所以在自动IP路由时代环境初始化时用户总是会预防性地多选择一些服务,以达到申请更大内存虚拟机的目的,而docker化之后,此种担忧不再存在,所以每环境部署的服务数量下降了约4个,动态环境总内存节省了约65%。
  测试环境搭建时间从30分钟-1小时下降至2分钟-5分钟,时间的节省主要来自无需提前申请kvm、docker资源隔离服务启动快、无内存扩容担忧初始化服务数量少。
每环境部署服数量曲线
  5.7 辅助设施
  docker化虽然带来了效率的提升,资源占用的下降,但是也引入了一些问题。每次部署IP地址都会变化,导致远程登录及debug的成本增加。在Http Header中添加路由标签增加了测试同学的工作量。为了解决这些问题,我们又开发了对应的辅助设施来提高工作效率。
  5.7.1 泛域名解析
  使用http传递标签,仍然需要配置host映射将域名映射至测试环境的nginx,如192.168.1.1 app.zhuanzhuan.com,否则dns解析会将app.zhuanzhuan.com解析至线上nginx。
  是否可以免去host配置呢,答案是可以的。通过直接使用域名传递标签的形式来实现免去host配置,如app.zhuanzhuan.com直接使用域名传递标签写作app-${tag}.test.zhuanzhuan.com,该域名会直接解析至测试环境nginx。在开发版app中内置了该功能,在app启动时输入环境标签即可实现域名的切换,无需配置host即可开始测试。
泛域名解析
  5.7.2 web shell
  docker化以后每次部署都是一个新的docker pod,IP地址也随之变化,如果需要登录查看日志,通过xshell等工具则需要在每次部署后使用新的IP重新登录。引入web shell功能只需要在环境平台页面中点击按钮即可通过web shell的方式直接登录,并且登录后的工作目录默认为该服务的日志目录。
web shell
  5.7.3 debug插件
  同样因为docker化以后IP地址总是变化,测试环境的远程debug也变得更加不方便,每次需要更换新的IP进行连接。为了解决此问题,我们开发了debug插件,该插件会自动获取项目名作为服务名,需要debug时输入环境标签,插件会自动向环境平台发起请求,而环境平台则通过解析jvm参数的方式获取debug端口并向插件返回IP和debug端口,插件在收到IP和debug端口后自动连接。
debug插件
  5.8 优缺点
  5.8.1 优点
  更加节省资源,仅部署X(修改的服务),不需要部署nginx+Entry。
  申请环境速度快,秒级完成。
  搭建环境速度快,约2-5分钟。
  无内存限制。
  5.8.2 缺点
  QA有感知,需要在HTTP Header中添加标签。
  6. 分布式调用跟踪系统
  以下图为例,在D调用E'时出现问题,E'中未打出相应的业务日志,到底是D没有调用呢,还是流量路由存在问题没有路由到E'呢。此时就需要分布式调用跟踪系统的辅助来排查问题。
  6.1 原理
  分布式调用跟踪系统的原理就是在链路中每个模块的入口和出口处进行埋点,并将埋点采集起来进行可视化展示。如下左图为调用链路,右图为采集到的埋点。
分布式调用跟踪系统原理
  每一条链路有唯一的Id称为TraceId,而每一个埋点称之为span,每个span有唯一的Id称为SpanId。
  6.2 架构
  转转分布式调用跟踪系统采用自研与开源结合的方式,如下图所示。其中Radar为转转自研分布式调用跟踪系统客户端,可与MQ、SCF(转转RPC框架)、Servlet进行整合,异步批量地将埋点上传到Collector服务,Collector服务再将埋点写入kafka。开源部分则使用zipkin实现,zipkin具备自动从kafka消费埋点并存入DB的能力,而且自带UI界面可供查询。
分布式调用跟踪系统架构图
  6.3 TraceId的获取
  转转使用统一日志门面slf4j,Radar客户端自动将TraceId、SpanId存入MDCContext中,只需在日志配置文件中加入相应的占位符就可以将TraceId、SpanId打印至日志中,如下图所示。
TraceId打印到日志中
  在Entry层每次请求结束后将TraceId以Http Header的形式返回至前端,前端收到响应后可立即获取TraceId进行查询。
网关层将TraceId返回
  6.4 在路由关键节点采集流量标签和当前节点标签
  如下图所示global.route.context.tag为流量标签,而global.route.instance.tag为当前节点标签,通过对比这两个标签是否匹配即可验证流量路由是否正确,本节开头所提到的问题也就迎刃而解。
流量标签及节点标签
  7. 总结
  转转测试环境治理共经历3个版本,物理隔离、基于自动IP标签的流量路由及基于手动标签的流量路由。
  物理隔离:随着转转业务的发展,服务数量的增多,搭建测试环境极端情况下需要数天的时间,每环境平均部署服务数量高达30-60个。
  基于自动IP标签的流量路由:每环境平均部署服务数量下降至7-8个,而环境搭建时间也下降至30分钟-1小时。
  基于手动标签的流量路由:每环境平均部署服务数量进一步下降至3-4个,搭建时间降至2分钟-5分钟。
  流量路由带来效率提升及资源占用下降的同时,也引入了一些问题,如链路复杂性高,ip地址变化等。为了更好地利用流量路由带来的便利,消除负面影响,就需要各种配套设施的辅助,如分布式调用跟踪、泛域名解析、web shell等。
  回头来看,流量路由减少了部署时间,降低了资源消耗,得到了业务线的一致好评。架构、运维与工程效率部门的同学排查问题的数量也大大减少。真真正正做到了降本增效,实实在在好项目。两个版本的流量路由分别获得转转公司优秀项目奖。
  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号