1、在Mysql的分散式環境中,為什麼不推薦使用自增主鍵?
--自增主鍵在分散式環境下有嚴重問題,例如有一張商品表:
有3個表分片,分別是表分片1(0-1億),表分片2(1-2億),表分片3(2-3億)
自增主鍵必須連續,只能採用‘範圍分片’形式,會產生‘尾部熱點’效應
--當有表A、B、C三個資料庫時,儲存資料時都是透過自增來進行儲存的,那麼當A庫沒有存滿時,那麼B庫和C庫就不會儲存資料,那麼某一個時間段,資料庫的壓力是集中在其中一個資料庫的,並沒有做到負載均衡
--當我們將資料同步到其他庫的時候,那麼由於採用了自增ID,在進行插入的過程中,入非常損耗效能,因為在同步過程中是加鎖來進行實現的
--每個庫都維護一份自己的自增序列,那麼當進行跨庫查詢的時候,就會產生ID重合的衝突。
2、UUID可以用來做主鍵嗎?會存在什麼問題?
--UUID是不能用來作為主鍵的,因為UUID是無序的,作為主鍵會涉及大量的索引重排
3、雪花演算法可以用做主鍵嗎?原理是什麼?有什麼優缺點?如何解決缺點?
--可以用來作為主鍵
是由符號位+時間戳+工作程序+序列號位的自增組成
優點:1、不會重複
2、有序 不會造成空間浪費
3、生成速度快
缺點:1、依賴機器時鐘,如果機器時鐘回撥,會導致重複ID生成
2、在單機上是遞增的但是由於涉及到分散式環境,每個機器的時鐘不可能完全同步,有時會出現不是全部遞增的
--解決:
時鐘回撥問題的解決思路:
1、直接丟擲異常
if (currentTimestamp < lastTimestamp) { throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - currentTimestamp)); }
2、使用Map<machine_id,max_id>儲存過去一段時間內每一臺機器在當前這一毫秒產生的ID的最大值,當某臺機器發生時鐘回撥,直接在這臺機器對應的max_id的基礎上繼續自增生成ID
3、將原本10位機器碼拆分成3位時鐘序列及機器碼,發生變化,那麼這時將時鐘序列新增一位,重新定義整個雪花id,同時為了避免例項重啟引用時間序列丟失,因此時鐘序列存到DB或者快取中
// 處理時間回撥 if (currentTimestamp < lastTimestamp) { clockSequence = (clockSequence + 1) & CLOCK_SEQUENCE_MASK; }