大家好,我是枫哥!今天和大家探讨一下服务器环境中用户 ID 的生成问题。很多小伙伴可能都熟悉雪花算法(Snowflake),这是个经典的分布式 ID 生成工具。然而,当我们需要生成短数字 ID时,雪花算法就有些捉襟见肘了。接下来,给大家介绍几种生成短 ID 的新方法!
背景
最近的项目中,需要为用户生成一个账号 ID,最开始使用 UUID(全球唯一标识符),但由于其字符串过长,既影响存储和传输性能,也不利于用户记忆。因此,生成一个相对短的数字 ID 成为了首要任务。
雪花算法的局限性
雪花算法基于 Twitter 开发的开源工具,生成 64 位长的数字 ID,既支持分布式,又高效、稳定。然而,生成的 ID 过长,不便于用户记忆和输入,显然无法满足我们的需求。为此,我们开始尝试一些其他方案。
方案尝试与优化1. 自增 ID 方案
首先,我们想到利用数据库的自增 ID 功能。在登录系统中,用户的登录请求会上传第三方的标识信息(如 openid 和 token),服务器会查询数据库,如果没有注册则生成一个新的数字 ID。这样,所有账号 ID 都存储在一张 ID 表中,并设置自增特性,确保每个新增 ID 都是唯一且按顺序递增的。
然而,单独使用自增 ID 也存在一定问题。特别是当数据量巨大时,数据库的性能可能会下降,另外还可能会因为并发插入操作出现死锁。经过测试后,发现 MySQL 的replace into语句在并发操作时可能会触发死锁。这意味着自增 ID 方案并非万无一失。
2. 分布式数据库方案
为了解决死锁问题,我们参考了美团的方案——通过分布式数据库生成 ID。具体而言,我们可以部署多个 MySQL 服务器,每个服务器负责一部分 ID 的生成任务。这种方式能显著提高生成效率并减少并发压力,但其部署成本较高,也不太适合小规模的应用场景。多台服务器的协调也为运维带来了额外负担,因此最终放弃了此方案。
3. 分片和步长调整
另一种方式是利用 MySQL 自增步长的特性,通过设置不同的步长使不同的分片生成不重叠的 ID 范围。例如,10 张分片表中,每张表的起始 ID 相隔 1,000,000。这种方式在小规模应用中表现良好,但当需求频繁变动时,可能会产生较大的维护难度。因此我们决定再尝试更精细的控制方法。
4. 预申请 ID 方案(最终方案)
我们最终决定采用一种「预申请 ID」的方式。每次生成一批 ID(如 1,000 个),并存储在缓存中,当缓存中 ID 即将耗尽时,再向数据库申请下一批新的 ID。这样的方式既减少了数据库的压力,也避免了 ID 的浪费。此外,当系统扩容或发生意外宕机时,这种方式也能灵活调整,保障 ID 的连续性。
方案实施细节
每次 ID 生成时,服务端会从预申请的批次中取出一个 ID,当剩余 ID 数量较少时,系统会自动请求一批新的 ID 段,确保服务的连续性。这种方法有效避免了死锁,同时降低了数据库的访问频率。此外,通过优化逻辑,我们还可以避免 ID 的过度浪费,使整个方案更经济、高效。
总结
以上就是我们在唯一 ID 生成方案上的探索之路。从雪花算法到预申请 ID,我们尝试了多个方案,不断优化。希望大家在今后的开发中也能找到最适合自己的唯一 ID 生成方案!如果你有更多有趣的方案,欢迎留言分享,我们共同探讨进步!
感谢你的阅读,别忘了点赞、关注哦!
背景
最近的项目中,需要为用户生成一个账号 ID,最开始使用 UUID(全球唯一标识符),但由于其字符串过长,既影响存储和传输性能,也不利于用户记忆。因此,生成一个相对短的数字 ID 成为了首要任务。
雪花算法的局限性
雪花算法基于 Twitter 开发的开源工具,生成 64 位长的数字 ID,既支持分布式,又高效、稳定。然而,生成的 ID 过长,不便于用户记忆和输入,显然无法满足我们的需求。为此,我们开始尝试一些其他方案。
方案尝试与优化1. 自增 ID 方案
首先,我们想到利用数据库的自增 ID 功能。在登录系统中,用户的登录请求会上传第三方的标识信息(如 openid 和 token),服务器会查询数据库,如果没有注册则生成一个新的数字 ID。这样,所有账号 ID 都存储在一张 ID 表中,并设置自增特性,确保每个新增 ID 都是唯一且按顺序递增的。
然而,单独使用自增 ID 也存在一定问题。特别是当数据量巨大时,数据库的性能可能会下降,另外还可能会因为并发插入操作出现死锁。经过测试后,发现 MySQL 的replace into语句在并发操作时可能会触发死锁。这意味着自增 ID 方案并非万无一失。
2. 分布式数据库方案
为了解决死锁问题,我们参考了美团的方案——通过分布式数据库生成 ID。具体而言,我们可以部署多个 MySQL 服务器,每个服务器负责一部分 ID 的生成任务。这种方式能显著提高生成效率并减少并发压力,但其部署成本较高,也不太适合小规模的应用场景。多台服务器的协调也为运维带来了额外负担,因此最终放弃了此方案。
3. 分片和步长调整
另一种方式是利用 MySQL 自增步长的特性,通过设置不同的步长使不同的分片生成不重叠的 ID 范围。例如,10 张分片表中,每张表的起始 ID 相隔 1,000,000。这种方式在小规模应用中表现良好,但当需求频繁变动时,可能会产生较大的维护难度。因此我们决定再尝试更精细的控制方法。
4. 预申请 ID 方案(最终方案)
我们最终决定采用一种「预申请 ID」的方式。每次生成一批 ID(如 1,000 个),并存储在缓存中,当缓存中 ID 即将耗尽时,再向数据库申请下一批新的 ID。这样的方式既减少了数据库的压力,也避免了 ID 的浪费。此外,当系统扩容或发生意外宕机时,这种方式也能灵活调整,保障 ID 的连续性。
方案实施细节
每次 ID 生成时,服务端会从预申请的批次中取出一个 ID,当剩余 ID 数量较少时,系统会自动请求一批新的 ID 段,确保服务的连续性。这种方法有效避免了死锁,同时降低了数据库的访问频率。此外,通过优化逻辑,我们还可以避免 ID 的过度浪费,使整个方案更经济、高效。
总结
以上就是我们在唯一 ID 生成方案上的探索之路。从雪花算法到预申请 ID,我们尝试了多个方案,不断优化。希望大家在今后的开发中也能找到最适合自己的唯一 ID 生成方案!如果你有更多有趣的方案,欢迎留言分享,我们共同探讨进步!
感谢你的阅读,别忘了点赞、关注哦!