对磁盘或者存储和性能造成挑战有两点:
1. 大数据存储
2. 数据分布不均。
1.浪费磁盘,2读取写入的性能较低。
目前的存储服务器管理磁盘的方法通常具有以下方法:
1. Hash桶挂接固定块大小的块, 分配的块都是固定大小,linux内核也是采用这种方法。很多的管理算法都是在这一方法上的变体,改进等。
2. Hash桶方法,按照不同的规格固定大小的块,具有块合并,回收系统,glibc采用的方法。
首先遇到的问题:
1. 固定块,块大小如何选择?
如何使得即具有高性能,又不造成空间的浪费。这里的一般选择是4K大小的块,因为linux的磁盘读写驱动是以4k为大小为单位进行读写的,磁盘也是以4k为大小为基准单位进行划分的。每次读写4k的块,系统的读写的性能很高。
如果数据大小平均为1k呢?这时如果选择4k大小的存储块,就会有75%的空间浪费,这个如何取舍呢?需要采用不同的规格的数据块的机制来补充。
定长的数据块组织图:
首先每个块都是分配在一个统计的管理链条中,首先是每个块必然存在于双向LRU中,这是最经典的淘汰策略了,每次淘汰就可以时间最久的那个淘汰。对于每个hash桶上挂载的一个存储块,也组成一个双向链表。对于每个hash桶上的记录也需要组成LRU链。还有一种方法就是把每个存储管理在堆中,但是这种数据结构要复杂一些,不易掌控,因此目前实际应用中很少采用这种实现。
对于数据的key来说,只有一个节点,但是对于其数据库来说,就不止一个块了。因此将key的数据库挂载到hash桶中,但是真正每个key的数据库却保存另一个系统中。
每个key都对应了一些数据保存在数据块管理单元中。对于数据单元的实现最重要,是数据组织的核心。这部分的管理涉及到空间的利用和磁盘的读写性能。
2. 如果采用不同规格的数据块大小,则性能将受到很大影响。
采用不同规格的数据库的大小的实现方案,大多都是基于glibc风格实现的。实现的方式如下:
采用64 字节128字节,256,512,768,1024,4096作为几种规格,实际中的规格不是这么大,因为考虑到一些数据结构的消耗,因此不同的规格的数字大小有所变化。
这种风格相当于管理了多个数据块组成的单元。这种方式更复杂,性能更高,能够做到高效率的利用存储空间。通常内存是比较短缺的资源,因此glibc为了高效的使用内存,因此采用这种方式分配内存。
对于保存数据的存储块来说,每个记录都有一个基本块和溢出块,基本块内部存储了很记录。当基本块使用完后,就要使用溢出块,当溢出块使用完后,无法在写入数据,必须分裂数据,这种机制会有一个问题:
如果每个记录的大小不一致,分布不均的话,就有可能导致某些桶上的存储块快速用满,当这些桶节点用满后,性能开始下降,因为分配不到存储空间。这时就需要迁移数据,而整体的数据库的使用率还很小。有时存储空间的利用率只有30%。因此这种模式有待改进。
原来的分配的机制最明显的特性是,没有考虑到数据大小的分布,所有的桶的分配存储空间是固定,是平均分配的思想。这也是问题的根源。因此要将平均分配改成按需分配。数据大的桶多分配,数据小的少分配。因此采用如下机制:
每个桶分配相同的基本块,将溢出块作为一个整体放在一个溢出池中,如果有基本块用完了的话,就从一个溢出池获取中。这样避免了基本库使用完了,溢出块也可以合理使用。
当存储记录不均匀时,记录较大的如果基本块用完,其使用较多的溢出块。这样就解决了当记录很大时,导致需要分裂,扩容,迁移等运维操作。