哈希算法
介绍
哈希算法:将任意长度的二进制值串映射为**固定长度的二进制值串(哈希值)**的映射规则
要求:
- 从哈希值不能反向推导出原始数据(所以哈希算法也叫单向哈希算法);
- 对输入数据非常敏感,哪怕原始数据只修改了一个 Bit,最后得到的哈希值也大不相同;
- 散列冲突的概率要很小,对于不同的原始数据,哈希值相同的概率非常小;
- 哈希算法的执行效率要尽量高效,针对较长的文本,也能快速地计算出哈希值。
哈希算法的应用
安全加密:难以反向推导
常用于加密的哈希算法:
- MD5:哈希值是128bit,表示为16进制编码就是32个字符,可以有 2 128 2^{128} 2128个哈希值,散列冲突的概率小于 1 / 2 128 1/2^{128} 1/2128
- SHA
- DES
- AES
针对字典攻击(用户信息被脱库后,黑客拿到用户密码的密文,但可以通过猜的方式来破解密码),可以引入盐(salt)跟用户的密码组合在一起之后,再做哈希加密。
唯一标识:图片重复比对
- 对大数据作信息摘要,通过一个较短的二进制编码来表示很大的数据
- 区块链:区块链是一块块区块组成的,每个区块分为区块头和区块体。区块头上保存着自己的区块体的哈希值和上一个区块头的哈希值。因为这种链式关系和哈希值的唯一性,只要区块链上任意一个区块被修改过,后面所有区块的哈希值就不对了。区块链使用的是SHA256哈希算法,计算哈希值非常耗时,如果要篡改一个区块,就必须重新计算该区块后面所有的区块的哈希值,短时间内几乎不可能做到。
- Git commit id
数据校验:下载文件后校验
校验数据的完整性和正确性,例如CRC校验。
散列函数:散列表设计
关注散列值是否能均匀分布、散列函数计算效率
负载均衡
如何能实现一个会话粘滞的负载均衡算法?意思是,在同一个客户端上,在一次会话中的所有请求,都路由到同一个服务器上。
方法一:维护会话id到服务器id的映射,问题是内存会很大、维护成本高;
方法二:会话id作哈希,哈希值对服务器个数取模,就是服务器id
数据分片
例子1: 统计“搜索关键词”出现的次数
- 问题:有1T日志文件,里面记录了用户的搜索关键词,想要快速统计处每个关键词的搜索次数。
- 难点:搜索日志过大不能放到一台机器的内存中;如果只用一台机器处理,时间会很长
- 方案:MapReduce。相同的关键词分配到同一台机器上(搜索关键词->哈希值->对机器数取模->机器id);每个机器分别计算关键词出现的次数,合并起来就是结果
例子2: 图片数量很多时如何快速判断图片是否在图库中
- 问题:图库中有1亿张图片,如何快速判断给定图片是否在图库中?
- 难点:图库图片数量太多以致哈希后散列表无法存储在单台机器上
- 方案:多机处理,让每台机器只维护某一部分图片对应的散列表。每次从图库中读取一个图片,计算唯一标识,然后对机器数取模,得到构建散列表的机器编号;判断时,将图片通过同样的哈希算法得到哈希值后对机器数取模,取相应编号的机器上取查散列表。
分布式存储
海量数据的读写需要分布式缓存,如果单纯通过数据哈希后对机器数取模来决定分配的机器,那在扩容缩容时会导致原缓存的哈希失效,从而穿透缓存直接请求数据库引发雪崩效应。
使用一致性哈希算法可以解决上述问题,基本思想是将哈希值的数据范围化成多个小区间,每台机器负责几个小区间。当有新的机器加入时,就将某几个小区间的数据搬移到新的机器中,这样既不用重新哈希、也保持了各机器上数据数量的均衡。