大流量下訂單號生成方法

流量不大的情況下,訂單號生成


很久之前寫過一篇利用DB生成業務主鍵的文章,介紹了利用DB來生成唯一的ID。當時便是用這種方式來生成訂單號的。只不過拿到ID後,根據訂單業務,簡單加個前綴而已。

@Service
public class KeyGen{
   @Autowired
   private KeyGenRepository keyGenRepository;
   public long genNo(){
   KeyGen keyGen = new KeyGen();
   keyGenRepository.genarateNo(keyGen );
   //這個就是我們需要的no
   long no = keyGen.getNo();
   }
}
private String generateOrderNo() {
        StringBuffer sbf=new StringBuffer();
        //前綴
        sbf.append("100");
        long no = keyGen.genNo();
        sbf.append(no);
        return sbf.toString();
    }

這種方式用了一段時間,沒發現有訂單號重複的情況。這種解決方案算是一個基礎的思路,再複雜的訂單生成規則,如果訂單號要包含一個唯一的屬性,利用數據庫的自增特性是個不錯的方案。


大流量下訂單號的生成


如果每個小時的訂單量非常大,比如說,一個小時有兩百萬個訂單,只用單獨一個key_gen表是支持不住的,畢竟寫入的壓力太大了,影響訂單號的生成速度。這個時候可以考慮針對訂單號的生成,搞單獨的庫,並分庫,降低insert的壓力,提高生成訂單號的速度。


分庫的規則


有一種做法是根據倉庫來映射,比如說,一家電商公司的倉庫總共有50個,那麼可以進行如下的映射:

warehouse1:數據庫0
warehouse2:數據庫0
warehouse3:數據庫1
warehouse4:數據庫1
warehouse5:數據庫2
warehouse6:數據庫2
warehouse7:數據庫3
warehouse8:數據庫3
warehouse9:數據庫3
warehouse10:數據庫4
。。。。。。
。。。。。。
warehouse50:數據庫9

將50個倉庫映射到【0-9】對應的數據庫上,當下單的時候,如果訂單對應的倉庫的是warehouse1,則映射到數據庫0,對應的倉庫如果是warehouse10,則對應的數據庫4。這樣子,訂單號的生成的壓力便分配到10個數據庫上了。

進行分庫後,每個分庫裏都有一張key_gen表。


組裝訂單號


上面的分庫分表,目的是爲了生成一個唯一的ID,這個ID是訂單號的一部分,生成ID藉助了數據庫,但是後面組裝訂單號則完全是業務邏輯操作,無需利用數據庫了。

訂單號的生成規則各個公司都有自己的要求,舉個例子:

時間 + 6位隨機數 + 數據庫生成的唯一ID+倉庫標識

時間的生成可以簡單的使用如下代碼生成:

SimpleDateFormat formatShort = new SimpleDateFormat("yyMMdd");
Date now = new Date();
String currentDate = formatShort.format(now);

六位的隨機數可以藉助JAVA的AtomicLong來實現,可以應付併發。

到此訂單號完整的生成了。那有沒有坑呢?因爲進行了分庫,每個庫都有key_gen,生成的ID只是庫內的唯一,多個庫則是未必的。比如說,兩個訂單創建的請求,倉庫分別是warehouse1和warehouse3,根據上面的配置規則,分別路由到了數據庫0數據庫1這兩個庫,這個時候,就可能產生相同的ID。但是不要忘記,訂單號的生成是包含倉庫標識的,一個1,一個是3,是不同的,另外還有隨機數,所以訂單號重複的機會基本不太可能的。


提供批量生成訂單號的接口


尤其是將生成訂單號定義爲一個微服務接口的,一定要提供批量生成訂單號的接口,在流量很大的情況下,每獲取一個訂單號就要走一次網絡調用,開銷實在太大了。那麼一次要生成多少個才合適呢,這個根據自己的業務情況,一般情況下20-50個是夠用的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章