大数据计算:如何仅用1.5KB内存为十亿对象计数

Clearspring,我们从事统计数据。统计一组不同元素且数量很大的数据集时,是一个挑战。

为了更好地理解已经明确基数的大数据集的挑战,我们假设你的日志文件包含16个字符的ID,并且你想统计不同ID的数量.例如:

4f67bfc603106cb2

这16个字符需要用128位来表示。6万5千个ID将需要1MB的空间。我们每天收到30多亿条事件记录,每条记录都有一个ID。这些ID需要3840亿位或45GB的存储。而这仅仅是ID字段需要的空间。我们采取一种简单的方法获取日常事件记录中以ID为基数的数据。最简单的办法就是使用哈希集合且存放到内存中,其中哈希集包含唯一ID的列表(即输入文件中可能会有多条记录的id是相同,但在哈希集中只存放一条)。即使我们假设只有1/3的条记录ID是唯一的(即2/3的记录ID是重复的),哈希集仍需要119GB的RAM,这其中不包括Java需要在内存中存储对象的开销。你需要一台配备几百GB内存的机器来计算不同的元素,并且这只是计算一天内日志事件记录的唯一ID的内存消耗。如果我们想要统计数周或数月的数据,这问题只会变得更加困难。我们身边当然不会有一台配备几百GB内存的空闲机器,所以我们需要一个更好的解决方案。

解决这一问题的常见办法是使用位图(博客:海量数据处理算法—Bit-Map)。位图可以快速、准确地获取一个给定输入的基数。位图的基本思想是使用哈希函数把数据集映射到一个bit位,每个输入元素与bit位是一一对应。这样Hash将没有产生碰撞冲突,并减少需要计算每个元素映射到1个bit的空间。虽然Bit-map大大节省了存储空间,但当统计很高的基数或非常大的不同的数据集,它们仍然有问题。例如,如果我们想要使用Bit-map计数十亿,你将需要Bit-map位,或需要每个约120 MB的计数器。稀疏的位图可以被压缩,以获得更多的空间效率,但也并不总是有帮助的。

幸运的是,基数估计是一个热门的研究领域。我们已经利用这项研究提供了一个开源实现的基数估计、集合元素检测和top-k算法。

基数估计算法就是使用准确性换取空间。为了说明这一点,我们用三种不同的计算方法统计所有莎士比亚作品中不同单词的数量。请注意,我们的输入数据集增加了额外的数据以致比问题的参考基数更高。这三种技术是:Java HashSet、Linear Probabilistic Counter以及一个Hyper LogLog Counter。结果如下:

该表显示,我们统计这些单词只用了512 bytes,而误差在3%以内。相比之下,HashMap的计数准确度最高,但需要近10MB的空间,你可以很容易地看到为什么基数估计是有用的。在实际应用中准确性并不是很重要的,这是事实,在大多数网络规模和网络计算的情况下,用概率计数器会节省巨大的空间。

线性概率计数器

线性概率计数器是高效的使用空间,并且允许实现者指定所需的精度水平。该算法在注重空间效率时是很有用的,但你需要能够控制结果的误差。该算法分两步运行:第一步,首先在内存中分配一个初始化为都为0的Bit-map,然后使用哈希函数对输入数据中的每个条目进行hash计算,哈希函数运算的结果是将每条记录(或者是元素)映射到Bit-map的一个Bit位上,该Bit位被置为1;第二步,算法计算空的bit位数量,并使用这个数输入到下面的公式来进行估算:

n=-m ln Vn

注意:ln Vn=Loge(Vn) 自然对数

在公式中,m是 Bit-map的大小,Vn是空bit位和map的大小的比率。需要重点注意的是原始Bit-map的大小,可以远小于预期的最大基数。到底小多少取决于你可以承受误差的大小。因为Bit-map的大小m小于不同元素的总数将会产生碰撞。虽然碰撞可以节省空间,但同时也造成了估算结果出现误差。所以通过控制原始map的大小,我们可以估算碰撞的次数,以致我们将在最终结果中看到误差有多大。

Hyper LogLog

顾名思义,Hyper LogLog计数器就是估算Nmax为基数的数据集仅需使用loglog(Nmax)+O(1) bits就可以。如线性计数器的Hyper LogLog计数器允许设计人员指定所需的精度值,在Hyper LogLog的情况下,这是通过定义所需的相对标准差和预期要计数的最大基数。大部分计数器通过一个输入数据流M,并应用一个哈希函数设置h(M)来工作。这将产生一个S = h(M) of {0,1}^∞字符串的可观测结果。通过分割哈希输入流成m个子字符串,并对每个子输入流保持m的值可观测 ,这就是相当一个新Hyper LogLog(一个子m就是一个新的Hyper LogLog)。利用额外的观测值的平均值,产生一个计数器,其精度随着m的增长而提高,这只需要对输入集合中的每个元素执行几步操作就可以完成。其结果是,这个计数器可以仅使用1.5 kb的空间计算精度为2%的十亿个不同的数据元素。与执行 HashSet所需的120 兆字节进行比较,这种算法的效率很明显。

合并分布式计数器

我们已经证明了使用上面描述的计数器我们可以估算大集合的基数。但是,如果你的原始输入数据集不适合于单台机器,将怎么做呢?这正是我们在Clearspring所面临的问题。我们的数据分散在数百台服务器上,并且每个服务器只包含整个数据集子集的一部分。这事实上我们能合并一组分布式计数器的内容是至关重要的。这个想法有点令人费解,但如果你花费一些时间去思考这个问题,就会发现其与基本的基数估计值相比并没有太大的不同。因为这个计数器表示映射中的位作为基数,我们可以采取两个兼容计数器并将他们bit位合并到单一的map上。这个算法已经处理碰撞,所以我们可以得到一个基数估计所需的精密,即使我们从来没有把所有的输入数据到一台机器。这是非常有用的,节省了我们在网络中移动数据的大量时间和精力。

Next Steps

希望这篇文章能帮助你更好地理解这个概念和概率计数器的应用。如果估算大集合的基数是一个问题,而你又碰巧使用一个基于JVM的语言,那么你应该使用stream-lib项目——它提供了其他几个流处理工具以及上文所述的算法的实现。

本文来自:High Scalability

本人结束语:自认英语不好,翻译可能会有出入。但我看了csdn的翻译,我怀疑那是技术员人翻译的吗? 一些翻译直接是工具翻译过来。

若深入了解Hyper LogLog:请看http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf和http://www.ic.unicamp.br/~celio/peer2peer/math/bitmap-algorithms/durand03loglog.pdf

At Clearspring we like to count things. Counting the number of distinct elements (the cardinality) of a set is challenge when the cardinality of the set is large.

To better understand the challenge of determining the cardinality of large sets let‘s imagine that you have a 16 character ID and you‘d like to count the number of distinct IDs that you‘ve seen in your logs. Here is an example:

4f67bfc603106cb2

These 16 characters represent 128 bits. 65K IDs would require 1 megabyte of space. We receive over 3 billion events per day, and each event has an ID. Those IDs require 384,000,000,000 bits or 45 gigabytes of storage. And that is just the space that the ID field requires! To get the cardinality of IDs in our daily events we could take a simplistic approach. The most straightforward idea is to use an in memory hash set that contains the unique list of IDs seen in the input files. Even if we assume that only 1 in 3 records are unique the hash set would still take 119 gigs of RAM, not including the overhead Java requires to store objects in memory. You would need a machine with several hundred gigs of memory to count distinct elements this way and that is only to count a single day‘s worth of unique IDs. The problem only gets more difficult if we want to count weeks or months of data. We certainly don‘t have a single machine with several hundred gigs of free memory sitting around so we needed a better solution.

One common approach to this problem is the use of bitmaps. Bitmaps can be used to quickly and accurately get the cardinality of a given input. The basic idea with a bitmap is mapping the input dataset to a bit field using a hash function where each input element uniquely maps to one of the bits in the field. This produces zero collisions, and reduces the space required to count each unique element to 1 bit. While bitmaps drastically reduce the space requirements from the naive set implementation described above they are still problematic when the cardinality is very high and/or you have a very large number of different sets to count. For example, if we want to count to one billion using a bitmap you will need one billion bits, or roughly 120 megabytes for each counter. Sparse bitmaps can be compressed in order to gain space efficiency, but that is not always helpful.

Luckily, cardinality estimation is a popular area of research. We‘ve leveraged this research to provide a open source implementation of cardinality estimators, set membership detection, and top-k algorithms.

Cardinality estimation algorithms trade space for accuracy. To illustrate this point we counted the number of distinct words in all of Shakespeare‘s works using three different counting techniques. Note that our input dataset has extra data in it so the cardinality is higher than the standard reference answer to this question. The three techniques we used were Java HashSet, Linear Probabilistic Counter, and a Hyper LogLog Counter. Here are the results:


Counter


Bytes Used


Count


Error


HashSet


10447016


67801


0%


Linear


3384


67080


1%


HyperLogLog


512


70002


3%

The table shows that we can count the words with a 3% error rate using only 512 bytes of space. Compare that to a perfect count using a HashMap that requires nearly 10 megabytes of space and you can easily see why cardinality estimators are useful. In applications where accuracy is not paramount, which is true for most web scale and network counting scenarios, using a probabilistic counter can result in tremendous space savings.

Linear Probabilistic Counter

The Linear Probabilistic Counter is space efficient and allows the implementer to specify the desired level of accuracy. This algorithm is useful when space efficiency is important but you need to be able to control the error in your results. This algorithm works in a two-step process. The first step assigns a bitmap in memory initialized to all zeros. A hash function is then applied to the each entry in the input data. The result of the hash function maps the entry to a bit in the bitmap, and that bit is set to 1. The second step the algorithm counts the number of empty bits and uses that number as input to the following equation to get the estimate.

n=-m ln Vn

In the equation m is the size of the bitmap and Vn is the ratio of empty bits over the size of the map. The important thing to note is that the size of the original bitmap can be much smaller than the expected max cardinality. How much smaller depends on how much error you can tolerate in the result. Because the size of the bitmap, m, is smaller than the total number of distinct elements, there will be collisions. These collisions are required to be space-efficient but also result in the error found in the estimation. So by controlling the size of the original map we can estimate the number of collisions and therefore the amount of error we will see in the end result.

Hyper LogLog

The Hyper LogLog Counter‘s name is self-descriptive. The name comes from the fact that you can estimate the cardinality of a set with cardinality Nmax using just loglog(Nmax) + O(1) bits. Like the Linear Counter the Hyper LogLog counter allows the designer to specify the desired accuracy tolerances. In Hyper LogLog‘s case this is done by defining the desired relative standard deviation and the max cardinality you expect to count. Most counters work by taking an input data stream, M, and applying a hash function to that set, h(M). This yields an observable result of S = h(M) of {0,1}^∞ strings. Hyper LogLog extends this concept by splitting the hashed input stream into m substrings and then maintains m observables for each of the substreams. Taking the average of the additional observables yields a counter whose accuracy improves as m grows in size but only requires a constant number of operations to be performed on each element of the input set. The result is that, according to the authors of thispaper, this counter can count one billion distinct items with an accuracy of 2% using only 1.5 kilobytes of space. Compare that to the 120 megabytes required by the HashSet implementation and the efficiency of this algorithm becomes obvious.

Merging Distributed Counters

We‘ve shown that using the counters described above we can estimate the cardinality of large sets. However, what can you do if your raw input dataset does not fit on single machine? This is exactly the problem we face at Clearspring. Our data is spread out over hundreds of servers and each server contains only a partial subset of the the total dataset. This is where the fact that we can merge the contents of a set of distributed counters is crucial. The idea is a little mind-bending but if you take a moment to think about it the concept is not that much different than basic cardinality estimation. Because the counters represent the cardinality as set of bits in a map we can take two compatible counters and merge their bits into a single map. The algorithms already handle collisions so we can still get a cardinality estimation with the desired precision even though we never brought all of the input data to a single machine. This is terribly useful and saves us a lot of time and effort moving data around our network.

Next Steps

Hopefully this post has helped you better understand the concept and application of probabilistic counters. If estimating the cardinality of large sets is a problem and you happen to use a JVM based language then you should check out the stream-lib project — it provides implementations of the algorithms described above as well as several other stream-processing utilities.

出处:http://blog.csdn.net/hguisu/article/details/8433731

时间: 2024-10-25 04:02:44

大数据计算:如何仅用1.5KB内存为十亿对象计数的相关文章

大数据计算平台Spark内核全面解读

1.Spark介绍 Spark是起源于美国加州大学伯克利分校AMPLab的大数据计算平台,在2010年开源,目前是Apache软件基金会的顶级项目.随着Spark在大数据计算领域的暂露头角,越来越多的企业开始关注和使用.2014年11月,Spark在Daytona Gray Sort 100TB Benchmark竞赛中打破了由Hadoop MapReduce保持的排序记录.Spark利用1/10的节点数,把100TB数据的排序时间从72分钟提高到了23分钟. Spark在架构上包括内核部分和4

一分钟了解阿里云产品:大数据计算服务MaxCompute概述

阿里云发布了许多产品,今天让我们来了解下大数据计算服务MaxCompute这款产品吧. 什么是MaxCompute呢? MaxCompute是由阿里云自主研发,是阿里巴巴自主研发的海量数据处理平台.提供针对TB/PB级数据.实时性要求不高的分布式处理能力,应用于数据分析.挖掘.商业智能等领域.主要服务于批量结构化数据的存储和计算,可以提供海量数据仓库的解决方案以及针对大数据的分析建模服务.阿里巴巴的离线数据业务都运行在MaxCompute上. MaxCompute有什么优势和特点呢?下面让我来简

大数据计算引擎之Flink Flink状态管理和容错

原文地址:大数据计算引擎之Flink Flink状态管理和容错 有状态计算 在Flink架构体系中,有状态计算可以说是Flink非常重要的特征之一.有状态计算是指在程序计算过程中,在Flink程序内部,存储计算产生的中间结果,并提供给Functions 或 孙子计算结果使用.如图所示: 状态数据可以维系在本地存储中,这里的存储可以是 Flink 的堆内存或者堆外内存,也可以借助第三方的存储介质,例如:Flink中已经实现的RocksDB,当然用户也可以自己实现相应的缓存系统去存储状态信息,以完成

SPARK大数据计算BUG处理:

大数据计算BUG处理: 程序修改前资源情况: Driver : 1台 Worker : 2台 程序提交申请内存资源 : 1G内存 内存分配情况 : 1. 20%用于程序运行 2. 20%用于Shuffle 3. 60%用于RDD缓存 单条TweetBean大小 : 3k 1. 内存溢出 原因:因为程序会把所有的TweetBean查询出来并且合并(union),该操作在内存中进行.则某个campaign数据量较大时,如500W数据,则500W*10k=50G,超出内存限制. 解决方法: 先按数据量

典型大数据计算模式与系统

典型大数据计算模式 典型系统 大数据查询分析计算 HBase,Hive,Cassandra,Impala,Shark,Hana等 批处理计算 Hadoop MapReduce,Spark等 流式计算 Scribe,Flume,Storm,S4, Spark Steaming等 迭代计算 HaLoop,iMapReduce,Twister,Spark等 图计算 Pregel,Giraph,Trinity,PowerGraph,GraphX等 内存计算 Dremel,Hana,Spark等

详说大数据计算的可类化Classable

可类化(Classable)是Laxcus大数据管理系统提供的一项基础功能,它能够将类转化为一串字节数组,或者逆向将字节数组转化为一个类.这项功能与JAVA提供的序列化(Serializable)非常相似,但是不同之处在于,可类化是可以由用户自己定义的,包括数据的选择.数据的样式.数据结构等一系列的规则. 这样的好处在于,我们摆脱了JAVA序列化的那种由系统硬性规定的固定格式,可以自由组织我们需要的数据,包括一些可能是私密的数据:不便在于,因为这种自由,程序员需要做些牺牲,编写代码来实现这项技术

Cubert:LinkedIn开源的大数据计算引擎

近日, Linkedin 宣布开源其正在使用的大数据计算引擎 Cubert ,该框架提供了一种新的数据模型来组织数据,并使用诸如MeshJoin 和Cube算法等算法来对组织后的数据进行计算,从而减轻了系统负荷和节省了CPU资源,最终提供给用户一个简单.高效的查询.Cubert比较适合的计 算领域包括统计计算.聚合.时间距离计算.增量计算.图形计算等. Cubert整个架构可分为三层,第一层是数据流语言层,主要用来实现执行计划,包括 Apache Pig . Apache Hive 以及Cube

一文读懂大数据计算框架与平台

1.前言 计算机的基本工作就是处理数据,包括磁盘文件中的数据,通过网络传输的数据流或数据包,数据库中的结构化数据等.随着互联网.物联网等技术得到越来越广泛的应用,数据规模不断增加,TB.PB量级成为常态,对数据的处理已无法由单台计算机完成,而只能由多台机器共同承担计算任务.而在分布式环境中进行大数据处理,除了与存储系统打交道外,还涉及计算任务的分工,计算负荷的分配,计算机之间的数据迁移等工作,并且要考虑计算机或网络发生故障时的数据安全,情况要复杂得多. 举一个简单的例子,假设我们要从销售记录中统

揭秘阿里云EB级大数据计算引擎MaxCompute

日前,全球权威咨询与服务机构Forrester发布了<The Forrester WaveTM: Cloud Data Warehouse, Q4 2018>报告.这是Forrester Wave首次发布关于云数仓解决方案(Cloud Data Warehouse,简称CDW)的测评.报告对云数仓的当前产品功能.产品路线和发展策略.市场表现等几个方面进行全面的评估,在产品能力排行榜中,阿里云力压微软排行第7. Forrester测评报告对CDW核心功能的评估主要从解决方案的多样性.数据集成.性