UUID5升级方案

建站
0 字 / 约 0 分钟

UUID5升级方案

问题背景

在项目运行过程中发现 UUID5 存在重复问题,具体表现为:

  • 发现重复的 UUID5:e78b7b7a6f
  • 原因:5位十六进制字符的冲突概率在 400+ 文件的项目中已经不可忽视
  • 影响:导致不同页面使用相同的 permalink,造成路由冲突

冲突概率分析

原始方案

  • UUID长度:5位十六进制字符
  • 可能组合:16^5 = 1,048,576 种
  • 冲突概率:在 400+ 文件的项目中,根据生日悖论,冲突概率显著增加

升级方案

  • UUID长度:6位十六进制字符
  • 可能组合:16^6 = 16,777,216 种
  • 冲突概率:降低到原来的 1/16

技术实现

1. 改进的 UUID 生成算法

javascript
// 生成UUID5的函数(改进版,降低重复概率)
function generateUuid5(filePath = '') {
  const timestamp = Date.now().toString()
  const random = Math.random().toString(36).substring(2)
  const processId = process.pid.toString()
  const fileInfo = filePath.replace(/\\/g, '/').replace(/\.md$/, '')
  
  // 组合更多信息来降低重复概率
  const combined = timestamp + random + processId + fileInfo
  const hash = createHash('md5').update(combined).digest('hex')
  
  // 增加到6位以进一步降低冲突概率
  return hash.substring(0, 6)
}

2. 关键改进点

增加输入信息

  • 时间戳Date.now().toString() - 确保时间唯一性
  • 随机数Math.random().toString(36).substring(2) - 增加随机性
  • 进程IDprocess.pid.toString() - 避免多进程环境冲突
  • 文件路径filePath - 确保不同文件生成不同 UUID

增加输出长度

  • 从 5 位增加到 6 位十六进制字符
  • 冲突概率降低 16 倍

更新正则表达式

javascript
// 检查当前permalink是否包含UUID5格式(5位或6位字符)
const uuid5Pattern = /\/[a-z0-9]{5,6}$/
const hasUuid5 = uuid5Pattern.test(currentPermalink)

3. 调用方式更新

所有调用 generateUuid5() 的地方都需要传入文件路径:

javascript
// 更新前
const uuid = generateUuid5()

// 更新后  
const uuid = generateUuid5(fileInfo.relativePath)

实施步骤

1. 代码修改

  • ✅ 更新 generateUuid5() 函数
  • ✅ 更新所有函数调用
  • ✅ 更新正则表达式匹配规则

2. 重复问题修复

  • ✅ 修复 docs/70.建站/52.本站主题/自动索引.md 中的错误 permalink
  • ✅ 移除文档示例中的重复 frontmatter 块

3. 重新生成

  • ✅ 运行 AutoFrontmatter 重新生成所有 permalink
  • ✅ 验证无重复 UUID 存在

验证结果

升级前

bash
# 发现重复的 UUID5
Count Name                      Group                                                                                  
----- ----                      -----                                                                                  
    2 e78b7                     {e78b7, e78b7}                                                                        
    2 b7a6f                     {b7a6f, b7a6f}

升级后

bash
# 无重复 UUID 存在
# 输出为空,表示没有重复

兼容性处理

向后兼容

  • 正则表达式支持 5 位和 6 位 UUID 格式
  • 现有 5 位 UUID 的 permalink 保持不变
  • 新生成的 UUID 使用 6 位格式

迁移策略

  • 已有 UUID 的 permalink 不强制更新
  • 新文件或缺少 permalink 的文件使用新算法
  • 前缀不匹配的 permalink 会被更新为新格式

性能影响

计算开销

  • 增加文件路径处理:轻微
  • 增加哈希计算输入:轻微
  • 增加输出长度:无影响

存储开销

  • 每个 permalink 增加 1 个字符
  • 对整体存储影响可忽略

最佳实践

1. 定期检查

建议定期运行以下命令检查重复:

bash
Get-ChildItem -Path "docs" -Recurse -Filter "*.md" | Select-String "permalink:" | ForEach-Object { $_.Line -replace ".*permalink: /[^/]+/", "" } | Sort-Object | Group-Object | Where-Object { $_.Count -gt 1 }

2. 监控日志

关注 AutoFrontmatter 运行时的日志输出,特别是指示重复的警告信息。

3. 测试验证

在添加大量新文件后,建议重新运行 AutoFrontmatter 并检查是否有新的重复。

总结

通过将 UUID5 从 5 位升级到 6 位,并结合文件路径、时间戳、随机数和进程ID等信息,成功解决了 permalink 重复问题。新方案在保持向后兼容的同时,大幅降低了冲突概率,提高了系统的稳定性和可靠性。

关键收益:

  • ✅ 消除 UUID 重复问题
  • ✅ 降低冲突概率 16 倍
  • ✅ 保持向后兼容性
  • ✅ 提高系统稳定性