性能优化之抛弃Calendar

作者: 美团Java | 来源:发表于2018-06-11 20:37 被阅读568次

    目前在做限流相关的需求,有这么一个限流策略,和用户相关,当系统发生故障时,允许一个非核心接口按照用户的百分比进行限流,如果完全按照UUID进行hash,那么每次都是限制同一批的用户,如果在UUID的基础上加上当天的日期,那么就可以有效的避免这个问题。

    所以在这个需求中,每次请求都需要拿到当前的日期,不过精确到天即可。
    嗖~的一下,完成了如下代码

    Calendar calendar = Calendar.getInstance();
    String time = "" + calendar.get(Calendar.YEAR) + calendar.get(Calendar.MONTH) +calendar.get(Calendar.DAY_OF_MONTH);
    

    很简单是不是,不过写完之后,很快就被业务同学diss了,Calendar性能太差了,在QPS很高的情况下,会使接口的999线劣化。

    QPS高的业务真是惹不起... (丢)

    为什么Calendar不行,因为每次请求都要创建一个Calendar实例,这个创建过程比较的耗时(qps低的时候可以忽略这种消耗),但是做基础组件的,应该考虑各种场景。

    因为只需要获取到与天相关数据,所以想到了另一个简单的解决方案

    private static final int DAY_MILLIS = 24 * 60 * 60 * 1000;
    long day = System.currentTimeMillis() / DAY_MILLIS;
    

    通过当前的时间戳(毫秒级别),除以一天的毫秒数,得到的结果就是从1970 到今天经历过的天数,这完全符合当前的需求。

    这个解决方案,只是恰好可以满足这种需求,对于其它更复杂一点的需求,我这里推荐使用Joda Time组件。

    下面通过Openjdk的JMH类库,对上述三种情况进行性能基准测试,还没有接触过JMH的同学,可以在官网上进行学习,传送门

    @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之前,需要引入相关依赖

    <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倍,真的不可忽略。

    更多精彩问题,欢迎加入知识星球
    450+小伙伴正在讨论

    相关文章

      网友评论

      • Abelfourier:你可以每24小时取一次epoc时间,毫秒数就毫秒数呗。
      • 乐逍遥5830:狼哥,java8的日期函数对比呢。
      • 此鱼不得水:从你的文章中学到了还有JMH这种工具,感谢
      • 罗曼蒂克:学到了两点,1:压测可以不用写for循环了。😀2:system.get更快。给楼主点赞
        美团Java:@罗曼蒂克 system没有可比性,应该和joda比

      本文标题:性能优化之抛弃Calendar

      本文链接:https://www.haomeiwen.com/subject/gcxqeftx.html