摘要:關于我為什么寫這篇文章是因為今天在做訂單模塊的時候看到之前的上描述的年月日用戶位企業位四位自增長數。背景對于其定訂單的生成。個人的看法是主要是唯一,其他關于業務方面的不是太太重要。自增實現了用于將的值遞增,并返回結果。
關于我為什么寫這篇文章是因為今天在做訂單模塊的時候,看到之前的PRD上描述的年月日+用戶id2位+企業id位
+四位自增長數。然后竟被我反駁的突然改成了精確時間+4位自增長數,于是我更失望了。
我們考慮一下,據我所常見的訂單基本都14-20位。(年月日時分秒和隨機數)基本上就有14位了。雖然一般項目做不到淘寶雙11這種
支付峰值達到每秒10萬筆訂單.但是我覺得至少事先可以考慮到,想必當初淘寶或許也沒意識到以后發展
得這么好。
對于其定訂單的生成。我覺得要至少要符合以下這三種,全局唯一 ,
在復雜的分布式系統中,很多場景需要的都是全局唯一ID的場景,一般為了防止沖突可以考慮的有36
位的UUID,twitter的snowflake等。
但是可以思考這些問題?
是不是應該有一些其他意義的思考,比如說訂單系統有買家的id(取固定幾位)
是否有商品的標識,方便熟悉業務的排查問題或者查詢也通過不去系統查找可以有個初步的認識,但是業務量大的話感覺就可以排除這個人為的去辨識了。
個人的看法是主要是唯一,其他關于業務方面的不是太太重要。
查閱了相關資料,主要有以下這幾種
1.UUID
組成:當前日期+時間+時鐘序列+機器識別號(Mac地址或其他)沒有mac網卡的話會有別的東西識別。
在分布式系統中,所有元素(WEB服務器)都不需要通過中央控制端來判斷數據唯一性。幾十年之內可以達到全球唯一性。
snowflake的結構如下(每部分用-分開):
2.Mysql通過AUTO_INCREMENT實現、Oracle通過Sequence序列實現。
在數據庫集群環境下,不同數據庫節點可設置不同起步值、相同步長來實現集群下生產全局唯一、遞增ID
3.Snowflake算法 雪花算法
41位時間戳+10位機器ID+12位序列號(自增) 轉化長度為18位的長整型。
Twitter為滿足美秒上萬條消息的創建,且ID需要趨勢遞增,方便客戶端排序。
Snowflake雖然有同步鎖,但是比uuid效率高。
4.Redis自增ID
實現了incr(key)用于將key的值遞增1,并返回結果。如果key不存在,創建默認并賦值為0。 具有原子性,保證在并發的時候。
但是我在這主要想說的是雪花算法生成id
關于序列
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
第一位為未使用,接下來的41位為毫秒級時間(41位的長度可以使用69年),然后是5位datacenterId和5位workerId(10位的長度最多支持部署1024個節點) ,最后12位是毫秒內的計數(12位的計數順序號支持每個節點每毫秒產生4096個ID序號)
一共加起來剛好64位,為一個Long型。(轉換成字符串長度為18)
snowflake生成的ID整體上按照時間自增排序,并且整個分布式系統內不會產生ID碰撞(由datacenter和workerId作區分),并且效率較高。據說:snowflake每秒能夠產生26萬個ID。
以下是代碼
部分借鑒與網絡
100萬個ID 耗時2秒
/** * Created by youze on 18-7-5 */ public class IdWorker { /** * 起始的時間戳 */ private final static long START_STMP = 1530795377086L; /** * 每一部分占用的位數 */ /** * 序列號占用的位數 */ private final static long SEQUENCE_BIT = 12; /** * 機器標識占用的位數 */ private final static long MACHINE_BIT = 5; /** * 數據中心占用的位數 */ private final static long DATACENTER_BIT = 5; /** * 每一部分的最大值 */ private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT); private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT); private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT); /** * 每一部分向左的位移 */ private final static long MACHINE_LEFT = SEQUENCE_BIT; private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT; private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT; /** * 數據中心 */ private long datacenterId; /** * 機器標識 */ private long machineId; /** * 序列號 */ private long sequence = 0L; /** * 上一次時間戳 */ private long lastStmp = -1L; public IdWorker(long datacenterId, long machineId) { if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) { throw new IllegalArgumentException("datacenterId can"t be greater than MAX_DATACENTER_NUM or less than 0"); } if (machineId > MAX_MACHINE_NUM || machineId < 0) { throw new IllegalArgumentException("machineId can"t be greater than MAX_MACHINE_NUM or less than 0"); } this.datacenterId = datacenterId; this.machineId = machineId; } /** * 產生下一個ID * @return */ public synchronized long nextId() { long currStmp = getNewstmp(); if (currStmp < lastStmp) { throw new RuntimeException("Clock moved backwards. Refusing to generate id"); } if (currStmp == lastStmp) { //相同毫秒內,序列號自增 sequence = (sequence + 1) & MAX_SEQUENCE; //同一毫秒的序列數已經達到最大 if (sequence == 0L) { currStmp = getNextMill(); } } else { //不同毫秒內,序列號置為0 sequence = 0L; } lastStmp = currStmp; return ( //時間戳部分 currStmp - START_STMP) << TIMESTMP_LEFT //數據中心部分 | datacenterId << DATACENTER_LEFT //機器標識部分 | machineId << MACHINE_LEFT //序列號部分 | sequence; } private long getNextMill() { long mill = getNewstmp(); while (mill <= lastStmp) { mill = getNewstmp(); } return mill; } private long getNewstmp() { return System.currentTimeMillis(); } public static void main(String[] args) { IdWorker snowFlake = new IdWorker(2, 3); long start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { System.out.println(snowFlake.nextId()); } System.out.println(System.currentTimeMillis() - start); } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71472.html
摘要:每個事物的范圍限定在單個聚合內。當然,記住僅僅因為是兩個表的關系設計不易任何方式表明他們是兩個聚合。一個捕獲這個事件,并在每個指定的聚合上執行命令。盡管如此,不得不訴諸于此解決方案,這表明您的聚合的總體邊界并不正確。 什么是聚合: 聚合是一個更大的封裝單位,而不僅僅是一個類。每個事物的范圍限定在單個聚合內。聚合組件的使用期被界限在整個聚合的生命周期中。 具體的,一個聚合將會處理命令,請...
摘要:由于初版需求及開發工作都沒有參與,在接手項目后過了遍前端結構發現所有交互及組件都是現擼,并未使用市面上已有的優秀前端框架從我個人角度理解上出發,后續需求變更中當需要實現某些常用組件樣式或交互時,基本上都需要現擼或者尋找合適的組件。 2016悄無聲息的過去了,再過不久便是農歷新年 這幾天相對清閑梳理了一下去年所做的工作,希望在新的一年能發展的更好 今年一共研發或升級了五款產品:合伙人、奪...
摘要:解決冪等問題的三部曲,也是作者的思考框架。這是解決冪等問題的第二部曲列出并減少副作用的分析維度。所以在并發執行的維度,將并發重復執行變成串行重復執行是最好的冪等解決方案。 綱要 文章目的:本文旨在提煉一套分布式冪等問題的思考框架,而非解決某個具體的分布式冪等問題。在這個框架體系內,會有一些方案舉例說明。文章目標:希望讀者能通過這套思考框架設計出符合自己業務的完備的冪等解決方案。文章內容...
摘要:結論二從不同的角度去看抽象一致性得出的結論是不一樣的只有最符合現有業務的沒有最正確的說明三對于實現一方法是查詢用戶的消費信息而這里的詳細計算訂單金額直接寫在這個方法里面抽象層次十分混亂所以實現一是不推薦的。 場景 用戶實體User 通過用戶Id查找用戶的訂單信息接口List orders = orderService.queryOrders(long userId) 通過用戶Id查找...
摘要:離職新路線年的總結在這里年總結,其實在發布這個文章之前,就已經跟阿里那邊再談新的,會以的級別入職阿里閑魚部門。總所周知,我司在月份調整了一次架構,具體如下美團調整了組織架構。 17年的總結來的更晚一點,其實是一直在猶豫要不要寫,主要感覺去年一年折騰的有點兇殘,連續換工作以及地點,一路走來有糾結,有痛苦,有快樂,有興奮,有迷茫,有得有失,所以想了很久,還是來記錄下這一年的關鍵點。 離職 ...
閱讀 3028·2021-09-08 10:43
閱讀 1031·2019-08-30 15:53
閱讀 965·2019-08-30 13:51
閱讀 836·2019-08-29 14:03
閱讀 796·2019-08-26 18:35
閱讀 1229·2019-08-26 13:38
閱讀 1580·2019-08-26 10:34
閱讀 3497·2019-08-26 10:21