本章描述了 region 压缩机制, 它的好处和利用率.
在 Geode 中有一种减少内存消耗的方式是在 Region 中启动内存压缩机制。Geode 允许你压缩内存的 region 值,使用插件化的压缩器。Geode 包含了 Snappy 压缩器作为内置的压缩编码器;然而,你能够为每个已经压缩的Region实现和指定一个不同的压缩器。
压缩什么值
在一个 Region 中当你启动压缩时,所有保存在 region 中的值都被压缩。Keys 和索引不能被压缩。新的值被压缩,当写入到缓存中时,当从缓存中读取数据时被解压缩。当持久化到磁盘时,这些值不压缩。当此值发送给其他成员或者客户端时进行解压缩操作。
当压缩启动时,region 中的每个值都被压缩,每个 region 条目都被压缩成一个单元. 单独压缩数据条目中的属性是不可能的.
在同一个缓存内可以有压缩和非压缩的混合模式
使用压缩指南
此篇描述了当什么时候进行压缩
回顾如下的指南决定是否启动压缩:
当 JVM 内存使用率太高时则使用压缩. 压缩允许你保存更多的 region 数据,同时减少 GC 循环周期,防止 JVMs 运行出 OOM异常故障,当内存使用高时.
为了确定是否 JVM 内存使用率高时, 检查如下的统计:
- vmStats>freeMemory
- vmStats->maxMemory
- ConcurrentMarkSweep->collectionTime
如果空闲内存量降低到 20% - 25% 或者 GC 循环处于高位时, 然后在 JVM 上的 region 比较合适启动压缩功能.
- 考虑region 数据条目的类型和长度. 当压缩在每个条目上单独执行, 考虑到跨单个条目的潜在重复数据问题. 重复字节的压缩更容易. 同时, region entries 初次持久化到一个字节区域,在压缩之前, 数据怎样压缩通过重复字节的数量和长度来确定-跨整个条目,而不只是单个域值. 最后, 条目越大,压缩越能达到更好地效果对于重复的字节, 和一系列的重复字节.
- 考虑到想要压缩的数据类型. 保存的数据类型在数据怎样压缩的方式上有一个重要影响. 字符串数据类型比数字数据类型压缩要好一些, 因为字符串字节重复率要高很多; 然而, 可能不经常出现这种情况. 例如, 一个Region 条目持有了一对 short 类型的数据, 唯一的字符串可能不提供相当的内存节省率, 与另外的 region 条目持有了大数的整型值. 当评估压缩一个 region 的潜在收益,考虑到重复字节的相似性, 更重要的是重复字节的长度, 对于一个单一的, 序列化的 region 条目. 另外,已经被压缩的数据, 例如 JPEG 格式文件, 可能会导致更多的内存使用.
- 压缩是否你正在保存大的文本值. 压缩是有利的,如果你正保存大的文本值 (例如 JSON 或 XML) 或者 blobs, 这些在压缩上都比较有效果.
- 考虑是否正在查询的域被索引. 你能够查询经过压缩的 regions; 然而, 如果你正在查询的域没有被索引, 然后域必须被解压缩,在它们使用之前. 你可能也会遭遇一些查询性能开销,当查询非索引域时.
- 保存在压缩 Region 中的对象必须被序列化. 压缩直操作在字节数组上, 因此在压缩 region 上保存的对象必须序列化和反序列化. 此对象能够实现 Serializable 接口 或者使用其他的 Geode 序列化机制 (例如 PdxSerializable). 实现应该经常被关注,当压缩被启动, 一个对象的实例放入到一个 region 将不是相同的实例, 当取出时. 因此, 瞬时属性将丢失它们的值, 当所包含的对象被放入,和取出时.
- 缺省情况下, 已经压缩的 region 将启动克隆. 设置一个压缩器, 然后在一个异常中禁用克隆结果. 此操作是不兼容的,因为压缩/序列化, 解压缩/反序列化将导致对象的不同实例, 可能在克隆对象的时候被中断.
怎样在 region 中启动压缩
在 region 中为了启动压缩, 需要在 cache.xml 中设置如下的 region 属性:
<?xml version="1.0" encoding= "UTF-8"?>
<cache xmlns="http://schema.pivotal.io/gemfire/cache"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://schema.pivotal.io/gemfire/cache http://schema.pivotal.io/gemfire/cache/cache-8.1.xsd"
version="8.1” lock-lease="120" lock-timeout= "60" search-timeout= "300" is-server= "true" copy-on-read= "false" >
<region name="compressedRegion" >
<region-attributes data-policy="replicate" ... />
<Compressor>
<class-name>com.gemstone.gemfire.compression.SnappyCompressor</class-name>
</Compressor>
...
</region-attributes>
</region>
</cache>
在压缩器元素中,指定压缩器实现的类名。此例子指定了 Snappy 压缩器,与Geode 边界。你也能够指定一个自定义的压缩器。查看使用压缩器的示例。
当 region 创建时,压缩就能够被启动
gfsh:
gfsh>create-region --name=”CompressedRegion” --compressor=”com.gemstone.gemfire.compression.SnappyCompressor”;
API:
regionFactory.setCompressor(new SnappyCompressor());
或者
regionFactory.setCompressor(SnappyCompressor.getDefaultInstance());
怎么检查是否压缩是启动的
你也能检查是否一个 region 有压缩启动,通过查询哪个 codec 正在被使用。一个 null codec 提示对于 region没有压缩被启动。
Region myRegion = cache.getRegion("myRegion");
Compressor compressor = myRegion.getAttributes().getCompressor();
使用压缩器
当使用 region 压缩的时候,你能够使用默认的 Snappy压缩器,你能够指定你自己的压缩器
The single, default instance of the SnappyCompressor may be retrieved with theSnappyCompressor.getDefaultInstance() static method.
压缩 API 构成了一个单独的接口,用于实现自定义的压缩。默认的压缩器(SnappyCompressor)是一个单独的压缩实现,与产品进行绑定。而压缩器是无状态的,在 JVM 中只需要一个实例;然而,多个实例可能需要被使用。SnappyCompressor单独的实例可能使用SnappyCompressor.getDefaultInstance()来查询,
注意: Snappy 仅支持 Linux, Windows, 和 OS X 平台的部署.
示例提供了一个自定义的 Compressor 实现:
package com.mybiz.myproduct.compression;
import com.gemstone.gemfire.compression.Compressor;
public class LZWCompressor implements Compressor {
private final LZWCodec lzwCodec = new LZWCodec();
@Override
public byte[] compress(byte[] input) {
return lzwCodec.compress(input);
}
@Override
public byte[] decompress(byte[] input) {
return lzwCodec.decompress(input);
}
}
在一个 Region 上使用一个新的自定义压缩器:
- 确保新的压缩器包可用于所有的 JVM 类路径, JVM 管理这些 Region.
- 配置自定义的压缩器,使用如下的机制:使用 gfsh:
gfsh>create-region --name=”CompressedRegion” \ - --compressor=”com.mybiz.myproduct.compression.LZWCompressor”
使用 API:
For example:regionFactory.setCompressor(new LZWCompressor());
cache.xml:<region-attributes> - <Compressor>
- <class-name>com.mybiz.myproduct.compression.LZWCompressor</class-name>
- </Compressor>
- </region-attributes>
为已经压缩的 Region更改压缩器
你已经在region上启动了压缩,在 region 创建时. 你不能修改压缩器或者禁用压缩 ,当region在线时.
然而,如果你需要改变压缩器或者禁用压缩,你能够通过执行如下的步骤来做这件事:
- 关闭你想要进行修改的成员.
- 对于此成员来说修改 cache.xml 文件,指定一个新的压缩器或者从 region 中删除压缩器属性.
- 重启成员.
比较压缩和非压缩的 Region
压缩 region 和非压缩 region的性能依赖于 region 怎么使用, 是否 region 在一个内存绑定的 JVM 上管理.
当考虑压缩的成本时, 你应该考虑读写压缩数据的相对成本,和压缩的成本 ,管理内存数据条目的时间百分比. operations than for region get operations. Because of this, enabling compression will create more overhead on regions that are write heavy than on regions that are read heavy.
通常来讲,启动压缩将增加 30% - 60% 以上的开销,对于 region 创建和更新来说。
然而,当你尝试评估启动压缩的性能开销时,你也应该考虑压缩的开销,与管理条目的开销相对应。一个 region 可能被调优,例如,一个不保存到磁盘的同步 region ,比分区 Region有更好地读写性能,在 region 上启动压缩,已经优化了读写性能,将提供更显著地结果,比在 region 上进行压缩,没有进行优化。性能将会几倍地降级,在一个读写优化 Region 上, 而在非优化的 region 上只会降级5-10百分点
在内存绑定的 JVM 中当启用压缩时。启用压缩通常假设 JVM 是内存边界的,因此耗费太多 GC 垃圾收集时间。在这种情况下,当运行在一个GC 周期中时,性能可能提升几倍,而 JVM 耗费GC 周期时间更小。
监控压缩性能
如下的统计提供缓存压缩的监控:
- compressTime
- decompressTime
- compressions
- decompressions
- preCompressedBytes
- postCompressedBytes