数据结构压缩_将数据压缩到数据结构中

数据结构压缩

这个故事是关于我们最近在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中的时间戳表示为当前时间与UTC 1970年1月1日午夜之间的毫秒差。 知道这一点后,我们可以将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

数据结构压缩

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337520.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

swing 状态视图分离_Java Swing模型视图适配器介体

swing 状态视图分离通常,我基于Spring Framework构建Java应用程序。 但是,最近有人要求我使用与语言无关的MVC框架PureMVC为客户端实现Java桌面应用程序,因此以下是我在Java Swing中为PureMVC进行员工管理展示的演示实现。 如果您想继续学习&…

超级炫酷的C语言技巧!

点击蓝字关注我们C语言常常让人觉得它所能表达的东西非常有限。它不具有类似第一级函数和模式匹配这样的高级功能。但是C非常简单,并且仍然有一些非常有用的语法技巧和功能,只是没有多少人知道罢了。一、指定的初始化很多人都知道像这样来静态地初始化数…

webgl 基础渲染demo_WebGL + ThreeJS 实现实时水下焦散 Part 1

知乎视频​www.zhihu.com采用 WebGL 和 ThreeJS 运行实时焦散运算,需要一点相关基础。本文主要介绍焦散的原理以及计算方法原作者https://github.com/martinRenou​github.com代码和原文https://github.com/martinRenou/threejs-caustics​github.com由于本人的笔电…

超硬核C++BestPractices翻译与阅读笔记

点击蓝字关注我们硬货开始这本书的副标题是:45ish Simple Rules with Specific Action items for better C ,这本书是由大佬推荐的, C学习有必要掌握一下这45条最佳实践, 可以很大程度上提升代码的可读性和健壮性, 而且这本书也不…

diskgenius单文件专业版_金蝶KIS专业版系列——系统工具六(业务套打工具)

导读:(一)问一问1.1.套打的作用1.2.举例(二)怎么进入套打设计器2.1.入口12.2.入口2(三)怎么使用套打设计器打开套打模板3.1.打开系统标准套打模板3.2.新建一个空白的套打模板3.3.保存套打模板3.…

面试常问的16个C语言问题,你全会吗?

点击蓝字关注我们金三银四不少小伙伴在找工作,这里我给大家分享一下面试中经常会遇到的一些嵌入式C语言问题,你看看能做到全会吗?1、用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题&#xff09…

高性能 高可用 可弹性伸缩_性能,可伸缩性和活力

高性能 高可用 可弹性伸缩本文是我们名为Java Concurrency Essentials的学院课程的一部分。 在本课程中,您将深入探讨并发的魔力。 将向您介绍并发和并发代码的基础知识,并学习诸如原子性,同步和线程安全性的概念。 在这里查看 !…

iptables命令_程序员最有用的linux命令汇总

总结程序员在工作中,最有用的linux命令如下:1、vi/vim 我们须要在服务器上代码一些代码时候,就用vi/vim命令就可以,vim是vi的升级,本色自带代码高亮工具,利于查看。dd 删除光标所在行o 向光标所在行向下增加…

详解C++异常

点击蓝字关注我们1、异常概念异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就可以抛出异常,让函数的直接或间接的调用者处理这个错误。throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。catch: …

C语言基础知识:指针与数组的区别是什么

点击蓝字关注我们在C语言教程中我们使用通过数组名通过偏移和指针偏移都可以遍历数组,那么指针和数组到底有什么区别??由于数组中的数据在内存中都是连续存放的,数组名默认就是数组的首地址,也是一个特殊的指针&#x…

java java se_Java 8 SE可选,严格的方法

java java se大约两周前,Stephen Colebourne提出了使用Optional的实用方法 。 如果您阅读了它,您可能会从我以前的建议中猜到我不同意。 总览 我必须以免责声明开头,然后我将直接解释为什么我认为他的方法不那么理想。 所有不归因于他人的报…

std::thread 还有哪些使用“姿势”?

点击蓝字关注我们C11 线程创建每一个 C11 程序都包含一个主线程即 main() 函数。在 C11 中我们可以通过创建 std::thread 对象来创建新的线程。每个 std::thread 对象都可以与一个线程相关联。需要引用的头文件&#xff1a;1#include <thread>std::thread 的构造函数中接…

用python画皇冠_手把手教你用 Python 绘制酷炫的桑基图!

原标题&#xff1a;手把手教你用 Python 绘制酷炫的桑基图&#xff01;作者 | 周志鹏 责编 | 郭 芮 最近&#xff0c;不止一次收到小伙伴的截图追问&#xff1a;“这个图叫什么&#xff1f;&#xff1f;&#xff1f;” “这个图真好看&#xff01;&#xff01;&#xff01;怎么…

为啥电脑从C盘开始?A、B盘去哪了?

点击蓝字关注我们前些天硬盘坏了&#xff0c;幸好不是系统盘&#xff0c;不然那些软件安装配置会把我折腾坏&#xff0c;或许这也是在暗示我该换电脑了。重要的数据部分没有遭到损坏&#xff0c;数据是无价的&#xff0c;还是要勤备份。于是换上了一张新的硬盘&#xff0c;当时…

java 锁_Java之线程并发的各种锁、锁、锁

因为两周没更新了...也不是懒&#xff0c;这两周确实有些忙&#xff0c;赶项目进度赶的不亦乐乎...终于赶在工期前&#xff0c;可以进入内测了&#xff0c;我也有了些时间&#xff0c;可以更新啦...线程并发锁是很常见的问题&#xff0c;而且在Java中锁的类型、概念、使用场景等…

C语言编程中错误异常该如何统一处理?1.8万字总结

点击蓝字关注我们本文主要总结嵌入式系统C语言编程中&#xff0c;主要的错误处理方式。一、错误概念1.1 错误分类从严重性而言&#xff0c;程序错误可分为致命性和非致命性两类。对于致命性错误&#xff0c;无法执行恢复动作&#xff0c;最多只能在用户屏幕上打印出错消息或将其…

pycharm remote 远程项目 同步 本地_利器:PyCharm本地连接服务器搭建深度学习实验环境的三重境界...

作为实验室社畜&#xff0c;常需要在本地使用Pycharm写代码&#xff0c;然后将代码同步到服务器上&#xff0c;使用远程登录服务器并运行代码做实验。这其中有很多事情如果没有好的工具&#xff0c;做起来会非常麻烦。比如如何快速同步本地与服务器的代码&#xff1f;如何优雅地…

防御性编程技巧

点击蓝字关注我们在防御性编程的大框架之下&#xff0c;有许多常识性的规则。人们在想到防御性编程的时候&#xff0c;通常都会想到“断言”&#xff0c;这没有错。我们将在后面对此进行讨论。但是&#xff0c;还是有一些简单的编程习惯可以极大地提高代码的安全性。尽管看上去…

cookie无法读取bdstoken_第二章(第12节):cookie操作

有时候我们需要验证浏览器中 cookie 是否正确&#xff0c;因为基于真实 cookie 的测试是无法通过白盒和集成测试进行的。WebDriver 提供了操作 cookie 的相关方法&#xff0c;可以读取、添加和删除 cookie信息。WebDriver 操作 cookie 的方法&#xff1a;get_cookies()&#xf…

C++ 基本的输入输出

点击蓝字关注我们C 标准库虽然提供了一组丰富的输入/输出功能&#xff0c;但是本章只讨论 C 编程中最基本和最常见的 I/O 操作。C 的 I/O 发生在流中&#xff0c;流是字节序列。如果字节流是从设备&#xff08;如键盘、磁盘驱动器、网络连接等&#xff09;流向内存&#xff0c;…