
电脑中,文件的名称具有唯一性。只要设定好名称,是不可能重复的。例如:新建一个文档,取名叫“文稿”,如果想再新建一个同名文件,会被系统提示“已包含同名文件”
但这只能证明名称而已,且再同一个文件夹中,适用此条件,换个文件夹还是可以使用同一名称,所以,还有一种方式,就是看文件的大小。
新建一个Word文档,里面有1000字,和1万字,文件大小也是绝对不一样的。
最后,可以通过查找文件的方式,输入文件名称来寻找同名文件及其所在的目录。
在MongoDB中,如果不特别指定,每个文档都会生成一个唯一的ObjectId作为其主键_id的值。这个值是一个看似随机的串。这个串到底是什么值?为什么MongoDB要使用这个值作为默认主键?它内部又包含了什么样的信息?如果你还不了解,就请看下面文章吧。MongoDB中数据的基本单元称为文档(Document)。文档是MongoDB的核心概念,多个键极其关联的值有序的放置在一起便是文档。
在一个特定集合内部,需要唯一的标识文档。因此MongoDB中存储的文档都由一个”_id”键,用于完成此功能。这个键的值可以是任意类型的,默认试ObjectId对象。ObjectId对象的生成思路是本文的主题,也是很多分布式系统可以借鉴的思路。
为了考虑分布式,“_id”要求不同的机器都能用全局唯一的同种方法方便的生成它。因此不能使用自增主键(需要多台服务器进行同步,既费时又费力),因此选用了生成ObjectId对象的方法。
ObjectId使用12字节的存储空间,其生成方式如下:
0 1 2 3 4 5 6 7 8 9 10 11
时间戳 机器ID PID 计数器
前四个字节时间戳是从标准纪元开始的时间戳,单位为秒,有如下特性:
时间戳与后边5个字节一块,保证秒级别的唯一性;
保证插入顺序大致按时间排序;
隐含了文档创建时间;
机器ID是服务器主机标识,通常是机器主机名的散列值。
同一台机器上可以运行多个mongod实例,因此也需要加入进程标识符PID。
前9个字节保证了同一秒钟不同机器不同进程产生的ObjectId的唯一性。后三个字节是一个自动增加的计数器(一个mongod进程需要一个全局 的计数器),保证同一秒的ObjectId是唯一的。同一秒钟最多允许每个进程拥有(256^3 = 16777216)个不同的ObjectId。
总结一下:时间戳保证秒级唯一,机器ID保证设计时考虑分布式,避免时钟同步,PID保证同一台服务器运行多个mongod实例时的唯一性,最后的计数器保证同一秒内的唯一性(选用几个字节既要考虑存储的经济性,也要考虑并发性能的上限)。
“_id”既可以在服务器端生成也可以在客户端生成,在客户端生成可以降低服务器端的压力。
在我们使用百度云盘上传文件的时候,有的时候一个上百兆甚至更大的文件,秒级上传。这其中一定是云盘识别了文件的唯一标识,所以根本就无需上传,直接提示的上传成功。这不仅在使用云盘服务的时候感受到了急速体验,也极大的节省后台的存储资源。这里的说的文件唯一标识不是文件的名字唯一,而是说用一段字符串来唯一标识出文件的内容。之前也接参考过一套源码 文件上传服务 ,每个上传的文件都是采用MD5计算出文件唯一名称,将文件存储在服务器的一个文件目录下,每次上传新文件,都会先根据文件MD5标识查重。
不论文件大小,MD5都会生成一个固定长度的字符串,例如我这里生成的都是这样的32位字符串 831a3cf0f43dc6b1f12a75fa22ed3bf5 。说实话,这个名字太长,当然存储在后台的磁盘里也没啥关系,但是如果放到URL中,或是文本编辑器中
将上面两个图中的文件标识提出来对比下
第一个文件标识采用md5算法生成,虽然保证了文件的唯一,但是明显过长。
第二个文件标识采用两种算法生成,左侧7位采用CRC32生成,右侧16位应该是md5算法生成后截取的一半。
第二个标识生成的规则给出了一个新的思路,采用md5和crc32两种算法相结合,再进行适当的截取字符串,这样即可以保证标识的唯一性也能有效的减少字符串的长度。
简单来说,crc32算法比md5算法在对同样一个文件进行摘录,耗时短,但同时摘录的信息量也少,所以只能做初筛选。对比多个文件是否重复的时候,首先采用crc32算法,如果两个文件的crc32摘录不一样,那两个文件肯定不重复,但是如果crc32摘录一样,那也不能说明两个文件重复。这时,md5摘录可以做进一步对比,这样对比的结果才是确定的。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)