一、API的性能优化方案
缓存@b@连接池@b@异步@b@N+1问题@b@分页@b@JSON序列化@b@压缩payload@b@精简log等
二、方案介绍
1)缓存 - 从缓存中读取,减少对数据库的访问,提升API性能。举个例子:假如访问 DB的耗时是 100ms,访问缓存的耗时是10ms,那么整个API的性能就提升 10倍 - 常用的缓存工具有 Redis 和 Google Guava cache(本地缓存)
2)连接池 - 数据库连接管理技术,可以避免频繁的创建和销毁数据库连接,提升API的性能。原因分析:服务器和数据库建立连接是基于 TCP协议,而TCP 需要3次握手,这个过程比较耗时,如果每次请求都需要创建一个连接,那么就会频繁的进行3次握手,从而影响 API的性能。
常用的池化工具有:JDBC,HikariCP,Druid,C3P0,DBCP,BoneCP等。
3) 异步 - 日常的业务开发中,通常包含核心链路和非核心链路。常用的异步方式有:线程池,消息队列,事件总线等。
4)“N+1 问题 - 是一个在数据库查询性能优化领域常见的概念 - 获取主表中的 N 条记录以及每条记录关联的另一个表中的相关信息时,会导致在获取相关信息时产生额外的查询操作,从而造成额外的负担和性能问题。
详细示例说明:假如有两张表,文章 “post”表 和文章评论”comment”表,现在要统计每篇文章的评论数,通常SQL语句写法如下(查询 1次 post表,假如 post中有 N条数据,这样就需要额外查询 N次 comment表,因此,产生了 N + 1次查询。)
sql复制代码SELECT id FROM post; // 1 @b@//for each post @b@SELECT count(*) FROM comment WHERE post_id = ? // N
解决”N+1 问题”的通常方法为:使用 JOIN 进行关联查询,如下SQL (数据冗余即空间换时间,比如:在 post表中,增加一个 comment_count字段,用于存储评论数,这样就可以避免 N+1问题,但是会造成数据冗余,增加了存储空间。)
sql复制代码@b@SELECT post.id, count(comment.id) FROM post LEFT JOIN comment ON post.id = comment.post_id GROUP BY post.id;
5)分页(Pagination) - 可以将大量的数据,分成多个页面进行展示,当数据量比较大时,通常会使用分页的方式进行查询,这样可以避免一次性查询大量的数据,造成内存溢出的问题。
6) JSON(JavaScript Object Notation)序列化 - 将数据结构或对象转换为JSON格式的字符串的过程,以便在网络传输、存储或与其他程序交互时进行数据交换。在各种编程语言中,可以使用库或内置函数来进行JSON序列化和反序列化操作。
7) 压缩 payload - 参数要尽量的少。因为参数越多,API的复杂度就越高,维护成本也就越高。比如:上传文件,通常会对文件进行压缩,以减少文件的大小,提升上传速度。
8)精简Log或者异步log - 增加 log来标记一些核心的流程,以及记录错误信息,方便排查问题。,log通常是磁盘操作,如果log过多,就会影响API的性能。因此,通常会对log进行精简,或者异步log。
日志缓冲区或队列:程序将要记录的日志信息放入缓冲区或队列中,然后可以继续执行其他任务。@b@日志写入线程:另一个线程负责从缓冲区或队列中获取日志数据,并将其写入实际的存储介质(如磁盘)中。这个过程是异步的,不会阻塞主程序的执行。@b@同步机制:由于异步操作涉及多线程,可能需要适当的同步机制来确保线程之间的安全性,避免竞态条件等问题。
异步日志(Asynchronous Logging)是一种在计算机程序中进行日志记录的技术。与传统的同步日志记录不同,异步日志记录允许程序在记录日志时不必等待日志写入磁盘或其他存储介质完成,而是将日志数据放入队列或缓冲区中,然后由另一个线程或进程负责将日志异步地写入存储介质。异步日志的优点可以减少主程序的延迟和性能损失的同时,提升性能。
另外,在API的开发中我们通常需要关注三个最常见的问题:
性能@b@安全性@b@健壮性