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