2020年7月26日 星期日

off-heap memory方式處理大量資料

如果真的有需要在JVM操作大量資料,又怕heap設定太大造成GC會STW(Stop the World),另一種做法是使用off-heap memory方式,把資料處理拉到OS層級,節省了記憶體的代價就是犧牲速度。

Off Heap Cache - OHCache - Simple Example
https://www.isaacnote.com/2018/09/ohcache-simple-example.html 

OHC - An off-heap-cache
https://github.com/snazy/ohc
OHCacheBuilder
https://github.com/snazy/ohc/blob/master/ohc-core/src/main/java/org/caffinitas/ohc/OHCacheBuilder.java
public OHCache<K, V> build()
{
    if (fixedKeySize > 0 || fixedValueSize > 0|| chunkSize > 0)
        return new OHCacheChunkedImpl<>(this); 
    return new OHCacheLinkedImpl<>(this); 
}


使用堆外内存优化JVM GC问题小记
https://juejin.im/post/5cdf8df4f265da1bd260bae9 
Java缓存类型
  • 堆缓存:使用java堆内存来存储对象,好处是不需要序列化/反序列化,速度快,缺点是受GC影响。可以使用Guava Cache、Ehcache 3.x、MapDB实现。
  • 堆外缓存:缓存数据存储在堆外,突破了JVM的枷锁,读取数据时需要序列化/反序列化,比对堆内缓存慢很多。可以使用Ehcache 3.x、MapDB实现。
  • 磁盘缓存:在JVM重启时数据还在,而堆缓存/堆外缓存数据会丢失,需要重新加载。可以使用Ehcache 3.x、MapDB实现。
  • 分布式缓存:没啥好说的了,Redis…

作者:xinlmain
链接:https://juejin.im/post/5cdf8df4f265da1bd260bae9
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Java 大内存应用(10G 以上)会不会出现严重的停顿?
https://www.zhihu.com/question/35109537

如果真的需要使用on-heap方式處理,可以參考HBase或Cassandra等的做法:
Tuning G1GC For Your HBase Cluster
https://blogs.apache.org/hbase/entry/tuning_g1gc_for_your_hbaseCDH6.3 
HBase: G1 GC Tuning with JDK11
https://blog.cloudera.com/cdh6-3-hbase-g1-gc-tuning-with-jdk11/ 
JVM 与 Hbase
https://www.selinux.tech/java/core/jvm-hbase 
Cassandra 3.0 Tuning Java resources
https://docs.datastax.com/en/cassandra-oss/3.0/cassandra/operations/opsTuneJVM.html
package ohcache;
import org.caffinitas.ohc.CacheSerializer;
import org.caffinitas.ohc.OHCache;
import org.caffinitas.ohc.OHCacheBuilder;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.UUID;
import java.util.stream.IntStream;
// 參考 https://www.isaacnote.com/2018/09/ohcache-simple-example.html
// 使用到Java Stream語法,需要JDK 8以上版本執行
public class SimpleMain {
public static void main(String[] params) {
Scanner scanner = new Scanner(System.in);
while(scanner.hasNextLine()) {
if (scanner.nextLine().trim().equals("GO")) {
System.out.println(Runtime.getRuntime().freeMemory()/1024/1024 + "/" + Runtime.getRuntime().totalMemory()/1024/1024);
//使用on-heap memory方式處理大量資料
//執行會Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
/*
Map<String, String> map = new HashMap<String, String>();
map.put("A", "A12345");
System.out.println(map.get("A"));
IntStream.range(0, 1000_000_000).forEach(idx -> {
map.put(UUID.randomUUID().toString(), UUID.randomUUID().toString()); });
*/
//使用off-heap memory方式處理大量資料
OHCache<String,String> ohc = OHCacheBuilder.<String,String>newBuilder()
.keySerializer(new StringSerializer())
.valueSerializer(new StringSerializer())
.build();
ohc.put("A", "A12345");
System.out.println(ohc.get("A"));
IntStream.range(0, 1000_000_000).forEach(idx -> {
ohc.put(UUID.randomUUID().toString(), UUID.randomUUID().toString()); });
System.out.println(Runtime.getRuntime().freeMemory()/1024/1024 + "/" + Runtime.getRuntime().totalMemory()/1024/1024);
} else {
System.out.println("input 'GO' then click enter");
}
}
} //end main
private static class StringSerializer implements CacheSerializer<String> {
@Override
public void serialize(String s, ByteBuffer byteBuffer) {
byteBuffer.put(s.getBytes());
}
@Override
public String deserialize(ByteBuffer byteBuffer) {
return StandardCharsets.UTF_8.decode(byteBuffer).toString();
}
@Override
public int serializedSize(String s) {
return s.getBytes().length;
}
}
}

2020年7月5日 星期日

sendStringParametersAsUnicode

JDBC預設是true,會自動把字元資料轉成Unicode格式送到伺服器
但是資料庫column不是開nchar之類的Unicode UCS-2欄位
因為SQL Server需要做型別轉換,會需要用到平行處理,會很耗cpu
從執行計畫可以看到"type conversion in expression"的警告訊息
解法一:column改成nvarvhar nchar這類的欄位
解法二:sendStringParametersAsUnicode設定成false,使用非Unicode格式送到伺服器(比如ASCII/MBCS)
今天上許致學老師的課才知道有這參數


"type conversion in expression" sql server