Google Guava缓存实现接口的限流
一.項(xiàng)目背景
最近項(xiàng)目中需要進(jìn)行接口保護(hù),防止高并發(fā)的情況把系統(tǒng)搞崩,因此需要對(duì)一個(gè)查詢接口進(jìn)行限流,主要的目的就是限制單位時(shí)間內(nèi)請(qǐng)求此查詢的次數(shù),例如1000次,來(lái)保護(hù)接口。
參考了 開(kāi)濤的博客聊聊高并發(fā)系統(tǒng)限流特技 ,學(xué)習(xí)了其中利用Google Guava緩存實(shí)現(xiàn)限流的技巧,在網(wǎng)上也查到了很多關(guān)于Google Guava緩存的博客,學(xué)到了好多,推薦一個(gè)博客文章:http://ifeve.com/google-guava-cachesexplained/,關(guān)于Google Guava緩存的更多細(xì)節(jié)或者技術(shù),這篇文章講的很詳細(xì);
這里我們并不是用緩存來(lái)優(yōu)化查詢,而是利用緩存,存儲(chǔ)一個(gè)計(jì)數(shù)器,然后用這個(gè)計(jì)數(shù)器來(lái)實(shí)現(xiàn)限流。
二.效果實(shí)驗(yàn)
static LoadingCache<Long, AtomicLong> count = CacheBuilder.newBuilder().expireAfterWrite(2, TimeUnit.SECONDS).build(new CacheLoader<Long, AtomicLong>() {@Overridepublic AtomicLong load(Long o) throws Exception {//System.out.println("Load call!");return new AtomicLong(0L);}});上面,我們通過(guò)CacheBuilder來(lái)新建一個(gè)LoadingCache緩存對(duì)象count,然后設(shè)置其有效時(shí)間為兩秒,即每?jī)擅腌娝⑿乱淮?#xff1b;緩存中,key為一個(gè)long型的時(shí)間戳類型,value是一個(gè)計(jì)數(shù)器,使用原子性的AtomicLong保證自增和自減操作的原子性, 每次查詢緩存時(shí)如果不能命中,即查詢的時(shí)間戳不在緩存中,則重新加載緩存,執(zhí)行l(wèi)oad將當(dāng)前的時(shí)間戳的計(jì)數(shù)值初始化為0。這樣對(duì)于每一秒的時(shí)間戳,能計(jì)算這一秒內(nèi)執(zhí)行的次數(shù),從而達(dá)到限流的目的;
這是要執(zhí)行的一個(gè)getCounter方法:
現(xiàn)在我們創(chuàng)建多個(gè)線程來(lái)執(zhí)行這個(gè)方法:
ublic class Test {public static void main(String args[]) throws Exception{for(int i = 0;i<100;i++){new Thread(){@Overridepublic void run() {try {System.out.println(Counter.getCounter());}catch (Exception e){e.printStackTrace();}}}.start();}} }這樣執(zhí)行的話,執(zhí)行結(jié)果很簡(jiǎn)單,就是很快地執(zhí)行這個(gè)for循環(huán),迅速打印0到99折100個(gè)數(shù),不再貼出。
這里的for循環(huán)執(zhí)行100個(gè)進(jìn)程時(shí)間是很快的,那么現(xiàn)在我們要限制每秒只能有10個(gè)線程來(lái)執(zhí)行g(shù)etCounter()方法,該怎么辦呢,上面講的限流方法就派上用場(chǎng)了:
這樣一來(lái),就可以限制每秒的執(zhí)行數(shù)了。對(duì)于每個(gè)線程,獲取當(dāng)前時(shí)間戳,如果當(dāng)前時(shí)間(當(dāng)前這1秒)內(nèi)有超過(guò)10個(gè)線程正在執(zhí)行,那么這個(gè)進(jìn)程一直在這里循環(huán),直到下一秒,或者更靠后的時(shí)間,重新加載,執(zhí)行l(wèi)oad,將新的時(shí)間戳的計(jì)數(shù)值重新為0。
執(zhí)行結(jié)果:
每秒執(zhí)行11個(gè)(因?yàn)閺?開(kāi)始),每一秒之后,load方法會(huì)執(zhí)行一次;
在上述這樣的情況下,一個(gè)線程如果遇到當(dāng)前時(shí)間正在執(zhí)行的線程超過(guò)limit值就會(huì)一直在while循環(huán),這樣會(huì)浪費(fèi)大量的資源,我們?cè)谧鱿蘖鞯臅r(shí)候,如果出現(xiàn)這種情況,可以不進(jìn)行while循環(huán),而是直接拋出異常或者返回,來(lái)拒絕這次執(zhí)行(查詢),這樣便可以節(jié)省資源。
轉(zhuǎn)載于:https://www.cnblogs.com/sunp823/p/5601395.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的Google Guava缓存实现接口的限流的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 选课平台需求分析
- 下一篇: 在VMware开启此虚拟机时出现内部错误