全链路追踪!微服务运维人员终于解放了
一个人身体不舒服才想起没有定期体检
显然已经晚了
微服务架构也是一样
只有实时监控、定期体检
系统中各服务的运行状态才会健康
那么,如何为“微服务”体检呢?
全链路追踪 就是微服务的“体检中心”
微服务的“身体构造”
当我们进行微服务架构开发时,通常会根据业务来划分微服务,各业务之间通过网络通信进行调用。一个用户操作,可能需要很多微服务的协同才能完成。在业务调用链路上,任何一个微服务出现问题或者网络超时,都会导致功能失败。随着业务越来越多,对于微服务之间的调用链的分析会越来越复杂。
在拥有众多服务的微服务应用中,如何知道一次请求调用的是哪条链路?当请求调用失败时,如何知道是哪个服务出现了问题导致调用失败?一次请求响应时间长,到底是哪些服务耗时长的?……
你可能会说,可以通过查看每个服务的日志来分析这些信息。但是应用的服务有可能部署到了上百个节点上,人工查找显然是不现实的。
为了查看微服务应用在实际运行中各个服务的运行状态,每次调用各个环节执行情况,我们需要一个微服务应用的体检中心,这就是全链路追踪。
为微服务“全身检查”
SaCa ACAP 在微服务领域积累了大量的技术实践,打造了一套独有的全链路追踪组件。
通过服务调用日志我们能够分析出整个微服务应用的调用情况。为了解决服务日志分散在各个节点上,首先需要将日志统一进行收集,然后将收集的数据进行过滤汇总,之后对汇总的数据进行链路分析,形成链路调用的数据,最后将数据用友好清晰的方式展现出来,这就是链路追踪的全过程。
你可能会说“这个过程听起来好像日志分析系统啊”,没错,我们的链路追踪就是基于 ELK 日志分析系统方案实现的。使用 Filebeat 收集各个服务的日志、使用 Logstash 完成日志数据的过滤, Elasticsearch 负责日志的存储于分析。
但是不要以为这就是链路追踪的全部,SaCa ACAP 还能解决更多问题。
代码入侵性
作为支撑业务组件,应当尽可能少入侵或者无入侵其他业务系统,对于使用方透明,减少开发人员的负担。
对于应用的程序员来说,是不需要知道有追踪系统这回事的。如果一个追踪系统想生效,就必须需要依赖应用的开发者主动配合,那么这个追踪系统也太脆弱了,往往由于追踪系统在应用中植入代码的 bug 或疏忽导致应用出问题,这样才是无法满足对追踪系统“无所不在的部署”这个需求。
为此 SaCa ACAP 采用了应用采用了应用监控组件 SkyWalking。它基于 Javaagent 技术,对代码无入侵。将应用和探针一起部署,就能实现对服务的监控。服务每次调用都会产生相应的日志信息。
探针的性能消耗
APM 组件服务的影响应该做到足够小。服务调用埋点本身会带来性能损耗,这就需要调用追踪的低损耗,在一些高度优化过的服务,即使一点点损耗也会很容易察觉到,而且有可能迫使在线服务的部署团队不得不将追踪系统关停。
性能的损耗很大一部分来自于将日志同步写入到文件当中。同步文件 IO 操作会产生阻塞,造成线程等待和线程上线文切换。
解决办法就是采用异步方法,异步方法先在堆内存中存储日志,然后批量写入到文件中。
但是异步写入会占用一部分用于处理业务的堆内存,为了尽可能的减少对业务运行的影响,我们首先将日志写入到堆外内存中,然后在写入到文件中。减少 IO 阻塞的同时也降低了对业务运行的影响。
分布式追踪 ID
业务系统中,涉及到各种各样的 ID ,如在支付系统中就会有支付 ID 、退款 ID 等。
一般来说有下面几点要素:
唯一性:确保生成的 ID 是全网唯一的有序递增性:确保生成的 ID 是对于某个用户或者业务是按一定的数字有序递增的高可用性:确保任何时候都能正确的生成 ID 带时间: ID 里面包含时间我们的 ID 生成算法是基于 Twitter 的 snowflake 算法。
41 位的时间序列,精确到毫秒,可以使用 69 年10 位的机器标识,最多支持部署 1024 个节点12 位的序列号,支持每个节点每毫秒产生 4096 个 ID 序号,最高位是符号位始终为 0同时我们对算法进行了优化,解决了分布式环境下会出现的 ID 非全局递增的情况。
体检报告实时展现
如何快速发现问题?如何判断故障影响范围?如何梳理服务依赖以及依赖的合理性?如何分析链路性能问题以及实时容量规划?等等这些问题除了需要一个优质的后端追踪组件外,还需要一个用户体验友好的交互界面。
SaCa ACAP 全链路追踪组件就是一套包含交互界面的完整方案。
应用拓扑追踪
直观展现整个应用的服务调用关系,服务间调用流量,服务部署主机信息,服务内组件类型,监控整个应用各个服务真实运行情况。
调用链路追踪
服务名称,服务类型等搜索条件快速定位调用链路,调用链路执行状态一目了然。
服务类型追踪
监控调用链路中服务里面各项组件,直观展现耗时比例。
全面识别监控 10 种类别 35 种组件与框架。
链路耗时追踪
监控调用链路中服务执行顺序,直观展现各个阶段耗时情况,助力性能分析和容量规划。
链路节点追踪详情
链路中服务执行详情展示,高效定位关键问题。
来源:东软平台产品 https://platform.neusoft.com/
以springcloud来讲,实现api的鉴权及保护,需要配合jwt技术(无状态)来实现,一般有两种方法:
方法一:
直接在网关中设置各种过滤器,并配置一定的路由拦截规则,并将部分用户认证的代码编码到网关中,来实现在网关侧的初步鉴权及认证。等于是将系统90%以上的鉴权认证全都压在网关上。所有客户端都请求网关的地址而非微服务的实际地址。当请求通过NGINX到达springcloud网关时,网关取出请求的前缀,再根据代码中配置的前置pre、post、错误error等过滤器选择进入对应的过滤器,根据请求中携带的jwt信息,解析后取出凭证信息,执行自定义的用户登录鉴权认证逻辑(一般是网关服务去调用用户中心服务查用户信息),若用户中心服务返回正确的结果,则网关服务接收到其的响应结果,将过滤器返回null放行,请求继续走到其他微服务中,执行完对应的业务逻辑后,对应业务服务再将结果返回给网关,网关再通过NGINX返回给客户端。
方法二:
原理同上,区别是这里新建一个微服务叫用户授权认证中心。当请求过来时,网关只做最基本的请求验证,如jwt格式是否合法、jwt是否过期这类判断,不再对用户进行鉴权操作,即不在网关查询用户,而是去调用用户授权认证中心,将必要的参数传给此中心的对应http方法,请求后得到结果并返回到网关,网关再给客户端具体的响应(鉴权后失败则返回给客户端失败信息,成功则在网关过滤器中放行即可)。等于是网关的活少了很多,90%以上的鉴权认证操作都压在授权认证中心上了。
两种办法都可以用,但更建议第二种,比较符合微服务的思想。第一种适合项目初期,规模还不是那么大的时候可以临时用用,流量上来了网关会顶不住,所以长远来看需要新开一个微服务来分流。
其实微服务的框架在国内通常采用 spring cloud 作为底层的架子,在此之上自己构建一些可以快速应用的组建, 当然也可以采用相对成熟一些的基于spring cloud 上增加了一些组建的框架 ,这里推荐 一个 开源的spring cloud 的集成框架 JVS 。
开源地址:https://gitee.com/software-minister/jvs开源项目介绍:JVS是面向软件开发团队可以快速实现应用的基础开发框架,采用微服务分布式框架,提供丰富的基础功能,集成众多业务引擎,它灵活性强,界面化配置对开发者友好,底层容器化构建,集合持续化构建。JVS是“软开企服”推出的面向软件开发团队可以快速实现应用的基础开发框架JVS的服务对象:中小型的开发团队JVS的核心目标:让中小型开发团队过得轻松一点,优化开发团队人力成本高、交付效率低、质量不可控、周期不确定、基础技术投入不足、高端技术支持不够等
项目标签
微服务、支持SaaS、私有化部署、DevOps、体验地址
开源协议:详见license体验地址:http://bctools.cn/#/login登陆可以通过微信扫码登陆,对于配置数据,请各位技术同学手下留情。技术栈说明:系统部分截图:越来越多的企业开始采用微服务架构来开发业务应用。统计数据表明,目前约有45%的企业正在使用微服务,16%的企业正在实验开发和测试微服务架构,24%的企业正在学习微服务准备转型。因此,可以说微服务架构在企业中的应用已经相当普遍。微服务架构可以降低业务的复杂性,让业务易于理解、修改和维护。此外,微服务架构还具有模块化部署、修改代价小、迭代速度快和扩展性等优点。因此,微服务架构已经被广泛应用于各种业务开发部门,帮助企业快速响应市场需求,提升竞争力。然而,微服务架构的实施和治理也存在一定的挑战。例如,微服务之间的通信、数据共享和安全性等问题需要妥善解决。同时,微服务架构的运维和管理也需要专业的技术和人才。因此,企业在采用微服务架构时需要综合考虑自身的实际情况和技术能力,选择合适的方案来实现业务价值的最大化。
考虑到微服务架构的特殊性,我以「微信」的技术架构举例,回答题主问题。
微信开发者团队最近一篇论文“Overload Control for Scaling WeChat Microservices(超大规模微信微服务中的过载控制)”透露了部分细节,主要讲述了微服务的过载控制。
基于这篇论文,本文核心要点有二。其一,解析微信的后端; 第二,解析微信五年生产化运行过程中,得到实践检验的过载控制系统DAGOR的设计思路。当然,如果你希望为自己的微服务制定策略,这是一份上手指南。
截至目前,微信后端共包含超过3000项移动服务,其中包括即时消息收发、社交网络、移动支付以及第三方验证等等。该平台每天接收到的外部请求量在 10^10-10^11次之间,其中每一项请求都会触发更多的内部微服务请求,这意味着微信后端整体每秒需要处理数亿次请求。
微信的微服务系统能够在微信业务系统中的2万多台设备上运行超过3000项服务。而随着微信的广泛普及,这一数字仍然不断增加……伴随着微信的不断发展,微服务系统一直在快速迭代并进行服务更新。举例来说,从2018年3月到5月,微信的微服务系统每天平均经历近千次变化。
微信将其微服务分类为“入口跳转”服务(用于接收外部请求的前端服务)、“共享跳转”服务(中间层协调服务)以及“基本服务”(不向任何其它服务扇出,因此可充当请求接收方的服务)。
图:微信的微服务架构
以普通的单日运行场景为例,微信的峰值请求率约为每日平均值的3倍。在一年中的某些特定时段(例如在中国的农历新年期间),峰值工作负载甚至有可能增长至每日平均值的10倍。
基于大规模微服务平台的过载控制挑战“Overload control… is essential for large-scale online applications that need to enforce 24×7 service availability despite any unpredictable load surge.”(过载控制……对于大规模在线应用程序而言至关重要,这些应用程序需要在遭遇不可预测的负载激增时实现24 x 7全天候服务可用性。)
传统的过载控制机制专门面向具有少量服务组件、“入口”相对狭窄且依赖性较为普通的场景所设计。
“… modern online services are becoming increasingly complex in their architecture and dependencies, far beyond what traditional overload control was designed for…”(…现代在线服务在架构与依赖性方面则变得越来越复杂,这远远超出了传统过载控制方案的设计目标。)
• 由于发送至微信后端的服务请求不存在单一入口点,因此在全球入口点(网关)进行集中式负载监控的传统方案将不再适用。
• 特定请求中的服务调用图可能取决于因请求而异的数据与服务参数,即使是相同类型的请求也可能存在这种差异。因此,当特定服务出现过载时,很难确定应该删除哪些类型的请求以缓解过载情况。
• 过多的请求中止(特别是在调用图中较深或请求流程内偏后的部分时)会浪费计算资源,并带来影响用户体验的高延迟问题。
• 由于微信的服务DAG(有向无环图)极其复杂且不断发展,因此用于实现高效跨服务协调的维护成本与系统开销都将超出可承受范围。
由于某项服务可能会对其所依赖的服务发出多次请求,并且有可能向多项后端服务发出请求,因此我们必须高度关注过载控制。对于调用多项过载服务或多次调用单一过载服务的情况,作者在论文中专门创造了一个新的词汇,即“后续过载”。
“Subsequent overload raises challenges for effective overload control. Intuitively, performing load shedding at random when a service becomes overloaded can sustain the system with a saturated throughput. However, subsequent overload may greatly degrade system throughput beyond that intended…”(后续过载会对过载控制机制的有效性提出挑战。直观来讲,在服务过载时执行随机减裁操作可以将系统的实际吞吐量维持在饱和状态。而后续过载则可能大大降低超出预期的系统吞吐量……)
这里考虑一个简单的场景,其中服务A对服务B进行了两次调用。如果B开始对全部传入请求中的半数加以拒绝,则服务A的调用成功率将下降至0.25。
DAGOR概述微信采用的过载控制系统被称为DAGOR,其旨在为所有服务提供过载控制功能,因此必须具有服务中立性。由于集中式全局协调将带来高昂的实现成本,因此过载控制需要以单一机器的细粒度方式运行。然而,其中还包含有处理后续过载情况所必需的轻量级机器间协调协议。最后,当由于严重过载而导致的减载变得不可避免时,DASGOR应尽可能维持服务的请求成功率。换言之,其应尽量减少浪费在失败服务任务上的计算资源(例如CPU与I/O等等)。
这里,我们有两项基本任务需要解决:检测过载情况,并在检测到过载之后决定如何加以处理。
过载检测对于过载检测,DAGOR着眼于待处理队列中各请求的平均等待时间(或者说排队时间)。排队时间的最大优势,在于能够抵消呼叫图中较低延迟的平均化影响(相较于请求处理时间等指标)。即使本地服务器本身没有发生过载,请求处理时间也有可能增加。DAGOR可采用基于窗口的监控机制,其中的容器为1秒或者2000次请求,以先到者为准。微信显然一直处在高效紧张地的运行状态之中:
“For overload detection, given the default timeout of each service task being 500ms in WeChat, the threshold of the average request queuing time to indicate server overload is set to 20ms. Such empirical configurations have been applied in the WeChat business system for more than five years with its effectiveness proven by the system robustness with respect to WeChat business activities.”(对于过载检测,假设微信中每个服务任务的默认超时为500毫秒,则表示服务器过载的平均请求排队时间阈值将设置为20毫秒。这种基于经验的配置方式已经在微信业务系统中应用了超过五年之久,其有效性通过系统对微信业务活动支持的稳健性表现得到了证实。)
接纳控制一旦检测到过载状况,我们就必须决定如何加以处理。或者更具体地讲,我们需要考量放弃哪些请求。这时,我们首先需要明确一点,各项请求之间并不是平等的:
“The operation log of WeChat shows that when WeChat Pay and Instant Messaging experience a similar period of service unavailability, user complaints against the WeChat Pay service are 100x those against the Instant Messaging service.”(微信的运营日志显示,每当与微信支付与即时消息体验相关的服务发生不可用问题时,用户对微信支付服务的投诉是针对即时消息收发服务的100倍。)
为了以服务中立性方式处理这个问题,每项请求在首次进入系统时都会被赋予一种业务优先级。这项优先级会随着所有下游请求一同继承。用户请求的业务优先级由其请求的操作类型决定。虽然存在数百个入口点,但实际其中只有几十个具有显性优先级,其它所有入口点都默认属于较低优先级。优先级设定保留在复制的哈希表当中。
图:用于存储微信入口服务内操作执行业务优先级的哈希表
当过载控制被设定为业务优先级n时,所有来自n+1等级的请求都将被放弃。这种方式对于混合型工作负载来说效果良好,但假定我们面对的是大量付款请求,而所有请求都具有相同的优先级(假定为p),那么一旦系统遭遇过载,我们就需要调整过载阈值以实现轻载,即将过载阈值变更为p-1。而一旦检测到轻载,过载阈值将再次增加至p,这时我们将重新面对过载状态。因此,要在大量具有相同优先级的请求引发超载时停止这种无意义的转换,我们需要采用超越业务优先级的细粒度调整。
微信对此拿出了一种良好的解决方案。其增加了基于用户ID的第二层接纳控制机制。
“User priority is dynamically generated by the entry service through a hash function that takes the user ID as an argument. Each entry service changes its hash function every hour. As a consequence, requests from the same user are likely to be assigned to the same user priority within one hour, but different user priorities across hours.”(用户优先级由入口服务通过以用户ID为参数的哈希函数动态生成。每项入口服务每小时变更一次其哈希函数,因此来自同一用户的请求很可能在一小时之内被分配予相同的用户优先级,但在数小时内被分配予不同的用户优先级。)
这就提供了公平性,同时亦能够在相对较长的时间周期内为个人用户提供一致的使用体验。另外,其还有助于解决后续过载问题,因为来自被分配予高优先级用户的请求更有可能在整体调用图中得到及时处理。
将业务优先级与用户优先级结合起来,即可为每个业务优先级提供配合128种用户优先级的复合接纳级别。
图:复合接纳级别
“With each admission level of business priority having 128 levels of user priority, the resulting number of compound admission levels is in the tens of thousands. Adjustment of the compound admission level is at the granule of user priority.”(由于每项业务优先级的接纳级别都包含128种用户优先级,因此其得出的复合接纳级别数量将达到数万种。对复合接纳级别的调整,能够细化至用户优先级粒度。)
另外值得一谈的是,为什么要采用用户ID而非会话ID来解决上述问题:因为如果以会话ID为解决方案,用户最终只会通过注销并重新登录的方式解决服务无影响问题,而由此带来的重新登录风暴将带来新的过载冲击!
DAGOR在每台服务器上都维持着一套关于请求的直方图,用于追踪超过接纳优先级的请求的大体分布情况。当在窗口期间检测到过载时,DAGOR会移动至另一“桶”(范围),这将使预期负载减少5%。而如果过载消失,其同样会移动至新的“桶”(范围),这将使预期负载增加1%.
服务器会在发送至上游服务器的每条响应消息中附带其当前接纳级别。通过这种方式,上游服务器将获知下游服务的当前接纳控制设置,甚至能够在发送之前即对该请求执行本地接纳控制操作。
因此,DAGOR的端到端过载控制系统将如下所示:
图:DAGOR过载控制工作流
实验DAGOR设计有效性的最佳证明,在于其已经在微信的生产环境中拥有长达五年的良好运作记录。不过这无法为学术论文提供必要的图表,因此我们进行了一组模拟实验。下图突出显示了基于排队时间——而非响应时间——的过载控制成效。在后续过载的情况下,这种收益最为明显(如图(b)所示)。
与CoDel以及SEDA相比,在进行一次后续调用时,DAGOR凭借着后续过载机制使请求成功率提高了50%。后续请求数量越大,这种收益就越是明显:
图:不同工作负载类型下的过载控制
最后,在公平性方面,CoDel在高压场景下更倾向于使用扇出量较小的服务,而DAGOR则在各类请求当中表现出大致相同的成功率水平。
图:过载控制的公平性
构建处有系统中的三项经验
即使你不打算完全按照微信的方式使用DAGOR,作者仍然总结出了三项宝贵的实践经验:
• 超大规模微服务架构下的过载控制必须在每项服务中实现分散与自治。
• 过载控制应当考虑到各种反馈机制(例如DAGOR的协调接纳控制),而非仅仅依赖于开环启发式机制。
• 应当通过对实际工作负载的处理行为进行分析,从而探索过载控制的设计思路。
还没有评论,来说两句吧...