你要有一种观念:Hash是将不同值进行合并存储🤔,以加强查询效率!
将任意长度的二进制值串映射为固定长度的二进制值串,这个映射的规则就是哈希算法,而通过原始数据映射之后得到的二进制值串就是哈希值。
哈希算法需要满足的几点要求:
- 从哈希值不能反向推导出原始数据(所以哈希算法也叫单向哈希算法);
- 对输入数据非常敏感,哪怕原始数据只修改了一个 Bit,最后得到的哈希值也大不相同;
- 散列冲突的概率要很小,对于不同的原始数据,哈希值相同的概率非常小;
- 哈希算法的执行效率要尽量高效,针对较长的文本,也能快速地计算出哈希值。
应用一:安全加密
最常用于加密的哈希算法是 MD5(MD5 Message-Digest Algorithm,MD5 消息摘要算法)和 SHA(Secure Hash Algorithm,安全散列算法)。(主流SHA,因为MD5已经快被破解完了)当然还有很多其他加密算法,比如 DES(Data Encryption Standard,数据加密标准)、AES(Advanced Encryption Standard,高级加密标准)。
MD5 SHA1 SHA256 这3种本质都是摘要函数,它们的长度 MD5 是 128 位,SHA1 是 160 位 ,SHA256 是 256 位。
应用二:大文件唯一标识
大文件数据,比如图片小则几十 KB、大则几 MB。
问题出现:需要对比两个图片是否完全相等,就需要对比这几 MB的bit,这将非常耗时!
方法: 每一个图片取一个唯一标识,或者说信息摘要:
从图片的二进制码串开头取 100 个字节,从中间取 100 个字节,从最后再取 100 个字节,然后将这 300 个字节放到一块,通过哈希算法(比如 MD5),得到一个哈希字符串,用它作为图片的唯一标识。 通过这个唯一标识来判定图片是否在图库中,如果哈希字符串表示相同,我们再做全量对比,这样就可以减少很多工作量。
应用三:数据校验
分布式结构的P2P文件共享程序:BT(Bit Torrent “比特洪流”) 协议验证文件块是否正确:
通过哈希算法,对 100 个文件块分别取哈希值,并且保存在种子文件中。当文件块下载完成之后,我们可以通过相同的哈希算法,对下载好的文件块逐一求哈希值,然后跟种子文件中保存的哈希值比对。如果不同,说明这个文件块不完整或者被篡改了,需要再重新从其他宿主机器上下载这个文件块。
应用四:散列函数
设计一个散列表的关键:散列函数也是哈希算法的一种应用。
散列函数主要考虑函数运算速度要快、数据分布均匀。
区块链使用的是哪种哈希算法吗?是为了解决什么问题而使用的呢?
区块链是由哈希指针将一个个区块串链而成的一条链。
每个区块分为两部分:区块头和区块体。
区块头保存着上一个区块头的哈希值和自己区块的信息。
自己区块的哈希值=SHA256(SHA256(区块头))(只要区块中的信息有改变,区块头就会有变化(利用的时间戳))
因为这种链式关系和哈希值的唯一性,只要区块链上任意一个区块被修改过,后面所有区块保存的哈希值就不对了。
区块链使用的是 SHA256 哈希算法,计算哈希值非常耗时,如果要篡改一个区块,就必须重新计算该区块后面所有的区块的哈希值,短时间内几乎不可能做到。
应用五:负载均衡
通过哈希算法,对客户端 IP 地址或者会话 ID 计算哈希值,将取得的哈希值与服务器数量进行取模运算,最终得到的值就是应该被路由到的服务器编号。 这样,我们就可以把同一个 IP 过来的所有请求,都路由到同一个后端服务器上。
应用六:数据分片
其实就是将数据进行hash算法 决定存储到哪台机器中!
1. 如何统计“搜索关键词”出现的次数?
假如我们有 1T 的搜索日志文件,想要快速统计出每个关键词被搜索的次数,该怎么做呢?
- 第一个是搜索日志很大,没办法放到一台机器的内存中。
- 第二个难点是,如果只用一台机器来处理这么巨大的数据,处理时间会很长。
为了提高处理的速度,我们用 n 台机器并行处理:
- 从搜索记录的日志文件中,依次读出每个搜索关键词, Hash(关键字)%n = 分配到的机器编号。
- 那么,相同的关键字一定被分配到同一台机器上。 每个机器会分别计算关键词出现的次数,最后合并起来就是最终的结果。
- 实际上,这里的处理过程也是 MapReduce 的基本设计思想。
2. 如何快速判断图片是否在图库中?
假设现在我们的图库中有 1 亿张图片,很显然,在单台机器上构建散列表是行不通的。因为单台机器的内存有限,而 1 亿张图片构建散列表显然远远超过了单台机器的内存上限。
- 准备 n 台机器,让每台机器只维护某一部分图片对应的散列表。
- 每次从数据库图库中读取一个图片,计算唯一标识,然后与机器个数 n 求余取模,得到的值就对应要分配的机器编号。
- 将这个图片的唯一标识和图片路径发往对应的机器构建散列表。
- 当我们要判断一个图片是否在图库中的时候,我们通过同样过程。
估算代价(还是很重要的):
假设我们通过 MD5 来计算哈希值,那长度就是 128 比特,也就是 16 字节。文件路径长度的上限是 256 字节,我们可以假设平均长度是 128 字节。如果我们用链表法来解决冲突,那还需要存储指针,指针只占用 8 字节(指针:32位系统,是4个字节;64位,则就为8个字节。)。所以,散列表中每个数据单元就占用 152 字节。
假设一台机器的内存大小为 2GB,散列表的装载因子为 0.75,那一台机器可以给大约 1000 万(2GB*0.75/152)张图片构建散列表。所以,如果要对 1 亿张图片构建索引,需要大约十几台机器。
应用七:分布式存储
高并发下海量用户访问数据库中的海量信息则会使数据库崩溃!
而且就算不崩溃,数据读写速度也会很慢。而缓存就相当于内存,响应速度很快!
解决方法:
- 需要将常用的信息缓存到多台缓存机器上(用户直接从缓存机器中拿数据,并不直接访问数据库。如果缓存中不存在,则再访问数据库)
- 通过上面的数据分片思想,从数据库中拿到信息存储进缓存机器中。
出现新问题:
如果需要增加缓存机器n,则所有数据的Hash%n就会全部改变,这就相当于缓存中的数据一下子就都失效了。所有的数据请求都会穿透缓存,直接去请求数据库。这样就可能发生雪崩效应,压垮数据库。
解决办法:一致性hash算法
为什么是 2^32 :因为一致性hash算法是来做服务器的负载均衡,而服务器的IP地址是32位,所以是2^32-1次方的数值空间。