为了统计2亿5千万个词的三元词组的出现频率,想了很多办法。三元组对象占用内存40bytes,计数器占用的内存16bytes,那么,光是2亿5千万个三元组,大约就要占用13G的空间,考虑到归并的情况,最少也要6G空间。
感觉最合适的应该是采用MapReduce计算模型,并行完成这么大数据量的计算。目前唯一开源的MapReduce项目是Hadoop,但我要真正用起来还没有条件,目前只有两台PC,而且都装的是Windows系统。但Hadoop绝对是应该重点研究的对象,因为今后要处理的是更加大的数据量。
Terracotta也考察了一下,本以为它可以联合多个PC作为一个能存储海量数据的distributed Hash Map,但Terracotta只是通过一个中心的server去协调多个节点来share数据,如果数据量很大,它会在server上persist data to disk。它使用的是Berkeley DB 作为 persistent layer。我不需要在多个node之间share数据,那还不如直接用Berkeley DB。
接着就是试用Berkeley DB,在没有任何优化的情况下,效率很低。虽然我给JVM开了1G的内存,但观察到程序运行时,内存使用增长非常的缓慢,马上就意识到应该加大buffer size,不要让I/O这么频繁。翻了一下文档,设置了如下的je.properties:
# If true (default is false) NIO is used for all file I/O.
je.log.useNIO=true
# If non-0 (default is 0) break all IO into chunks of this size.
# This setting is only used if je.log.useNIO=true.
# minimum = 0
# maximum = 67108864
je.log.chunkedNIO=8192
# If true (default is false) direct NIO buffers are used.
# This setting is only used if je.log.useNIO=true.
je.log.directNIO=true
# The maximum size of each individual JE log file, in bytes.
# minimum = 1000000
# maximum = 4294967296
# 100M
je.log.fileMax=104857600
# maximum starting size of a JE log buffer
# 32M
je.log.bufferSize=33554432
# The number of JE log buffers
# minimum = 2
je.log.numBuffers=2
# The total memory taken by log buffers, in bytes. If 0, use
# 7% of je.maxMemory
# minimum = 6144
# 32M * 2
je.log.totalBufferBytes=67108864
# By default, JE sizes the cache as a percentage of the maximum
# memory available to the JVM. For example, if the JVM is
# started with -Xmx128M, the cache size will be
# (je.maxMemoryPercent * 128M) / 100
# Setting je.maxMemory to an non-zero value will override
# je.maxMemoryPercent
# minimum = 1
# maximum = 90
je.maxMemoryPercent=60
# If true (the default), use an LRU-only policy to select nodes for
# eviction. If false, select by Btree level first, and then by LRU.
je.evictor.lruOnly=false
# The number of nodes in one evictor scan
# minimum = 1
# maximum = 1000
je.evictor.nodesPerScan=100
打开NIO,关掉LRU cache management policy(http://www.oracle.com/technology/products/berkeley-db/faq/je_faq.html#35)。把buffer size加到了32M。运行效率有了质的提升,1个小时处理了一千多万个词。但随后的处理速度又明显的下降了。根据Jconsole观察的结果,似乎把cache设置的过大,导致Heap memory大部分都被cache占据。于是又把maxMemoryPercent降到了60%,运行程序,回家走人,等着周一看结果。谁知道周日下午得知,公司周末停电了。faint。看来下周还要重新运行,但起码现在有了一点阶段性的成果。记录之。