前言
我們在進行平臺賬號體系設計的時候,遇到這么一個需求:在平臺注冊的用戶ID以n位的數字展現。
乍一看,這個需求很簡單,就一句話。但仔細思考后,發現這里面還是有很多地方需要思考的:
- 用戶ID是隨機生成還是順序自增?
- 如果是隨機生成的:
- 如何保證每次生成的ID都是唯一的?
- 如果是順序自增的:
- 是不是會泄露平臺用戶規模,增加安全隱患?
- 如何保證分布式高并發下的ID順序自增?
- 如果用戶數量達到n位數上限后,如何自動擴展ID?
思路
首先,先確定ID是自增還是隨機,從上面的思考中,可以發現用戶ID自增會帶來一些安全隱患:如當系統存在某種bug,可以通過用戶ID查詢用戶信息時,就會面臨通過遍歷用戶ID,達到獲取平臺全量用戶信息的隱私泄露問題。另外,自增也會暴露平臺用戶規模,不利于商業行為。所以,用戶ID必須是隨機生成。
那么,用戶ID隨機生成,如何保證每次都是一個唯一值呢?這里有兩個思路:
- 設計一種算法,通過數學運算,以一定的入參,得到一個一一映射的出參,該出參的范圍在n為數字的大小范圍內。數學表達式為:
y = f(x_0,x_1,...,x_m,n)
其中,m=入參個數,由m個入參確定唯一性,n=y的范圍大小。
- 借助于工程思想,利用各種中間件實現該需求。如借助與MySQL+redis。
方案
針對第一個思路,可以參考唯一隨機數映射算法
這里主要展開下使用工程思想,借助MySQL+Redis+定時器的實現方式。
在MySQL里創建一張表t_user_id_pool, 該表中放入所有符合條件的用戶id,如000000-999999。
設計定時器邏輯為:每隔1小時,去redis中讀取key為id_pool的鍵,
- 如果id_pool不存在,則隨機地從數據庫中讀取1000個用戶id,以隊列的形式存入redis的id_pool里;
- 如果id_pool存在但隊列里id數量小于等于200時,從數據庫隨機獲取1000個用戶id,push到redis的id_pool里。
業務側生成用戶id的時候,從redis的id_pool里pop一個值出來作為用戶id。因為redis天然單線程結構,所以不用擔心,高并發情況下會獲取相同的id。