现有的主流的NoSQL存储系统,如Cassandra、BigTable、HBase等在RAM中直接使用跳表、队列或者树结构等方式来管理Key/Value键值对,整个Key/Value集合被称为MemTable。当MemTable中的数据大小达到阈值的时候会被写入磁盘。因为用户的写操作都是将数据写入MemTable,为了避免MemTable中的数据在转存到磁盘时导致用户写操作失败,在转储之前MemTable会将所有数据转存入一个Immutable MemTable,清空后的MemTable继续响应用户的操作,Immutable MemTable负责将数据转存到磁盘,当数据转存完成以后,Immutable MemTable就可以删除了。
之所以采用MemTable策略而不是把数据直接写入磁盘有以下的好处:
1.加快写入的速度。把数据写入内存的速度要比写入磁盘的速度快几个数量级。
2.加快读的速度。数据存在内存中,读取的时候直接从内存读取,避免了磁盘操作,提高了读的性能。
3.提高数据写入磁盘的效率。将多个数据一次写入磁盘要比多个数据分开写入要高效的多,因为多个数据一次写入避免了每次写数据时的磁盘寻到开销。
以上这种方式中,MemTable阈值的设置是一个问题。如果MemTable的阈值设置的过大,会有以下的缺点:
1.数据转储到磁盘的时间过长,会影响到这个期间其他线程或进程的读写操作;
2.当Immutable MemTable中的数据都转存到磁盘以后,MemTable中没有新数据写入的时候,会导致内存中短时间内没有可用的有效数据,从而导致大量的读操作需要进行磁盘访问,从而形成一个读操作的性能低谷。如果MemTable的阈值设置的太小,会有以下的问题:
1.内存的利用率会偏低;
2.在内存中有效数据较少,导致很多读操作需要去访问磁盘;
3.因为阈值较少,会导致数据转存到磁盘的操作频繁法发生。
为了解决以上的问题,本文设计了一种多MemTable的方案。该方案的核心思想就是系统运行的时候可以在内存中最多同时存在N个MemTable。在系统运行过程中,开始的时候数据会存储在第一个MemTable中,当该MemTable的数据存满以后会把数据存储在第二个MemTable中,当第二个MemTable存储的数据量达到阈值时,会以此类推的存在下一个MemTable中。当N个MemTable的数据都存满以后,会把最老的一个MemTable(也就是第一个MemTable)的数据转存到Immutable MemTable中,然后执行数据从内存转存到磁盘的操作。
假设在多MemTable方案中每个MemTable的大小为m,传统单MemTable方案中每个MemTable的大小为M,那么只要保证满足以下两个条件,就可以保证多MemTable方案有以下的优势:
I m<M
II.(m/M)*N>1
1.数据转储时间比单MemTable方案短;
2.内存利用率高;
3.即使刚发生完转储也不会出现因为内存中可用数据较少而导致频繁读磁盘操作。
多MemTable方案的缺点在于:如果发生断电情况,重启的时候需要从日志中恢复上一次的数据,由于内存中存储的有效数据较多,所以恢复时间会比传统的单MemTable方案要长。
如前所述,在本文中数据写入内存中的MemTable中即可认为写操作完成。本存储系统使用了多MemTable机制 。 以2个MemTable 为例说明从开始存储到转储的整个过程。如图 所示,数据首先被存放在MemTableA中,当MemTableA存放的数据量达到阈值会把新写入的数据存放在MemTableB中;当MemTableB存放的数据也达到阈值的时候会把MemTableA的数据存入Immutable中,为接下来的转储做准备 ;同时会生成一个新的MemTableC来存储新写入的数据。
在数据写入MemTable的时候,日志会把相关的操作记录下来,防止断电造成的数据丢失;当数据从内存转储到磁盘以后,相应的日志会被删除。
值得一提的是,这里的日志是写在机械磁盘上的,这是因为:其一机械磁盘的顺序写速度较快,性能较高;其二反复擦写对SSD的寿命不好。而此处的日志文件经常需要进行的是顺序写操作和文件的删除操作,只有当出现问题,下次开机恢复的时候才会读取日志文件恢复MemTable中的数据,所以此处将日志写入机械磁盘既不会对性能造成很大影响,也不会存在寿命的问题。