接口耗时10秒如何优化为1秒

技术面试中,一定会被问到性能优化有关的问题。这一类问题大多数都是开放性的,考察求职者的知识储备和逻辑思维。我们的脑洞可以开大一点,多说一些解决方案,充分展示自己的能力。

比如这个题:一个接口耗时10秒,如何优化为1秒? 这个问题脱离实际生产情况,属于八股文。如果生产环境中出现性能低下的接口,通常怎么应对?

  • 根据接口重要性确定是否优化

过早优化是万恶之源。性能优化的目标是,在最合适的性价比下达到理想的性能提升。过度优化会增加系统复杂度和维护成本,使得开发和测试周期变长。如果接口承接着非核心业务,调用方也能忍受目前的耗时,优化工作可以暂缓,比这重要的活儿多得是。

  • 无法精准预测优化后的耗时

优化方案再好,也只能保证优化方向的正确。压测报告出来之前,谁都不能保证采用某方案耗时一定在1秒以内,精确预测结果是不科学的。

确定接口要优化的话,实际开展的步骤是:

  1. 接口调研:根据日志确定耗时高是常态,不是偶发性。结合监控系统、链路跟踪系统等工具定位性能瓶颈。
  2. 制定方案:结合调用方的需求和开发人员的经验确定优化方案,比如调用方希望耗时在3秒内或者接受异步通知。
  3. 实施方案:通过代码重构、引入中间件等方式改造接口,最好包含灰度方案或者动态切换新老逻辑的开关。

回到面试题本身,如何回答这个问题,能让面试官满意呢?这个题目的重点是“优化”和“1秒”,必须说出几种可能的性能瓶颈以及对应优化方案,方案为什么可以降低耗时。

常规业务系统譬如电商、物流都属于数据密集型系统,即数据是系统成败的决定性因素,包括数据的规模、数据的复杂度、数据产生与变化的速率。这类系统对IO的操作频率远远高于CPU,减少IO操作、提高CPU利用率是性能优化的大方向。排除掉网络质量问题,导致接口性能问题的原因很多,下面聊聊性能瓶颈与优化方案。

1.业务逻辑复杂

随着业务的发展,接口逻辑变复杂是难免的,重点是做好复杂度的管理。代码层面上,要充分的模块化,理清核心逻辑与辅助逻辑。如果在接口上叠加新需求,要全盘考虑合理性和扩展性。

  • 接口异步调用

接口异步调用是最直接的方案,耗时都在网络请求和RPC连接上,耗时肯定在1秒内。由于无法同步返回数据,调用方要异步处理结果,增加了系统复杂性。

以常用的RPC框架Dubbo为例,在消费端引用服务时增加async配置即可实现异步调用。如下所示,name为需要异步调用的方法名,async=true表示是否启用:

<dubbo:reference id="asyncOrderService" check="false" interface="com.alibaba.dubbo.demo.AsyncOrderService">
    <dubbo:method name="createOrder" async="true" />
</dubbo:reference>

配置了异步调用,直接调用将返回null:

Order order = asyncOrderService.createOrder(createOrderDto);

通过RpcContext获取Future对象,调用get方法时阻塞获取返回结果:

asyncOrderService.createOrder(createOrderDto);
Future<String> future = RpcContext.getContext().getFuture();
Order order = future.get();
  • 业务异步处理

如果不能接受整个接口异步调用,考虑将部分非核心流程异步执行。比如下单接口包含查库存、生成订单、发送短信三个步骤,发送短信不是核心流程,可以改为发送MQ消息触发短信,能省下一点耗时。

    /**
     * 创建订单
     * @return
     */
    public Order createOrder()
    {
        //查询库存
        ProductStore productStore = productStoreService.queryProductStore(productSkuDto);
        //TODO 判断库存
        //生成订单
        Order order = orderService.createUserOrder(createOrderDto);
        if(order == null) {
            throw new Exception("创建订单失败");
        }
        //TODO 组装短信消息
        //发送订单成功短信MQ
        mqProducer.sendMessage(orderSuccessMsg);
        retrun order;
    }
  • 并行处理

在满足业务逻辑的前提下,将没有关联的步骤由串行改为并行执行。比如有A和B两个步骤,分别耗时200ms和100ms,并行执行后最大耗时就是A的200ms。以下代码演示了Java语言的并行处理,将“查询满100减10信息”和“查询可用优惠券信息”的结果汇总返回给接口。

/**
* 查询购物车优惠活动标签
*/
public void getDiscountActivityTag(CartItemDTO cartItemDTO) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        List<Callable<String>> tasks = Lists.newArrayList();
        tasks.add(new Callable<String>() {
            @Override
            public String call() throws Exception {
                //查询满100减10信息
                 return null;
            }
        });
        tasks.add(new Callable<String>() {
            @Override
            public String call() throws Exception {
                //查询可用优惠券信息
                return null;
            }
        });
        try {
            List<Future<String>> futureList = executorService.invokeAll(tasks, 3000, TimeUnit.MILLISECONDS);
            if(CollectionUtils.isEmpty(futureList) {
                return STR_BLANK;
            }
            //组装优惠活动标签
            return StringUtils.join(futureList,STR_SPLIT);
        } catch (InterruptedException e) {
            logger.info("查询购物车优惠活动标签发生错误",e);
        }
        executorService.shutdown();
        
        return STR_BLANK;
    }

  • 调整业务流程

从10秒优化到1秒是个不小的挑战,如果没有好的技术方案能够实现,可以尝试调整业务流程。将一个接口做完的事情,拆成两三个接口来做,每个接口的耗时自然就减少了。通过校验业务数据,保证拆分后的接口的顺序调用。

2.数据库读写性能差

系统发展到一定的阶段,单实例的数据库一定无法支撑高并发的读写,优先考虑的应该是索引优化和冷数据归档,分库分表是最后的大招。

  • 冷数据归档:将用户不太关注的历史数据从单表中迁移走,前端提示用户只提供最近N个月数据。保证每个表的数据在一千万左右,查询耗时在0.5秒以内。

  • 索引优化:索引可以大大提高数据的查询速度。索引优化需要重点关注索引失效的原因。如果单表的数据量过大,优化索引也无法改善性能。

  • 数据缓存:读多写少、弱实时性的场景,尝试缓存数据。缓存的介质常常是内存,查询速度远高于数据库的磁盘,提升性能的效果非常明显。常用分布式缓存组件是Redis,二级缓存组件有Guava Cache、Caffeine、Encache,Spring Cache可以集成使用这三者。

文章出处:https://www.codingbrick.com/archives/834.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,874评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,151评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,270评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,137评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,116评论 5 370
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,935评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,261评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,895评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,342评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,854评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,978评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,609评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,181评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,182评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,402评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,376评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,677评论 2 344

推荐阅读更多精彩内容