流量来源监控 | 轻量级微服务流量管理实践

点击「京东金融技术说」可快速关注

「引言」如今微服务作为一种架构模式已经非常成熟和普及,在大规模的应用实践中,服务监控和流量管理经常是一大痛点,尤其是对于有着大量应用调用者和几十万QPS/TPS的服务方来说,如何能快速定位和监控当前流量的来源?如何对特定服务流量进行降级或限流?如何对流量进行授权管理?常常是非常大痛点。

目前公司内也有着如埋点式的业务监控、traceId调用链监控、接口监控等诸多类型的监控系统,它们在确保服务稳定和分析定位问题等方面起到了非常关键的作用,但是针对上面痛点却多少有些忽视。

在一次备战大促的过程中,我们团队以渐进式的设计思想快速实现了一个轻量的监控管理系统,在解决这一痛点的同时,达到了轻量(投入少开发快)、健壮(容错高影响小)、低侵入(易于使用)等特点,本文主要分享一下实践过程和解决问题的思路,看看如何从零构建一个监控系统。

流量管理的过程主要有三个步骤:采集和发送监控数据、监控数据结构化存储、使用监控数据进行报警和管理控制,这三个流程由客户端、数据存储和管理端交互完成。

  • 客户端:通过pom依赖集成在所有服务方应用,需配置过滤器和启动Bean。

  • 数据存储:目前使用了Redis集群,3分片每分片1GB内存,目前存储100+服务所有流量两天的监控信息,使用了40%空间。

  • 管理端:独立部署的应用,用于展示图表等监控信息、发送报警通知、配置降级限流和授权等功能的参数。

  

1

 采集和发送监控数据

 

一、采集监控数据

监控系统为了采集监控数据,需要对每一次请求都进行记录,如果这一过程发生异常或占用较多资源将影响正常服务运行,因此采集客户端需要足够的轻量和高效,并隔离异常以确保不影响原流程。主流RPC框架(JSF、dubbo、rest等)中都提供了Filter过滤器的扩展能力,我们通过在自定义的服务端过滤器中对请求进行记录和控制。 

每一次请求必须的监控关键信息是服务信息(接口名、方法名)、来源应用(将来源IP自动转换为应用名,后面会解释如何转换)、时间戳,即监控每一个服务方法的每一个来源的每秒调用量。根据时间戳精度,如果记录每秒钟的调用量则每个服务每个调用来源一天需要86400个记录,显然这是一个比较庞大的记录量,一番权衡之后,目前记录每个服务每个调用来源4秒的请求量,除以4得到该时间范围的平均TPS。

如何采集上述信息呢?我们在每个应用实例中创建一个静态的并发Map,将每一个服务者和来源作为key,对应值为该服务的一个原子计数器,每当调用时发生时进行计数器自增操作。同时在应用启动时会创建一个监控主线程,它通过定时器每4秒执行一次计划任务,这个任务需要一些技巧严格维持在每分钟的0秒、4秒、8秒……56秒这样的时间戳执行,任务会将当前时间戳和Map中所有计时器统计结果发送到异步队列,同时清零所有原子计数器。由于这个过程没有耗时性任务,这样能保证精准完成统计信息并且不影响原服务流程。

二、发送监控数据

接下来如何发送采集的监控数据呢?为了尽量减少资源占用和减少复杂性,我们没有选择本地日志记录发送的方式,而是直接在消费队列的异步线程中将4秒一次的统计信息发送到Redis集群。针对每一个服务-调用来源-时间戳作为key,调用量作为value在redis中进行存储,因此每次发送实际是一个个INCRBY操作,所有应用实例操作后就能得到整个集群准确的流量信息。

实际应用中这种方案会造成大量的Redis并发写入,从整个Redis集群监控中可以看到4秒一次的非常高的TPS波峰,一个简单的思路是将异步线程发送随机延后,这可以起到一定削峰效果,但是依然有很大优化空间,大量的Redis调用可以通过pipeline机制进行加速。使用pipeline进行批量操作不仅可以节约每次单独调用时的RTT(网络来回延迟),还能减少Redis内部处理时的IO系统调用。经优化提高了10倍左右的性能。为了使用批量发送,需要将队列任务收集并积累为一批任务发送,我们通过队列的poll和超时检测,将未发生出队超时的(一批)任务批量一次发送。

2

 监控数据结构化存储和读取

从轻量和效率等因素考虑,我们直接使用内部申请的Redis集群作为存储。

  • 第一种办法:前面我们提到的key-value存储结构比较简单,它通过系统名-接口名-方法名-调用方应用名-时间戳这样的key,设置value为计数量,这是最简单但是最浪费存储空间的设计方式,因为key会非常长,优点是逻辑简单直接。

  • 第二种办法:针对它的直接优化,将所有接口名、方法名等都转换为数字序列id,如0-0-0-0这样,这样key精简到非常简短,但同时增加复杂性,实际上空间占用还是很大。最好的办法是利用hash这类的数据结构进行存储,如key中包括系统名-接口名-方法名-调用方、filed中存储简短的时间戳、对应的value中存储计数量,这种方式能极大的减少存储空间。经测试按同样规则生产的100个1天范围的采集数据。

  • 第三种办法:hash结构存储比第一种简单方式(带超时信息)减少了一半以上的存储空间。

在读取和生成监控图表的过程,经常会面对非常大时间范围,如果此时还使用秒级数据将导致查询结果非常多,数据会超过图表的像素容量,此时最好在存储时进行汇总,即通过后台任务将前一分钟秒级监控数据汇总为分钟级,较大范围查询时直接查询分钟级数据,类似的如果查询较高级别的查询则通过查询所有下一级数据进行汇总展示,同时读取批量数据也可以同pipeline进行批量读取加速。

3

报警和管理控制

 

一、监控管理端提供多维度页面进行来源和TPS等信息展示,可以迅速了解当前服务的流量来源和分布,此外可以针对每一个接口方法来源进行TPS报警和控制,通过预先配置的调用来源预估调用量,当超过阈值时进行报警通知。并可采取以下三种管理措施:

  • 降级:根据配置开关,当触发熔断条件时进行自动或手动操作降级,降级后采集端的过滤器会直接对新请求新返回失败,在不影响其他调用方的情况下对服务端进行保护。

  • 限流:与降级类似的方案是限流,由于分布式系统中进行总量限流会依赖中心节点进行令牌桶这类计算,同步调用对原接口影响较大,非严格的情况下并不是一个很通用的选择,这里我们使用了一个简单方案,即在每个服务节点进行单位时间固定量限制,即4秒内超过限制量的请求会被阻挡,虽然不是平滑限流,而且设置量也需要根据机器数进行调整,但该方案对正常的流量影响最小。

  • 流量许可:除了对异常流量进行降级和限流外,还可以通过白名单机制对部分接口进行流量许可,没有预先加入白名单的视为非授权请求。

以上这些降级、限流以及白名单的配置存储在Redis中,客户端本地缓存在map中并每分钟刷新,在过滤器中通过简单规则匹配实现管理逻辑,不强依赖存储和管理端。

二、管理端还承担了各类定时任务,如定期每分钟汇总秒级数据到分钟级数据,将所有IP转换为应用名,各类系统控制开关和配置项等。

这里有个前文忽略的一点,在监控过滤器中的取到的调用方IP,它是如何转换成应用名称呢?京东当前有多个应用部署平台,其中通过J-ONE发布的应用在调用时会携带应用名参数,但是其他部署平台就只能获得IP信息,我们通过访问统一的运维平台,主动查询IP地址到应用名的映射关系,进行存储并定期每天刷新,过滤器本地也保持有该映射的缓存并定期刷新,在减少影响和实时性之间作了权衡。由于生产环境不允许混合部署(一个实例多个应用),因此不会产生识别冲突,更多可能的延迟主要在应用缩容扩容时,可以通过缩容扩容主动刷新缓存的方案解决。

4

总    结

 受限于条件和目标,上述流量管理方案有不足可优化之处,如:

  • 范围限制在了服务端(provider);

  • 调用方客户端(consumer)也有更多扩展思路,例如限流或降级的开关应该设置在客户端,当降级时甚至不需要再发起远程调用请求;

  • 超过几千台规模的应用实例的情况下可能会产生较高的Redis写入压力,可以通过增加Redis集群分片数量解决;

  • 也可考虑其他同步和存储方案,如Kafka异步传输和HBase集群存储等。

但作为一个快速实现的监控管理系统,可以看出很多通用监控的思路和要点,同时加强了对微服务流量方面的治理,希望能对大家有所帮助,欢迎后续和作者一起探讨沟通。


京东金融技术说

   ▼▼▼     

原创·实用·技术·专业

不只一技之长

我有N技在手

你看,我写,共成长!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值