聊聊接口優(yōu)化的幾種方法
往期熱門文章:
1、3 步完成 Spring Boot 的日志脫敏 2、線上MySQL的自增id用盡怎么辦?被面試官干趴下了! 3、求求你別再用 System.currentTimeMillis() 統(tǒng)計代碼耗時了,真的太 Low 了! 4、如何將 @Transactional 事務注解運用到爐火純青? 5、不知道怎么解耦業(yè)務?Spring Event 了解一下!
背景
哪些問題會引起接口性能問題?
數(shù)據(jù)庫慢查詢 深度分頁問題 未加索引 索引失效 join過多 子查詢過多 in中的值太多 單純的數(shù)據(jù)量過大 業(yè)務邏輯復雜 循環(huán)調(diào)用 順序調(diào)用 線程池設計不合理 鎖設計不合理 機器問題(fullGC,機器重啟,線程打滿)
問題解決
慢查詢(基于mysql)深度分頁
select name,code from student limit 100,20
select name,code from student limit 1000000,20
select name,code from student where id>1000000 limit 20
慢查詢未加索引
show create table xxxx(表名)
慢查詢索引失效

某個字段只可能有3個值,那這個字段的索引區(qū)分度就很低。 再比如,某個字段大量為空,只有少量有值; 再比如,某個字段值非常集中,90%都是1,剩下10%可能是2,3,4....
select name,code from student force index(XXXXXX) where name = '天才'
join過多 or 子查詢過多
in的元素過多
select id from student where id in (1,2,3 ...... 1000) limit 200
if (ids.size() > 200) {
throw new Exception("單次查詢數(shù)據(jù)量不能超過200");
}
單純的數(shù)據(jù)量過大
業(yè)務邏輯復雜
循環(huán)調(diào)用
List<Model> list = new ArrayList<>();
for(int i = 0 ; i < 12 ; i ++) {
Model model = calOneMonthData(i); // 計算某個月的數(shù)據(jù),邏輯比較復雜,難以批量計算,效率也無法很高
list.add(model);
}
// 建立一個線程池,注意要放在外面,不要每次執(zhí)行代碼就建立一個,具體線程池的使用就不展開了
public static ExecutorService commonThreadPool = new ThreadPoolExecutor(5, 5, 300L,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(10), commonThreadFactory, new ThreadPoolExecutor.DiscardPolicy());
// 開始多線程調(diào)用
List<Future<Model>> futures = new ArrayList<>();
for(int i = 0 ; i < 12 ; i ++) {
Future<Model> future = commonThreadPool.submit(() -> calOneMonthData(i););
futures.add(future);
}
// 獲取結果
List<Model> list = new ArrayList<>();
try {
for (int i = 0 ; i < futures.size() ; i ++) {
list.add(futures.get(i).get());
}
} catch (Exception e) {
LOGGER.error("出現(xiàn)錯誤:", e);
}
順序調(diào)用

A a = doA();
B b = doB();
C c = doC(a, b);
D d = doD(c);
E e = doE(c);
return doResult(d, e);
CompletableFuture<A> futureA = CompletableFuture.supplyAsync(() -> doA());
CompletableFuture<B> futureB = CompletableFuture.supplyAsync(() -> doB());
CompletableFuture.allOf(futureA,futureB) // 等a b 兩個任務都執(zhí)行完成
C c = doC(futureA.join(), futureB.join());
CompletableFuture<D> futureD = CompletableFuture.supplyAsync(() -> doD(c));
CompletableFuture<E> futureE = CompletableFuture.supplyAsync(() -> doE(c));
CompletableFuture.allOf(futureD,futureE) // 等d e兩個任務都執(zhí)行完成
return doResult(futureD.join(),futureE.join());
線程池設計不合理


創(chuàng)建非核心線程運行
核心線程設置過小:核心線程設置過小則沒有達到并行的效果 線程池公用,別的業(yè)務的任務執(zhí)行時間太長,占用了核心線程,另一個業(yè)務的任務到達就直接進入了等待隊列 任務太多,以至于占滿了線程池,大量任務在隊列中等待
鎖設計不合理
public synchronized void doSome() {
File f = calData();
uploadToS3(f);
sendSuccessMessage();
}
public void doSome() {
File f = null;
synchronized(this) {
f = calData();
}
uploadToS3(f);
sendSuccessMessage();
}
機器問題(fullGC,機器重啟,線程打滿)
萬金油解決方式
緩存
簡單的 mapguava等本地緩存工具包緩存中間件: redis、tair或memcached
memcached現(xiàn)在用的很少了,因為相比于redis他不占優(yōu)勢。tair則是阿里開發(fā)的一個分布式緩存中間件,他的優(yōu)勢是理論上可以在不停服的情況下,動態(tài)擴展存儲容量,適用于大數(shù)據(jù)量緩存存儲。相比于單機redis緩存當然有優(yōu)勢,而他與可擴展Redis集群的對比則需要進一步調(diào)研。回調(diào) or 反查

結語
往期熱門文章:
1、線上MySQL的自增id用盡怎么辦?被面試官干趴下了! 2、計算機專業(yè)會不會成為下一個土木? 3、xxl-job驚艷的設計,怎能叫人不愛 4、ArrayList#subList這四個坑,一不小心就中招 5、面試官:大量請求 Redis 不存在的數(shù)據(jù),從而影響數(shù)據(jù)庫,該如何解決? 6、MySQL 暴跌! 7、超越 Xshell!號稱下一代 Terminal 終端神器,用完愛不釋手! 8、IDEA 官宣全新默認 UI,太震撼了??! 9、讓你直呼「臥槽」的 GitHub 項目! 10、Kafka又笨又重,為啥不選Redis?
評論
圖片
表情
