引出
大家都用过QQ或者微信吧, 当我们注册的时候, 会被自动分配一个QQ号, 这个号码是全局唯一且固定的, 那么, 如果是你来写的话, 如何为新注册的用户分配一个号码呢? 亦或是一个电商网站, 要为每个订单生成一个订单号? 再或是一个即时聊天, 要为每个消息生成一个消息ID?? 我简单想了想
方案一
其实这事说简单点, 不就是要为每个用户都配一个数字么? 而且这个数字必须是之前没有用过的. 那简单了, 数数就完了呗, 123456往下数, 来一个发一个记一个.
如何实现? MySQL主键自增, 或者redis记一个key, 每次incr
自增. 什么? QQ号从1开始太丑了? 简单, 自增设置一个起始ID.
完美, 实现方案简单粗暴, 而且不会出现重复.
方案二
使用时间戳. 使用当前时间戳来生成, 比如: 1585390459
这样的数字. 但是时间戳是以秒为单位的, 如果一秒发生了多次请求, 那不就重复了么? 我想了想, 有一个简单到爆的处理方法, 在后面再拼上0000
–9999
的随机数, 这样每秒有一万个不重复的, 重复的概率就降低了, 在生成后还需要查询是否已经存在, 若存在则重复生成.
方案三
说起来, 要生成这样的随机ID, 总要有一个地方来记录已生成的进度, 如果完全随机生成的话, 就不可避免的需要回查是否存在. 记录生成进度的可以有很多: redis、MySQL等等. 或者可以存在一个发号器, 所有的ID都有它来生成, 不停的生成, 供其他请求分配使用, 就是一个生产者消费者.
小结
通过想了几种方案, 发现了一些规律.
要想生成随机ID, 首先, 要有一个不是随机的而又是当前唯一持有的. 在这个前提下, 再各种添油加醋, 生成最终的ID. 就算你要调用随机函数, 也得设置一个随机种子不是? 莫非这就是传说中的以不变应万变..
很好, 那么现在问题就归结为, 如何给每个用户都配一个唯一标识
1.数数
直接想到的方案, 从1开始, 慢慢往后数, 而这个过程可以借助MySQL的主键自增, 也可以借助redis的单线程优势. 等等吧,
2.用户特征
可以根据不同用户的特征, 如用户的地域、性别、生辰等等, 来生成每个人的唯一标识, 此举可以参考身份证号码的生成, 每个人都是不一样的
3.当前机器特征
找到执行代码时的特定特征, 如: mac地址、时间戳、机器编号、线程ID等等
4.代码运行次数
线程共享变量, 每次执行则+1.
等等等等
简单想下来, 其实重要的是找到其中每次生成都和别人不一样的那个点, 然后拿来稍作加工即可. 有点找不同的赶脚. 对了, 在网上看到了twitter
的雪花算法, 基本也是找不同的思路. 关键就在于你是否能从各种功能繁杂的信息中找到那个不同的点. 如果实在找不到不同, 就只能人为的赋予他们不同了(自增ID等).
现在已经有很多工具了, uuid, MongoDB的objectid等, 基本可以拿来直接使用.