高性能 Swift 唯一 ID 生成器,灵感来源于 Snowflake,并进行了一些小的调整,旨在为分布式系统环境设置,该环境具有中等程度的活跃实体(数百个),这些实体应能够独立生成唯一标识符。
在 M1 基础机器上,它可以每秒生成约 1.15 亿个唯一标识符,并且大小是 UUID 的一半。
它采用略有不同的方法来最大限度地减少生成开销。
与 Snowflake 相比,一个关键的区别是 Frostflake 重复使用一个冻结的时间点,直到用完其生成标识符,这避免了为每个生成的 ID 获取当前时间 - 它将每生成 1K 个标识符(默认情况下)更新该冻结时间点,因此对于中等流量生成,时间戳将定期更新,以在大多数时间保持跨服务的时间排序——目的是使唯一标识符适合用作例如数据库键。
FrostflakeIdentifier 的默认输出是 base58 字符串,以便于人类阅读(例如 FungET5sN9j
),但 UInt64 原始值也可用。
添加到您的项目
dependencies: [
.package(url: "https://github.com/ordo-one/package-frostflake", .upToNextMajor(from: "6.0.0")),
]
然后将依赖项添加到您的目标,例如
.executableTarget(
name: "MyExecutableTarget",
dependencies: [
.product(name: "Frostflake", package: "package-frostflake")
]),
generatorIdentifier
在给定的时间点必须是唯一使用的,要么需要通过配置文件/持久化设置它,要么全局代理需要在运行时将其分配给需要 flake 生成器的组件,以确保同一标识符不会被并发使用。
import Frostflake
func testFrostflake() {
let frostflakeFactory = Frostflake(generatorIdentifier: 1)
let frostflake = frostflakeFactory.generate()
let decription = frostflake.debugDescription
print(decription)
}
还有一个可选的共享类生成器(性能约为 1/2)
Frostflake.setup(generatorIdentifier: 1) // Must always be set up once, globally shared
let frostflake1 = FrostflakeIdentifier()
let frostflake2 = FrostflakeIdentifier()
// Or optionally:
let frostflake3 = Frostflake.generate()
let frostflake4 = Frostflake.generate()
> swift run flake
JERHwh5PXjL
> swift run flake --identifier JERHwh5PXjL
Frostflake JERHwh5PXjL decoded:
JERHwh5PXjL 7423342004626526207 (2024-10-08 09:58:17 UTC, sequenceNumber:1, generatorIdentifier:2047)
> swift run flake --identifier 7423342004626526207
Frostflake JERHwh5PXjL decoded:
JERHwh5PXjL 7423342004626526207 (2024-10-08 09:58:17 UTC, sequenceNumber:1, generatorIdentifier:2047)
Frostflake 是一个 64 位值,就像 Snowflake 一样,但位分配略有不同。
默认情况下,Frostflake 为时间戳分配 32 位(约 136 年跨度),为序列号分配 21 位(允许每个给定生成器每秒最多 2,097,152 个标识符),为生成器标识符分配 11 位(允许系统中最多 2,048 个唯一的工作节点/节点)。
未来可能的一个方向是允许用户在序列标识符和生成器标识符之间分配位,以便更容易地适应不同的用例——只要这在服务窗口期间重新分配(服务窗口只需要比集群中最不同步的两个节点之间的时钟差长),时间戳部分将继续确保唯一性。
预计主机应启用 NTP,并且在操作期间不应跳跃式重置时钟(典型的 NTP 使用会缓慢地倾斜时钟,不应有任何问题,但需要注意)。 不同机器的相对同步时间无关紧要,因为如果设置正确,generatorIdentifier 会唯一标识标识符的各种生产者。
默认情况下,每个 generatorIdentifier 持续的最大生成速率约为每秒 200 万个标识符 - 如果超过此速率,我们将中止。 这给出了每个标识符约 477 纳秒 - 对于设计目的而言,这远远超过了以往的使用量 - 但如果您有真正高容量生成的用例,您也可以通过调整 generatorIdentifier 和 sequenceNumbers 之间的分配来重新分配大的分配,以适应这种情况。
可以使用 swift package benchmark
运行。
> swift package benchmark
...
==================
Running Benchmarks
==================
100% [------------------------------------------------------------] ETA: 00:00:00 | FrostflakeBenchmark:Frostflake descriptions
100% [------------------------------------------------------------] ETA: 00:00:00 | FrostflakeBenchmark:Frostflake shared generator
100% [------------------------------------------------------------] ETA: 00:00:00 | FrostflakeBenchmark:Frostflake shared generator with FrostflakeIdentifier() convenience
100% [------------------------------------------------------------] ETA: 00:00:00 | FrostflakeBenchmark:Frostflake with locks
100% [------------------------------------------------------------] ETA: 00:00:00 | FrostflakeBenchmark:Frostflake without locks
=====================================================================================================
Baseline 'Current_run'
=====================================================================================================
Host 'ice.local' with 20 'arm64' processors with 128 GB memory, running:
Darwin Kernel Version 24.0.0: Mon Aug 12 20:51:54 PDT 2024; root:xnu-11215.1.10~2/RELEASE_ARM64_T6000
===================
FrostflakeBenchmark
===================
Frostflake descriptions
╒═══════════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric │ p0 │ p25 │ p50 │ p75 │ p90 │ p99 │ p100 │ Samples │
╞═══════════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Instructions (K) * │ 36 │ 36 │ 36 │ 36 │ 36 │ 37 │ 37 │ 928 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Malloc (total) * │ 30 │ 30 │ 30 │ 30 │ 30 │ 30 │ 30 │ 928 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Memory (resident peak) (K) │ 9519 │ 9871 │ 9871 │ 9880 │ 9880 │ 9880 │ 9880 │ 928 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (K) │ 479 │ 477 │ 476 │ 472 │ 460 │ 443 │ 434 │ 928 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (ns) * │ 2092 │ 2101 │ 2107 │ 2122 │ 2177 │ 2253 │ 2286 │ 928 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (wall clock) (ns) * │ 2090 │ 2099 │ 2103 │ 2120 │ 2173 │ 2261 │ 2306 │ 928 │
╘═══════════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛
Frostflake shared generator
╒═══════════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric │ p0 │ p25 │ p50 │ p75 │ p90 │ p99 │ p100 │ Samples │
╞═══════════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Instructions * │ 245 │ 245 │ 245 │ 245 │ 245 │ 249 │ 254 │ 1000 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Malloc (total) * │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 1000 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Memory (resident peak) (K) │ 9322 │ 9740 │ 9740 │ 9748 │ 9748 │ 9748 │ 9748 │ 1000 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (M) │ 63 │ 63 │ 63 │ 61 │ 61 │ 49 │ 36 │ 1000 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (ns) * │ 18 │ 18 │ 18 │ 18 │ 19 │ 22 │ 30 │ 1000 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (wall clock) (ns) * │ 16 │ 16 │ 16 │ 16 │ 16 │ 20 │ 28 │ 1000 │
╘═══════════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛
Frostflake shared generator with FrostflakeIdentifier() convenience
╒═══════════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric │ p0 │ p25 │ p50 │ p75 │ p90 │ p99 │ p100 │ Samples │
╞═══════════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Instructions * │ 245 │ 245 │ 245 │ 245 │ 245 │ 245 │ 260 │ 1000 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Malloc (total) * │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 1000 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Memory (resident peak) (K) │ 9339 │ 9757 │ 9757 │ 9765 │ 9765 │ 9765 │ 9765 │ 1000 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (M) │ 64 │ 63 │ 63 │ 63 │ 62 │ 58 │ 41 │ 1000 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (ns) * │ 18 │ 18 │ 18 │ 18 │ 18 │ 20 │ 27 │ 1000 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (wall clock) (ns) * │ 16 │ 16 │ 16 │ 16 │ 16 │ 17 │ 24 │ 1000 │
╘═══════════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛
Frostflake with locks
╒═══════════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric │ p0 │ p25 │ p50 │ p75 │ p90 │ p99 │ p100 │ Samples │
╞═══════════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Instructions * │ 198 │ 198 │ 198 │ 198 │ 198 │ 198 │ 198 │ 169 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Malloc (total) * │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 169 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Memory (resident peak) (K) │ 9421 │ 9806 │ 9822 │ 9830 │ 9830 │ 9830 │ 9830 │ 169 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (M) │ 86 │ 85 │ 85 │ 85 │ 83 │ 82 │ 82 │ 169 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (ns) * │ 12 │ 12 │ 12 │ 12 │ 12 │ 12 │ 12 │ 169 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (wall clock) (ns) * │ 12 │ 12 │ 12 │ 12 │ 12 │ 12 │ 12 │ 169 │
╘═══════════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛
Frostflake without locks
╒═══════════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric │ p0 │ p25 │ p50 │ p75 │ p90 │ p99 │ p100 │ Samples │
╞═══════════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Instructions * │ 175 │ 175 │ 175 │ 175 │ 175 │ 175 │ 175 │ 226 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Malloc (total) * │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 226 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Memory (resident peak) (K) │ 9421 │ 9822 │ 9822 │ 9830 │ 9830 │ 9830 │ 9830 │ 226 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (M) │ 115 │ 115 │ 114 │ 114 │ 111 │ 109 │ 107 │ 226 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (ns) * │ 9 │ 9 │ 9 │ 9 │ 9 │ 9 │ 9 │ 226 │
├───────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (wall clock) (ns) * │ 9 │ 9 │ 9 │ 9 │ 9 │ 9 │ 9 │ 226 │
╘═══════════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛