华人澳洲中文论坛

热图推荐

    接口响应提早案例剖析

    [复制链接]

    2022-10-24 12:08:44 22 0

    本文以实际案例引见下:对于接口响应慢时所要排查的一些角度以及在对顺序进行剖析零碎提早的时分所用到的一些工具。
    零碎提早的实质是因为cpu在这段时间里没有去及时的运算你的运用顺序代码,致使你的运用顺序代码在梗阻之后,再被调度回来的全部时间距离会太长,从用户的角度看,就会表示为全部接口提早会太高,响应时间太长。
    形成提早的缘故,第一个是从过程外部看,有多是你的机器的网络io或磁盘io这类梗阻操作或者是cpu的使用率 达到瓶颈之后会形成调度你的顺序代码会对比慢。
    第二个是调第三方零碎,像mysql、redis,假如在履行查问的时分,像慢查问,全部运用顺序的吞吐量确定会有所降落的。
    比来线上有个golang的运用顺序会隔三差五的、晚上10点摆布,总会有慢sql的报警泛起,而且在平时略有顶峰期,好比晚上6-9:30,偶然也会泛起sql的报警,这个报警是对sql履行时长的一个报警,sql报警是在运用顺序外部经过对sql操作减少钩子函数,而后对sql先后履行的地位进行计时,对两个计时相减失掉sql在咱们运用顺序外部履行的时间,假如时间大于1s就报警。
    晚上10点正好是业务顶峰期,所以得多接口偶然泛起一些sql报警而且响应时长会超过两秒。一个接口超过2秒才响应,对用户的体验是极为欠好的,所以对此进行了优化。因为这个是慢sql的一个报警,所以首先看的是这个sql的写法有无问题,有无索引,看了下后盾慢sql的查问日志,发现并无慢sql日志打印出来,而后从新履行了这条sql,又发现它的履行时间,依然在毫秒之内是可以实现的。


    所以我的一个设法是排除掉了sql写法自身所带来的机能问题。为何这条sql不是慢查问,然而运用顺序的办法调度回来之后变慢了?所以有无多是零碎资源达到了瓶颈之后,致使cpu来不迭调度到运用顺序代码,所以又去看了零碎的硬件资源。


    cpu使用率 、内存使用率,能够看到是在一个很低的值,线上cpu是4核,顶峰期才达到25%的一个使用率,内存使用率也是根本上25%摆布,没有泛起过量的颠簸。
    独一在顶峰期有一点点偏高的是零碎负载,在顶峰期的时分可能会超过4这个值,达到5也缺乏以说硬件资源达到了瓶颈。既然硬件资源没有达到瓶颈,运用顺序为何在此刻没有被cpu调度到,所以颇有可能运用顺序处于一种梗阻等候的形态,而这个梗阻等候是不会耗损cpu的或者说在这个梗阻等候形态的时分所履行的举措对cpu的使用其实不高。
    所以斟酌顺序是在履行一个cpu使用率不高的举措然而这个举措又不是在履行用户代码,运用顺序可能会在梗阻之后,全部顺序可能会再履行一个调度的举措:寻觅那些能够履行的协程去履行,而这个调度的举措并非很耗cpu的一个举措,症结要看运用顺序到底梗阻在了哪一部份,它等候在了哪一部份。
    这里用到了off cpu的一个工具 fg prof,off cpu指的是可以展现出来运用顺序等候cpu所损耗的时间占比,通罕用go tool pprof去看cpu的时分,看的是cpu真正履行的时间。
    而关于咱们这个场景,它是没无意义的,由于咱们的cpu使用率不高。
    可能等候cpu的时间才是咱们应该斟酌的一个关注点,经过fg prof能够看到,占用off cpu太高的一个办法,这个办法外面实际上是在进行一个sql的操作,


    然而这个sql的操作并非因为慢查问到的,它多是因为withLock,个别咱们加锁运用顺序,极可能就会堕入梗阻,而且经过跟mysql的一个读写操作,波及到了网络io的部份,那这个网络io和withLock所占用的等候cpu的时间会占一个很大的比例,所以这里就初步断定了颇有多是因为这个接口在高频的进行这类梗阻操作的代码,致使了这个接口在对外袒露的时分,有一部份接口响应时间会超过两秒。
    而后用更精密的工具去看零碎提早的时间,由于仅仅经过fg prof去看零碎提早的时分,能够知道这部份代码在off cpu占了大部份时间,然而详细占用多少时间,经过fg prof仍是无奈剖析出来的,这里是为了百分之百确实定确实是这部份代码致使的问题。用了golang民间提供的go trace这个工具,go trace可以将运用顺序此时一个形态而且履行的状况残缺的给你展现出来而且记载顺序在履行举措的时分所损耗的时长。经过go trace咱们失掉了这样的图,


    进行了3秒的采样,最左侧是协程编号, 这个协程网络等候时间在三秒之内的话,都达到了两秒多,所以能够看到网络等候时长实际上是很长的。
    这里不克不及仅仅由于网络的io就断定这个协程是因为网络等候io所酿成的梗阻,首先要明确网络等候io算法的原理:网络等候io它是在进行调度网络io代码的时分,会记载下此时协程的时间,并把协程从p队列拿上去,而后异步的等候epoll回调通知,比及文件形容符可读之后,它会把这个协程再参加到p队列,这个时分从新履行调度函数。
    所以网络等候时间就是从p队列拿上去到参加到p队列的时间距离,协程真正会再次被调度的时分是要等候这个图外面的scheduler wait时间,才会真实的被履行、被cpu调度到。
    为何说一个协程仅仅看网络等候时间不克不及断定是因为网络等候时间所酿成的梗阻?是因为一个协程可能会履行屡次申请,由于开了keepalive之后,一条衔接是可以履行屡次申请的,而在golang http办事外面的一个衔接是对应一个协程,一个协程颇有多是在for循环外面,频繁的去等候着衔接可读,所以形成了等候时长减少,而等候下一次申请这个时间距离的网络io时间,是不会影响你的全部接口变慢的,所以除了要看网络等候时间,也能够去看看其余目标。


    在这里将scheduler wait进行了从大到小的排序之后,能够看到三秒钟之内仍是有一些协程,它们的一个等候调度时间都达到了800多毫秒,梗阻的时长也是可以达到700多毫秒,这样的占比,确定会致使咱们的申请会带来更大的提早,由于保不许这个协程在履行申请的时分,它可能比及被调度的时分,会再去等候一个800毫秒才会真实的去履行你的代码,而全部响应提早超过2秒也很常见了。
    因为咱们是在进行频繁的一个网络申请和一个梗阻操作 wthLock,能够将这部份操作彻底的放到内存外面来,这样就可以够增加对数据库的网络申请,增加因数据库发生的withLock操作带来的梗阻问题,


    优化了这部份代码之后,晚上6点到9点半这部份响应时间超过两秒的接口曾经不存在了,然而在10点的时分仍是有部份接口时超过2秒的,起初通过排查发现,因为咱们的线上机器同时了部署了多个其余办事,因为其余办事影响致使的,所当前续可能还会做持续的优化,让其余办事的接口处置才能晋升下来或者将过程资源进行隔离。

    发表回复

    您需要登录后才可以回帖 登录 | 立即注册

    返回列表 本版积分规则

    :
    注册会员
    :
    论坛短信
    :
    未填写
    :
    未填写
    :
    未填写

    主题26

    帖子38

    积分171

    图文推荐