将数据压缩到数据结构中

这个故事是关于我们最近在Plumbr进行的容量优化任务。 一切始于将无害的要求添加到现有组合中。

如您所知,Plumbr监视解决方案作为连接到服务器的Java代理分发。 只需少量添加即可跟踪一段时间内所有已连接的代理,以便可以实时回答以下问题:

  • 我们有多久没有收到这个特定JVM的消息了?
  • 另一个JVM的最后一次已知停机时间是什么?

当每个代理每秒发送一次心跳时,我们在服务器端需要做的就是跟踪所有心跳。 由于每个心跳都附加有唯一的时间戳记,因此天真的解决方案就像将Set或Map中的所有心跳都扔掉一样容易。 那么-简单,完成,接下来,请?

胖男人大肚子

但是,一些快速的数学运算表明,最初的想法可能行不通。 考虑到:

  • 时间戳记的类型很长 ,需要8个字节才能容纳它自己
  • 一年中有365 x 24 x 60 x 60 = 31,536,000秒

我们可以快速进行数学计算,发现单个JVM仅使用一年原始数据就需要240MB 。 仅原始数据的大小就已经足够吓人了,但是当打包到HashSet时,结构的保留大小 激增至约2GB ,而所有开销java.util.Collection API实现都隐藏在它们的腹部

幼稚的解决方案已经无法解决,我们需要一个替代方案。 最初我们不必走得很远,因为在同一java.util包中,一个等待被发现的意外之举叫java.util.BitSet 。 根据该类的javadoc:

BitSet类实现一个按需增长的位向量。 位集合的每个分量都有一个布尔值。 BitSet的位由非负整数索引。 可以检查,设置或清除各个索引位。

那么,如果我们将从代理获取的心跳存储为由心跳时间戳记索引的布尔值,该怎么办? Java中的时间戳表示为当前时间与1970年1月1日UTC午夜之间的毫秒差。 知道这一点后,我们可以将UTC表示为2015年9月1日12:00 UTC,即数字1441108800。那么,如果当我们看到一个Agent在时间戳1441108800处向我们发送心跳信号时,我们会将带有索引1441108800的位设置为true ,否则被保留为默认false

解决方案的问题隐藏在一个事实中,即BitSet中的位是用整数而不是long索引的。 要继续执行此解决方案,我们将需要一种将整数映射到long而不丢失任何信息的方法。 如果似乎不可能,那么让我们回顾一下这样一个事实,即需要一秒而不是一毫秒的精度。 知道了这一点,我们可以将索引缩小1,000倍,并以秒而不是毫秒的精度标记时间。

但是仅使用整数就可以表示多少秒? 显然,Integer.MAX_VALUE足够大,可以表示从1970年1月1日到19.01.2038的每一秒。 除了制造2038年的问题外,它还应该足够好,对吗?

不幸的是,正如我们的餐巾纸计算所显示的那样,一年的数据价值仍需要约800MB的堆空间。 这是从原始HashSet的2GB向正确方向迈出的一小步,但对于实际使用而言仍然太多了。

为了克服该问题,可能需要重新阅读/重新考虑“足以代表1970年1月1日的每一秒”的部分。 (不幸的)先生。 直到1995年,高斯林才发明Java虚拟机。18年后,Plumbr看到了曙光。 因此,我们直到1970年才需要回顾历史,并且每个整数都有一堆零。 可以从01.01.2013开始,而不是从01.01.1970开始,并使用一个索引0对应于01.01.2013 00:00(UTC)。

重做我们的餐巾纸数学,并在实践中检查结果使我们成为赢家。 现在一年的数据量只能存储在20MB中 。 与原始2GB相比,我们将所需容量减少了100倍 。 由于现有的基础架构已经可以解决这个问题,因此已经处于舒适区域,因此我们没有在优化路径上走得更远。

故事的道德启示? 当您有需求时,请找出对应用程序性能的影响。 我的意思是性能的各个方面,因为不仅有延迟和吞吐量,还应该忘记容量。 并且–了解您的域名。 没有它,您将无法做出决策,如果仅仅配备了有关数据结构的智能书籍,这些决策就显得不安全且危险。

翻译自: https://www.javacodegeeks.com/2015/09/squeezing-data-into-the-data-structure.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值