对于 DyanamoDB 支持的 Web 应用程序,我需要生成唯一、稳定的 URL,这些 URL 可靠地引用 DynamoDB 表中的唯一行。
过去,对于 PostgreSQL 支持的应用程序,我使用自动递增整数作为主键并使用整数的hashid得到了很好的结果:
In [1]: import hashids
In [2]: hasher = hashids.Hashids(min_length=5, alphabet='abcdefghijklmnopqrstuvwxyz0123456789')
In [3]: hasher.encode(12345)
Out[2]: 'e763y'
然后我会在 URL 中使用它:
http://example.com/random-mutable-title-e763y/
但是,对于 DynamoDB,没有自动递增的主键,而是建议使用 UUID。
但是,UUID 包含 128 位,并且 UUID 的 hashid 更长:
In [3]: import uuid
In [4]: hasher.encode(uuid.uuid4().int)
Out[4]: '5j257lmv00xwo5pvo132783jv0qkq'
URL 太长了,或者至少是丑陋的:
http://example.com/random-mutable-title-5j257lmv00xwo5pvo132783jv0qkq/
我已经看到建议简单地掩盖 UUID:
In [5]: hasher.encode((uuid.uuid4().int & (1 << 64) - 1))
Out[5]: 'v0qnq92ml7oj382'
但即使这样似乎也有点长:
http://example.com/random-mutable-title-v0qnq92ml7oj382/
我可以看到更多的位:
In [6]: hasher.encode((uuid.uuid4().int & (1 << 32) - 1))
Out[6]: 'lj044pkn'
但这似乎有点危险:
In [7]: len(set(uuid.uuid4().int & (1 << 32) - 1 for _ in range(100000)))
Out[7]: 99999
在这里做什么最好/最安全?我预计此表不会有繁重的写入负载,所以我是否需要分解并实现一个带有条件写入的自动递增整数方案?
更新:
我刚刚意识到,如果我右移 UUID1 的 32 位,它似乎是相当独特的:
In [8]: len(set(uuid.uuid1().int >> 32 for _ in range(1000000)))
Out[8]: 1000000
但这会回来咬我吗?:D
更新 2:
要回答评论中的一些问题:
我的应用程序将是唯一一个写入此表的应用程序。
该应用程序是用 Python 编写的。
表的数据架构使用用户 ID 的哈希键和根据行中存储的内容而变化的排序键。假设我正在存储用户记录、用户的项目和项目中包含的文档。我可能最终会拥有一个全局二级索引来支持基于 URL hashid 的查询,除非 hashid 和记录的主键最终是等价的。
该表的常见查询将是:
- 另一个 GSI 支持的电子邮件用户(用于登录)
- 所有用户(通过哈希键)
- 一个用户的所有项目(使用 hash key 和 sort key
beginswith()
) - 一个特定的项目(由正在讨论的 GSI 支持)
- 特定项目中的所有文档(哈希键和排序键
beginswith()
) - 单个文件(由 GSI 支持,讨论中)