性能优化之抛弃Calendar

目前在作限流相关的需求,有这么一个限流策略,和用户相关,当系统发生故障时,容许一个非核心接口按照用户的百分比进行限流,若是彻底按照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+小伙伴正在讨论

相关文章
相关标签/搜索