哈希算法
哈希算法
将任意长度的二进制值串映射为固定长度的二进制值串,这个映射的规则就是哈希算法,而通过原始数据映射之后得到的二进制值串就是哈希值
优秀的哈希算法需要满足的几点要求:
- 从哈希值不能反向推导出原始数据(所以哈希算法也叫单向哈希算法);
- 对输入数据非常敏感,哪怕原始数据只修改了一个 Bit,最后得到的哈希值也大不相同;
- 散列冲突的概率要很小,对于不同的原始数据,哈希值相同的概率非常小;
- 哈希算法的执行效率要尽量高效,针对较长的文本,也能快速地计算出哈希值。
哈希算法的应用
应用一:安全加密
最常用于加密的哈希算法是 MD5(MD5 Message-Digest Algorithm,MD5 消息摘要算法)、 SHA(Secure Hash Algorithm,安全散列算法)、DES(Data Encryption Standard,数据加密标准)、AES(Advanced Encryption Standard,高级加密标准)。
没有绝对安全的加密。越复杂、越难破解的加密算法,需要的计算时间也越长
应用二:唯一标识
应用三:数据校验
应用四:散列函数
散列函数是设计一个散列表的关键。它直接决定了散列冲突的概率和散列表的性能。
散列函数中用到的散列算法,更加关注散列后的值是否能平均分布,也就是,一组数据是否能均匀地散列在各个槽中。除此之外,散列函数执行的快慢,也会影响散列表的性能,所以,散列函数用的散列算法一般都比较简单,比较追求效率。
应用五:负载均衡
负载均衡算法有很多,比如轮询、随机、加权轮询等。
如何实现一个会话粘滞(session sticky)的负载均衡算法?
需要在同一个客户端上,在一次会话中的所有请求都路由到同一个服务器上。
最直接的方法就是,维护一张映射关系表,这张表的内容是客户端 IP 地址或者会话 ID 与服务器编号的映射关系。客户端发出的每次请求,都要先在映射表中查找应该路由到的服务器编号,然后再请求编号对应的服务器。
弊端:
- 如果客户端很多,映射表可能会很大,比较浪费内存空间;
- 客户端下线、上线,服务器扩容、缩容都会导致映射失效,这样维护映射表的成本就会很大;
可以通过哈希算法,对客户端 IP 地址或者会话 ID 计算哈希值,将取得的哈希值与服务器列表的大小进行取模运算,最终得到的值就是应该被路由到的服务器编号。
应用六:数据分片
如何统计“搜索关键词”出现的次数?
假如我们有 1T 的日志文件,这里面记录了用户的搜索关键词,想要快速统计出每个关键词被搜索的次数,该怎么做呢?
可以先对数据进行分片,然后采用多台机器处理的方法,来提高处理速度。
具体思路:为了提高处理的速度,我们用 n 台机器并行处理。我们从搜索记录的日志文件中,依次读出每个搜索关键词,并且通过哈希函数计算哈希值,然后再跟 n 取模,最终得到的值,就是应该被分配到的机器编号。
哈希值相同的搜索关键词就被分配到了同一个机器上,每个机器会分别计算关键词出现的次数,最后合并起来就是最终的结果。
如何快速判断图片是否在有1 亿张图片的图库中?
可以对数据进行分片,然后采用多机处理。
具体思路:准备 n 台机器,让每台机器只维护某一部分图片对应的散列表。我们每次从图库中读取一个图片,计算唯一标识,然后与机器个数 n 求余取模,得到的值就对应要分配的机器编号,然后将这个图片的唯一标识和图片路径发往对应的机器构建散列表。
当要判断一个图片是否在图库中的时候,通过同样的哈希算法,计算这个图片的唯一标识,然后与机器个数 n 求余取模。假设得到的值是 k,那就去编号 k 的机器构建的散列表中查找。
应用七:分布式存储
现在互联网面对的都是海量的数据、海量的用户。为了提高数据的读取、写入能力,一般都采用分布式的方式来存储数据,比如分布式缓存。
该如何决定将哪个数据放到哪个机器上呢?可以借用数据分片的思想,即通过哈希算法对数据取哈希值,然后对机器个数取模,这个最终值就是应该存储的缓存机器编号。
如果数据增多,原来的 10 个机器已经无法承受了,就需要扩容,比如扩到 11 个机器,但这里并不是简单地加个机器就可以了。
所有的数据都要重新计算哈希值,然后重新搬移到正确的机器上。这样就相当于,缓存中的数据一下子就都失效了。所有的数据请求都会穿透缓存,直接去请求数据库。这样就可能发生雪崩效应,压垮数据库。
一致性哈希算法:假设有 k 个机器,数据的哈希值的范围是[0, MAX]。将整个范围划分成 m 个小区间(m 远大于 k),每个机器负责 m/k 个小区间。当有新机器加入的时候,我们就将某几个小区间的数据,从原来的机器中搬移到新的机器中。这样,既不用全部重新哈希、搬移数据,也保持了各个机器上数据数量的均衡
- 本文作者:bobo
- 本文链接:https://boyolo.github.io/article/60365.html
- 版权声明:本博客所有文章均采用 BY-NC-SA 许可协议,转载请注明出处!