[原文地址:https://blog.ti-node.com/blog...]php
惟一ID的生成并非一件小事 , 想说爱它 , 也并非像简单来一个uniqid()这样一件容易的事 .node
为何要惟一ID ?mysql
1 . 数据库的自增ID在分库的时候 , 会是一场灾难 . 假设分两个库 , 由于每一个库都会开始从1开始自增 , 届时 , 系统中将会出现两个id为1的用户 .nginx
2 . 自增id会暴露用户量或者其余业务量 .git
3 . 自增id会让有心者经过API获得任意用户的信息资料 .github
解决方案呢 ?sql
1 . UUID , 全称Universally Unique Identifier , 中文通用惟一标识符 . 这个是开放软件基金会组织提出的一个标准 , 为的就是解决分布式环境下生成惟一标识符的问题 . UUID的长度是固定的32位 , 组织格式8-4-4-4-12 , 固然了在用的时候 , 中间的分隔符是要去掉的 . 这个货有几个问题不得不提 , 首先是字母数字混合 , 在一些传统数据库下 , 索引不太好作 , 不只索引体积大 , 查询效率也差 . 其次是它自己也很是大 .数据库
2 . MongoDB ObjectId , 格式模样都很相似于UUID , 是Mongodb内置的一种数据类型 , 若是你在插入数据的时候不指定_id , 那么Mongodb默认就会采用用这个货才填充_id , 在Mongodb这种类kv性质的数据库中 , 有着不错的查询效率 .flask
3 . 自建解决方案 , 为了可以解决业务问题 , 不少公司都本身提出一些解决方案 , 这些方案无疑都要作到以下几点 :服务器
市面上有的几种解决方案为Twitter的snowflake , Flikr的数据库自增方案 , Instagram的数据库存储过程方案 . 重点说下Twitter的snowflake解决方案原理 .
snowflask使用了64bit来表示一个id , Twitter的工程师们将它分红了4个段 , 每段表示不一样的含义 . 以下图 :
前41bit段 , 是时间戳 , 单位会精确到毫秒级 . 因此该bit段能够容纳的时间容量为 2^41 = 2.199x10^12 毫秒 , 也就是 2.199x10^9 秒 . 换算成年 , 就是大概为69.7年 . 也就说 , 从1970年1月1日开始 , 可使用69.7年 , id产生机器的上限就到了 .
中10bit段 , 是机器ID , 最大能够容纳2^10=1024台机器 . 你能够部署1一台以上的机器 , 给每一个机器配置一个不同凡响的独立的id号 , 好比从1号开始 , 最多能够部署到1024号机器 . 而后机器集群最前面挡一台nginx之类的服务器作代理 , 就能够完成一个不错的id发号集群了 .
后12bit段 , 是自增序列( 你能够等同为mysql的自增id ) , 它表示的1毫秒内的自增序列 . 也就是说从0毫秒开始一直到1毫秒结束这段时间内自增 . 也就说1毫秒内最多产生2^12=4096个序列 , 也就是说同一台机器上同一毫秒内最多产生4096个序列 , 若是超过了该数字 , 那就等待下一毫秒产生新的id .
TIPS : 顺带提一下 , php的uniqid()函数存在很大的风险 , 它生成的id并不能像它的名字那样作到uniqid , 重复几率略高 . 详情查看该函数的手册页评论 . 点击这里
TIPS : 推荐一个基于snowflake的php id产生器 : donkeyid生成器