`

KV存储

 
阅读更多
KV-存储 之 Hash算法


http://www.cesclub.com/bw/jishuzhongxin/bianchengyuyan/2011/0924/10415.html



生活生计不是局限于人类寻求本身的实际目标所进行的日常步履,而是显示了人类参加到一种宇宙韵律中来,这种韵律以形形的体式格式证实其自身的存在。生活生计中你应当碰到如许的工作:  你要去近邻班级拿本书给某位同窗, 不巧的是他当时不在,你也不知道他的座位, 你会选择问离你比来的同窗,他坐哪. 他会毫不迟疑的答复你: 第几排第几个座位.  这是个很常见的例子, 然则里面却蕴含了极其巨大的Hash算法. 试想 那位同窗能在近似常数时候内帮你指出你要知道的那位同窗的地位是因为所有同窗的地位他已经记在思维中了(假设全部).  他不会去从第一排第一个地位慢慢去搜刮.而是直接定位. ---- 哈希 又叫 散列 

一小我只要他有纯粹的心灵,无愁无恨,他的芳华时代定可是以而耽误。策画机中内存接见速度很快,假如有个64G大小的内存,我须要接见内存中的cache的一段, 想在O(1)时候内进行定位,就须要Hash的帮助。






持续经由过程上方的例子不和得出:

(1).要想进行Hash搜刮 必须先记住每个元素的地位


(2).要想哄骗策画机存储器记住每个元素的地位,必须分派必然的空间来存储这些地位.


(3).要想知道每个元素的地位在哪,必须有个好的Hash算法进行策画每个元素的地位.


这三点可以说浓缩了Hash的精华, 下面首要讲Hash算法.因为是它决意了Hash的短长.




Hash算法(v1~v8为整数)




如图所示, v1~v8 ,8个值 经由过程Hash Alg 得出Hash 桶, 这里Hash Table就像个数组, v1在 索引 0 地位 ...v8在索引 7 地位. 今后 就可以经由过程0~7(key) 对其进行常数时候内的查找了.


这是一个斗劲简单的Hash,也是一个幻想的Hash,为什么说是幻想呢? 请看下面的这张图.



如图所示,假如有10W个值,甚至更大,遵守前面的Hash算法就须要开辟10W个大小的空间(Hash Table).若是元素更多,开辟的空间就更多,显然这不是一个好算法,然则 这又是速度最快的算法,因为查询随便率性元素都在O(1)内.  这是个空间换时候的思惟,然则空间也是有限的,如何调和这是个值得思虑的题目.


当HashTable必然, 哈希的元素个数 <=  HashTable的空间大小 , 则可以在有限的HashTable内 哈希的元素对应不合的索引.

当HashTable必然, 哈希的元素个数  >    HashTable的空间大小,  则会有2个或多个以上的元素被映射到 雷同的索引上. 如下图:



须要哈希的&#20540;v5 和 v9产生了冲突, vv10产生了冲突. 这个冲突就是我们要解决的,冲突的频率决意了一个Hash算法的短长. 冲突越多,Hash算法效力越低. 

其实冲突是不成避免的,比如说,刚才这个例子,我们须要存放10个元素, 而HashTable中只有8个, 幻想景象是须要 10 个HashTable的地位 , 我们可以 对 8 进行取模H(v) = V mod 8 生成的成果会都在0~7之间.

这种Hash算法可以称为 取模Hash ,这种算法很简单,Hash速度很快, 然则 缺点很大,1. 斗劲合适Key为整数景象 2. 若是HashTable的元素数量选的不敷好 则轻易造成分布不均匀,比如 HT(HashTable)的元素数量为 2 的倍数, 须要哈希的元素都为偶数,那么所有 !(X % 2 == 0) 的地位都为空. 为了避免这种景象,凡是包管表的大小为素数.

若是Key为字符串,凡是做法是把字符串中的字符的ASCII码加起来.然后把累加的&#20540;与HT的大小进行取模 .


#define HTSIZE 10007 //为素数
int htV (char* key) {
int i = 0;
int sum = 0;
for (; key[i]!=""""; i++) {
  sum += (int)key[i];
}

return sum % htSize;
}上方就是对字符串进行Hash的一段代码.然则这个Hash函数分布也不是很均匀,假设key最大为8字节长. char的最大&#20540;为127, 是以可以得出Hash函数能在0 ~ 127*8(1016) 之间获得. 冲突率很是高.持续看一段代码.


#define HTSIZE 10007
int htV_better (char* key) {
u16 sum= 0;
while (*key!="""") {
  sum= (sum<<5) + *key++;
}

return sum % htSize;
}
这段代码应用了Horner法例:

假设有n&#43;2个实数a0,a1,…,an,和x的序列,要对多项式Pn(x)= anx ^n&#43;a(n-1)x^(n-1)&#43;…&#43;a1x&#43;a0求&#20540;,直接办法是对每一项分别求&#20540;,并把每一项求的&#20540;累加起来,这种办法十分低效,它须要进行n&#43;(n-1)&#43;…&#43;1=n(n&#43;1)/2次乘法运算和n次加法运算。有没有更高效的算法呢?答案是必然的。经由过程如下变换我们可以获得一种快得多的算法,即Pn(x)= anx ^n&#43;a(n-1)x^(n-1)&#43;…&#43;a1x&#43;a0=((…(((anx &#43;an-1)x&#43;an-2)x&#43; an-3)…)x&#43;a1)x&#43;a0,这种求&#20540;的安排我们称为霍纳法例

下面是该评论辩论下解决Hash冲突的题目了,总结一下有下面几种解决Hash冲突的办法.

链地址算法:

这个是解决冲突最常见的办法,所谓开放是指每个桶都可以进行"开放", 经由过程把桶起冲突元素用链表链接在一路. 如下图. 如许空间斗劲随便




Index = 4 这个地位 ,有3个元素起了冲突,遵守时候插入次序依次分列.

检索过程其实就是Hash&#43;List的过程.先定位到H(v5) 若是则返回.不是则持续读下一个.插入数据时,若是遵守"次序思维"须要一个元素一个元素的遍历下去直到下一个指针为NULL,固然链表进行的是一个线性操纵,然则若是冲突较少,也就是链表较短,效力也是很高的, 其实也可以推敲下链表的特点,我们可以插入在头部,如许插入就为O(1), 效力也就进步上去了. SGI STL中hash table用的就是这种算法。

再经由过程下面的图一步一步熟悉下 开放链地址法

Hash Table初始化为 13 个桶 (从0开端 0~12),Hash算法为对Hash table 取模

Step 1:

向hash Table中插入 1, 2, 3, 4, 5 这5个元素

插入地位分别为 1%13, 2%13, 3%13, 4%13, 5%13



Step 2:

向Hash Table中插入 13, 100

插入的地位为 13%13, 100%13




如图所示,进行模运算后 100地位在 第10个地位,那么如今我插入 9 再看下:




可以看出,在第10个地位生成了一个链表,元素地位是按照时候来入的,就像一个Stack!

如今我们来查找 100 这个元素:

   ------> 形象的描述了 链表的遍历过程





开放定址算法

若是h(k)已经被占用,则按如下序列探查:(h(k)&#43;p(1))%TSize, (h(k)&#43;p(2))%TSize, …,(h(k)&#43;p(i))%TSize,…


此中,h(k)为哈希函数,TSize为哈希表长,p(i)为探查函数。在 h(k)&#43;p(i-1))%TSize的根蒂根基上,若发明冲突,则应用增量 p(i) 进行新的探测,直至无冲突呈现为止。此中,按照探查函数p(i)的不合,开放定址法又分为线性探查法(p(i) = i : 1 , 2 , 3 , …),二次探查法(p(i)=(-1)i-1((i&#43;1)/2)2: 12 , -12 , 22 , -22 …),随机探查法(p(i): 随机数 ),双散列函数法(双散列函数h(key) ,hp (key)若h(key)呈现冲突,则再应用hp (key)求取散列地址。探查序列为:h(k), h(k)&#43; hp(k),…, h(k)&#43; i*hp(k)). --- <百科>


线性探测法:

p(i) = 1, 2, 3 (<TSize-1) 也就是 通项式为 p(i) = i

当发明冲突时 应用p(i)函数进行新的探测,每次移动一个元素,直到无冲突为止.来形象的看下具体过程:

初始化Hash为29个,取模Hash

Step 1: 插入 1




Step 2: 再插入 1



可以看到 1 被放置于 2 的地位,假如2的地位已经有2了 那么1会被放置在哪呢? 我们返回后再来看下成果。

1被放置了2的后面。这个按照(1&#43; p(2)) % 29 可以得出。

二次探查法


通项式为:p(i) = 1,1,4,-4,9,-9 (i*i,-i*i)  [<Tsize/2]


我们插入1,1,1 来看下元素分派:




若是再插入两个1后插入一个5 再插入一个1呢,应当还是再次遵守二次探查法来进行下一步的操纵.




随机探查法


把p(i)从线性探测改成随机数(伪随机) p(i) = Random ,其它类&#20284;。




KV-存储

Hash在存储中应用,也就是KV(key-value)存储,因为Hash本身的限制,KV存储也只能支撑Put, Get, Del几个原语操纵。 然则也已经足够了。

KV存储实现不难,然则有一些器材须要重视,可以让效力提拔一个阶层。

(1). Put操纵时若是你进行及时写,效力很一般,然则你若是应用次序读入内存再批量写入磁盘,速度会提拔很多,也就是所谓的延迟写操纵和批处理惩罚化,这点可以参看Google开源的LevelDB

http://code.google.com/p/leveldb/

,LogTree算法

http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.44.2782


(2).Get操纵建议应用mmap,因为文件映射就&#20284;直接读内存差不久不多(道理是把文件调入过程的地址空间,本博有具体解析)

(3).Del操纵建议直接做标识表记标帜,因为数据量大,不建议直接做真正删除操纵,因为如许会很轻易形成内存碎片. 当然若是你承认本身机制做的好的话可以进行直接删除,然后一按时辰 进行碎片收拾。

分享到:
评论

相关推荐

    一款Java分布式KV存储系统源码.zip

    《深入解析Java分布式KV存储系统源码》 Java分布式KV(Key-Value)存储系统是现代互联网服务中不可或缺的一部分,其高效、可扩展的特性使其在大数据处理、缓存服务等领域广泛应用。本篇文章将深入剖析一款基于Java...

    分布式 KV 存储系统 Cellar 演进之路--美团.pdf

    ### 分布式KV存储系统Cellar演进之路 #### Cellar起源 Cellar作为一个分布式键值(Key-Value, KV)存储系统,最初起源于美团在2014年初引入阿里巴巴的Tair作为NoSQL存储解决方案的过程。随着业务的发展,Tair在美团...

    cpp-Zeppelin奇虎360出品的高性能分布式KV存储平台

    **cpp-Zeppelin奇虎360出品的高性能分布式KV存储平台** Zeppelin是由奇虎360公司研发的一款高效、可扩展的分布式键值(KV)存储系统,旨在为大规模数据处理提供强大的支撑。这款数据库系统是用C++语言编写的,体现...

    基于LSM树的KV存储综述1

    摘要:伴随着数据量的大规模爆发和云计算的快速发展,早期由于缺乏标准化和其他问题而发展缓慢的键值存储(keyvaluestorage,KVStorage)进入了飞

    Go-Redix一个非常快速的持久化支持的KV存储使用与redis相同的协议

    《Go-Redix:高速持久化KV存储与Redis协议兼容详解》 在现代软件开发中,Key-Value存储系统因其简单高效的特点,被广泛应用在缓存、数据存储等多个场景。Redis作为一款广受欢迎的Key-Value数据库,其丰富的功能和高...

    Rust实现KV存储系统

    以下是对这个KV存储系统实现的关键知识点的详细说明: 1. **Rust与dashmap**: Rust是一种系统级编程语言,强调零成本抽象和内存安全。在这个KV存储系统中,我们选择了dashmap库来实现键值对的存储。Dashmap是一个...

    小米KV存储系统Pegasus

    ### 小米自研分布式KV存储系统Pegasus详解 #### 背景介绍 随着互联网技术的迅猛发展,海量数据的高效存储与处理成为各行业面临的共同挑战。尤其是在大规模在线服务场景下,如广告系统、支付平台等,对数据存储系统...

    万亿级KV存储架构与实践.pptx

    万亿级KV存储架构与实践 基于美团点评的KV存储架构和实践,涵盖了 KV 存储发展历程、内存KV Squirrel架构和实践、持久化KV Cellar架构和实践、发展规划和业界趋势等方面的知识点。 一、KV 存储发展历程 KV 存储是...

    cpp-FlyDB一个基于C语言实现的kv存储

    【FlyDB:C语言实现的键值存储系统】 FlyDB是一个用C语言编写的轻量级键值(Key-Value)存储系统,它为开发者提供了一种高效、简单的方式来存储和检索数据。作为NoSQL数据库的一种,FlyDB不遵循传统的表格型数据库...

    基于C++11和跳表的KV存储引擎项目源码+文档说明.zip

    基于C++11和跳表的KV存储引擎项目源码+文档说明.zip基于C++11和跳表的KV存储引擎项目源码+文档说明.zip基于C++11和跳表的KV存储引擎项目源码+文档说明.zip基于C++11和跳表的KV存储引擎项目源码+文档说明.zip ...

    云音乐分布式KV存储实践和演进共21页.pdf.zip

    【云音乐分布式KV存储实践和演进】 在现代互联网服务中,尤其是音乐流媒体平台,海量数据的存储和快速访问是关键。云音乐通过采用分布式KV(Key-Value)存储系统,解决了这个问题,实现了高效、高可用的服务。...

    KV存储系统介绍1

    在IT领域,KV存储系统是一种常见的数据存储解决方案,主要用于处理键值对形式的数据。这种系统设计简洁,易于操作,适用于大量快速读写操作。本文主要围绕KV存储系统的网络通信机制、事件处理模型以及Linux缓存IO...

    基于Raft的简易分布式KV存储系统源码+项目使用说明.zip

    基于Raft的简易分布式KV存储系统源码+项目使用说明.zip 该项目是个人毕设项目,答辩评审分达到95分,代码都经过调试测试,确保可以运行!欢迎下载使用,可用于小白学习、进阶。 该资源主要针对计算机、通信、人工...

    Tendis SSD高性能KV存储

    Tendis存储版是腾讯互娱CROS DBA团队 & 腾讯云数据库团队 自主设计和研发的开源分布式高性能KV存储。Tendis存储版完全兼容redis协议,并使用rocksdb作为存储引擎。同时,Tendis存储版支持远超内存的磁盘容量,可以...

    Go 基于 Raft 共识算法的分布式可靠的 KV 存储系统源码.zip

    本压缩包“Go基于Raft共识算法的分布式可靠的KV存储系统源码.zip”包含了一个使用Go实现的基于Raft的键值对(KV)存储系统,名为gokvs-master。下面将详细介绍这个系统的关键知识点。 1. **Raft共识算法**:Raft是...

    go语言编写的兼容redis协议的kv存储

    本文将深入探讨一个基于Go语言编写的、兼容Redis协议的KV存储系统,它允许开发者利用Go语言的高效性能和Redis的强大功能进行数据管理。 标题中的“go语言编写的兼容redis协议的kv存储”意味着这个系统采用了开源...

    磁盘的KV存储 JDBM2.7z

    《磁盘的KV存储:深度解析JDBM2》 在计算机科学中,键值对(Key-Value,简称KV)存储是一种常见的数据存储模型,它以键为索引,以值为数据,提供快速的查找和访问。JDBM2是其中的一款开源实现,专为磁盘上的KV存储...

    基于C++11语言的集群KV存储数据库WSS_REDIS设计源码

    该项目为基于C++11语言的集群KV存储数据库WSS_REDIS设计源码,总计包含101个文件,涵盖37个头文件(.h)、31个C++源文件(.cpp)、9个JSON文件(.json)、4个Shell脚本文件(.swp)、3个Markdown文件(.md)、1个Git...

    基于raft的高可用kv存储系统,golang实现,适应于深入理解redis

    基于 Raft 的高可用 KV 存储系统是一种分布式存储解决方案,利用 Raft 共识算法实现数据的一致性和容错能力。该系统通常被设计成支持高并发、自动容错、数据持久化,能够应对分布式环境中的故障。以下是该系统的资源...

Global site tag (gtag.js) - Google Analytics