目前在作限流相關的需求,有這麼一個限流策略,和用戶相關,當系統發生故障時,容許一個非核心接口按照用戶的百分比進行限流,若是徹底按照UUID進行hash,那麼每次都是限制同一批的用戶,若是在UUID的基礎上加上當天的日期,那麼就能夠有效的避免這個問題。java
因此在這個需求中,每次請求都須要拿到當前的日期,不過精確到天便可。 嗖~的一下,完成了以下代碼bash
Calendar calendar = Calendar.getInstance();
String time = "" + calendar.get(Calendar.YEAR) + calendar.get(Calendar.MONTH) +calendar.get(Calendar.DAY_OF_MONTH);
複製代碼
很簡單是否是,不過寫完以後,很快就被業務同窗diss了,Calendar性能太差了,在QPS很高的狀況下,會使接口的999線劣化。ide
QPS高的業務真是惹不起... (丟)性能
爲何Calendar不行,由於每次請求都要建立一個Calendar實例,這個建立過程比較的耗時(qps低的時候能夠忽略這種消耗),可是作基礎組件的,應該考慮各類場景。學習
由於只須要獲取到與天相關數據,因此想到了另外一個簡單的解決方案測試
private static final int DAY_MILLIS = 24 * 60 * 60 * 1000;
long day = System.currentTimeMillis() / DAY_MILLIS;
複製代碼
經過當前的時間戳(毫秒級別),除以一天的毫秒數,獲得的結果就是從1970 到今天經歷過的天數,這徹底符合當前的需求。ui
這個解決方案,只是剛好能夠知足這種需求,對於其它更復雜一點的需求,我這裏推薦使用Joda Time
組件。spa
下面經過Openjdk的JMH類庫,對上述三種狀況進行性能基準測試,尚未接觸過JMH的同窗,能夠在官網上進行學習,傳送門.net
@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以前,須要引入相關依賴code
<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>
複製代碼
最終結果以下
這裏只是測試了Calendar和Joda對象的建立耗時,能夠發現Joda的性能比Calendar整整高了10倍,真的不可忽略。
更多精彩問題,歡迎加入知識星球 460+小夥伴正在討論