如何使用Node.js/JavaScript生成类似Zerodha的唯一易记用户ID
符合Zerodha规则的6位易记唯一用户ID实现方案
该格式的ID总容量为 26*26*10000=6760000,完全满足中小规模产品的用户量需求,实现可以从易记性优化、唯一性保证两个维度落地:
一、易记性优化规则
要降低记忆成本,生成的时候需要提前过滤掉高认知成本的组合:
- 剔除易混淆字符:字母部分排除大写的
I、O、L,避免和数字1、0产生混淆,实际可用字母共23个,可生成的字母组合为 23*23=529 种 - 优先关联用户特征:如果有用户的姓名、昵称等信息,优先取姓名拼音首字母作为前两位(比如姓名“张三”取
ZS,“王二狗”取WG),比纯随机生成的字母记忆成本低90%以上 - 数字部分过滤无效序列:排除4位完全相同(如
0000、1111)、连续递增/递减(如1234、4321)的特殊序列,这类序列不仅容易被恶意遍历,批量生成时撞号概率也更高 - 有条件的可以优先使用常见字母组合,比如常用拼音首字母、高频英文缩写,避免
XQ、ZV这类使用频率极低的生僻组合
二、唯一性保证方案
根据项目规模可以选择两种实现方式:
方案1:预生成ID池(推荐,适配用户量<500万的项目)
提前全量生成符合规则的ID,按需取用,性能最高,完全避免重复问题:
- 按照上述易记规则生成所有可用ID,存入单独的数据库表,字段至少包含
id(主键)、uid(生成的用户ID,加唯一索引)、is_used(是否已被使用,默认0)、used_time(使用时间) - 提前将1000-2000条未使用的ID缓存到Redis,每次用户注册时直接从缓存中弹出一条使用,同时异步更新数据库的
is_used状态,缓存不足时自动补全 - 示例生成代码(Python):
import random import string # 过滤易混淆字母 ALLOWED_LETTERS = [c for c in string.ascii_uppercase if c not in {"I", "O", "L"}] # 排除的数字序列 BANNED_NUM_SEQ = {"1234","2345","3456","4567","5678","6789", "9876","8765","7654","6543","5432","4321","3210"} def generate_valid_uid_pool() -> list: uid_pool = [] for l1 in ALLOWED_LETTERS: for l2 in ALLOWED_LETTERS: for num in range(10000): num_str = f"{num:04d}" # 过滤4位相同数字 if len(set(num_str)) == 1: continue # 过滤特殊序列 if num_str in BANNED_NUM_SEQ: continue uid_pool.append(f"{l1}{l2}{num_str}") # 打乱池顺序 random.shuffle(uid_pool) return uid_pool
方案2:实时生成校验(适配不想预生成的场景)
不需要提前生成ID,每次注册时实时生成校验:
- 按照易记规则随机生成一个符合格式的ID
- 查询用户表中该ID是否存在(用户表的展示ID字段必须加唯一索引)
- 不存在则直接返回使用,存在则重试,最多重试10次,避免ID池耗尽时无限循环
- 并发量高的场景可以加分布式锁,避免同一时间多个请求生成相同ID
三、边界注意事项
- 如果项目预期用户量超过500万,建议扩展ID格式,比如改为3位字母+4位数字,总容量可以提升到23^3*10000≈1200万,足够覆盖大部分C端产品需求
- 该ID仅作为对外展示的用户标识,不要用作数据库主键,主键建议使用自增ID或者雪花ID,避免业务调整时需要修改主键逻辑
- 有条件的可以开放自定义前缀功能,允许用户选择自己喜欢的两位字母前缀,系统自动匹配可用的数字后缀,进一步降低用户记忆成本
内容的提问来源于stack exchange,提问作者Bhavesh Gohel
相关产品推荐
相关产品推荐

