当前位置: 首页 > Web前端 > HTML

没有流量染色,你说你要搞微服务?

时间:2023-03-29 11:10:23 HTML

1.前言在当前盛行的微服务架构下,大量服务带来的依赖问题往往成为开发过程中的绊脚石。在各种技术交流会上经常听到类似的话题,大家也都在积极讨论如何解决这类问题。所以决定给大家介绍一下流量着色的原理,以及微服务架构下在开发过程中可以解决哪些问题。2.流量着色的概念流量着色说白了就是给请求的流量打上标签进行染色,然后请求会在整个链路中携带标签信息,通过标签可以进行流量调度等功能。基于流量染色可以实现很多功能,比如灰度逻辑、蓝绿部署、车道隔离等,这里简单说一下流量染色和微服务的关系,免得你以为这是一篇头条文章。试想,如果是单体应用,流量着色还能有应用场景吗?请求的一般流程是App->LoadBalancer->Application。整个链路非常简单,流量着色在这种场景下完全没用。只有当服务数量较多,一个业务功能涉及N个服务时,才需要进行流量控制,解决开发测试过程中遇到的问题。3、基于流量染色的应用测试环境多套部署痛点,只需要增量部署。目前我们的测试环境除了经常使用的T环境外,还有很多MF环境。独立需求基本使用MF环境,正常版本迭代使用T环境。问题一:每个环境的配置不一样,就会出现问题。很多功能都是在T环境下测试的。当MF环境中有独立的需求需要测试时,需要部署相应的服务。在部署过程中,我们经常会遇到各种配置缺失或错误导致应用无法启动的情况。问题二:没有变化的服务也要部署。有需求需要在MF环境进行测试,服务已经部署。但是联调的时候发现依赖的下游服务都没有部署。但是在这个需求中这些服务并没有改变,依赖的接口也是已经上线的功能。如果没有部署在相应的环境中,则无法调整整个链路。所以这时候就需要找到对应的下游,让下游去部署这些服务。在下游部署过程中,也可能会出现环境配置不同的问题,导致前期联调耗时较长,影响项目进度。交通着色是如何解决上述问题的?例如,如果当前正在开发一个需求,将在要更改的应用程序中配置一个版本,并将版本信息存储在注册中心的元数据中。然后创建属于该需求的swimlane(独立环境)进行部署,只需要部署该需求变化的应用即可。该应用所依赖的下游应用不需要部署。如果当前环境找不到对应的服务提供者,则路由到稳定环境。如果稳定环境下没有对应的服务提供者,会报错。研发本地启动随机注册问题研发有时会在本地启动服务,主要是调试某个问题。优点是可以在测试环境中快速重现问题,及时发现问题代码。由于本地启动的服务也会在注册中心注册,测试环境的请求可能会路由到研发本地启动的服务,而研发本地服务代码可能不是最新的,导致调用异常。目前常见的解决这个问题的方法是在本地启动服务时屏蔽掉服务的注册功能,即不注册,这样就不会被正常的测试请求路由。如果你有流量着色的功能,你可以在开发本地启动服务的时候指定一个自己的版本号,只要和正常测试的版本不一致即可。正常的测试请求不会路由到研发注册的实例。应用层的灰度针对的是界面层的灰度,目前在应用内部进行灰度控制。但是在应用层面,目前还没有特别好的方法来控制灰度。比如有技术改造的需求,需要把RedisClient从Lettuce改成Jedis。这个场景的灰度在应用层面。目前的方法是释放一个节点,然后结束释放过程。具体可以灰度化的数量由服务实例总数决定,不能灵活控制。如果存在流量着色,您可以启动一个新节点并升级该节点的版本。例如,如果以前的版本是V1,那么新版本将是V2。首先,V1版本必须承担所有的生产流量,可以通过网关控制将流量按照一定的方式转发给V2版本,比如用户白名单、地域、用户比例等。如果有问题,流量可以随时切换回V1,非常方便。服务的优雅下线服务,要想服务优雅下线不丢失,还需要做很多工作。一定时间后,缓存被清空,对应的目标实例将不再被请求。如果是基于染色实现,需要下线的实例信息(IP:PORT)通过配置中心推送到网关进行染色处理。染色信息跟随请求贯穿整个链路,应用中的负载均衡组件,MQ等中间件将要下线的目标实例信息进行过滤,让任何流量都不会去到要下线的实例。生产环境加速发布目前主流的发布都是滚动部署。滚动发布的好处是成本低,不需要额外增加部署资源。一萝一坑,慢慢换就好了。不好的一点就是发布时间长,整个环节太依赖了。如果在发布前依赖关系紊乱,则为线上失败。为了解决这个发布速度的问题,可以基于流量着色来实现蓝绿部署。即在发布时重新部署一个V2版本。本次V2版本实例数与V1一致。由于这个V2版本没有流量,所以不存在依赖关系。您可以同时释放它。全部发布完成后,就可以通过网关分发流量了。先给V2版本分一点流量做验证。如果没有问题,可以慢慢增加流量,然后发布容器的V1版本。发布速度确实提高了,但问题是蓝绿部署成本太高,资源成本要成倍增加。虽然旧资源在释放后被回收了,但是你的总资源池还是要同时容纳这两个版本。好的。在不增加资源成本的情况下,是否有折衷方案可以提高发布效率?发布时可以使用替换形式,先发布一半的实例。这一半实例是我们的V2版本。发布期间没有流量,所以还是可以并行发布的。发布完成后,开始加卷到V2版本,然后验证。验证通过后,可以释放另一半实例。这样一来,总的资源是不会变的,但是有一个比较严重的问题,就是如果直接停了一半的实例,剩下的实例是否可以支撑当前的流量,因为事务中的应用都是为了C端用户,流量很可能在短时间内达到高流量。全链路压测全链路压测对于电商业务来说必不可少。每年有N次大促,需要提前做压力测试,保证大促的稳定性。其中,全链路压测的核心点是流量的区分。需要区分是正常用户请求流量还是压测平台压测流量。只有对流量进行区分,才能对压测流量进行相应的路由。例如数据库、Redis等流量需要路由到影子数据库。基于流量着色,方便标记流量,区分流量类型。4、流量着色的实现需要有版本的概念。每个应用程序都需要有版本的概念。事实上,它可以绑定到每个迭代。只是把这个版本信息放到项目中的配置文件中。当项目启动时,这个版本信息会和自己的实例信息一起注册到注册中心。这种信息一般称为元数据(Metadata)。有了Metadata,就可以在控制流量路由时,根据染色信息进行相应的匹配。比如一个request指定调用一个订单应该使用V2版本,那么在路由时如何匹配V2版本的实例信息呢??您需要依赖元数据。着色信息的全链路透传至关重要。如果无法实现全链路透传,则无法对所有节点进行流量路由控制。染色信息的透明传输其实和分布式链路跟踪是同一个原理。目前支持分布式链路跟踪的主流有Skywalking、Jaeger等,基本都是借鉴了GoogleDapper的思想。每个请求都会在入口处生成一个唯一的TraceId,通过它可以关联整个链路。这个TraceId需要在整个链路中传输,流量着色信息也需要在整个链路中传输。传递的方式一般有两种,一种是在独立的Agent包中传递,另一种是在基础框架中埋点传递。如果使用Http来调用内网之间的接口,则在请求头中传递信息。如果使用RPC,则可以使用RpcContext进行传递。信息传递给应用后,下游的其他接口会继续在这个应用中被调用。此时要继续透传,一般是把信息放到ThreadLocal中,然后在发起接口调用的时候继续透传。这里需要注意的是使用ThreadLocal是为了防止线程池切换的场景,否则ThreadLocal中的信息会丢失。当然也有一些手段可以解决ThreadLocal异步场景下的信息传递问题,比如使用transmittable-thread-local。流量路由控制当流量带有标签信息时,剩下的工作就是根据标签信息将请求路由到正确的实例。如果内部框架是SpringCloud系统,可以通过Ribbon控制路由。如果是Dubbo系统,可以通过继承Dubbo的AbstractRouter重新制定路由逻辑。如果是内部自研的RPC框架,必须有相应的扩展来控制路由。五、总结流量着色总体上还是很有用的,但也是一次重大的技术改造。除了在基础架构层面打通染色信息的传递,更重要的是各业务方的配合。当然,如果访问是Agent模式就更好了。不然每个业务方都要升级套餐,实在是太烦人了。.*文/尹继焕@达物技术公众号