1.關于訂單號
訂單號用于記錄用戶在電商網站中的下單信息(通常有商品列表、金額、時間等),用戶下單后可根據訂單號查詢支付狀態、物流狀態等,也可以根據訂單號進行投訴、反饋、售后咨詢等。
訂單號的生成通常要滿足的需求:
1)唯一性:訂單號不可重復,以免發生業務沖突
2)簡短:便于記錄、存儲
3)業務相關性:可根據訂單號定位相關業務
4)時間相關性:可根據訂單號定位發生時間范圍
5)有序性:訂單號應當有序,便于建立索引,提高查詢速度
6)安全性:訂單號不應透露用戶量、交易量等信息,也不要讓別人隨便就能拼出來。
馬克思告訴我們,具體問題具體分析,生成訂單號也應該以具體業務需求為準。先來看一下淘寶的3個訂單號:
123736088576847054
121102577636847054
119636777937847054
對比這3個訂單號你能發現什么規律嗎?除了后6位相同似乎沒有別的規律。相同的后6位可能是截取自用戶id或以用戶id作為因子。這樣做有什么好處呢?如果業務量大、并發較高可在訂單號生成中加入用戶id作為因子,由于單個用戶在某一時間段內的請求是有限的(一般系統也可能會對用戶操作的頻率、下單次數進行限制,限制用戶在某一時間段最多可以操作多少次或限制用戶某一時間段內最多可以下多少單),所以這樣做可以一定程度降低生成的訂單號的重復率。
當然,可以借鑒和自己公司業務比較接近的公司的產品的訂單號格式,如打車業務可以借鑒滴滴出行, 支付業務可以接近支付寶或微信支付等。
2.訂單號生成策略比較
1)UUID: UUID是通用唯一識別碼(Universally Unique Identifier)的縮寫,由時間戳、機器標識碼、隨機數組成。優點是簡單粗暴(可使用JDK自帶的UUID實現- java.util.UUID),缺點是無序,不適合建立索引。
2)DB sequence:可以使用數據庫提供的自增序列(如oracle和PostgreSQL的sequence,Redis的incr)作為訂單號,缺點是位數不確定,有溢出風險,高并發情況下有性能瓶頸。
3)Snowflake: 也叫雪花算法,是由Twitter開源的分布式id生成算法,生成id時的因子是:時間戳+遞增序列+機器號+業務號,默認生成的id是18位的long型數字。我測了一下4核CPU每秒可生成100w+個id,可以說性能還是不錯的。查看其源碼會發現,該算法只有簡單的邏輯判斷與位運算,沒有字符串拼接也沒有時間格式化。這應該是該算法相較于普通算法性能較高的主要原因。下面截圖是snowflake算法生成id的關鍵代碼:
twitter-scala版本: https://github.com/twitter/snowflake
java版本:https://github.com/downgoon/snowflake
想要在自己的項目中引入Snowflake很簡單,可以引入其maven依賴,也可以直接復制其源代碼(主要就一個Snowflake.java)到項目中。
使用Snowflake生成訂單號(id)非常簡單,需要注意的是其中兩個參數的含義:
// dataCenterId可用于區分機器,workerId可用于區分業務
// datacenter: 2; workerId: 5
Snowflake snowflake = new Snowflake(2, 5);
long id1 = snowflake.nextId();
long id2 = snowflake.nextId();
如果需要解析生成的id,可以使用如下方式:
上圖中arr[0-3]分別代表id生成的時間戳,機器標識,業務標識,序列號
當然,Snowflake算法雖然性能較高,但不一定符合實際業務,如果條件允許可以根據Snowflake源碼做定制化實現,結合實際業務并汲取snowflake優秀的地方重新實現。