• 数据结构与算法简记--哈希算法


    哈希算法


     定义

    将任意长度的二进制值串映射为固定长度的二进制值串,这个映射的规则就是哈希算法。

    而通过原始数据映射之后得到的二进制值串就是哈希值

    特点

    • 从哈希值不能反向推导出原始数据(所以哈希算法也叫单向哈希算法);
    • 对输入数据非常敏感,哪怕原始数据只修改了一个 Bit,最后得到的哈希值也大不相同;
    • 散列冲突的概率要很小,对于不同的原始数据,哈希值相同的概率非常小;
    • 哈希算法的执行效率要尽量高效,针对较长的文本,也能快速地计算出哈希值。

    应用一:安全加密

    • 常用于加密的哈希算法:

       MD5(MD5 Message-Digest Algorithm,MD5 消息摘要算法)

    SHA(Secure Hash Algorithm,安全散列算法)。

    • 其他加密算法:DES(Data Encryption Standard,数据加密标准)、AES(Advanced Encryption Standard,高级加密标准)。

    应用二:唯一标识

    • 图片唯一标识
      • 从图片的二进制码串开头取 100 个字节,从中间取 100 个字节,从最后再取 100 个字节,然后将这 300 个字节放到一块,通过哈希算法(比如 MD5),得到一个哈希字符串
      • 用它作为图片的唯一标识。通过这个唯一标识来判定图片是否在图库中,这样就可以减少很多工作量

    应用三:数据校验(利用输入数据敏感性)

    • BT下载原理
      • 基于 P2P 协议的。从多个机器上并行下载一个 2GB 的电影,这个电影文件可能会被分割成很多文件块(比如可以分成 100 块,每块大约 20MB)。等所有的文件块都下载完成之后,再组装成一个完整的电影文件就行了
    • BT下载文件的数据检验:
      • 通过哈希算法,对 100 个文件块分别取哈希值,并且保存在种子文件中
      • 当文件块下载完成之后,通过相同的哈希算法,对下载好的文件块逐一求哈希值,然后跟种子文件中保存的哈希值比对。
      • 如果不同,说明这个文件块不完整或者被篡改了,需要再重新从其他宿主机器上下载这个文件块。

    应用四:散列函数

    • 散列函数关注点:
      • 不关心是否能反向解密
      • 关注散列后的值是否能平均分布
      • 关注散列算法的性能

    如何防止数据库中的用户信息被脱库?

    • 通过哈希算法,对用户密码进行加密之后再存储,不过最好选择相对安全的加密算法,比如 SHA 等(因为 MD5 已经号称被破解了)
    • 字典攻击风险:维护一个常用密码的字典表,把字典中的每个密码用哈希算法计算哈希值,然后拿哈希值跟脱库后的密文比对。如果相同,基本上就可以认为,这个加密之后的密码对应的明文就是字典中的这个密码。
    • 针对字典攻击策略:引入一个盐(salt),跟用户的密码组合在一起,增加密码的复杂度。我们拿组合之后的字符串来做哈希算法加密,将它存储到数据库中,进一步增加破解的难度。

     应用五:负载均衡

    • 负载均衡算法:轮询、随机、加权轮询等。
    • 那如何才能实现一个会话粘滞(session sticky)的负载均衡算法呢?也就是说,我们需要在同一个客户端上,在一次会话中的所有请求都路由到同一个服务器上。
      • 直接的方法:
        • 维护一张映射关系表,这张表的内容是客户端 IP 地址或者会话 ID 与服务器编号的映射关系。客户端发出的每次请求,都要先在映射表中查找应该路由到的服务器编号,然后再请求编号对应的服务器。
        • 弊端:如果客户端很多,映射表可能会很大,比较浪费内存空间;客户端下线、上线,服务器扩容、缩容都会导致映射失效,这样维护映射表的成本就会很大;
      • 借助hash算法:
        • 通过哈希算法,对客户端 IP 地址或者会话 ID 计算哈希值,将取得的哈希值与服务器列表的大小进行取模运算,最终得到的值就是应该被路由到的服务器编号。 这样,我们就可以把同一个 IP 过来的所有请求,都路由到同一个后端服务器上。

    应用六:数据分片

    • 统计“搜索关键词”出现的次数: 1T 的日志文件,记录了用户的搜索关键词,快速统计出每个关键词被搜索的次数,该怎么做呢?
      • 先对数据进行分片,然后采用多台机器处理的方法,来提高处理速度:
      • 用 n 台机器并行处理,从搜索记录的日志文件中,依次读出每个搜索关键词,并且通过哈希函数计算哈希值,然后再跟 n 取模,最终得到的值,就是应该被分配到的机器编号。
    • 快速判断图片是否在图库中:
      • 判断一个图片是否在图库中的时候,通过应用二同样的哈希算法,计算这个图片的唯一标识,然后与机器个数 n 求余取模。假设得到的值是 k,那就去编号 k 的机器构建的散列表中查找

    应用七:分布式存储

    • 互联网面对的都是海量的数据、海量的用户。为了提高数据的读取、写入能力,一般都采用分布式的方式来存储数据,比如分布式缓存。海量的数据需要缓存,需要将数据分布在多台机器上
      • 借用前面数据分片的思想,即通过哈希算法对数据取哈希值,然后对机器个数取模,这个最终值就是应该存储的缓存机器编号。
      • 机器扩容问题:如果原有10台机器,数据13,通过hash算法算出机器编号为13%10=3,现扩容至11台,则机器编号为13%11=2,缓存机器编号计算不一致了,缓存就失效了,都要去数据库查询,大大影响性能。
      • 一致性哈希算法
        • 把全量的缓存空间当做一个环形存储结构。环形空间总共分成2^32个缓存区,在Redis中则是把缓存key分配到16384个slot。
        • 每一个缓存key都可以通过Hash算法转化为一个32位的二进制数,也就对应着环形空间的某一个缓存区。我们把所有的缓存key映射到环形空间的不同位置。
        • 我们的每一个缓存节点(Shard)也遵循同样的Hash算法,比如利用IP做Hash,映射到环形空间当中。
        • 如何让key和节点对应起来呢?很简单,每一个key的顺时针方向最近节点,就是key所归属的存储节点。所以图中key1存储于node1,key2,key3存储于node2,key4存储于node3。
        • 增加节点:当缓存集群的节点有所增加的时候,整个环形空间的映射仍然会保持一致性哈希的顺时针规则,所以有一小部分key的归属会受到影响。

          • 图中加入了新节点node4,处于node1和node2之间,按照顺时针规则,从node1到node4之间的缓存不再归属于node2,而是归属于新节点node4。因此受影响的key只有key2。

          • 最终把key2的缓存数据从node2迁移到node4,就形成了新的符合一致性哈希规则的缓存结构
        • 删除节点与增加类似

        • 注意缓存迁移的意思:并不是把数据复制过去,而是在所属的新的节点上缓存不命中时刷新缓存。

        • 虚拟节点:为了防止节点在环上分布不均匀使得数据分布不均匀,创建多个虚拟节点,虚拟节点按一定的规则与真实节点形成映射关系。

    其他应用

    • 网络协议中的 CRC 校验
    • Git commit id 
  • 相关阅读:
    《挑战程序设计竞赛》 一二章部分代码题解
    动态规划之矩阵连乘和POJ 1651
    关于图片的重绘,从而进行压缩
    iOS开发:读取pdf文件
    如何改变tableview的section的颜色
    端口的作用
    Mac 下,配置SVN
    cocoaPods 的安装和使用
    关于如何调用苹果自带的地图APP
    关于 HTTP 请求头的内容
  • 原文地址:https://www.cnblogs.com/wod-Y/p/12198550.html
Copyright © 2020-2023  润新知