TL;DR;
這是一篇為了完成寫作KPI而寫的博客,總結起來就是提供了一種用Common Lisp實現來自于Twitter的雪花算法的實現方案。成品在這里,本文只是簡單地描述一下生成雪花ID的大致思路,詳細內容請各位移步代碼倉庫查看。
上述代碼倉庫中的snowflake算法——如果我的實現確實可以稱作snowflake算法的話——的思路來自于下列兩個地方:
如何獲取時間戳
Common Lisp本身提供了一個獲取時間戳的函數,也就是get-universal-time
,可惜的是,這個函數所返回的并不是通常意義上的Epoch時間戳,而是自己的一套計算時間的方式中的表示時間的整數。為了獲得UNIX時間戳,需要借助于第三方庫local-time
。為了可以獲取到毫秒精度的時間戳,一個可運行的函數如下
(defun now ()
"Returns the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC."
(let* ((now (local-time:now))
(seconds (local-time:timestamp-to-unix now))
(milliseconds (local-time:timestamp-millisecond now)))
(+ (* 1000 seconds) milliseconds)))
如何獲取機器ID
這里參考了Sony的雪花ID算法中的思路,基于機器的內網IP地址來生成機器ID。當然了,Common Lisp標準中是沒有提供獲取機器的內網IP地址的方法的,這一點也可以借助于第三方庫實現,選用的是ip-interfaces
。通過這個庫提供的get-ip-interfaces
函數可以獲取到機器的所有“接口”,遍歷這個接口的列表后即可找出其中的內網IP。一臺機器可能會有多個內網IP,我的方法是選用了第一個找到的內網IP地址。當然了,還需要一個將向量轉化為數值的函數,并取出轉化為數值后的IP地址的低10位,作為機器ID。
序號
如果希望生成的ID是保持遞增的,那么就需要維護一個可以原子遞增的數值計數器。在真實的使用中可以通過Redis的INCR指令來生成這一個ID,但是因為這里的雪花ID算法是作為一個獨立的庫實現的,不需要依賴于數據庫等外部組建,因此這里就直接使用了Common Lisp自帶的random
函數來生成這個序號了。
全文完