OHC系统吞吐提升

单机想突破性能瓶颈,即使用上Redis,ES这些缓存神器,但是也无法突破网络操作的耗时瓶颈,项目中的基础数据可考虑堆外缓存,整体提升系统吞吐,同时又不用担心GC导致JVM响应变慢,系统接口也跟着变慢。

package com.iamdog.rest;

import com.alibaba.fastjson.JSON;
import javafx.util.Pair;
import org.caffinitas.ohc.OHCache;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * OHC堆外内存管理接口
 *
 * @author iamdog
 */
@RestController
@RequestMapping(value = "/iamdog/ohc")
public class IamDogOHCManageController {

    @Resource(name="dogOHCache")
    private OHCache ohCache;

    @RequestMapping(value = "/get.app.do")
    public String get(@RequestBody String key) {
        return (String)ohCache.get(key);
    }

    @RequestMapping(value = "/batchGet.app.do")
    public String batchGet(@RequestBody List<String> keys) {
        List<Pair> results=new ArrayList<>();
        keys.stream().forEach(key->{
            String value=(String)ohCache.get(key);
            Pair p=new Pair(key,value);
            results.add(p);
        });
        return JSON.toJSONString(results);
    }

    @RequestMapping(value = "/set.app.do")
    public String set(@RequestBody Pair pair) {
        ohCache.put(pair.getKey(),pair.getValue());
        return "OK";
    }

    @RequestMapping(value = "/batchSet.app.do")
    public String batchSet(@RequestBody List<Pair> pairs) {
        pairs.stream().forEach(pair->{
            ohCache.put(pair.getKey(),pair.getValue());
        });
        return "OK";
    }

    @RequestMapping(value = "/remove.app.do")
    public String remove(@RequestBody String key) {
        ohCache.remove(key);
        return "OK";
    }

    @RequestMapping(value = "/batchRemove.app.do")
    public String batchRemove(@RequestBody List<String> keys) {
        keys.stream().forEach(key->{
            ohCache.remove(key);
        });
        return "OK";
    }

    @RequestMapping(value = "/clear.app.do")
    public String clear() {
        ohCache.clear();
        return "OK";
    }

    @RequestMapping(value = "/status.app.do")
    public String status() {
        ohCache.clear();
        return "Capacity:"+ohCache.capacity()/1024/1024+"MB,"
                + "freeCapacity:"+ohCache.freeCapacity()/1024/1024+"MB";
    }
}

堆外内存配置类:

package com.iamdog.config;

import com.iamdog.cache.MyOHCStringSerializer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.caffinitas.ohc.Eviction;
import org.caffinitas.ohc.HashAlgorithm;
import org.caffinitas.ohc.OHCache;
import org.caffinitas.ohc.OHCacheBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @Author: iamdog
 * @Description: 堆外内存OHC配置
 * @Date: Created At 2021-10-18 11:16
 * @Modified By:
 */
@Slf4j
@Configuration
public class MyOHCConfig {


    @Value("${iamdog.ohc.capacity}")
    private int capacity;

    @Value("${iamdog.ohc.ttl}")
    private int ttl;


    /**
    * @Author: iamdog
    * @Description:
     *  OHC介绍文档https://github.com/snazy/ohc
    * @Date: Created At 2021-10-18 14:51
    */
    @Bean("dogOHCache")
    public OHCache getOHCache(){
        return OHCacheBuilder.<String, String>newBuilder()
                .keySerializer(new MyOHCStringSerializer())
                .valueSerializer(new MyOHCStringSerializer())
                .hashMode(HashAlgorithm.CRC32C)
                //单位是字节,默认2GB空间
                .capacity(capacity*1024*1024*1024L)
                .timeouts(true)
                .defaultTTLmillis(ttl*1000)
                //"LRU" 最近最少使用的, "W_TINY_LFU" 使用频率较低的条目被逐出
                .eviction(Eviction.W_TINY_LFU)
                .build();
    }

}
 

序列化类:

package com.iamdog.cache;

import org.caffinitas.ohc.CacheSerializer;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

/**
 * @Author: iamdog
 * @Description:
 * @Date: Created At 2021-10-18 16:43
 * @Modified By:
 */
public class MyOHCStringSerializer implements CacheSerializer<String> {

    /**
     * 计算字符串序列化后占用的空间
     *
     * @param value 需要序列化存储的字符串
     * @return 序列化后的字节数
     */
    @Override
    public int serializedSize(String value) {
        byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
        // 设置字符串长度限制,2^16 = 65536  8KB
        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(StandardCharsets.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, StandardCharsets.UTF_8);
    }
}

参考博客:OHC Java堆外缓存详解与应用 - 星火燎原智勇 - 博客园

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值