分布式數據庫當然也有主鍵的需求,但是為什么不直接使用uuid作為主鍵呢?作為曾經被這個問題困惑過的人,試着回答一下
1. UUID生成速率低下
Java的UUID依賴於SecureRandom.nextBytes方法,而SecureRandom又依賴於操作系統提供的隨機數源,在Linux系統下,它的默認依賴是/dev/random,而這個源是阻塞的。最可怕的是,這個nextBytes方法還是一個synchronized方法,也就是說,如果多線程調用UUID,生成速率不升反降。
測試結果:在一台64線程的服務器上,調用UUID.randomUUID方法,生成一千萬個uuid平均耗時在130s,tps不到8w
2. UUID主鍵在innodb中會引發性能問題
a. innodb中的主鍵索引也是聚集索引,如果插入的數據是順序的,那么b+樹的葉子基本都是滿的,緩存也可以很好的發揮作用。如果插入的數據是完全無序的,那么葉子節點會頻繁分裂,緩存也基本無效了。這會減少tps
b. uuid占用的空間較大
3. UUID完全沒有意義,如果有一個主鍵是全局自增的,那么數據排列順序就是數據的插入順序
解決方案:
1. 分布式全局序列生成(使用zk的DistributedAtomicLong,一次自增一個步長,用戶用完了步長內的序列,再找zk要)
2. Twitter的snowflake算法
當然自增序列也不是完美的,因為在極大並發的情況下,按自增主鍵插入會發生爭用,主鍵的上界會出現熱點。但總的來說,還是可以接受的