objectid是12字节组成,四个成分timestamp+machash+pid+inc
默认mongodb collection内的_id是唯一的。客户插入文档时依赖driver自动生成的_id能否保证唯一呢?
自动objectid的唯一性
自动生成并不是mongo daemon生成的,而是driver生成的。
目前没有发现使用服务端生成objectid的,从实验看出mongoshell和javaclient都是客户端生成objectid。后续会发现,同一个客户端进程生成的最后三个byte总是连续的,因为起始的随机值进程启动时就全局确定了,而如果是server端一般服务启动后就长时间运行,server端提供的话多个客户端的objectid可能后缀不是连续的,而事实是连续的。
显然machine name+pid是hash出来的并不能保证objectid唯一,不同的机器的mac地址有可能是相同的,但是可能性比较小;当前进程的id也可能是hash冲突的,可能性也是比较低的;当前进程加载ObjectId的时候给了一个随机值,从这个随机值开始递增计数,随着时间推移,不同进程的递增值发生交叉也是可能的,但是可能性也很低。
如果要发生冲突,那么需要以上四个维度的小概率同时发生,所以但是这个冲突的可能性微乎其微,一般只要按照这个driver的规范使用就可以了。
实际上driver的这种算法可以看作UUID的一种实现,是的多个client在整个时间轴上生成的id总是唯一的。这样服务端不需要维护id如何生成。
当db自动添加objectid入库的时候,如果有已经存在的objectid则会插入失败。一般应用层不用考虑insert时候发生id冲突,由于这个原因导致丢失的document的概率很小。
为什么objectid比递增integer作为id和uuid好?
如果是integer递增势必会影响并发插入,多个客户端无法知道当前最新的id,唯一性都交给服务端保证,只能顺序处理doc insert。生成id的任务多机负载均衡也不灵活,虽然mysql有配置递增步长作为解决方案。objectid由12个字节组成,所有的驱动按照这个规范生成objectid,基本上保证唯一性。
ObjectId可以看作UUID的另一种实现。