深入理解 Hash:它不是一个函数,而是一种思想

很长一段时间里,我以为 Hash 是某个特定的函数,直到深入研究后才发现------Hash 是一种转化思想,类似于"协议",由谁来实现、如何实现并不唯一。本文将从词源、本质、常见算法、实际应用场景全方位拆解 Hash。


一、Hash 这个词从哪来的

Hash 最早是一个厨房用语 ,来自法语 hacher ,意思是"切碎、剁碎"。法语 hacher 又源自古法语 hache(斧头)。

英语里至今还有一道菜叫 corned beef hash------把牛肉和土豆切碎混炒。剁完之后,你已经认不出原来的食材了,但同样的食材、同样的剁法,出来的结果是一样的。

1953 年,IBM 研究员 Hans Peter Luhn 在一篇内部备忘录中描述了一种通过数学函数将数据"打散"后快速查找的技术。后来学术界发现这个过程和"剁碎"的意象非常吻合:

  • 输入一段完整的数据(一块食材)
  • 经过函数处理后变成一段面目全非的短输出(剁成碎末)
  • 无法从碎末还原出原来的食材(不可逆)
  • 同样的食材同样剁法,结果一致(确定性)

于是 Hash Function(哈希函数)这个术语在 1960 年代被正式确立。

中文"哈希"是纯粹的音译 ,就像"巧克力"翻译自 chocolate。另一个译名"散列"是意译,强调"打散排列"的效果。两者都常见,"哈希"使用更广泛。


二、Hash 的本质:一种契约,而非某个具体函数

这是理解 Hash 最关键的一步。

Hash 是一种规范(specification),不是一种实现(implementation)。 就像"排序"不是指某个具体算法,而是"把无序变有序"这个目标------冒泡、快排、归并都是排序的不同实现。

Hash 的契约是:

约定 含义
输入任意长度 可以是一个字符、一篇文章、一个文件
输出固定长度 无论输入多大,输出总是固定位数
确定性 同样的输入,永远得到同样的输出
高效性 计算速度要快
均匀性 输出尽量均匀分布,避免扎堆

至于具体怎么实现这个契约,由不同的哈希算法各自决定。就像 HTTP 是协议,Nginx 和 Apache 都是实现;Hash 是思想,MD5 和 SHA256 都是实现。


三、常见的 Hash 函数全景

3.1 非加密型哈希函数(追求速度和均匀)

这类函数不在乎安全性,追求的是极致的速度和均匀的分布,主要用于数据结构内部。

DJB2
复制代码
hash = 5381
for each char c in string:
    hash = hash * 33 + c
  • 发明者:Daniel J. Bernstein
  • 特点:实现极其简单,只用乘法和加法
  • 应用:早期很多语言的字符串哈希默认实现
MurmurHash
  • 发明者:Austin Appleby(2008)
  • 特点:速度极快,分布极均匀,针对现代 CPU 优化
  • 应用:Redis 的字典内部哈希、Hadoop、Cassandra、Elasticsearch 的分片路由
xxHash
  • 发明者:Yann Collet(2012,就是写 zstd 压缩算法的那位)
  • 特点:目前已知最快的非加密哈希函数之一
  • 应用:Linux 内核、大数据框架中的校验和
CRC32 / CRC16
  • 全称:Cyclic Redundancy Check(循环冗余校验)
  • 特点:本质是除法取余,计算快,但碰撞率稍高
  • 应用:网络协议校验(以太网帧用 CRC32)、Redis Cluster 用 CRC16 计算槽
FNV(Fowler--Noll--Vo)
复制代码
hash = offset_basis
for each byte b in data:
    hash = hash XOR b
    hash = hash * FNV_prime
  • 特点:实现简单,碰撞率低
  • 应用:DNS 服务器、各种编程语言内置哈希
SipHash
  • 特点:兼顾速度和安全性,能防御 HashDoS 攻击
  • 应用:Python 3.4+、Rust、Ruby 的字典默认哈希函数

为什么 Python 要换成 SipHash? 因为如果哈希函数可预测,攻击者可以构造大量碰撞的 key,让哈希表退化成链表(O(n) 查找),导致拒绝服务。SipHash 引入了随机种子,使得攻击者无法预测哈希值。

3.2 加密型哈希函数(追求安全性)

这类函数在上面的基础契约上,额外增加了安全性要求

安全要求 含义
抗原像攻击 给定哈希值 h,无法反推出输入 x
抗碰撞攻击 极难找到两个不同输入 x ≠ y 使得 hash(x) == hash(y)
雪崩效应 输入变一个 bit,输出变化超过 50%
MD5(Message Digest 5)
  • 发明者:Ronald Rivest(1991)

  • 输出:128 位(32 个十六进制字符)

  • 现状:已被破解,2004 年王小云教授团队找到了高效的碰撞方法

  • 现在还能用吗:不能用于安全场景(数字签名、密码存储),但仍可用于文件校验(只要不涉及对抗攻击)

    MD5("hello") = 5d41402abc4b2a76b9719d911017c592
    MD5("hellp") = 9f27079dbf2b3e20c18bee20e4dd5049 // 只差一个字母,结果天差地别

SHA 家族(Secure Hash Algorithm)
算法 输出长度 状态 典型应用
SHA-1 160 位 已不安全,Google 2017 年实现碰撞 Git 的 commit ID(历史原因)
SHA-256 256 位 安全,广泛使用 比特币挖矿、SSL 证书、区块链
SHA-512 512 位 安全,更长 高安全要求场景
SHA-3 可变 最新标准(2015),不同于 SHA-2 的架构 下一代安全场景
bcrypt / scrypt / Argon2(密码哈希函数)

这是一类特殊的哈希函数,专门设计来故意变慢

  • 普通哈希追求快,但密码哈希要慢------防止暴力破解

  • bcrypt 引入 salt (随机盐)和 cost factor(计算轮数)

  • scrypt 额外消耗大量内存,对抗 GPU/ASIC 暴力破解

  • Argon2 是 2015 年密码哈希竞赛的冠军,目前公认最佳

    同样的密码,因为 salt 不同,每次结果都不一样

    bcrypt("password123") = 2b12LJ3m4ys3Lg...(第一次) bcrypt("password123") = 2b12Kx9q2Wd5Rp...(第二次)


四、Hash 在实际系统中的应用全景

4.1 数据结构:哈希表(HashMap)

这是 Hash 最经典的应用。几乎所有编程语言的"字典"底层都是哈希表:

复制代码
Java     → HashMap          使用扰动函数(高16位异或低16位)
Python   → dict             使用 SipHash(防 HashDoS)
Go       → map              使用随机种子 + 类似 AES 的哈希
Redis    → dict             使用 MurmurHash2(内部字典),CRC16(集群分槽)

当两个 key 的哈希值碰撞时,不同语言的解决策略也不同:

  • 链地址法:碰撞的 key 挂成链表(Java 8 之前的 HashMap,Redis 的 dict)
  • 链表 + 红黑树:链表长度超过 8 时转为红黑树(Java 8+ 的 HashMap)
  • 开放寻址法:碰撞后找下一个空位(Python 的 dict,Go 的 map)

4.2 分布式系统:一致性哈希(Consistent Hashing)

普通取模 hash(key) % N 有个致命问题:N(节点数)一变,几乎所有 key 都要重新映射。

一致性哈希的解决思路:把哈希值空间组织成一个环(0 ~ 2^32-1),节点和 key 都映射到环上,key 顺时针找到最近的节点。当增删节点时,只有相邻的少量 key 需要迁移。

复制代码
应用场景:
- Memcached 客户端分片
- Amazon Dynamo 的数据分区
- CDN 的请求路由

Redis Cluster 选择了另一条路------哈希槽(Hash Slot),用 16384 个固定槽做中间层,槽的迁移粒度更可控。

4.3 数据完整性校验

复制代码
# 下载文件后验证 SHA256
sha256sum ubuntu-24.04-desktop-amd64.iso
# 对比官方公布的哈希值,一致则文件未被篡改

这就是利用了哈希的确定性------同样的文件一定产生同样的哈希值,文件被修改哪怕一个字节,哈希值就完全不同。

4.4 Git 的版本控制

Git 的每一个对象(commit、tree、blob)都用 SHA-1 哈希作为 ID:

复制代码
git log --oneline
# a1b2c3d  feat: add login page
# e4f5g6h  fix: null pointer bug

这些 a1b2c3d 就是 commit 内容的 SHA-1 哈希值前几位。Git 用它来保证:任何内容的篡改都会导致哈希值变化,整个历史链条就断裂了。

4.5 区块链与比特币挖矿

比特币的"挖矿"本质上是一个暴力求解哈希的过程:

复制代码
找到一个 nonce,使得 SHA256(SHA256(区块头 + nonce)) < 目标值

因为哈希的不可逆性,没有捷径,只能一个一个试。这就是"工作量证明"(Proof of Work)的原理。

4.6 布隆过滤器(Bloom Filter)

布隆过滤器用多个不同的哈希函数同时映射一个元素,判断元素"可能存在"或"一定不存在":

复制代码
应用场景:
- 浏览器判断 URL 是否在恶意网站黑名单中(Chrome 用的就是 Bloom Filter)
- 数据库查询前快速判断 key 是否可能存在,减少无效磁盘读取(HBase、RocksDB)
- 爬虫的 URL 去重

4.7 负载均衡

Nginx 可以根据请求的某个字段做哈希,保证同一个用户始终路由到同一台后端服务器:

复制代码
upstream backend {
    hash $request_uri consistent;  # 根据 URI 一致性哈希
    server 192.168.1.1;
    server 192.168.1.2;
    server 192.168.1.3;
}

五、Hash 过程的完整拆解

回到最初的困惑:以 Redis Cluster 为例,CRC16(key) % 16384 这个过程里到底哪部分是 Hash?

复制代码
key  →  CRC16(key)    →  % 16384    →  slot  →  node
         ↑                  ↑
      这是哈希           这是取模映射
     (把数据"剁碎"      (把哈希结果
       成固定长度)        压缩到指定范围)

CRC16 是哈希函数,负责把任意长度的 key 变成一个 0~65535 的 16 位整数。

% 16384 是取模映射,负责把哈希结果进一步压缩到 0~16383 的槽范围。

业界习惯把整个过程统称为"hash",但严格来说,取模本身不是哈希,它是对哈希结果的再映射


六、一张图总结

复制代码
                        Hash:一种将任意输入映射为固定输出的思想
                                       |
              ┌────────────────────────┴─────────────────────────┐
         非加密型(追求速度)                              加密型(追求安全)
              |                                                  |
   ┌──────┬──────┬──────┬──────┐              ┌──────┬────────┬────────┬────────┐
  DJB2  Murmur xxHash  CRC   FNV            MD5   SHA-1   SHA-256  bcrypt
   |      |      |      |     |              |      |        |        |
  简单  极快   最快  校验和 简洁          已破解  不安全   主流安全   密码存储

七、总结

Hash 不是一个函数,而是一种思想,一种契约:

  • 目标:把任意长度的输入,映射为固定长度的输出
  • 实现:MD5、SHA256、MurmurHash、CRC16......都是这个契约的不同实现
  • 侧重:非加密型追求速度均匀,加密型追求安全不可逆,密码型故意求慢
  • 应用:从编程语言的字典、数据库索引,到分布式系统路由、区块链挖矿、文件校验------Hash 无处不在

理解了这一点,再回头看 Redis Cluster 的 CRC16(key) % 16384,就能清晰地分辨出:CRC16 是哈希(剁碎),取余是映射(分队),两者配合完成从 key 到 slot 的定位。

Hash 就像面向对象中的"接口"------它定义了"做什么",至于"怎么做",由每个具体的哈希算法自己决定。


如果这篇文章帮你理清了 Hash 的本质,欢迎点赞收藏。有问题欢迎评论区交流。

相关推荐
春日见2 小时前
端到端自动驾驶综述
linux·人工智能·算法·机器学习·自动驾驶
呆子也有梦2 小时前
思考篇:积分是存成道具还是直接存数值?——ET/Skynet 框架下,从架构权衡到代码实现全解析
游戏·架构·c#·lua
balmtv2 小时前
国内AI镜像站实测:GPT、Gemini、Claude三款旗舰模型技术比拼
人工智能·gpt
ywfwyht2 小时前
nvidia/PhysicalAI-Autonomous-Vehicles数据集
人工智能·自动驾驶
balmtv2 小时前
Claude 4.6国内镜像实测:编程技术硬核拆解
人工智能
Rorsion2 小时前
对优化器的改进
人工智能·机器学习
学嵌入式的小杨同学2 小时前
STM32 进阶封神之路(十八):RTC 实战全攻略 —— 时间设置 + 秒中断 + 串口更新 + 闹钟功能(库函数 + 代码落地)
c++·stm32·单片机·嵌入式硬件·mcu·架构·硬件架构
fajianchen2 小时前
如何设计微服务统一认证中心
微服务·云原生·架构·iam