从3s到25ms!看看京东的接口优化技巧,确实很优雅!!

这篇具有很好参考价值的文章主要介绍了从3s到25ms!看看京东的接口优化技巧,确实很优雅!!。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

大家好,最近看到京东云的一位大佬分享的接口优化方案,感觉挺不错的,拿来即用。建议收藏一波或者整理到自己的笔记本中,随时查阅!

来源:https://toutiao.io/posts/0kwkbbt

下面是正文。

一、背景

针对老项目,去年做了许多降本增效的事情,其中发现最多的就是接口耗时过长的问题,就集中搞了一次接口性能优化。本文将给小伙伴们分享一下接口优化的通用方案。

从3s到25ms!看看京东的接口优化技巧,确实很优雅!!

二、接口优化方案总结

1.批处理

批量思想:批量操作数据库,这个很好理解,我们在循环插入场景的接口中,可以在批处理执行完成后一次性插入或更新数据库,避免多次 IO。

//for循环单笔入库
list.stream().forEatch(msg->{
    insert();
});
//批量入库
batchInsert();

2. 异步处理

异步思想:针对耗时比较长且不是结果必须的逻辑,我们可以考虑放到异步执行,这样能降低接口耗时。

例如一个理财的申购接口,入账写入申购文件是同步执行的,因为是 T+1 交易,后面这两个逻辑其实不是结果必须的,我们并不需要关注它的实时结果,所以我们考虑把入账写入申购文件改为异步处理。如图所示:

从3s到25ms!看看京东的接口优化技巧,确实很优雅!!

至于异步的实现方式,可以用线程池,也可以用消息队列,还可以用一些调度任务框架。

推荐一个开源免费的 Spring Boot 最全教程:

https://github.com/javastacks/spring-boot-best-practice

3. 空间换时间

一个很好理解的空间换时间的例子是合理使用缓存,针对一些频繁使用且不频繁变更的数据,可以提前缓存起来,需要时直接查缓存,避免频繁地查询数据库或者重复计算。

需要注意的事,这里用了合理二字,因为空间换时间也是一把双刃剑,需要综合考虑你的使用场景,毕竟缓存带来的数据一致性问题也挺令人头疼。

这里的缓存可以是 R2M,也可以是本地缓存、memcached,或者 Map。

举一个股票工具的查询例子:

因为策略轮动的调仓信息,每周只更新一次,所以原来的调接口就去查库的逻辑并不合理,而且拿到调仓信息后,需要经过复杂计算,最终得出回测收益和跑赢沪深指数这些我们想要的结果。如果我们把查库操作和计算结果放入缓存,可以节省很多的执行时间。如图:

从3s到25ms!看看京东的接口优化技巧,确实很优雅!!

4. 预处理

也就是预取思想,就是提前要把查询的数据,提前计算好,放入缓存或者表中的某个字段,用的时候会大幅提高接口性能。跟上面那个例子很像,但是关注点不同。

举个简单的例子:理财产品,会有根据净值计算年化收益率的数据展示需求,利用净值去套用年化收益率计算公式计算的逻辑我们可以采用预处理,这样每一次接口调用直接取对应字段就可以了。

5. 池化思想

我们都用过数据库连接池,线程池等,这就是池思想的体现,它们解决的问题就是避免重复创建对象或创建连接,可以重复利用,避免不必要的损耗,毕竟创建销毁也会占用时间。

池化思想包含但并不局限于以上两种,总的来说池化思想的本质是预分配与循环使用,明白这个原理后,我们即使是在做一些业务场景的需求时,也可以利用起来。

比如:对象池

6. 串行改并行

串行就是,当前执行逻辑必须等上一个执行逻辑结束之后才执行,并行就是两个执行逻辑互不干扰,所以并行相对来说就比较节省时间,当然是建立在没有结果参数依赖的前提下。

比如,理财的持仓信息展示接口,我们既需要查询用户的账户信息,也需要查询商品信息和 banner 位信息等等来渲染持仓页,如果是串行,基本上接口耗时就是累加的。如果是并行,接口耗时将大大降低。

如图:

从3s到25ms!看看京东的接口优化技巧,确实很优雅!!

7. 索引

加索引能大大提高数据查询效率,这个在接口设计之出也会考虑到,这里不再多赘述,随着需求的迭代,我们重点整理一下索引不生效的一些场景,希望对小伙伴们有所帮助。

具体不生效场景不再一一举例,后面有时间的话,单独整理一下。

从3s到25ms!看看京东的接口优化技巧,确实很优雅!!

8. 避免大事务

所谓大事务问题,就是运行时间较长的事务,由于事务一致不提交,会导致数据库连接被占用,影响到别的请求访问数据库,影响别的接口性能。

举个例子:

@Transactional(value ="taskTransactionManager", propagation =Propagation.REQUIRED, isolation =Isolation.READ_COMMITTED, rollbackFor ={RuntimeException.class,Exception.class})
    publicBasicResultpurchaseRequest(PurchaseRecordrecord){
        BasicResult result =newBasicResult();
        //插入账户任务
        taskMapper.insert(ManagerParamUtil.buildTask(record,TaskEnum.Task_type.pension_account.type(),TaskEnum.Account_bizType.purchase_request.type()));
        //插入同步任务
        taskMapper.insert(ManagerParamUtil.buildTask(record,TaskEnum.Task_type.pension_sync.type(),TaskEnum.Sync_bizType.purchase.type()));
        //插入影像件上传任务
        taskMapper.insert(ManagerParamUtil.buildTask(record,TaskEnum.Task_type.pension_sync.type(),TaskEnum.Sync_bizType.cert.type()));
        result.setInfo(ResultInfoEnum.SUCCESS);
        return result;
    }

上面这块代码主要是申购申请完成后,执行一系列的后续操作,如果现在新增申购完成后,发送 push 通知用户的需求。很有可能我们会在后面直接追加,如下图所示:事务中嵌套 RPC 调用,即非 DB 操作,这些非 DB 操作如果耗时较大的话,可能会出现大事务问题。大数据引发的问题主要有:死锁、接口超时、主从延迟等。

@Transactional(value ="taskTransactionManager", propagation =Propagation.REQUIRED, isolation =Isolation.READ_COMMITTED, rollbackFor ={RuntimeException.class,Exception.class})
    publicBasicResultpurchaseRequest(PurchaseRecordrecord){
        BasicResult result =newBasicResult();
        ...
        pushRpc.doPush(record);
        result.setInfo(ResultInfoEnum.SUCCESS);
        return result;
    }

所以为避免大事务问题,我们可以通过以下方案规避:

1,RPC 调用不放到事务里面

2,查询操作尽量放到事务之外

3,事务中避免处理太多数据

9. 优化程序结构

程序结构问题一般出现在多次需求迭代后,代码叠加形成。会造成一些重复查询、多次创建对象等耗时问题。在多人维护一个项目时比较多见。解决起来也比较简单,我们需要针对接口整体做重构,评估每个代码块的作用和用途,调整执行顺序。

10. 深分页问题

深分页问题比较常见,分页我们一般最先想到的就是 limit ,为什么会慢,我们可以看下这个 SQL:

select*from purchase_record where productCode ='PA9044'andstatus=4orderby orderTime desclimit100000,200

limit 100000,200 意味着会扫描 100200 行,然后返回 200 行,丢弃掉前 100000 行。所以执行速度很慢。一般可以采用标签记录法来优化,比如:

select*from purchase_record where productCode ='PA9044'andstatus=4and id >100000limit200

这样优化的好处是命中了主键索引,无论多少页,性能都还不错,但是局限性是需要一个连续自增的字段

11.SQL 优化

sql 优化能大幅提高接口的查询性能,由于本文重点讲述接口优化的方案,具体 sql 优化不再一一列举,小伙伴们可以结合索引、分页、等关注点考虑优化方案。

12. 锁粒度避免过粗

锁一般是为了在高并发场景下保护共享资源采用的一种手段,但是如果锁的粒度太粗,会很影响接口性能。

关于锁粒度:就是你要锁的范围有多大,不管是 synchronized 还是 redis 分布式锁,只需要在临界资源处加锁即可,不涉及共享资源的,不必要加锁,就好比你要上卫生间,只需要把卫生间的门锁上就可以,不需要把客厅的门也锁上。

错误的加锁方式:

//非共享资源
privatevoidnotShare(){
}
//共享资源
privatevoidshare(){
}
privateintwrong(){
    synchronized(this){
      share();
      notShare();
    }
}

正确的加锁方式:

//非共享资源
privatevoidnotShare(){
}
//共享资源
privatevoidshare(){
}
privateintright(){
    notShare();
    synchronized(this){
    share();
 }
}

三、最后

我相信很多接口的效率问题不是一朝一夕形成的,在需求迭代的过程中,为了需求快速上线,采取直接累加代码的方式去实现功能,这样会造成以上这些接口性能问题。

变换思路,更高一级思考问题,站在接口设计者的角度去开发需求,会避免很多这样的问题,也是降本增效的一种行之有效的方式。

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!文章来源地址https://www.toymoban.com/news/detail-445040.html

到了这里,关于从3s到25ms!看看京东的接口优化技巧,确实很优雅!!的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 京东接口对接流程(以下举例物流接口):

    1.注册成为京东宙斯开发者 2.创建应用 控制中心 – 已经应用类型选择京东物流 – 二级应用类型选择青龙应用 注:选择的接口在和京东对接联调的时候可以咨询京东开发者 3.等待审核通过 创建好了应用后等待审核 4.审核通过,设置回调URL并且获取Appkey、App Secret、access_toke

    2024年02月12日
    浏览(69)
  • 京东云接入【风险识别】接口

    京东云的接入文档写的真的跟逗你玩一样,就给提供了一个简单的实例,其他的全靠自己摸索。 这篇文章描述的是激动云【风险识别接口】接入,也会介绍如何接入其他的一些未在文章内描述到的接口。 这里使用的是python SDK,先安装 引用和实例 京东云的sdk就纯代码量来讲

    2024年02月11日
    浏览(31)
  • 优雅地处理参数传递:Spring Boot中的技巧

    目录 一:四种传参方式 1.1:在 URL 中传递参数 1.2:PathVariable 传递参数(Restful 风格) 1.3:在请求体中传递参数 1.4:在请求头中传递参数  二:文件上传接口测试  2.1 : test.java  三、@RequestParam 3.1 多个参数  3.2 单个参数  四、@PathVariable 4.1  单个参数  4.2  多个参数 五、@

    2024年02月05日
    浏览(54)
  • C#多线程精解:优雅终止线程的实用方法与技巧

      概述: 在C#多线程编程中,合理终止线程是关键挑战。通过标志位或CancellationToken,实现安全、协作式的线程终止,确保在适当时机终止线程而避免资源泄漏。 在C#多线程编程中,有时需要终止正在运行的线程,例如在用户取消操作、程序关闭等情况下。 线程终止通常涉及

    2024年02月19日
    浏览(38)
  • React请求机制优化思路 | 京东云技术团队

    说起数据加载的机制,有一个绕不开的话题就是前端性能,很多电商门户的首页其实都会做一些垂直的定制优化,比如让请求在页面最早加载,或者在前一个页面就进行预加载等等。随着react18的发布,请求机制这一块也是被不断谈起,并且在后续其实也给出了明确的方向。

    2024年02月12日
    浏览(42)
  • 简单看看就会的tomcat全家桶(部署-多实例-监控-远程上传-日志-优化等)

    1.配置JDK环境 2.部署tomcat 下载地址:https://dlcdn.apache.org/tomcat/tomcat-8/v8.5.87/bin/apache-tomcat-8.5.87.tar.gz 压缩二进制包 3.tomcat的常用命令 1.修改配置文件 2.开启目录浏览功能 3.创建目录 4.重启tomcat服务 5.查看效果 1.创建多实例 2.更改端口(避免端口冲突) 3.启动多实例 4.测试 打开浏

    2024年02月01日
    浏览(34)
  • LeetCode952三部曲之三:再次优化(122ms -> 96ms,超51% -> 超91%)

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本文是《LeetCode952三部曲之三》的终篇,先回顾一下前文的成果,看看我们之前已经优化到什么程度: 前文的优化思路是减小并查集数组的规模,带来的结果是节省内存、减少数组相关的执行次数,

    2024年02月10日
    浏览(38)
  • 京东API接口解析,实现获得JD商品评论

    要获取京东商品评论,需要使用京东的开放平台API接口。以下是一个基本的示例,解析并实现获取JD商品评论的API接口。 首先,你需要访问京东开放平台并注册一个开发者账号。注册完成后,你需要创建一个应用并获取到API的权限。 在获取到API权限后,你可以在开发者的控制

    2024年02月10日
    浏览(39)
  • Vue 使用技巧:优雅的进行二次封装 UI 库组件

    作为一个前端搬砖工程师经常需要搬砖,封装一些第三方组件,在添加新的属性、插槽、事件时候就会想应该怎么去保留,向外抛出封装原本第三方组件提供的属性、插槽、事件;但是如果是一个个属性和事件以及插槽进行重新声明定义,虽然也是可行的,但是未免也太过于

    2024年02月01日
    浏览(44)
  • LeetCode952三部曲之二:小幅度优化(137ms -> 122ms,超39% -> 超51%)

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本文是《LeetCode952三部曲》系列之二,在前文中,咱们详细分析了解题思路,然后按照思路写出了代码,在LeetCode提交成功,成绩如下图所示,137ms,超过39% 不得不说这个成绩很不理想,于是今天咱们

    2024年02月10日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包