哈希算法原来有这么多应用场景!

本文涉及的产品
实时计算 Flink 版,1000CU*H 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
实时数仓Hologres,5000CU*H 100GB 3个月
简介: 1 什么是哈希算法? 将任意长度的二进制值串映射为固定长度的二进制值串,映射规则就是哈希算法 通过原始数据映射之后得到的二进制值串就是哈希值

1 啥是哈希算法?

  • 将任意长度的二进制值串映射为固定长度的二进制值串,映射规则就是哈希算法
  • 通过原始数据映射之后得到的二进制值串就是哈希值

2 哈希算法的绩效

  • 从哈希值不能反推出原数据所以哈希算法也称单向哈希算法
  • 对输入数据敏感即使原数据只修改一bit,最后的哈希值也大不相同
  • 散列冲突的概率要很小即对不同原数据,哈希值相同的概率要非常小
  • 执行效率要尽量高效针对较长的文本,也要能快速算得哈希值

这些定义和要求都比较理论,可能还是不好理解,我拿MD5这种哈希算法来具体说明一下。

如:

  • 公众号
  • JavaEdge

这两个字符串,计算MD5哈希值,得到两串看起来毫无规律的字符串(MD5的哈希值是128位的Bit长度,为了方便表示,我把它们转化成了16进制编码)。无论要哈希的文本有多长、多短,通过MD5哈希之后,得到的哈希值的长度都是相同的,而且得到的哈希值看起来像一堆随机数,完全没有规律。

MD5("公众号") = 215feec56c2ae2ebc5c15e0bf7baf63bMD5("JavaEdge") = a2a78ee5e4c9c0547a6e9acca6b54393

“公众号!”和“公众号”。这两个字符串仅一叹之差。但MD5后 hash 值大不相同:MD5("公众号!") = c9a7de168253f3d653b6db1b35bab5a8MD5("公众号") = 215feec56c2ae2ebc5c15e0bf7baf63b

你看看,通过算后的hash值,你狠难反推原数据吧?

3 适用场景

3.1 安全加密

常用加密的哈希算法:

  • MD5(MD5 Message-Digest Algorithm,MD5消息摘要算法)
  • SHA(Secure Hash Algorithm,安全散列算法)
  • DES(Data Encryption Standard,数据加密标准)
  • AES(Advanced Encryption Standard,高级加密标准)

散列冲突概率要很小。

不管啥哈希算法,只能尽量减少碰撞冲突的概率,理论无法做到完全不冲突。

哈希算法产生的哈希值的长度是固定且有限的。比如前面举的MD5的例子,哈希值是固定的128位二进制串,能表示的数据是有限的,最多能表示2^128  个数据,而我们要哈希的数据是无穷的。基于鸽巢原理,如果我们对2^128+1个数据求哈希值,就必然会存在哈希值相同的情况。哈希值越长的哈希算法,散列冲突的概率越低。

即便哈希算法存在散列冲突的情况,但是因为哈希值的范围很大,冲突的概率极低,所以相对来说还是很难破解的。像MD5,有2^128个不同的哈希值,这个数据已经是一个天文数字了,所以散列冲突的概率要小于1/ 2^128。

如果我们拿到一个MD5哈希值,希望通过毫无规律的穷举的方法,找到跟这个MD5值相同的另一个数据,那耗费的时间应该是个天文数字。所以,即便哈希算法存在冲突,但是在有限的时间和资源下,哈希算法还是被很难破解的。

无绝对安全的加密。越复杂、越难破解的加密算法,需计算时间也越长。如SHA-256比SHA-1更复杂、更安全,计算时间就较长。密码学界一直致力于找到一种快速且难破解的哈希算法。需权衡破解难度和计算时间,决定用哪种加密算法。

可通过哈希算法,对用户密码进行加密后再存储,不过最好选择相对安全的加密算法,如SHA等(因MD5已号称被破解)。

加密后存储就够了吗?

字典攻击

如用户信息被“脱库”,黑客虽拿到密文,但可通过“猜”破解密码,因为有些用户密码太简单。如00000、123456,所以现在都强制大小写字母数字都有。

就需维护一个常用密码的字典表,把字典中的每个密码用哈希算法计算哈希值,然后拿哈希值跟脱库后的密文比对。如相同,基本可认为,这加密后的密码对应明文就是字典中的这密码。(哈希算法存在散列冲突,也可能密文一样,但明文不一样)

可引入一个盐(salt),跟用户密码组合,增加密码复杂度。拿组合后的字符串做哈希算法加密,存储到数据库,进一步增加破解难度。

3.2 唯一标识

对大数据做信息摘要,通过一个较短二进制编码以表示很大的数据。

在海量图库搜索一张图,不能简单用图片元信息(比如图片名)做比对,有可能:

  • 名称相同,但内容不同
  • 名称不同,内容相同

咋搜索?

任何文件在计算中都是二进制码序列,所以,粗暴的就是将待搜索图片的二进制码序列与图库中所有图片二进制码序列一一比对。

但图片大小从几K~几M,转化成二进制就是一个超长的序列,比对极耗时!咋更快?

给每个图片取个唯一标识或信息摘要。如,从图片的二进制码序列:

  • 开头取100个字节
  • 中间取100个字节
  • 最后再取100个字节

将这300个字节放到一块,通过哈希算法(如MD5),得到一个哈希字符串,作为图片唯一标识。

还能更快吗?

把每个图片的唯一标识和相应图片文件在图库中的路径信息,都存储在hash表。

搜索某图片时:

通过哈希算法对该图片取唯一标识;

在hash表查找是否存在该标识:

  • 不存在:该图片不在图库
  • 存在:再通过hash表中存储的文件路径,获取该已存在图片,跟现在要插入的图片做全量比对,看是否完全一样:
  • 一样说明已存在
  • 不一样说明两张图片尽管唯一标识相同,但并非相同图片

3.3 数据校验

P2P下载,从多个机器并行下载一个2G电影,该电影文件可能被分割成很多文件块。等所有的文件块都下载完成之后,再组装成一个完整的电影文件就行了。

网络传输不安全,下载的文件块可能被宿主机器恶意修改,或下载过程出错,所以下载的文件块可能不完整。若无能力检测这种恶意修改或文件下载出错,就导致最终合并后的电影无法观看,甚至中毒。

咋校验文件块的安全、正确、完整?

哈希算法对100个文件块分别取哈希值,并保存在种子文件。只要文件块内容有丁点改变,最后哈希值就完全不同。所以,当文件块下载完成后:

  1. 使用相同哈希算法对下载好的文件块逐一求哈希;
  2. 对比种子文件中的哈希值:
  1. 若不同:说明该文件块不完整或被篡改,重新从其它宿主机器下载该文件块

3.4 Hash函数

该场景:

  • 对hash算法冲突的要求较低,偶尔hash冲突问题不大
  • 也不关心hash函数对于hash算法计算得到的值,是否能反向解密

hash函数中用到的hash算法,更加关注hash后的值是否能均匀分布。hash函数执行的快慢,也影响hash表的性能,所以,hash函数用的hash算法一般较简单,追求效率。

哈希算法还能解决很多分布式问题。

3.5 负载均衡

实现一个会话粘滞(session sticky)负载均衡算法,需在同一客户端上,在一次会话中的所有请求都路由同一服务器。

最直接的维护一张映射关系表:客户端IP地址或会话ID -> 服务器编号的映射关系。

客户端发出的每次请求,先映射表查找路由的服务器编号,再请求对应服务器。简单直观,但:

  • 客户端很多映射表可能会很大,比较浪费内存空间
  • 客户端下线、上线,服务器扩容、缩容都会导致映射失效维护映射表的成本很大

借助哈希算法即可解决:对客户端IP地址或会话ID计算哈希值,与服务器列表的大小取模,最终得到的值即被路由到的服务器编号。 这就可以把同一IP过来的所有请求,都路由到同一后端服务器。

3.6 数据分片

统计关键词

假如1T日志文件,这里面记录了用户的搜索关键词,快速统计出每个关键词被搜索的次数。这个问题有两个难点:

  • 搜索日志很大,没法放到一台机器的内存
  • 如果只用一台机器来处理这么巨大的数据,处理时间会很长。

可以先对数据进行分片,然后采用多台机器处理提高处理速度:用n台机器并行处理:

  • 从搜索记录的日志文件依次读出每个搜索关键词
  • 通过哈希函数计算哈希值
  • 再跟n取模
  • 得到应该被分配到的机器编号

哈希值相同的搜索关键词就被分配到了同一个机器上。即同一个搜索关键词会被分配到同一个机器上。每个机器会分别计算关键词出现的次数,最后合并起来就是最终的结果。

MapReduce的基本思想。

快速判断图片是否在图库

前面提到可以给每个图片取唯一标识(或者信息摘要),然后构建hash表。

现在图库现有1亿张图片,单机构建hash表就做不到了。因为单台机器的内存有限,而1亿张图片构建散列表显然远远超过了单台机器的内存上限。

我们同样可以对数据进行分片,然后采用多机处理。我们准备n台机器,让每台机器只维护某一部分图片对应的散列表。我们每次从图库中读取一个图片,计算唯一标识,然后与机器个数n求余取模,得到的值就对应要分配的机器编号,然后将这个图片的唯一标识和图片路径发往对应的机器构建散列表。

当我们要判断一个图片是否在图库中的时候,我们通过同样的哈希算法,计算这个图片的唯一标识,然后与机器个数n求余取模。假设得到的值是k,那就去编号k的机器构建的散列表中查找。

现在,我们来估算一下,给这1亿张图片构建散列表大约需要多少台机器。

散列表中每个数据单元包含两个信息,哈希值和图片文件的路径。假设我们通过MD5来计算哈希值,那长度就是128比特,也就是16字节。文件路径长度的上限是256字节,我们可以假设平均长度是128字节。如果我们用链表法来解决冲突,那还需要存储指针,指针只占用8字节。所以,散列表中每个数据单元就占用152字节(这里只是估算,并不准确)。

假设一台机器的内存大小为2GB,散列表的装载因子为0.75,那一台机器可以给大约1000万(2GB*0.75/152)张图片构建散列表。所以,如果要对1亿张图片构建索引,需要大约十几台机器。在工程中,这种估算还是很重要的,能让我们事先对需要投入的资源、资金有个大概的了解,能更好地评估解决方案的可行性。

海量数据处理都可采用多机分布式处理方案。分片设计以突破单机内存、CPU等资源的限制。

3.7 分布式存储

为提高数据读、写能力,一般采用分布式存储,比如分布式缓存。因为大量数据要缓存,所以单机缓存肯定不够,就需要将数据分布在多机。

哪个数据又该存在哪个机器呢?

参考数据分片设计,通过哈希算法处理数据,然后对机器个数取模,就得到该缓存数据应存储的机器编号。

但若数据增多,原先10个机器已无法支撑,就得扩容,比如扩到11个节点。但问题也来了,原先数据通过与10取模,现在节点多了一个,所有数据需重新计算哈希值,然后迁移到现在的对应节点。这时,原缓存中的数据突然大量失效,这些缓存数据的请求就会穿透缓存,直接请求DB。

所以,此时我们就需要一个方案,能在加新节点后,无需做大量数据迁移。救星就是一致性 hash 算法!

先假设:

  • 有k个节点
  • 数据哈希值范围[0, MAX]
  • 将整个范围划分成m个小区间(m>>k)
  • 每个节点负责m/k个小区间

加入新节点时,就将某几个小区间的数据,从原节点迁移至新节点。这就避免了全部重新哈希、搬移数据,也保持了各个机器上数据数量的均衡。

这就是一致性哈希算法的基本思想。

案例

钟表有 60 分钟,从 0 开始到 59,共 60 个点。现在将机器往这 60 个点分配,规则如下:

hash(ip) % 60

假设 3 台机器 A,B 和 C,分别被分配到了 14,37 和 46 三个点。

图片的分配规则类似:

hash(image_id) % 60

现有 3 张图片 x, y, z,分别被分配到 5,30,50 这三个点。

图片都没被分配到机器的节点,这咋办?在钟表上顺时钟往前寻找,第一台遇到的机器,就是它的归属。

不凑巧,A B C 三台机器分别分配到 5,10,15 这三个点。这样对 A 很不公平啊!要负责存储绝大多数的图片,那这怎么办呢?

为避免不必要争端,于是引入“虚拟节点”,每台机器都可拔一根汗毛,变成若干台,把虚拟节点分散到 60 个点,归属“虚拟节点”的图片,均保存到它的真身。这就能解决分配不均匀问题。

应用时,将 60 替换下即可,如替换为 2^32。

参考


关注我,紧跟本系列专栏文章,咱们下篇再续!

作者简介:魔都架构师,多家大厂后端一线研发经验,在分布式系统设计、数据平台架构和AI应用开发等领域都有丰富实践经验。

各大技术社区头部专家博主。具有丰富的引领团队经验,深厚业务架构和解决方案的积累。

负责:

  • 中央/分销预订系统性能优化
  • 活动&券等营销中台建设
  • 交易平台及数据中台等架构和开发设计
  • 车联网核心平台-物联网连接平台、大数据平台架构设计及优化
  • LLM Agent应用开发
  • 区块链应用开发

目前主攻市级软件项目设计、构建服务全社会的应用系统。

参考:

目录
相关文章
|
5月前
|
存储 监控 算法
内网监控桌面与 PHP 哈希算法:从数据追踪到行为审计的技术解析
本文探讨了内网监控桌面系统的技术需求与数据结构选型,重点分析了哈希算法在企业内网安全管理中的应用。通过PHP语言实现的SHA-256算法,可有效支持软件准入控制、数据传输审计及操作日志存证等功能。文章还介绍了性能优化策略(如分块哈希计算和并行处理)与安全增强措施(如盐值强化和动态更新),并展望了哈希算法在图像处理、网络流量分析等领域的扩展应用。最终强调了构建完整内网安全闭环的重要性,为企业数字资产保护提供技术支撑。
132 2
|
11月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
411 1
|
12月前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
192 3
|
10月前
|
算法 安全
散列值使用相同的哈希算法
当使用相同的哈希算法对相同的数据进行散列时,所产生的散列值(也称为哈希值或摘要)总是相同的。这是因为哈希算法是一种确定性的函数,它对于给定的输入将始终产生相同的输出。 例如,如果你用SHA-256算法对字符串"hello world"进行哈希处理,无论何时何地,只要输入是完全一样的字符串,你都会得到相同的160位(40个十六进制字符)的SHA-256散列值。 但是,需要注意的是,即使是输入数据的微小变化也会导致产生的散列值完全不同。此外,不同的哈希算法(如MD5、SHA-1、SHA-256等)会对相同的数据产生不同的散列值。 哈希算法的一个关键特性是它们的“雪崩效应”,即输入中的一点小小
176 4
|
12月前
|
存储 算法 C#
C#哈希查找算法
C#哈希查找算法
|
算法 安全 JavaScript
安全哈希算法:SHA算法
安全哈希算法:SHA算法
485 1
安全哈希算法:SHA算法
|
12月前
|
算法 安全 Go
Python与Go语言中的哈希算法实现及对比分析
Python与Go语言中的哈希算法实现及对比分析
205 0
|
12月前
|
存储 算法 C++
【算法】哈希映射(C/C++)
【算法】哈希映射(C/C++)
|
机器学习/深度学习 人工智能 算法
【人工智能】传统语音识别算法概述,应用场景,项目实践及案例分析,附带代码示例
传统语音识别算法是将语音信号转化为文本形式的技术,它主要基于模式识别理论和数学统计学方法。以下是传统语音识别算法的基本概述
668 2
|
JavaScript 算法 前端开发
国标哈希算法基础:SHA1、SHA256、SHA512、MD5 和 HMAC,Python和JS实现、加盐、算法魔改
国标哈希算法基础:SHA1、SHA256、SHA512、MD5 和 HMAC,Python和JS实现、加盐、算法魔改
1328 1