测试开发基础之算法(10):Hash算法的常见应用

想象一下,在软件测试实践中,测试上传下载图片或者文件的接口时,我们如何对上传或者下载的图片和文件的正确性进行校验呢?
带着这个问题,我们开启hash算法的学习。hash算法在软件编程中应用非常广泛,常见的比如MD5、SHA等。我们一般不会动手写一个hash算法,更多的是拿现成的来用。我们这篇文章也是重点介绍,如何运用hash算法解决现实问题。

1. 什么是hash算法?

前面提到的散列表数据结构,其中用到散列函数进行散列值的计算。散列函数中的算法就是hash算法。
用一话定义hash算法,就是将任意长度的二进制串转换为固定长度的二进制串。这个固定长度的二进制串叫做hash值。设计一个优秀的hash算法挺难的,所以我们通常只是用前辈们设计的经典hash算法,而不自己实现。

优秀的hash算法应该具有以下几点要求:

  • 根据hash值不能反推处原始数据
  • 对输入数据非常敏感,哪怕原始数据只是变化一点点,得到的hash值也会大不相同
  • 散列冲突概率小
  • hash算法执行效率要高,对于很长的文本或者文件,也能很快得到hash值。

我们拿典型的md5算法,来理解一下上面的几点。

import hashlib

print(hashlib.md5("hash算法".encode('utf-8')).hexdigest())
print(hashlib.md5("hash算法.".encode('utf-8')).hexdigest())  # 原始数据只差了一个点,但是得到的hash值相差十万八千里了

file_name = "binary_search.py"
with open(file_name, 'rb') as fp:
    data = fp.read()
file_md5 = hashlib.md5(data).hexdigest() # 对很大的文件,也能很快的得到hash值
print(file_md5)

不管原始数据多大,得到的hash值都是相同长度的。
哈希算法的应用非常非常多,列举最常见的七个,分别是安全加密、唯一标识、数据校验、散列函数、负载均衡、数据分片、分布式存储。下面我们来分别看看。

2. 安全加密

在加密领域常用的hash算法有MD5、SHA、AES等。为啥hash算福安可以用来做安全加密呢?
主要是因为:第一,通过hash值很难反推处原始数据;第二,散列冲突的概率小。

第一点,很容易理解,不能反推原始数据肯定就安全了嘛。第二点如何理解呢?拿MD5为例,它的hash值有128位,它能表示的数据有2的128次方个,这么大的范围产生hash冲突的概率很低。如果我们拿到一个MD5值,希望通过穷举法找到与这个MD5值相同的原数数据,耗费的时间是个天文数字。

通常我们的账号密码,在数据库中存储的都是明文密码的hash值,就是对明文密码进行hash计算,存储到数据库中。进一步加强密码安全性的策略上号,引入一个salt,与用户的密码组合在一起,增加密码的复杂度,然后再计算组合之后的字符串的hash值,将它存到数据库中,这样就进一步增加了破解的难度。

3. 唯一标识

在海量图库中,想要唯一标识一张图片,使用hash值是个非常好的办法。因为再多的图片元数据也不能保证图片的唯一性。
那如何用hash值来标识唯一一张图片呢?我们可以从图片的二进制数据中,从开头,中间和结尾处各取100个字节拼接到一起,然后在通过MD5算法计算出MD5值。用这个MD5值来唯一标识图片。这样通过这个唯一的标识判断一张图片是否存在,就大大提高了效率。

进一步优化,将图片的地址和hash值存储到散列表中。当查看某个图片是否在图库中的时候,先计算这个图片的hash值,然后散列表中查找这个hash值。如果不存在,说明图片不在图库中。如果存在,在通过散列表中的图片路径拿到图片,与待查找的图片进行全量对比,看是否完全一样。如果一样,则说明图片存在。如果不一样,说明图片尽管唯一标识一样,但是并不是相同的图片。

3. 数据校验

在进行软件测试时,通过接口下载的文件,对于较大的文件,服务器会分成很多文件块并行下载。等所有的文件块都下载完毕了,再组装成一个文件。
如果下载过程中出现了错误,那么下载的文件块就是不完整。我们如何判断下载下来的文件块是否正确呢?

在服务器端每个文件块分别计算一个hash值,并保存下来。因为hash算法对输入数据极其敏感,只要文件块的内容有一点点变化,最后计算出来的hash值也肯定不同。
所以,对下载的文件块通过相同的hash算法计算hash值,跟服务器端的文件快的hash值进行对比。如果相同表示文件块正确,如果不相同,则文件块发生了错误。

4. 散列函数

在散列表中,散列函数是关键。散列函数就是hash算法的一种应用。这里不再展开。

5. 负载均衡

负载均衡有很多经典的算法,比如轮询、随机、加权轮询等。那如何我想要同一个客户端再一次会话中的所有请求都路由到同一个后端服务器上。该如何做呢?借助hash算法就可以完美解决这个问题,通过hash算法,对客户端的IP和会话ID计算hash值,再将hash值对服务器个数取模,最终得到的值,就是应该路由的服务器编号。这样,我们就可以把同一个IP过来的所有请求,都路由到同一个后端服务器上了。
其实这个思想,还可以扩展到很多场景,就是计算数据的hash值之后在分配到不同的机器上进行处理。比如,分布式存储,数据分片处理等。

发布了187 篇原创文章 · 获赞 270 · 访问量 172万+

猜你喜欢

转载自blog.csdn.net/liuchunming033/article/details/103476054