1、背景

  在当前微服务体系架构中,有很多服务例如,在 特征组装 与 排序等场景都需要有大量的数据支撑,快速读取这些数据对提升整个服务于的性能起着至关重要的作用。

  缓存在各大系统中应用非常广泛。尤其是业务程序所依赖的数据可能在各种类型的数据库上(mysql、hive 等),那么如果想要获取到这些数据需要通过网络来访问。再加上往往数据量又很庞大,网络传输的耗时,自然会增加系统的相应时间。为了降低相应时间,业务程序可以将从数据库中读取到的部分数据,缓存在本地服务器可以很方便快速的直接使用。

  缓存框架OHC基于Java语言实现,并以类库的形式供其他Java程序调用,是一种以单机模式运行的堆外缓存。

2、OHC 简介

  缓存的分类与实现机制多种多样,包括单机缓存与分布式缓存等等。具体到JVM应用,又可以分为堆内缓存和堆外缓存。

  OHC 全称为 off-heap-cache,即堆外缓存,是一款基于Java 的 key-value 堆外缓存框架。

  OHC是2015年针对 Apache Cassandra 开发的缓存框架,后来从 Cassandra 项目中独立出来,成为单独的类库,其项目地址为:https://github.com/snazy/ohc

 2.1、堆内和堆外

  Java程序运行时,由Java虚拟机(JVM)管理的内存区域称为堆(heap)。垃圾收集器会扫描堆内空间,识别应用程序已经不再使用的对象,并释放其空间,这个过程称为GC。

  堆内缓存,顾名思义,是指将数据缓存在堆内的机制,比如 HashMap 就可以用作简单的堆内缓存。由于垃圾收集器需要扫描堆,并且在扫描时需要暂停应用线程(stop-the-world,STW),因此,缓存数据过多会导致GC开销增大,从而影响应用程序性能。

   与堆内空间不同,堆外空间不影响GC,由应用程序自身负责分配与释放内存。因此,当缓存数据量较大(达到G以上级别)时,可以使用堆外缓存来提升性能。

  OHC Java堆外缓存详解与应用

 2.2、OHC 的特性

  相对于持久化数据库,可用的内存空间更少、速度也更快,因此通常将访问频繁的数据放入堆外内存进行缓存,并保证缓存的时效性。OHC主要具有以下特性来满足需求:

  1. 数据存储在堆外,不影响GC
  2. 支持为每个缓存项设置过期时间
  3. 支持配置LRU、W-TinyLFU逐出策略
  4. 能够维护大量的缓存条目(百万量级以上)
  5. 支持异步加载缓存
  6. 读写速度在微秒级别

  OHC具有低延迟、容量大、不影响GC的特性,并且支持使用方根据自身业务需求进行灵活配置。

 2.3、使用示例

  在Java项目中使用OHC,主要包括以下步骤:

  1. 在项目中引入OHC。如果使用Maven来管理依赖,可以将OHC的坐标添加到到项目的POM文件中。

<dependency>
    <groupId>org.caffinitas.ohc</groupId>
    <artifactId>ohc-core</artifactId>
    <version>0.7.0</version>
</dependency>

  2. OHC是将Java对象序列化后存储在堆外,因此用户需要实现 org.caffinitas.ohc.CacheSerializer 类,OHC会运用其实现类来序列化和反序列化对象。例如,以下例子是对 string 进行的序列化实现:

public class StringSerializer implements CacheSerializer<String> {
 
    /**
     * 计算字符串序列化后占用的空间
     *
     * @param value 需要序列化存储的字符串
     * @return 序列化后的字节数
     */
    @Override
    public int serializedSize(String value) {
        byte[] bytes = value.getBytes(Charsets.UTF_8);
 
        // 设置字符串长度限制,2^16 = 65536
        if (bytes.length > 65536)
            throw new RuntimeException("encoded string too long: " + bytes.length + " bytes");
        // 设置字符串长度限制,2^16 = 65536
        return bytes.length + 2;
    }
 
    /**
     * 将字符串对象序列化到 ByteBuffer 中,ByteBuffer是OHC管理的堆外内存区域的映射。
     *
     * @param value 需要序列化的对象
     * @param buf   序列化后的存储空间
     */
    @Override
    public void serialize(String value, ByteBuffer buf) {
        // 得到字符串对象UTF-8编码的字节数组
        byte[] bytes = value.getBytes(Charsets.UTF_8);
        // 用前16位记录数组长度
        buf.put((byte) ((bytes.length >>> 8) & 0xFF));
        buf.put((byte) ((bytes.length) & 0xFF));
        buf.put(bytes);
    }
 
    /**
     * 对堆外缓存的字符串进行反序列化
     *
     * @param buf 字节数组所在的 ByteBuffer
     * @return 字符串对象.
     */
    @Override
    public String deserialize(ByteBuffer buf) {
        // 判断字节数组的长度
        int length = (((buf.get() & 0xff) << 8) + ((buf.get() & 0xff)));
        byte[] bytes = new byte[length];
        // 读取字节数组
        buf.get(bytes);
        // 返回字符串对象
        return new String(bytes, Charsets.UTF_8);
    }
}
View Code

相关文章:

  • 2023-02-11
  • 2022-12-23
  • 2022-12-23
  • 2021-06-01
  • 2021-12-26
  • 2021-09-19
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2021-12-20
  • 2022-12-23
  • 2021-04-26
  • 2021-05-02
相关资源
相似解决方案