
API貨幣化的最佳實(shí)踐:定價(jià)、打包和計(jì)費(fèi)
這個(gè)命令將顯示查詢的執(zhí)行計(jì)劃,包括使用了哪些索引。
如果索引生效,你會在輸出結(jié)果中看到相關(guān)的信息。
通過這幾列可以判斷索引使用情況,執(zhí)行計(jì)劃包含列的含義如下圖所示:
說實(shí)話,SQL語句沒有使用索引,除去沒有建索引的情況外,最大的可能性是索引失效了。
以下是索引失效的常見原因:
了解這些原因,可以幫助你在查詢優(yōu)化時(shí)避免索引失效的問題,確保數(shù)據(jù)庫查詢性能保持最佳。
此外,你是否遇到過這樣一種情況:明明是同一條SQL語句,只是入?yún)⒉煌?/p>
有時(shí)候使用的是索引A,有時(shí)候卻使用索引B?
沒錯(cuò),有時(shí)候MySQL會選錯(cuò)索引。
必要時(shí)可以使用 FORCE INDEX 來強(qiáng)制查詢SQL使用某個(gè)索引。
例如:SELECT * FROM
order
FORCE INDEX (index_name) WHERE code='002';
至于為什么MySQL會選錯(cuò)索引,原因可能有以下幾點(diǎn):
了解這些原因,可以幫助你更好地理解和控制MySQL的索引選擇行為,確保查詢性能的穩(wěn)定性。
插播一條:如果你近期準(zhǔn)備面試跳槽,建議在cxykk.com在線刷題,涵蓋 1萬+ 道 Java 面試題,幾乎覆蓋了所有主流技術(shù)面試題、簡歷模板、算法刷題。
如果優(yōu)化了索引之后效果不明顯,接下來可以嘗試優(yōu)化一下SQL語句,因?yàn)橄鄬τ谛薷腏ava代碼來說,改造SQL語句的成本要小得多。
以下是SQL優(yōu)化的15個(gè)小技巧:
多時(shí)候,我們需要在一個(gè)接口中調(diào)用其他服務(wù)的接口。
例如,有這樣的業(yè)務(wù)場景:
在用戶信息查詢接口中需要返回以下信息:用戶名稱、性別、等級、頭像、積分和成長值。
其中,用戶名稱、性別、等級和頭像存儲在用戶服務(wù)中,積分存儲在積分服務(wù)中,成長值存儲在成長值服務(wù)中。為了將這些數(shù)據(jù)統(tǒng)一返回,我們需要提供一個(gè)額外的對外接口服務(wù)。
因此,用戶信息查詢接口需要調(diào)用用戶查詢接口、積分查詢接口和成長值查詢接口,然后將數(shù)據(jù)匯總并統(tǒng)一返回。
調(diào)用過程如下圖所示:
調(diào)用遠(yuǎn)程接口總耗時(shí) 530ms = 200ms + 150ms + 180ms
顯然這種串行調(diào)用遠(yuǎn)程接口性能是非常不好的,調(diào)用遠(yuǎn)程接口總的耗時(shí)為所有的遠(yuǎn)程接口耗時(shí)之和。
那么如何優(yōu)化遠(yuǎn)程接口性能呢?
上面說到,既然串行調(diào)用多個(gè)遠(yuǎn)程接口性能很差,為什么不改成并行呢?
如下圖所示:
調(diào)用遠(yuǎn)程接口的總耗時(shí)為200ms,這等于耗時(shí)最長的那次遠(yuǎn)程接口調(diào)用時(shí)間。
在Java 8之前,可以通過實(shí)現(xiàn)Callable接口來獲取線程的返回結(jié)果。
在Java 8之后,可以通過CompletableFuture類來實(shí)現(xiàn)這一功能。
以下是一個(gè)使用CompletableFuture的示例:
public?class?RemoteServiceExample?{
????public?static?void?main(String[]?args)?throws?ExecutionException,?InterruptedException?{
????????//?調(diào)用用戶服務(wù)接口
????????CompletableFuture<String>?userFuture?=?CompletableFuture.supplyAsync(()?->?{
????????????//?模擬遠(yuǎn)程調(diào)用
????????????simulateDelay(200);
????????????return?"User?Info";
????????});
????????//?調(diào)用積分服務(wù)接口
????????CompletableFuture<String>?pointsFuture?=?CompletableFuture.supplyAsync(()?->?{
????????????//?模擬遠(yuǎn)程調(diào)用
????????????simulateDelay(150);
????????????return?"Points?Info";
????????});
????????//?調(diào)用成長值服務(wù)接口
????????CompletableFuture<String>?growthFuture?=?CompletableFuture.supplyAsync(()?->?{
????????????//?模擬遠(yuǎn)程調(diào)用
????????????simulateDelay(100);
????????????return?"Growth?Info";
????????});
????????//?匯總結(jié)果
????????CompletableFuture<Void>?allOf?=?CompletableFuture.allOf(userFuture,?pointsFuture,?growthFuture);
????????//?等待所有異步操作完成
????????allOf.join();
????????//?獲取結(jié)果
????????String?userInfo?=?userFuture.get();
????????String?pointsInfo?=?pointsFuture.get();
????????String?growthInfo?=?growthFuture.get();
????}
}
為了提升接口性能,尤其在高并發(fā)場景下,可以考慮數(shù)據(jù)冗余,將用戶信息、積分和成長值的數(shù)據(jù)統(tǒng)一存儲在一個(gè)地方,比如Redis。
這樣,通過用戶ID可以直接從Redis中查詢所需的數(shù)據(jù),從而避免遠(yuǎn)程接口調(diào)用
但需要注意的是,如果使用了數(shù)據(jù)異構(gòu)方案,就可能會出現(xiàn)數(shù)據(jù)一致性問題。
用戶信息、積分和成長值有更新的話,大部分情況下,會先更新到數(shù)據(jù)庫,然后同步到redis。
但這種跨庫的操作,可能會導(dǎo)致兩邊數(shù)據(jù)不一致的情況產(chǎn)生。
那如何解決數(shù)據(jù)一致性問題呢?
由于篇幅有限,本文就不展開詳細(xì)說這塊了,感興趣的同學(xué)可以看我的另一篇文章《億級電商流量,高并發(fā)下Redis與MySQL的數(shù)據(jù)一致性如何保證》
在我們的日常工作代碼中,重復(fù)調(diào)用非常常見,但如果沒有控制好,會嚴(yán)重影響接口的性能。
讓我們一起來看看這個(gè)問題。
4.1 循環(huán)查數(shù)據(jù)庫 有時(shí)候,我們需要從指定的用戶集合中查詢出哪些用戶已經(jīng)存在于數(shù)據(jù)庫中。
一種實(shí)現(xiàn)方式如下:
public?List<User>?findExistingUsers(List<String>?userIds)?{
????List<User>?existingUsers?=?new?ArrayList<>();
????for?(String?userId?:?userIds)?{
????????User?user?=?userRepository.findById(userId);
????????if?(user?!=?null)?{
????????????existingUsers.add(user);
????????}
????}
????return?existingUsers;
}
上述代碼會對每個(gè)用戶ID執(zhí)行一次數(shù)據(jù)庫查詢,這在用戶集合較大時(shí)會導(dǎo)致性能問題。
那么,我們?nèi)绾蝺?yōu)化呢?
我們可以通過批量查詢來優(yōu)化性能,減少數(shù)據(jù)庫的查詢次數(shù)。public?List<User>?findExistingUsers(List<String>?userIds)?{
????//?批量查詢數(shù)據(jù)庫
????List<User>?users?=?userRepository.findByIds(userIds);
????return?users;
}
這里有個(gè)需要注意的地方是:id集合的大小要做限制,最好一次不要請求太多的數(shù)據(jù)。要根據(jù)實(shí)際情況而定,建議控制每次請求的記錄條數(shù)在500以內(nèi)。
在進(jìn)行接口性能優(yōu)化時(shí),有時(shí)候需要重新梳理業(yè)務(wù)邏輯,檢查是否存在設(shè)計(jì)不合理的地方。
假設(shè)有一個(gè)用戶請求接口,需要執(zhí)行以下操作:
這個(gè)接口表面上看起來沒有問題,但如果你仔細(xì)梳理一下業(yè)務(wù)邏輯,會發(fā)現(xiàn)只有業(yè)務(wù)操作才是核心邏輯,其他的功能都是非核心邏輯。
在這里有個(gè)原則就是:
核心邏輯可以同步執(zhí)行,同步寫庫。非核心邏輯,可以異步執(zhí)行,異步寫庫。
上面這個(gè)例子中,發(fā)站內(nèi)通知和用戶操作日志功能,對實(shí)時(shí)性要求不高,即使晚點(diǎn)寫庫,用戶無非是晚點(diǎn)收到站內(nèi)通知,或者運(yùn)營晚點(diǎn)看到用戶操作日志,對業(yè)務(wù)影響不大,所以完全可以異步處理。
異步處理方案
異步處理通常有兩種主要方式:多線程和消息隊(duì)列(MQ)
使用線程池改造之后,接口邏輯如下
使用線程池有個(gè)小問題就是:如果服務(wù)器重啟了,或者是需要被執(zhí)行的功能出現(xiàn)異常了,無法重試,會丟數(shù)據(jù)。
為了避免使用線程池處理異步任務(wù)時(shí)出現(xiàn)數(shù)據(jù)丟失的問題,可以考慮使用更加健壯和可靠的異步處理方案,如消息隊(duì)列(MQ)。消息隊(duì)列不僅可以異步處理任務(wù),還能夠保證消息的持久化和可靠性,支持重試機(jī)制。
使用mq改造之后,接口邏輯如下:
插播一條:如果你近期準(zhǔn)備面試跳槽,建議在cxykk.com在線刷題,涵蓋 1萬+ 道 Java 面試題,幾乎覆蓋了所有主流技術(shù)面試題、簡歷模板、算法刷題。
很多小伙伴在使用Spring框架開發(fā)項(xiàng)目時(shí),為了方便,喜歡使用@Transactional注解提供事務(wù)功能。
沒錯(cuò),使用@Transactional注解這種聲明式事務(wù)的方式提供事務(wù)功能,確實(shí)能少寫很多代碼,提升開發(fā)效率。
但也容易造成大事務(wù),引發(fā)性能的問題。
那么我們該如何優(yōu)化大事務(wù)呢?
為了避免大事務(wù)引發(fā)的問題,可以考慮以下優(yōu)化建議:
在一些業(yè)務(wù)場景中,為了避免多個(gè)線程并發(fā)修改同一共享數(shù)據(jù)而引發(fā)數(shù)據(jù)異常,通常我們會使用加鎖的方式來解決這個(gè)問題。
然而,如果鎖的設(shè)計(jì)不當(dāng),導(dǎo)致鎖的粒度過粗,也會對接口性能產(chǎn)生顯著的負(fù)面影響。
在Java中,我們可以使用synchronized關(guān)鍵字來為代碼加鎖。
通常有兩種寫法:在方法上加鎖和在代碼塊上加鎖。
1. 方法上加鎖
public?synchronized?void?doSave(String?fileUrl)?{
????mkdir();
????uploadFile(fileUrl);
????sendMessage(fileUrl);
}
在方法上加鎖的目的是為了防止并發(fā)情況下創(chuàng)建相同的目錄,避免第二次創(chuàng)建失敗而影響業(yè)務(wù)功能。
但這種直接在方法上加鎖的方式,鎖的粒度較粗。
因?yàn)閐oSave方法中的文件上傳和消息發(fā)送并不需要加鎖,只有創(chuàng)建目錄的方法需要加鎖。
我們知道,文件上傳操作非常耗時(shí),如果將整個(gè)方法加鎖,那么需要等到整個(gè)方法執(zhí)行完之后才能釋放鎖。
顯然,這會導(dǎo)致該方法的性能下降,得不償失。
2. 代碼塊上加鎖我們可以將加鎖改在代碼塊上,從而縮小鎖的粒度, 如下:
public?void?doSave(String?path,?String?fileUrl)?{
????synchronized(this)?{
????????if?(!exists(path))?{
????????????mkdir(path);
????????}
????}
????uploadFile(fileUrl);
????sendMessage(fileUrl);
}
這樣改造后,鎖的粒度變小了,只有并發(fā)創(chuàng)建目錄時(shí)才加鎖。
創(chuàng)建目錄是一個(gè)非常快的操作,即使加鎖對接口性能的影響也不大。
最重要的是,其他的文件上傳和消息發(fā)送功能仍然可以并發(fā)執(zhí)行。
多節(jié)點(diǎn)環(huán)境中的問題 在單機(jī)版服務(wù)中,這種做法沒有問題。但在生產(chǎn)環(huán)境中,為了保證服務(wù)的穩(wěn)定性,同一個(gè)服務(wù)通常會部署在多個(gè)節(jié)點(diǎn)上。如果某個(gè)節(jié)點(diǎn)掛掉,其他節(jié)點(diǎn)的服務(wù)仍然可用。
多節(jié)點(diǎn)部署避免了某個(gè)節(jié)點(diǎn)掛掉導(dǎo)致服務(wù)不可用的情況,同時(shí)也能分?jǐn)傉麄€(gè)系統(tǒng)的流量,避免系統(tǒng)壓力過大。
但這種部署方式也帶來了新的問題:synchronized只能保證一個(gè)節(jié)點(diǎn)加鎖有效。
如果有多個(gè)節(jié)點(diǎn),如何加鎖呢?
在分布式系統(tǒng)中,由于Redis分布式鎖的實(shí)現(xiàn)相對簡單且高效,因此它在許多實(shí)際業(yè)務(wù)場景中被廣泛采用。
使用Redis分布式鎖的偽代碼如下:
public?boolean?doSave(String?path,?String?fileUrl)?{
????try?{
????????String?result?=?jedis.set(lockKey,?requestId,?"NX",?"PX",?expireTime);
????????if?("OK".equals(result))?{
????????????if?(!exists(path))?{
????????????????mkdir(path);
????????????????uploadFile(fileUrl);
????????????????sendMessage(fileUrl);
????????????}
????????????return?true;
????????}
????}?finally?{
????????unlock(lockKey,?requestId);
????}
????return?false;
}
與之前使用synchronized關(guān)鍵字加鎖時(shí)一樣,這里的鎖的范圍也太大了,換句話說,鎖的粒度太粗。這會導(dǎo)致整個(gè)方法的執(zhí)行效率很低。
實(shí)際上,只有在創(chuàng)建目錄時(shí)才需要加分布式鎖,其余代碼不需要加鎖。
于是,我們需要優(yōu)化代碼:
public?void?doSave(String?path,?String?fileUrl)?{
????if?(tryLock())?{
????????try?{
????????????if?(!exists(path))?{
????????????????mkdir(path);
????????????}
????????}?finally?{
????????????unlock(lockKey,?requestId);
????????}
????}
????uploadFile(fileUrl);
????sendMessage(fileUrl);
}
private?boolean?tryLock()?{
????String?result?=?jedis.set(lockKey,?requestId,?"NX",?"PX",?expireTime);
????return?"OK".equals(result);
}
private?void?unlock(String?lockKey,?String?requestId)?{
????//?解鎖邏輯
}
上面的代碼將加鎖的范圍縮小了,只有在創(chuàng)建目錄時(shí)才加鎖。這樣的簡單優(yōu)化后,接口性能可以得到顯著提升。
并發(fā)度越高,接口性能越好。因此,數(shù)據(jù)庫鎖的優(yōu)化方向是:
插播一條:如果你近期準(zhǔn)備面試跳槽,建議在cxykk.com在線刷題,涵蓋 1萬+ 道 Java 面試題,幾乎覆蓋了所有主流技術(shù)面試題、簡歷模板、算法刷題。
有時(shí)候,我需要調(diào)用某個(gè)接口來批量查詢數(shù)據(jù),例如,通過用戶ID批量查詢用戶信息,然后為這些用戶贈送積分。
但是,如果一次性查詢的用戶數(shù)量太多,例如一次查詢2000個(gè)用戶的數(shù)據(jù),傳入2000個(gè)用戶的ID進(jìn)行遠(yuǎn)程調(diào)用時(shí),用戶查詢接口經(jīng)常會出現(xiàn)超時(shí)的情況。
調(diào)用代碼如下:List<User> users = remoteCallUser(ids);
眾所周知,調(diào)用接口從數(shù)據(jù)庫獲取數(shù)據(jù)需要經(jīng)過網(wǎng)絡(luò)傳輸。如果數(shù)據(jù)量過大,無論是數(shù)據(jù)獲取速度還是網(wǎng)絡(luò)傳輸速度都會受到帶寬限制,從而導(dǎo)致耗時(shí)較長。
那么,這種情況下該如何優(yōu)化呢?
答案是:分頁處理。
將一次性獲取所有數(shù)據(jù)的請求,改為分多次獲取,每次只獲取一部分用戶的數(shù)據(jù),最后進(jìn)行合并和匯總。
其實(shí),處理這個(gè)問題可以分為兩種場景:同步調(diào)用和異步調(diào)用。
如果在job中需要獲取2000個(gè)用戶的信息,它要求只要能正確獲取到數(shù)據(jù)即可,對獲取數(shù)據(jù)的總耗時(shí)要求不高。
但對每一次遠(yuǎn)程接口調(diào)用的耗時(shí)有要求,不能大于500ms,否則會有郵件預(yù)警。
這時(shí),我們可以同步分頁調(diào)用批量查詢用戶信息接口。
具體示例代碼如下:
List<List<Long>>?allIds?=?Lists.partition(ids,?200);
for?(List<Long>?batchIds?:?allIds)?{
????List<User>?users?=?remoteCallUser(batchIds);
}
代碼中我使用了Google Guava工具中的Lists.partition方法,用它來做分頁簡直太好用了,不然要寫一大堆分頁的代碼。 8.2 異步調(diào)用 如果是在某個(gè)接口中需要獲取2000個(gè)用戶的信息,需要考慮的因素更多。
除了遠(yuǎn)程調(diào)用接口的耗時(shí),還需要考慮該接口本身的總耗時(shí),也不能超過500ms。
這時(shí),使用上面的同步分頁請求遠(yuǎn)程接口的方法肯定是行不通的。
那么,只能使用異步調(diào)用了。
代碼如下:
List<List<Long>>?allIds?=?Lists.partition(ids,?200);
final?List<User>?result?=?Lists.newArrayList();
allIds.stream().forEach(batchIds?->?{
????CompletableFuture.supplyAsync(()?->?{
????????result.addAll(remoteCallUser(batchIds));
????????return?Boolean.TRUE;
????},?executor);
});
使用CompletableFuture類,通過多個(gè)線程異步調(diào)用遠(yuǎn)程接口,最后匯總結(jié)果統(tǒng)一返回。
通常情況下,我們最常用的緩存是:Redis和Memcached。
但對于Java應(yīng)用來說,絕大多數(shù)情況下使用的是Redis,所以接下來我們以Redis為例。
在關(guān)系型數(shù)據(jù)庫(例如:MySQL)中,菜單通常有上下級關(guān)系。某個(gè)四級分類是某個(gè)三級分類的子分類,三級分類是某個(gè)二級分類的子分類,而二級分類又是某個(gè)一級分類的子分類。
這種存儲結(jié)構(gòu)決定了,想一次性查出整個(gè)分類樹并非易事。這需要使用程序遞歸查詢,而如果分類很多,這個(gè)遞歸操作會非常耗時(shí)。
因此,如果每次都直接從數(shù)據(jù)庫中查詢分類樹的數(shù)據(jù),會是一個(gè)非常耗時(shí)的操作。
這時(shí)我們可以使用緩存。在大多數(shù)情況下,接口直接從緩存中獲取數(shù)據(jù)。操作Redis可以使用成熟的框架,比如:Jedis和Redisson等。 使用Jedis的偽代碼如下:
String?json?=?jedis.get(key);
if?(StringUtils.isNotEmpty(json))?{
????CategoryTree?categoryTree?=?JsonUtil.toObject(json);
????return?categoryTree;
}
return?queryCategoryTreeFromDb();
注意引入緩存之后,我們的系統(tǒng)復(fù)雜度就上升了,這時(shí)候就會存在數(shù)據(jù)不一致的問題
如何解決數(shù)據(jù)不一致的問題,感興趣的小伙伴可以看我的另一篇文章,《億級電商流量,高并發(fā)下Redis與MySQL的數(shù)據(jù)一致性如何保證》
有時(shí)候,接口性能受限的并不是其他方面,而是數(shù)據(jù)庫。
當(dāng)系統(tǒng)發(fā)展到一定階段,用戶并發(fā)量增加,會有大量的數(shù)據(jù)庫請求,這不僅需要占用大量的數(shù)據(jù)庫連接,還會帶來磁盤IO的性能瓶頸問題。
此外,隨著用戶數(shù)量的不斷增加,產(chǎn)生的數(shù)據(jù)量也越來越大,一張表可能無法存儲所有數(shù)據(jù)。由于數(shù)據(jù)量太大,即使SQL語句使用了索引,查詢數(shù)據(jù)時(shí)也會非常耗時(shí)。
那么,這種情況下該怎么辦呢?
答案是:需要進(jìn)行分庫分表。
如下圖所示:
圖中將用戶庫拆分成了三個(gè)庫,每個(gè)庫都包含了四張用戶表。
如果有用戶請求過來,先根據(jù)用戶ID路由到其中一個(gè)用戶庫,然后再定位到某張表。
路由的算法有很多:
7%4=3
,模為3,路由到用戶表3。1. 垂直分庫分表
垂直分庫分表(即業(yè)務(wù)方向)更簡單,將不同的業(yè)務(wù)數(shù)據(jù)存儲在不同的庫或表中。
例如,將用戶數(shù)據(jù)和訂單數(shù)據(jù)存儲在不同的庫中。
2. 水平分庫分表
水平分庫分表(即數(shù)據(jù)方向)上,分庫和分表的作用有區(qū)別,不能混為一談。
優(yōu)化接口性能問題,除了上面提到的這些常用方法之外,還需要配合使用一些輔助功能,因?yàn)樗鼈冋娴目梢詭臀覀兲嵘檎覇栴}的效率。
通常情況下,為了定位SQL的性能瓶頸,我們需要開啟MySQL的慢查詢?nèi)罩尽0殉^指定時(shí)間的SQL語句單獨(dú)記錄下來,方便以后分析和定位問題。
開啟慢查詢?nèi)罩拘枰攸c(diǎn)關(guān)注三個(gè)參數(shù):
通過MySQL的SET
命令可以設(shè)置:
SET?GLOBAL?slow_query_log?=?'ON';
SET?GLOBAL?slow_query_log_file?=?'/usr/local/mysql/data/slow.log';
SET?GLOBAL?long_query_time?=?2;
設(shè)置完之后,如果某條SQL的執(zhí)行時(shí)間超過了2秒,會被自動記錄到slow.log文件中。
當(dāng)然,也可以直接修改配置文件my.cnf:
[mysqld]
slow_query_log = ON
slow_query_log_file = /usr/local/mysql/data/slow.log
long_query_time = 2
但這種方式需要重啟MySQL服務(wù)。
很多公司每天早上都會發(fā)一封慢查詢?nèi)罩镜泥]件,開發(fā)人員根據(jù)這些信息優(yōu)化SQL。
為了在出現(xiàn)SQL問題時(shí)能夠及時(shí)發(fā)現(xiàn),我們需要對系統(tǒng)做監(jiān)控。
目前業(yè)界使用比較多的開源監(jiān)控系統(tǒng)是:Prometheus。
它提供了監(jiān)控和預(yù)警的功能。
架構(gòu)圖如下:
我們可以用它監(jiān)控如下信息:
它的界面大概長這樣子:
可以看到MySQL的當(dāng)前QPS、活躍線程數(shù)、連接數(shù)、緩存池的大小等信息。
如果發(fā)現(xiàn)連接池占用的數(shù)據(jù)量太多,肯定會對接口性能造成影響。
這時(shí)可能是由于代碼中開啟了連接卻忘記關(guān)閉,或者并發(fā)量太大導(dǎo)致的,需要進(jìn)一步排查和系統(tǒng)優(yōu)化
有時(shí)候,一個(gè)接口涉及的邏輯非常復(fù)雜,例如查詢數(shù)據(jù)庫、查詢Redis、遠(yuǎn)程調(diào)用接口、發(fā)送MQ消息以及執(zhí)行業(yè)務(wù)代碼等等。
這種情況下,接口的一次請求會涉及到非常長的調(diào)用鏈路。如果逐一排查這些問題,會耗費(fèi)大量時(shí)間,此時(shí)我們已經(jīng)無法用傳統(tǒng)的方法來定位問題。
有沒有辦法解決這個(gè)問題呢?
答案是使用分布式鏈路跟蹤系統(tǒng):SkyWalking。
SkyWalking的架構(gòu)圖如下:
在SkyWalking中,可以通過traceId(全局唯一的ID)來串聯(lián)一個(gè)接口請求的完整鏈路。你可以看到整個(gè)接口的耗時(shí)、調(diào)用的遠(yuǎn)程服務(wù)的耗時(shí)、訪問數(shù)據(jù)庫或者Redis的耗時(shí)等,功能非常強(qiáng)大。
之前沒有這個(gè)功能時(shí),為了定位線上接口性能問題,我們需要在代碼中加日志,手動打印出鏈路中各個(gè)環(huán)節(jié)的耗時(shí)情況,然后再逐一排查。這種方法不僅費(fèi)時(shí)費(fèi)力,而且容易遺漏細(xì)節(jié)。
如果你用過SkyWalking來排查接口性能問題,你會不自覺地愛上它的功能。如果你想了解更多功能,可以訪問SkyWalking的官網(wǎng):skywalking.apache.org。
認(rèn)真看到這里的同學(xué),相信已經(jīng)對API接口性能優(yōu)化有一個(gè)清晰的、系統(tǒng)的認(rèn)知了,如果在面試中能夠完整的說出這11種API接口性能優(yōu)化的思路,相信面試官一定會對你刮目相看的。
文章轉(zhuǎn)自 微信公眾號@程序員江小北
API貨幣化的最佳實(shí)踐:定價(jià)、打包和計(jì)費(fèi)
應(yīng)用程序開發(fā)中不可或缺的開放API
開發(fā)者生產(chǎn)力提升的API終極指南
制定藍(lán)圖:什么樣的API策略能夠確保未來的成功?
詳解API:應(yīng)用程序編程接口終極指南
精通API規(guī)范:構(gòu)建明確指導(dǎo)和預(yù)期的指南
API 優(yōu)先方法如何徹底改變軟件開發(fā)
掌握良好的 API 設(shè)計(jì)原則:是什么、為什么和怎么辦
API-first產(chǎn)品經(jīng)理的熱門 API 工具和 API 指標(biāo)