标签:page alt 原来 kill 方式 通过 参数 还需要 address
这篇纯碎是碎碎念记录。
每个value都是4KB,总共最多会写6400W个value,算下来就是64 * 1000 * 1000 * 4 * 1024 Bytes ≈ 256G。
每个value存储到文件中的时候,需要知道它在文件中的位置,这个位置是一个长整型,8 Bytes。Key也是8 Bytes。这两个值要放在一起,以便我们能在内存中构建起一对一的索引。而它们的存储所耗的最大空间是(8 + 8) * 64 * 1000 * 1000 Bytes ≈ 1G。
Key和Value还需要落盘,所以它们也需要大约1GB的磁盘空间。
以上是大佬写的,我的初始实现是magic2 + key8 + magic2 + pos4落盘
感觉浪费了四个magic位,不过这四位只会存盘不会存到内存。
4*8的整型数值存储为是2GB地址空间[带符号位,可以删除扩充到4GB],然后2GB*4096位的长度,实际上可以存8T的磁盘,如果删除符号位可以存16T磁盘,应对测试环境的6400W条数据没有问题,灵位内存用key8+pos4,可以相对减少内存占用。
测试过程发现
Exception in thread "Thread-45" java.lang.ClassCastException: java.util.HashMap$Node cannot be cast to java.util.HashMap$TreeNode
at java.util.HashMap$TreeNode.moveRootToFront(HashMap.java:1832)
at java.util.HashMap$TreeNode.putTreeVal(HashMap.java:2012)
at java.util.HashMap.putVal(HashMap.java:638)
at java.util.HashMap.put(HashMap.java:612)
at org.lee.MappedPageSource.lambda$initKeys$0(RaceConcurrentHashMap.java:1362)
at java.lang.Thread.run(Thread.java:882)
多线程加载key-index文件的过程中,多线程put到一个hashmap会引发上述问题,多个线程修改同一映射,使用同步锁,顺序put解决
不需要,因为key-pos内存的键值覆盖会直接覆盖value的pos位置,这样,一个键值映射的value文件位置是不变的,所以key-index文件中,不存在相同key的数据块。
目前使用洁净的文件策略,由于mappedbyteBuffer的分配尽量以大数据块为主,所以存在kill -9情况下没有进行truncate的问题
请求的操作无法在使用用户映射区域打开的文件上执行 java nio
使用mappedbyteBuffer的缓存之后,尝试去关闭,报错,原来还在读的地方使用了buffer没有及时关闭导致的问题。
public byte[] readValue(int address) {
if(address % 50000 == 0 && System.currentTimeMillis()%5000==0)
log.info("{}", address);
long pos = address<<VALUE_BIT;
byte[] result = new byte[1<<VALUE_BIT];
long size= 0;
try {
size= raf.length();
raf.seek(pos);
raf.read(result);
} catch (Exception e) {
log.info("ADDRESS={} POS={} len={}", address, pos, size);
e.printStackTrace();
}
return result;
}
这里数量增长之后偶尔在seek操作时报错,java.io.IOException: Negative seek offset
因为存在内存中的position是int整型,映射文件position是乘以地址块4K(右移12),所以这里传参用整型,但是问题在于<<12之后是int这时候就会溢出了显示pos是一个负数。最后类型申明改为long就不会溢出了。【后来改用filechaanel进行pos位置的直接读取】
640W的数据,调整了 initialCapacity 值之后,不会引起rehash操作,这个比较耗时
Connected to the target VM, address: '127.0.0.1:53096', transport: 'socket'
13:37:30,512 INFO org.lee.MappedPageSource.initKeys(RaceConcurrentHashMap.java:1343) - 0
13:37:30,556 INFO org.lee.disk.App.test(App.java:30) - start write
13:40:46,510 INFO org.lee.disk.App.test(App.java:35) - write elapsed 3115 ms
13:43:34,460 INFO org.lee.disk.App.test(App.java:43) - detach assert read elapsed 363903 ms
https://blog.csdn.net/keketrtr/article/details/74448127
使用jvisualvm的插件GC进行判断,设置参数平截图,减少GC问题
以下是四张图,表示顺序写入+顺序读取640W次数的过程
-server -Xms1536m -Xmx1536m -XX:MaxDirectMemorySize=512m -XX:MaxMetaspaceSize=300m -XX:NewRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:-UseBiasedLocking
-server -Xms1876m -Xmx1876m -XX:MaxDirectMemorySize=512m -XX:MaxMetaspaceSize=300m -XX:NewRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:-UseBiasedLocking
-server -Xms1876m -Xmx1876m -XX:MaxDirectMemorySize=512m -XX:MaxMetaspaceSize=128m -XX:NewRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:-UseBiasedLocking
线上64CPU, ssd云盘,它的IO性能和CPU性能和本地机器没有任何可比性,于是本地640W写入过程中,速度改善的方法,在线上可能速度变慢。
最后经过总结,云盘SSD的IO通道能同时支持大写文件的并发写入读取,由于IO足够,写入的时候如果是多文件写入,可以减少文件写入锁带来的占用问题,而线下环境中,IO性能差劲,单文件的写入效果远胜于多文件的写入。对于读取性能,线上环境直接使用CPU缓存进行二进制的读取,不使用缓存的方式远胜于使用内存缓存MappedByteBuffer的方式,而线下环境中,如果使用内存缓存,读取的性能会更好,这里主要差别在于64核CPU的计算和缓存速度与本地CPU的不同。
PolarDB阿里初赛问题记录 PolarDB 阿里 中间件 比赛 性能 工程手册
标签:page alt 原来 kill 方式 通过 参数 还需要 address
原文地址:https://www.cnblogs.com/lijianming180/p/12371144.html