数据结构与算法 --哈希算法(十二)
一、什么是哈希算法?
不管 “ 散列” 还是 “哈希” ,这都是中文翻译的差别,英文其实就是 “ Hash” 。所以常听到有人把 “散列表” 叫做 “哈希表”,“Hash表”,把 “哈希算法” ,叫做 “Hash算法” 或者 “散列算法” 那到底什么是哈希算法?
将任意长度的二进制串映射为固定长度的二进制串,这个映射规则就是哈希算法
通过原始数据映射之后得到的二进制值串就是哈希值
需要满足的要求:
- 从哈希值不能反向推导出原始数据(单向哈希算法)
- 原始数据有一点变化,哈希值都会发生巨大不同
- 散列冲突要很小,对于不同的原始数据,哈希值相同的概率要小
- 计算效率要高,对于很长的文本,也要很快计算出哈希值
二、哈希算法的应用
1、安全加密
最常用于加密的哈希算法:
- MD5(Message-Digest Algorithm,MD5消息摘要算法)
- SHA(Secure Hash Algorithm.安全散列算法)
- DES(Data Encryption Standard,数据加密标准)
- AES(Advanced Encryption Standard,高级加密标准)
对于加密的哈希算法有两点格外重要:
- 不能从哈希值推导出原始数据
- 散列冲突的概率要很小
无论什么哈希算法,我们只能减少碰撞的概率,理论上无法做到完全不冲突。为什么这么说呢?
基于数学一个基础的理论:鸽巢原理(也叫抽屉原理)。 10个鸽巢,有11个各自,必然有一个鸽巢数量大于一
2、唯一标识(消息摘要)
在海量的图库中寻找一张图是否存在?
给每个图片取一个唯一标识,或者说消息摘要。比如从图片二进制串码开头取100个字节,中间100字节,最好100字节,然后将300个字节放到一块通过哈希算法得到一个哈希字符串作为图片的唯一标识。
如果想继续提高效率,可以把每个图片的唯一标识,和相应的图片文件在图库中的路径信息都存储在散列表中。当查看某个图片是否在图库中,通过哈希算法取得唯一标识,在散列表中查找比对,找到后在根据路径获取图片进行全量比对,如果不一样说明两张图片尽管唯一标识相同,但是不是相同图片
3、数据校验(用于检验数据的完整性和正确性)
BT的下载原理基于P2P协议。从多个机器下载一个2G的文件将会被分成 很多文件块。等所有文件块下载完成在组装成一个完整的电影文件
我们可以对每个文件块分别取哈希值保存在种子文件中。当文件下载完成之后,通过相同的哈希算法来逐个文件快校验。如果不同,说明文件块不完整
4、散列函数
散列函数也是哈希算法的一种应用
散列函数对于散列算法冲突的要求要低很多。即便出现冲突,也可以通过开放寻执法或链表法解决
对是否能从哈希值反推导出原始值也不关心。更加关注的是否能均匀分布
三、哈希算法在分布式中的应用
5、负载均衡
负载均衡的算法有很多,比如轮询,随机,加权轮询等。如何实现一个会话粘滞的负载均衡算法呢?也就是说需要在同一客户端,在一次会话中的所有请求都路由到同一个服务器上。
答: 维护一张映射表,表的内容是客户端的IP地址或者会话ID与服务器编号的映射关系。客户端每一次请求都要先在映射表中查找路由到的服务器编号。然后再请求编号对应的服务器。
弊端:
- 如果客户端很多就需要维护更多的映射关系
- 客户端上线下线,服务器扩容,缩容都会导致映射失败,维护映射表成本大
借助哈希算法就可以轻松解决。通过哈希算法对客户端IP地址或者会话ID计算哈希值,然后与服务器的大小进行取模运算。最终得到的值就是对应的服务器编号。这样就可以把同一个IP的请求路由到同一个后端服务器上。
6、数据分片
两个例子:
1)如何统计‘搜索关键词’的出现次数?
假如有1T的日志文件,记录了用户的搜索关键词,如何快速统计每个关键词被搜索的此说呢?
难点:数据量太大,无法放在一台机器的内存中,如果只有一台机器处理,时间会很长
因此我们用n台机器并行处理。从搜素记录中依次读取关键词,通过哈希函数计算出哈希值然后跟n取模运算,最终得到的值,就是被分配到的机器号
这样相同的关键词就被分散到同一机器。每个机器分别计算关键词出现的次数,最后合并就是最终的结果
2)如何快速判断图片是否在图库中?
假如有一亿张图片,显然在一台机器构建散列表是行不通的,因为一台机器的内存有限
我们需要n台机器,用哈希算法取每张图片的唯一标识,在和n求余取模运算,得到 的就是要分到的机器号,然后把唯一标识和路径发往这台机器构建散列表。当我们查找一个图片时,就用同样的哈希算法得到哈希值和n取模运算,假如得到的是k,就去k这台机器寻找
针对海量的数据,可以用多机分布式处理。借用这中分片的思想,可以突破单机内存,和CPU的限制
7、分布式存储
面对海量的数据和海量的用户,为了提高数据的读取和写入能力,一般都采用分布式来存储数组,比如分布式缓存。海量的数据需要缓存,一个缓存机器肯定是不够的,所以需要将数据分布在多台机器
借用数据分片的思想,通过哈希算法对数据取哈希值,然后对机器个数取模,这个最终值就是存储的缓存机编号
但是数据增多,需要扩容,比如扩到11个机器。原来的数据通过与 10 来取模的。比如13这个数组,存储在编号为3机器上。但是新增一个机器,对数据按照11取模,原来这个数据就被分配到2号机器上了
因此,所以数据都要重新计算哈希值,然后搬移到正确的机器上。缓存中的数据全部失效。所有的数据请求都会穿透缓存,直接取请求数据库。这样就可能发送雪崩效应,压垮数据库
解决方案是什么?
①这时,需要一种方法,使得新加入一个机器后,并不需要做大量的数据搬移。那就是在分布式系统中应用非常广泛的一致性哈希算法。
②一致性哈希算法的基本思想是什么呢?为了说清楚这个问题,我们假设有k个机器,数据的哈希值范围是[0-MAX],我们将整个范围划分成m个小区间(m远大于k),每个机器复负责m/k个小区间。当有新机器加入的时候,我们就将某几个小区间的数据,从原来的机器中搬移到新的机器中。这样,既不用全部重新哈希、搬移数据,也保持了各个机器上数据量的均衡。