隨機(jī)數(shù)
隨機(jī)數(shù)的性質(zhì)從弱到強(qiáng)分為3類: 詳見:計算機(jī)中的隨機(jī)數(shù)
1. 隨機(jī)性??
2. 不可預(yù)測性
3. 不可重現(xiàn)性
在上面的三個性質(zhì)中叛买,越往下就越嚴(yán)格。具備隨機(jī)性蹋订,不代表一定具備不可預(yù)測性聪全;具備不可預(yù)測性,不代表一定具備不可重現(xiàn)性;但如果具備不可重現(xiàn)性辅辩,一定具備隨機(jī)性和不可預(yù)測性。
滿足上面的3性依次對應(yīng)著:弱偽隨機(jī)數(shù)娃圆,強(qiáng)偽隨機(jī)數(shù)玫锋,真隨機(jī)數(shù)。
在計算機(jī)中讼呢,用軟件生成的隨機(jī)數(shù)都是偽隨機(jī)數(shù)撩鹿,即弱偽隨機(jī)數(shù)和強(qiáng)偽隨機(jī)數(shù)。由于弱偽隨機(jī)數(shù)不具備不可預(yù)測性悦屏,因此在密碼學(xué)中只使用強(qiáng)隨機(jī)數(shù)和真隨機(jī)數(shù)(在密碼學(xué)中节沦,隨機(jī)數(shù)常常被用于生成密鑰,因此具備可預(yù)測性是危險的)
至此础爬,我們知道甫贯,密碼學(xué)中使用的隨機(jī)數(shù)一定是強(qiáng)偽隨機(jī)數(shù)或者真隨機(jī)數(shù)。由于真隨機(jī)數(shù)用純軟件產(chǎn)生很困難看蚜,因此我們在軟件設(shè)計中都是用強(qiáng)偽隨機(jī)數(shù)叫搁。不過遺憾的是,一些語言提供的隨機(jī)數(shù)生成函數(shù)都是弱隨機(jī)數(shù)供炎。比如java.util.Random類生成的就是弱偽隨機(jī)數(shù),當(dāng)時java中的java.security.SecureRandom類提供的是強(qiáng)隨機(jī)數(shù)渴逻。
UUID
UUID是指Universally Unique Identifier,翻譯為中文是通用唯一識別碼,UUID 的目的是讓分布式系統(tǒng)中的所有元素都能有唯一的識別信息。如此一來佃牛,每個人都可以創(chuàng)建不與其它人沖突的 UUID盗似,就不需考慮數(shù)據(jù)庫創(chuàng)建時的名稱重復(fù)問題。
UUID 的十六個八位字節(jié)被表示為 32個十六進(jìn)制數(shù)字堕伪,以連字號分隔的五組來顯示纺弊,形式為 8-4-4-4-12圆恤,總共有 36個字符(即三十二個英數(shù)字母和四個連字號)聋袋。例如:
123e4567-e89b-12d3-a456-426655440000
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
數(shù)字M的四位表示 UUID 版本队伟,當(dāng)前規(guī)范有5個版本,M可選值為1, 2, 3, 4, 5幽勒;
數(shù)字N的一至四個最高有效位表示 UUID 變體( variant )嗜侮,有固定的兩位10xx因此只可能取值8, 9, a, b
UUID版本通過M表示,當(dāng)前規(guī)范有5個版本啥容,M可選值為1, 2, 3, 4, 5锈颗。這5個版本使用不同算法,利用不同的信息來產(chǎn)生UUID咪惠,各版本有各自優(yōu)勢击吱,適用于不同情景。具體使用的信息
version 1, date-time & MAC address
version 2, date-time & group/user id
version 3, MD5 hash & namespace
version 4, pseudo-random number
version 5, SHA-1 hash & namespace
UUID Version 1:基于時間的UUID
基于時間的UUID通過計算當(dāng)前時間戳遥昧、隨機(jī)數(shù)和機(jī)器MAC地址得到覆醇。由于在算法中使用了MAC地址,這個版本的UUID可以保證在全球范圍的唯一性炭臭。但與此同時永脓,使用MAC地址會帶來安全性問題,這就是這個版本UUID受到批評的地方鞋仍。如果應(yīng)用只是在局域網(wǎng)中使用常摧,也可以使用退化的算法,以IP地址來代替MAC地址--Java的UUID往往是這樣實現(xiàn)的(當(dāng)然也考慮了獲取MAC的難度)威创。
UUID Version 2:DCE安全的UUID
DCE(Distributed Computing Environment)安全的UUID和基于時間的UUID算法相同,但會把時間戳的前4位置換為POSIX的UID或GID肚豺。這個版本的UUID在實際中較少用到溃斋。
UUID Version 3:基于名字的UUID(MD5)
基于名字的UUID通過計算名字和名字空間的MD5散列值得到。這個版本的UUID保證了:相同名字空間中不同名字生成的UUID的唯一性吸申;不同名字空間中的UUID的唯一性盐类;相同名字空間中相同名字的UUID重復(fù)生成是相同的。
UUID Version 4:隨機(jī)UUID
根據(jù)隨機(jī)數(shù)呛谜,或者偽隨機(jī)數(shù)生成UUID在跳。這種UUID產(chǎn)生重復(fù)的概率是可以計算出來的,但隨機(jī)的東西就像是買彩票:你指望它發(fā)財是不可能的隐岛,但狗屎運通常會在不經(jīng)意中到來猫妙。
UUID Version 5:基于名字的UUID(SHA1)
和版本3的UUID算法類似,只是散列值計算使用SHA1(Secure Hash Algorithm 1)算法聚凹。
uuid應(yīng)用:
從UUID的不同版本可以看出割坠,Version 1/2適合應(yīng)用于分布式計算環(huán)境下齐帚,具有高度的唯一性;Version 3/5適合于一定范圍內(nèi)名字唯一彼哼,且需要或可能會重復(fù)生成UUID的環(huán)境下对妄;至于Version 4,我個人的建議是最好不用(雖然它是最簡單最方便的)敢朱。
使用較多的是版本1和版本4剪菱,其中版本1使用當(dāng)前時間戳和MAC地址信息。版本4使用(偽)隨機(jī)數(shù)信息拴签,128bit中孝常,除去版本確定的4bit和variant確定的2bit,其它122bit全部由(偽)隨機(jī)數(shù)信息確定蚓哩。
因為時間戳和隨機(jī)數(shù)的唯一性构灸,版本1和版本4總是生成唯一的標(biāo)識符。若希望對給定的一個字符串總是能生成相同的 UUID岸梨,使用版本3或版本5喜颁。
通常我們建議使用UUID來標(biāo)識對象或持久化數(shù)據(jù),但以下情況最好不使用UUID:
映射類型的對象曹阔。比如只有代碼及名稱的代碼表半开。
人工維護(hù)的非系統(tǒng)生成對象。比如系統(tǒng)中的部分基礎(chǔ)數(shù)據(jù)次兆。
對于具有名稱不可重復(fù)的自然特性的對象,最好使用Version 3/5的UUID锹锰。比如系統(tǒng)中的用戶芥炭。如果用戶的UUID是Version 1的,如果你不小心刪除了再重建用戶恃慧,你會發(fā)現(xiàn)人還是那個人园蝠,用戶已經(jīng)不是那個用戶了。(雖然標(biāo)記為刪除狀態(tài)也是一種解決方案痢士,但會帶來實現(xiàn)上的復(fù)雜性彪薛。)
隨機(jī) UUID 的重復(fù)機(jī)率:
Java中 UUID 使用版本4進(jìn)行實現(xiàn),所以由java.util.UUID類產(chǎn)生的 UUID怠蹂,128個比特中善延,有122個比特是隨機(jī)產(chǎn)生,4個比特標(biāo)識版本被使用城侧,還有2個標(biāo)識變體被使用易遣。利用生日悖論,可計算出兩筆 UUID 擁有相同值的機(jī)率約為
其中x為 UUID 的取值范圍嫌佑,n為 UUID 的個數(shù)豆茫。
每秒產(chǎn)生10億筆 UUID 侨歉,100年后只產(chǎn)生一次重復(fù)的機(jī)率是50%。如果地球上每個人都各有6億筆 UUID揩魂,發(fā)生一次重復(fù)的機(jī)率是50%幽邓。與被隕石擊中的機(jī)率比較的話,已知一個人每年被隕石擊中的機(jī)率估計為170億分之1火脉,也就是說機(jī)率大約是0.00000000006 (6 x 10-11)牵舵,等同于在一年內(nèi)生產(chǎn)2000億個 UUID 并發(fā)生一次重復(fù)。
綜上所述忘分,產(chǎn)生重復(fù) UUID 并造成錯誤的情況非常低棋枕,是故大可不必考慮此問題。
機(jī)率也與隨機(jī)數(shù)產(chǎn)生器的質(zhì)量有關(guān)妒峦。若要避免重復(fù)機(jī)率提高重斑,必須要使用基于密碼學(xué)上的強(qiáng)偽隨機(jī)數(shù)產(chǎn)生器來生成值才行。
Java中 UUID 對版本4進(jìn)行了實現(xiàn)肯骇,原理是由強(qiáng)偽隨機(jī)數(shù)生成器生成偽隨機(jī)數(shù)窥浪。
UUID生成器:
Java UUID Generator (JUG):開源UUID生成器,LGPL協(xié)議笛丙,支持MAC地址漾脂。
UUID:特殊的License,有源碼胚鸯。
Java 5以上版本中自帶的UUID生成器:好像只能生成Version 3/4的UUID骨稿。