Contents

这篇纯碎是碎碎念记录。

每个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,可以相对减少内存占用。

测试流程

  1. 写入64W数据,读取64W数据
  2. 重启进程,读取64W数据
  3. 重启进程,读取64W数据过程中kill -9进程,然后再行重启读取64W

测试过程发现

  • 1 失败 1成功 2 成功 1成功 2 成功 1成功 2 成功
  • 1 成功 1失败 2 失败 1失败 2 失败 1失败 2 失败
  • 初次操作,使用<byte[], Integer>组装concurrenthashmap,但是调整一直出错,自己的测试有毛病,提交测试之后还通过正确性测试。
  1. 以上两项测试的原因在于,同内存写入的时候,进行读取的操作,key值的内存数值一样,所以在第一次1里面成功。但是进程重启之后,byte[]的hashcode是会随着进程的不同而变化的,所以找不到key,进行get时候会报空。
  2. 没有覆盖的问题:我在写入key的时候,如果是覆盖性操作,就将值写入到oldPosition位置,但是发现连续进行1的测试流程时候,值并未覆盖到oldPosition,文件同样会增长,key数量也会增长,并未进行覆盖key操作。经过调试,发现byte[]的操作太过风骚,从文件读取出来的byte[]和测试生成的byte[]的来源不一样,所以hashcode不一样,同时也用到equal操作,于是也要重写equal操作,使用Array.equal代替。
  3. 发现byte[]直接写入hashmap会读取不到,对于基础类型数值,hashcode值每次jvm进程中数值都不一样,这影响key的分布和查找
    于是使用bytebuffer,正确性检查没问题,不过超时,主要是因为性能太差,byte[]与bytebuffer的转换过程不能忍受
  4. 回归使用byte[],解决了hashcode的问题[仿照bytebuffer重写hash]之后,发现equal函数也不一样,会调用原生的==进行判断,于是改用array.equal进行判断
  5. byte[]还是出问题,写入6400w的阶段总是读取校验出错,打印出数量不够6400W,总是差300-400个,然后发现,hashcode函数有问题,,重写,检验了3亿个hash值,确定不会重复之后提交,总算通过,最后成绩243.44秒,最好排35名,最差到55名

并发问题

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-index文件是否需要顺序加载

不需要,因为key-pos内存的键值覆盖会直接覆盖value的pos位置,这样,一个键值映射的value文件位置是不变的,所以key-index文件中,不存在相同key的数据块。

key的覆盖和value的覆盖

目前使用洁净的文件策略,由于mappedbyteBuffer的分配尽量以大数据块为主,所以存在kill -9情况下没有进行truncate的问题

  1. 对于正常结束,调用truncat进行keyfile和valueFile的截断
  2. 强制退出情况下,下次初始化时候,加载key文件,对非MAGIC开始的字节,进行一刀 大专栏  PolarDB阿里初赛问题记录 PolarDB 阿里 中间件 比赛 性能 工程手册切,后续字节被truncate,相应的后续value文件被截断,正确初始化count数量,便于下次写value的时候,写入count自增的地址

mappedbyteBuffer的回收

请求的操作无法在使用用户映射区域打开的文件上执行 java nio

使用mappedbyteBuffer的缓存之后,尝试去关闭,报错,原来还在读的地方使用了buffer没有及时关闭导致的问题。

int long溢出问题

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次数的过程

增加jvm参数

-server -Xms1536m -Xmx1536m -XX:MaxDirectMemorySize=512m -XX:MaxMetaspaceSize=300m -XX:NewRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:-UseBiasedLocking

无参数,使用intellij默认

只增加内存大小

-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 阿里 中间件 比赛 性能 工程手册的更多相关文章

  1. PolarDB · 新品介绍 · 深入了解阿里云新一代产品 PolarDB

    背景意义 云计算为如今的互联网时代提供了更多的计算能力,乃至创造能力,关系型数据库作为所有应用不可或缺的重要部件,开箱即用,高性价加比特性的云数据库深受开发者的喜爱.作为一线的开发和运维人员,在阿里云 ...

  2. 阿里RocketMq试用记录+简单的Spring集成

    CSDN学院招募微信小程序讲师啦 程序猿全指南,让[移动开发]更简单! [观点]移动原生App开发 PK HTML 5开发 云端应用征文大赛,秀绝招,赢无人机! 阿里RocketMq试用记录+简单的S ...

  3. 云计算之路-阿里云上:访问阿里云CDN上的图片,自动跳转到百度首页

    昨天有用户向我们反馈一篇博文(一条语句导致CPU持续100%)中的部分图片不能显示,我们的图片访问用的是阿里云CDN,原以为是某个CDN节点不稳定的问题,但在排查时发现这些图片不能显示竟然是因为请求时 ...

  4. 阿里官方Java代码规范标准《阿里巴巴Java开发手册 终极版 v1.3.0》

    终极版 v1.3.0 2017年开春之际,阿里诚意献上重磅大礼:<阿里巴巴Java开发手册>,首次公开阿里官方Java代码规范标准.这套Java统一规范标准将有助于提高行业编码规范化水平, ...

  5. 阿里官方Java代码规范标准《阿里巴巴Java开发手册》下载

    https://bbs.aliyun.com/read/306592.html?page=e 2017年开春之际,诚意献上重磅大礼:阿里巴巴Java开发手册,首次公开阿里官方Java代码规范标准. 这 ...

  6. 阿里云云主机添加swap分区与swap性能优化

    1.swap的功能与相应内核参数 Linux 将物理内存分为内存段的部分被称作“页面”.交换是指内存页面被复制到预先设定好的硬盘空间(叫做交换空间)的过程,目的是释放用于页面的内存.物理内存和交换空间 ...

  7. 全能中间件 REST API 使用手册

    全能中间件 REST API 使用手册 Ver:17.6.24 技术支持QQ:64445322 QQ群:339616649    任何第三方应用或网站都可以通过使用开放API为用户提供实时优质的服务. ...

  8. react第十八单元(redux中间件redux-thunk,redux工程目录的样板代码,规范目录结构)

    第十八单元(redux中间件redux-thunk,redux工程目录的样板代码,规范目录结构) #课程目标 中间件:中间件增强redux的可扩展性,实现功能复用的目的. redux-thunk异步逻 ...

  9. 你有什么理由还不选择阿里云服务器呢--从阿里云发布自研商用关系型数据库POLARDB想到的

    最近几天,阿里云发布自研商用关系型数据库POLARDB的消息可谓是重磅炸弹啊.借用官方宣传的话就是:6倍性能于MySQL并100%兼容/100TB存储容量/2分钟创建只读副本/3分钟创建容灾实例,第三 ...

随机推荐

  1. requests.get()///post函数///base64函数

    1.requests.get() 一般的用法:r=requests.get(url) 或者是用上session: r=requests.session() r=r.get(url) get()收集的是 ...

  2. opencv python图片编码解码

    cv2.imdecode()函数从指定的内存缓存中读取数据,并把数据转换(解码)成图像格式;主要用于从网络传输数据中恢复出图像.cv2.imencode()函数是将图片格式转换(编码)成流数据,赋值到 ...

  3. 18 11 04 初用单片机 c语言学习

    ---恢复内容开始--- 1 作为单片机使用的的 c 语言学习 ++ 增位运算符 在原有基础上加一 -- 相同 由于单片机只有 ~ 取反 & 两个 参数里有没有 | 两个 参数里有没有 ^ 两 ...

  4. Ubuntu编译protobuf

    个人博客地址:http://www.bearoom.xyz/2019/08/24/ubunt-protobuf/ 因为编译了tensorflow C++的版本,然后提示protobuf的版本不对应引起 ...

  5. Django的模板变量

    变量的值来自context中的数据字典, 类似于字典对象的keys到values的映射关系. 变量是被}}和{{括起来的部分 变量看起来就像是这样: {{ variable }}. 当模版引擎遇到一个 ...

  6. 到头来还是逃不过Java - 流程控制

    流程控制 没有特殊说明,我的所有这个系列的Java13的笔记都是从廖老师那里摘抄.总结过来的,侵删 引言 兜兜转转到了大四,学过了C,C++,C#,Java,Python,学一门丢一门,到了最后还是要 ...

  7. springboot的http监控接口启动器的配置

    基于SpringBoot框架企业级应用系统开发全面实战()->03.07_http监控_recv.mp4 监控接口启动器 自定义监控接口启动器的配置 ====================== ...

  8. one_day_one_linuxCmd---wget命令

    <坚持每天学习一个 linux 命令,今天我们来学习 wget 命令> Linux wget 是一个文件下载工具,它用在命令行下,使用也非常方便,不但体积小而且功能完善,并支持很多强大的功 ...

  9. ZJNU 2208 - 你渴望力量吗

    在图的最外面套一层0(防止到头) 然后搜索图有多少块在 '0'有两块0,一块1 '1'有一块0,一块1 其余情况不存在 #include<stdio.h> ],dx[]={,,,-},dy ...

  10. JavaSE--【JAVA】unicode为12288字符

    转载:http://blog.csdn.net/zfpigpig/article/details/8186470 今天做一个导入数据功能时发现一个问题,就是一个unicode为12288的字符显示为空 ...