目前在做限流相關(guān)的需求课竣,有這么一個限流策略童太,和用戶相關(guān),當系統(tǒng)發(fā)生故障時栓始,允許一個非核心接口按照用戶的百分比進行限流务冕,如果完全按照UUID進行hash,那么每次都是限制同一批的用戶幻赚,如果在UUID的基礎(chǔ)上加上當天的日期禀忆,那么就可以有效的避免這個問題。
所以在這個需求中落恼,每次請求都需要拿到當前的日期箩退,不過精確到天即可。
嗖~的一下佳谦,完成了如下代碼
Calendar calendar = Calendar.getInstance();
String time = "" + calendar.get(Calendar.YEAR) + calendar.get(Calendar.MONTH) +calendar.get(Calendar.DAY_OF_MONTH);
很簡單是不是戴涝,不過寫完之后,很快就被業(yè)務(wù)同學(xué)diss了,Calendar性能太差了啥刻,在QPS很高的情況下奸鸯,會使接口的999線劣化。
QPS高的業(yè)務(wù)真是惹不起... (丟)
為什么Calendar不行郑什,因為每次請求都要創(chuàng)建一個Calendar實例府喳,這個創(chuàng)建過程比較的耗時(qps低的時候可以忽略這種消耗),但是做基礎(chǔ)組件的蘑拯,應(yīng)該考慮各種場景。
因為只需要獲取到與天相關(guān)數(shù)據(jù)兜粘,所以想到了另一個簡單的解決方案
private static final int DAY_MILLIS = 24 * 60 * 60 * 1000;
long day = System.currentTimeMillis() / DAY_MILLIS;
通過當前的時間戳(毫秒級別)申窘,除以一天的毫秒數(shù),得到的結(jié)果就是從1970 到今天經(jīng)歷過的天數(shù)孔轴,這完全符合當前的需求剃法。
這個解決方案,只是恰好可以滿足這種需求路鹰,對于其它更復(fù)雜一點的需求贷洲,我這里推薦使用Joda Time
組件。
下面通過Openjdk的JMH類庫晋柱,對上述三種情況進行性能基準測試优构,還沒有接觸過JMH的同學(xué),可以在官網(wǎng)上進行學(xué)習(xí)雁竞,傳送門
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
public class Main {
static int millis = 24 * 3600 * 1000;
public static void main(String[] args) throws Exception {
Options options = new OptionsBuilder().include(Main.class.getName()).forks(1).build();
new Runner(options).run();
}
@Benchmark
@Threads(5)
public void runCalendar() {
Calendar calendar = Calendar.getInstance();
}
@Benchmark
@Threads(5)
public void runJoda() {
DateTime dateTime = new DateTime();
}
//
@Benchmark
@Threads(5)
public void runSystem() {
long result = System.currentTimeMillis() / millis;
}
}
使用benchmark之前钦椭,需要引入相關(guān)依賴
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.21</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.21</version>
<scope>provided</scope>
</dependency>
最終結(jié)果如下
這里只是測試了Calendar和Joda對象的創(chuàng)建耗時,可以發(fā)現(xiàn)Joda的性能比Calendar整整高了10倍碑诉,真的不可忽略彪腔。