这个项目不再维护!!!
OHC应使用非均匀内存架构在商品硬件和大型系统上提供良好的性能。
尚无性能测试结果 - 您可以尝试使用OHC基准测试工具。请参阅下面的说明。速度上的一个非常基本的印象是_benchmarking_节中。
Java 8 VM支持64位,并具有sun.misc.Unsafe
(X64 Intel CPU上的Oracle JVM)。
OHC针对Linux和OSX。它应该在Windows和其他Unix OSS上使用。
OHC为不同的缓存输入特性提供了两种实现: - _linked_实现分别为每个条目分别分配了临时内存,并适用于中等和大参赛作品。 - _chunked_实施将为整个哈希段分配外部内存,并用于小条目。
片段的数量通过org.caffinitas.ohc.OHCacheBuilder
配置,默认为# of cpus * 2
,并且必须是2的幂。条目是使用64个位哈希码中最重要的片段在段上分发的。每个段上的访问都同步。
每个哈希地图条目都是单独分配的。条目是免费的(交易)的,当它们不再由外部地图本身或任何外部参考(例如org.caffinitas.ohc.DirectValueAccess
或org.caffinitas.ohc.CacheSerializer
引用时。
该实现的设计将细分市场的锁定时间缩短到很短的时间。将/替换操作分配内存,首先分配内存,调用org.caffinitas.ohc.CacheSerializer
序列化键和值,然后将完全准备好的入口放入该段。
使用LRU算法进行驱逐。通过每个段的所有缓存元素链接列表用于跟踪最大条目。
存储器分配块外部实现。
与链接的实现相比,此实现的目的是减少相对较小的缓存条目的开销,因为整个段的内存已预先分配。此实现适用于具有org.caffinitas.ohc.CacheSerializer
的快速(de)序列化实现的小条目。
细分与链接的实现相同。片段的数量通过org.caffinitas.ohc.OHCacheBuilder
配置,默认为# of cpus * 2
,并且必须是2的幂。条目是使用64个位哈希码中最重要的片段在段上分发的。每个段上的访问都同步。
每个部分分为多个块。每个细分市场负责总容量(capacity / segmentCount)
的一部分。在初始化期间,将这种内存量分配后一次分配,并在逻辑上分为可配置数量的块。每个块的大小都使用org.caffinitas.ohc.OHCacheBuilder
中的chunkSize
选项进行配置。
像链接的实现一样,哈希条目首先将其序列化为临时缓冲区,然后在实际投入到一个细分市场中(Semement Operations同步)。
新条目放入当前写入块中。当块满时,下一个空的块将成为新的写作块。当所有块都满时,最近使用的最少使用的块,包括其包含的所有条目,都将被驱逐出境。
指定fixedKeyLength
和fixedValueLength
Builder属性可将内存足迹减少每个条目8个字节。
在本实现中不支持序列化,直接访问和获取加载器功能。
要启用块的实现,请在org.caffinitas.ohc.OHCacheBuilder
中指定chunkSize
。
注意:块的实现仍应被视为实验。
OHC支持三种驱逐算法:
使用类OHCacheBuilder
来配置所有必要的参数
通常,您应该使用一个大哈希桌。哈希表越大,每个哈希分区中的链接列表越短 - 这意味着链接的步行和性能提高。
所需的关闭内存的总量是总容量加上哈希表。每个哈希桶(当前)需要8个字节 - 因此公式为capacity + segment_count * hash_table_size * 8
。
OHC直接绕过Java的离容器内存限制直接分配了主内存。这意味着,OHC分配的所有内存都不计入-XX:maxDirectMemorySize
。
由于尤其是链接的实现为每个单独的条目执行异链/自由操作,因此请考虑可能发生内存碎片。
另外,由于某些分配可能仍在飞行中,并且“其他东西”(操作系统,JVM等)需要内存,因此请留下一些头部空间。这取决于使用模式需要多少头空间。请注意,链接的实现将在写操作过程中分配内存_before_,它被计入段,这将驱逐较旧的条目。这意味着:请勿将所有可用的内存献给OHC。
我们建议使用Jemalloc保持碎片较低。在UNIX操作系统上,预付Jemalloc。
出于性能原因,OSX通常不需要Jemalloc。另外,请确保您使用的是Jemalloc的最新版本 - 某些Linux发行版仍然提供相当旧的版本。
要在Linux上预紧jemalloc,请使用export LD_PRELOAD=<path-to-libjemalloc.so
,在OSX上预留jemalloc,请使用export DYLD_INSERT_LIBRARIES=<path-to-libjemalloc.so
。可以在Apache Cassandra项目中找到用于预加载的脚本模板。
QuickStart:
ohcache ohcache = ohcachebuilder.newbuilder() 。 .Valueserializer(YourValueserializer) 。建造();
此QuickStart使用至少默认配置:
有关选项的完整列表,请参见CacheBuilder
的Javadoc。
键和值序列化需要实现CacheSerializer
界面。该接口具有三种方法:
int serializedSize(T t)
以返回给定对象的序列化大小void serialize(Object obj, DataOutput out)
以序列化给定对象到数据输出T deserialize(DataInput in)
从数据输入中对象进行对象化克隆GIT存储库到您当地的机器。使用稳定的主分支或发布标签。
git clone https://github.com/snazy/ohc.git
您需要OpenJDK 11或更新才能从源构建。只是执行
mvn clean install
您需要从源构建OHC,因为大型基准工件未上传到Maven Central。
执行java -jar ohc-benchmark/target/ohc-benchmark-0.7.1-SNAPSHOT.jar -h
(从源来构建时)以获取一些帮助信息。
通常,基准工具启动了一堆线程,并使用_get_和_put_ operations配置的键分布同时执行_et_和_put_操作。还需要配置价值大小分布。
可用命令行选项:
-cap <arg>缓存的大小 -d <ARG>基准持续时间秒 -H帮助,打印此命令 -lf <arg>哈希表负载因子 -r <arg>读取版评分(作为双重0..1代表读取的机会) -rkd <arg>热键使用分布 - 默认值:统一(1..10000) -sc <arg>段数(单个非主映射的数量) -t <arg>线程执行 -vs <arg>值大小 - 默认值:固定(512) -wkd <arg>热键使用分布 - 默认值:统一(1..10000) -wu <arg>热身 - <Work-Secs>,<Sleep-Secs> -z <arg>哈希表尺寸 -cs <arg>块尺寸 - 如果指定,它将使用“块”实现 -fks <arg>修复了字节中的密钥大小 -fvs <arg>字节中的固定值大小 -Mes <ARG>最大输入大小在字节中 -unl不使用锁定 - 仅适当用于单线读模式 -HM <ARG> HASH算法要使用-Murmur3,XX,CRC32 -BH统计数据中显示存储库纪录 -kl <arg>启用桶形直方图。默认值:false
可以使用以下功能配置读取键,写键和值大小的分布:
Exp(min..max)在[min..max]范围内的指数分布 极端(最小值,形状)在[min..max]范围内的极值(weibull)分布 qExtreme(min..max,Shape,Quantas)一个极值,分为Quantas,其中选择的机会是均匀的 高斯(min..max,stdvrng)高斯/正态分布,其中平均值=(min+max)/2,stdev为(平均值)/stdvrng 高斯(Min..max,平均,stdev)的高斯/正态分布,具有明确定义的平均值和stdev 在[min,max]范围内的均匀分布(最小值)均匀分布 固定(val)固定分布,总是返回相同的值 在使用〜的名称之前将倒转分布,例如exp(1..10)将产生最多的10,而不是通常,通常会产生 别名:extr,qextr,高斯,正常,标准,威布尔
(注意:这些类似于Apache Cassandra压力工具 - 如果您知道,您都知道;)
读/写入比为.9
的快速示例,大约1.5GB最大容量,16个线程运行30秒:
Java -Jar OHC基准/target/ohc-benchmark-0.5.1-snapshot.jar
(请注意,JAR文件名中的版本可能有所不同。)
在2.6GHz Core i7系统(OSX)上,以下数字是典型运行上述基准测试的(.9读/写比):
当在很大的堆中使用大量对象时,虚拟机将遭受GC压力的增加,因为它基本上必须检查每个对象是否可以收集它并必须访问所有内存页面。缓存应保持一组热门对象,以便快速访问(例如省略磁盘或网络往返机)。唯一的解决方案是使用本机内存 - 您最终将选择通过JNI使用某些本机代码(C/C ++)或使用Direct Memory访问。
使用JNI使用C/C ++的本机代码具有您必须自然编写每个平台的C/C ++代码的缺点。尽管大多数Unix OS(Linux,OSX,BSD,SOLARIS)在处理诸如“比较”和“盘”或“ Posix库”之类的内容时非常相似,但您通常还希望支持其他平台(Windows)。
本机代码和直接内存访问都有一个缺点,即他们必须“离开” JVM“上下文” - 想说访问OFF HEAP内存的访问比对Java Heap中数据的访问较慢,并且每个JNI调用都有一些'逃离JVM上下文“成本”。
但是,当您不得不处理大量/多个GB的缓存内存时,堆内的内存非常好,因为DOS没有对Java垃圾收集器施加任何压力。让Java GC在该库为缓存数据完成工作的应用程序中完成工作。
TL; DR直接分配了异位记忆并绕过ByteBuffer.allocateDirect
对GC非常柔和,我们对内存分配有明确的控制,更重要的是免费。 Java中的库存实施在垃圾收集期间释放了临时内存 - 另外:如果没有更多的离容器内存,则可能会触发全GC,如果多个线程同时遇到这种情况,这是有问题的,因为这意味着很多。完整的GC依次。此外,股票实施使用全局同步的链接列表来跟踪非主机内存分配。
这就是为什么OHC直接分配离容器内存并建议在Linux系统上预努加载Jemalloc以提高内存管理性能的原因。
OHC于2014/15年开发,用于Apache Cassandra 2.2和3.0,用作新的Row-Cache后端。
由于没有合适的完全离子缓存实现,因此已决定构建一个全新的速度 - 这就是OHC。但是事实证明,仅OHC也可能适用于其他项目 - 这就是为什么OHC是一个单独的库。
一个很大的“谢谢”必须向Benedict Elliott Smith和DataStax的Ariel Weisberg提供对OHC非常有用的意见!
Ben Manes,咖啡因的作者,咖啡因是使用W-Biny LFU的高度可配置的植型缓存。
开发人员:罗伯特·斯图普(Robert Stupp)
版权(c)2014罗伯特·斯图普,德国科恩,罗伯特 - 斯图普。
根据Apache许可证(版本2.0(“许可”)获得许可;除了符合许可外,您不得使用此文件。您可以在
http://www.apache.org/licenses/license-2.0
除非适用法律要求或以书面形式同意,否则根据许可证分配的软件是按照“原样”分发的,没有任何明示或暗示的任何形式的保证或条件。请参阅许可证,以获取执行许可条款和限制的特定语言。