codeserf

记录工作、生活上的点滴

Java非托管堆存储数据

2013-02-22 posted in [编程语言]

当前随着Nosql的兴起,已经有大量的key-value存储或者缓存的系统,基本没必要重复造轮子,但是对于引入例如redis/memcached这样的系统,则必须使用其协议,不能重用现有的一套东西,所以想着开发一套Java的缓存系统。

一般的方案是通过HashMap这样的结构保存数据, 但是这样一般有两个问题,一是太浪费内存,java对象占用的空间太大。二是随着内存使用的增大,对于GC而已负担太大。所以我实现的方案是将大部分数据保存在非托管堆上,部分索引数据保存在托管堆上。

主要的Feature如下:

  • 将数据保存在非托管堆上,减少gc的消耗
  • 自动进行碎片整理
  • 使用读写锁保证线程安全

主要的实现细节如下:

数据储存

记录格式如下::

+--------------+------------------+
|     name     |      length      |
+--------------+------------------+
| magic number | 1byte            |
| next         | 8byte            |
| key size     | varint           |
| value size   | varint           |
| key          | <data>           |
| value        | <data>           |
| padding      | <not used space> |
+--------------+------------------+
  • magic number标识了记录是否被释放以及进行越界检查。
  • next为long类型,保存了冲突链表。
  • key size以及value size为varint编码,节省空间。
  • padding主要是由于在找到合适的空闲块的时候,如果有多余的空间没继续进行split。

记录存放在在NonHeap分配的数据段,每个数据段为固定大小,可以在初始化的时候指定。

索引记录

在DB被初始化的时候可以指定hashpower,其用于定于索引buckets的大小,根据预计的缓存量进行分配,如果太小,将导致冲突链增大,将极大的影响性能。

索引buckets为long类型的数组,buckets里的值保存记录在NonHeap数据区的偏移以及整个大小。前2个字节为大小,后2个字节为数据段的index, 最后4个字节为在数据段的偏移。

碎片管理

记录被删除后,将magic number置为删除状态,并按照其size有序的保存在分配在托管堆的TreeSet里。在下次分配记录空间的时候,先通过bestfit的方式查找到最适合的大小,复用原有的空间。

在碎片率到达一定程度后,将对数据段进行碎片整理,将多个碎片合并为一个碎片。

PS: 可以使用类似memcached slab分配器的方式分配内存,这样出现碎片的机率比较小。

项目地址在https://github.com/believe3301/NonHeapDB

-EOF-

measure everything , monitor everything

2013-02-17 posted in [Linux]

Python字符编码

2013-01-10 posted in [编程语言]

redis源码阅读

2012-12-24 posted in [Nosql]

软中断不均的调优

2012-09-11 posted in [性能调优]

dns介绍以及dig使用

2012-08-07 posted in [Linux]

通过strace分析zookeeper服务器端连接超时

2012-08-01 posted in [工具]

codeserfRSS feed

About

tiger yang

enjoy coding,enjoy life

Copyright

知识共享许可协议

Fork me on GitHub

Powered by

Disqus, GitHub, Google Custom Search, Gravatar, HighlightJS, jekyll