欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[详解]优化API接口响应速度的套路

程序员文章站 2024-01-13 18:40:10
...

前言

API接口响应慢?
SLA一直提不上去?
其实这是后端程序员想进阶必须要跨过去的坎:就是把它优化掉。
那么这其中到底有没有套路呢?答案是:有的。

本文将介绍目前正在用并且十分“无脑”有效的这个套路。

正文

埋点追踪分析,找出真凶

首先呢,第一部肯定是在关键函数(有db、文件、复杂计算等操作)的前后,进行时间的记录。

这里分享一个前文跟踪的类Trace.php

<?php
class Trace{
    var $startTime = [];
    var $endTime = [];

    var $single_mode= false;
    var $trace_mode = false;

    function getTimestamp(){
        return microtime(true);
    }
    function start($type, $time=0){
        if(empty($this->trace_mode)) return 0;

        if(!$time) {
            $time = $this->getTimestamp();
        }

        if($this->single_mode) {
            $this->startTime[$type]=$time;
        } else {
            $this->startTime[$type][]=$time;
        }
    }
    function stop($type, $time=0){
        if(empty($this->trace_mode)) return 0;

        if(!$time) {
            $time = $this->getTimestamp();
        }

        if($this->single_mode) {
            $this->endTime[$type]=$time;
        } else {
            $this->endTime[$type][]=$time;
        }
    }
    function time($type) {
        if(empty($this->trace_mode)) return 0;

        if(!isset($this->endTime[$type])) return 0;

        if(is_array($this->endTime[$type])) {
            return array_sum($this->endTime[$type]) - array_sum($this->startTime[$type]);
        } else  {
            return $this->endTime[$type]-$this->startTime[$type];
        }
    }
    function log($type){
        if(empty($this->trace_mode)) return 0;

        $log['type'] = $type;
        $log['time'] = $this->time($type);;
        // 每个框架不同的记日志方式,可切换
        writeLog($log, 'trace_log');
    }


    function logAll($prefix = '', $ext = array()){
        if(empty($this->trace_mode)) return 0;

        if(!empty($ext)) {
            $log = $ext;
            $log['elapse_time'] = $this->output(false);
        } else {
            $log = $this->output(false);
        }

        if(!empty($log)) {
            $prefix = strtolower(preg_replace('/((?<=[a-z])(?=[A-Z]))/', '_', $prefix));
            // 每个框架不同的记日志方式,可切换
            writeLog($log, 'trace_' . $prefix . '_log');
        }
    }

    function output($with_endtime = true){
        $output = array();
        if(!empty($this->startTime)) {
            foreach($this->startTime as $_type => $_time) {
                $exec_time = $this->time($_type);
                if($exec_time) {
                    $output[$_type] = $exec_time;
                    if($with_endtime) {
                        if(is_array($this->endTime[$_type])) {
                            $output[$_type] .= '|' . max($this->endTime[$_type]);
                        } else {
                            $output[$_type] .= '|' . $this->endTime[$_type];
                        }
                    }
                }
            }
        }
        return $output;
    }

    function reset($type = null){
        if(empty($type)) {
            $this->startTime = null;
            $this->endTime = null;
        } else {
            unset($this->startTime[$type]);
            unset($this->endTime[$type]);
        }

        return $this;
    }
    function enableTrace($exit = true){
        $this->trace_mode = $exit;
    }
}
?>

怎么使用呢?

$Trace = loadClass('Trace');
$Trace->enableTrace(true);
$Trace->start('total');

$Trace->start('func1');
$this->run_slow_function1();
$Trace->stop('func1');

$Trace->start('func2');
$this->run_slow_function2();
$Trace->stop('func2');


$Trace->stop('total');
$Trace->logAll('咖啡色的羊驼');
$Trace->reset();

此时去找trace_咖啡色的羊驼_log就可以找到每一步跑的时间。根据实际可以一眼看出是哪一步跑慢了。那么这一步就是主要优化的方向了。

ps:此类对线上接口产生的耗时基本可以忽略,所以放心用。

根据上下文,找到解决方案

既然找到了跑得慢的函数。那么就开始优化吧。

先说前提:前端已有lvs负载均衡、nginx反向代理转发请求。

首先需要分析为何跑慢了?

1.是不是资源层面的瓶颈?
2.是不是缓存没添加,如果加了,是不是热点数据导致负载不均衡?
3.是不是有依赖于第三方接口?
4.是不是接口涉及业务太多,导致程序跑很久?
5.是不是sql层面的问题导致的等待时机加长,进而拖慢接口?
6.网络层面的原因?带宽?DNS解析?
7.代码确实差???
8.未知?

暂时就想到这么多,有补充欢迎留言,谢谢。

对症下药

1.资源紧张,加机器,干上去,负载均衡搞起来
2.加缓存可以解决的问题都不是什么大问题,存在热点数据可以将某几个热点单独出来用专门的机器进行处理,不要因为局部影响整体
3.一方面与第三方沟通接口响应问题,另一方面超时时间注意把控,如果可以非核心业务能异步久异步掉。
4.把非核心的业务进行异步化操作。记住如果代码层面是非核心业务,但是会影响用户感知,需要慎重决定是否异步。
5.如果是代码不良导致加锁了,尽量优化索引或sql语句,让锁的级别最小(到行),一般来说到行差不多了。如果是单个sql跑慢了,需要分析是不是索引没加活着sql选的索引错了,索引该加的就加了,该force index也加了。
6.网路原因,需要联系运营商一起商量下怎么解决,单方面比较难有大的优化。
7.代码确实差,那也无药可救了。我选择狗带。

通用套路

异步化