操屁眼的视频在线免费看,日本在线综合一区二区,久久在线观看免费视频,欧美日韩精品久久综

新聞資訊

    在Windows中可以使用 事件查看器 來查看相關(guān)日志,并結(jié)合日志ID進(jìn)行日志篩選。常見的日志有:

    • 4634 - 賬戶被注銷
    • 4647 - 用戶發(fā)起注銷
    • 4624 - 賬戶已成功登錄
    • 4625 - 賬戶登錄失敗
    • 4648 - 試圖使用明確的憑證登錄(可以用以查看遠(yuǎn)程登陸的相關(guān)信息,比如遠(yuǎn)程登陸的IP地址等)

    一、使用事件查看器查看日志信息

    下面以查看遠(yuǎn)程連接的日志為例展示事件查看器的使用。

    1.1 在搜索框中搜索 “事件查看器”,雙擊打開。(事件查看器的位置在C:\WINDOWS\system32,名字為eventvwr.msc)

    1.2 展開左側(cè)的 “Windows 日志” 然后雙擊 “安全”。(其他的日志可能需要選擇其他選項)

    1.3 點擊最右邊”操作” 欄中的 “刪選當(dāng)前日志…”

    1.4 在彈出的窗口選擇記錄時間 (Logged), 和輸入事件ID : 4648, 我這里是想查看過去七天的遠(yuǎn)程到本機(jī)的記錄

    1.5 選中一條過濾出來的記錄, 然后 點擊 下方的 “詳情”, 其中 “EventData” 下的 “IpAddress” 即為遠(yuǎn)程過來的IP地址,127.0.0.1表示是本地登陸,‘TargetUserName’是本電腦的名字。

    二、常用的日志ID

     審計目錄服務(wù)訪問

      4934 - Active Directory 對象的屬性被復(fù)制

      4935 -復(fù)制失敗開始

      4936 -復(fù)制失敗結(jié)束

      5136 -目錄服務(wù)對象已修改

      5137 -目錄服務(wù)對象已創(chuàng)建

      5138 -目錄服務(wù)對象已刪除

      5139 -目錄服務(wù)對象已經(jīng)移動

      5141 -目錄服務(wù)對象已刪除

      4932 -命名上下文的AD的副本同步已經(jīng)開始

      4933 -命名上下文的AD的副本同步已經(jīng)結(jié)束

      審計登錄事件

      4634 - 帳戶被注銷

      4647 - 用戶發(fā)起注銷

      4624 - 帳戶已成功登錄

      4625 - 帳戶登錄失敗

      4648 - 試圖使用明確的憑證登錄

      4675 - SID被過濾

      4649 - 發(fā)現(xiàn)重放攻擊

      4778 -會話被重新連接到Window Station

      4779 -會話斷開連接到Window Station

      4800 – 工作站被鎖定

      4801 - 工作站被解鎖

      4802 - 屏幕保護(hù)程序啟用

      4803 -屏幕保護(hù)程序被禁用

      5378 所要求的憑證代表是政策所不允許的

      5632 要求對無線網(wǎng)絡(luò)進(jìn)行驗證

      5633 要求對有線網(wǎng)絡(luò)進(jìn)行驗證

      審計對象訪問

      5140 - 網(wǎng)絡(luò)共享對象被訪問

      4664 - 試圖創(chuàng)建一個硬鏈接

      4985 - 交易狀態(tài)已經(jīng)改變

      5051 - 文件已被虛擬化

      5031 - Windows防火墻服務(wù)阻止一個應(yīng)用程序接收網(wǎng)絡(luò)中的入站連接

      4698 -計劃任務(wù)已創(chuàng)建

      4699 -計劃任務(wù)已刪除

      4700 -計劃任務(wù)已啟用

      4701 -計劃任務(wù)已停用

      4702 -計劃任務(wù)已更新

      4657 -注冊表值被修改

      5039 -注冊表項被虛擬化

      4660 -對象已刪除

      4663 -試圖訪問一個對象

      審計政策變化

      4715 - 對象上的審計政策(SACL)已經(jīng)更改

      4719 - 系統(tǒng)審計政策已經(jīng)更改

      4902 - Per-user審核政策表已經(jīng)創(chuàng)建

      4906 - CrashOnAuditFail值已經(jīng)變化

      4907 - 對象的審計設(shè)置已經(jīng)更改

      4706 - 創(chuàng)建到域的新信任

      4707 - 到域的信任已經(jīng)刪除

      4713 - Kerberos政策已更改

      4716 - 信任域信息已經(jīng)修改

      4717 - 系統(tǒng)安全訪問授予帳戶

      4718 - 系統(tǒng)安全訪問從帳戶移除

      4864 - 名字空間碰撞被刪除

      4865 - 信任森林信息條目已添加

      4866 - 信任森林信息條目已刪除

      4867 - 信任森林信息條目已取消

      4704 - 用戶權(quán)限已分配

      4705 - 用戶權(quán)限已移除

      4714 - 加密數(shù)據(jù)復(fù)原政策已取消

      4944 - 當(dāng)開啟Windows Firewall時下列政策啟用

      4945 - 當(dāng)開啟Windows Firewall時列入一個規(guī)則

      4946 - 對Windows防火墻例外列表進(jìn)行了修改,添加規(guī)則

      4947 - 對Windows防火墻例外列表進(jìn)行了修改,規(guī)則已修改

      4948 - 對Windows防火墻例外列表進(jìn)行了修改,規(guī)則已刪除

      4949 - Windows防火墻設(shè)置已恢復(fù)到默認(rèn)值

      4950 - Windows防火墻設(shè)置已更改

      4951 - 因為主要版本號碼不被Windows防火墻承認(rèn),規(guī)則已被忽視

      4952 - 因為主要版本號碼不被Windows防火墻承認(rèn),部分規(guī)則已被忽視,將執(zhí)行規(guī)則的其余部分

      4953 - 因為Windows防火墻不能解析規(guī)則,規(guī)則被忽略

      4954 - Windows防火墻組政策設(shè)置已經(jīng)更改,將使用新設(shè)置

      4956 - Windows防火墻已經(jīng)更改主動資料

      4957 - Windows防火墻不適用于以下規(guī)則

      4958 - 因為該規(guī)則涉及的條目沒有被配置,Windows防火墻將不適用以下規(guī)則:

      6144 - 組策略對象中的安全政策已經(jīng)成功運(yùn)用

      6145 - 當(dāng)處理組策略對象中的安全政策時發(fā)生一個或者多個錯誤

      4670 - 對象的權(quán)限已更改

      審計特權(quán)使用

      4672 - 給新登錄分配特權(quán)

      4673 - 要求特權(quán)服務(wù)

      4674 - 試圖對特權(quán)對象嘗試操作

      審計系統(tǒng)事件

      5024 - Windows防火墻服務(wù)已成功啟動

      5025 - Windows防火墻服務(wù)已經(jīng)被停止

      5027 - Windows防火墻服務(wù)無法從本地存儲檢索安全政策,該服務(wù)將繼續(xù)執(zhí)行目前的政策

      5028 - Windows防火墻服務(wù)無法解析的新的安全政策,這項服務(wù)將繼續(xù)執(zhí)行目前的政策

      5029 - Windows防火墻服務(wù)無法初始化的驅(qū)動程序,這項服務(wù)將繼續(xù)執(zhí)行目前的政策

      5030 - Windows防火墻服務(wù)無法啟動

      5032 - Windows防火墻無法通知用戶它阻止了接收入站連接的應(yīng)用程序

      5033 - Windows防火墻驅(qū)動程序已成功啟動

      5034 - Windows防火墻驅(qū)動程序已經(jīng)停止

      5035 - Windows防火墻驅(qū)動程序未能啟動

      5037 - Windows防火墻驅(qū)動程序檢測到關(guān)鍵運(yùn)行錯誤,終止。

      4608 -Windows正在啟動

      4609 - Windows正在關(guān)機(jī)

      4616 - 系統(tǒng)時間被改變

      4621 - 管理員從CrashOnAuditFail回收系統(tǒng),非管理員的用戶現(xiàn)在可以登錄,有些審計活動可能沒有被記錄

      4697 - 系統(tǒng)中安裝服務(wù)器

      4618 - 監(jiān)測安全事件樣式已經(jīng)發(fā)生

      想查看所有事件的完整列表,請訪問微軟網(wǎng)站:Microsoft /加利福尼亞州消費者隱私法案(CCPA)選擇退出圖標(biāo)

    分布式唯一ID介紹

    分布式系統(tǒng)全局唯一的 id 是所有系統(tǒng)都會遇到的場景,往往會被用在搜索,存儲方面,用于作為唯一的標(biāo)識或者排序,比如全局唯一的訂單號,優(yōu)惠券的券碼等,如果出現(xiàn)兩個相同的訂單號,對于用戶無疑將是一個巨大的bug。

    在單體的系統(tǒng)中,生成唯一的 id 沒有什么挑戰(zhàn),因為只有一臺機(jī)器一個應(yīng)用,直接使用單例加上一個原子操作自增即可。而在分布式系統(tǒng)中,不同的應(yīng)用,不同的機(jī)房,不同的機(jī)器,要想生成的 ID 都是唯一的,確實需要下點功夫。

    一句話總結(jié):

    分布式唯一ID是為了給數(shù)據(jù)進(jìn)行唯一標(biāo)識。

    分布式唯一ID的特征

    分布式唯一ID的核心是唯一性,其他的都是附加屬性,一般來說,一個優(yōu)秀的全局唯一ID方案有以下的特點,僅供參考:

    • 全局唯一:不可以重復(fù),核心特點!
    • 大致有序或者單調(diào)遞增:自增的特性有利于搜索,排序,或者范圍查詢等
    • 高性能:生成ID響應(yīng)要快,延遲低
    • 高可用:要是只能單機(jī),掛了,全公司依賴全局唯一ID的服務(wù),全部都不可用了,所以生成ID的服務(wù)必須高可用
    • 方便使用:對接入者友好,能封裝到開箱即用最好
    • 信息安全:有些場景,如果連續(xù),那么很容易被猜到,攻擊也是有可能的,這得取舍。

    分布式唯一ID的生成方案

    UUID直接生成

    寫過 Java 的朋友都知道,有時候我們寫日志會用到一個類 UUID,會生成一個隨機(jī)的ID,去作為當(dāng)前用戶請求記錄的唯一識別碼,只要用以下的代碼:

    String uuid=UUID.randomUUID();
    

    用法簡單粗暴,UUID的全稱其實是Universally Unique IDentifier,或者GUID(Globally Unique IDentifier),它本質(zhì)上是一個 128 位的二進(jìn)制整數(shù),通常我們會表示成為 32 個 16 進(jìn)制數(shù)組成的字符串,幾乎不會重復(fù),2 的 128 次方,那是無比龐大的數(shù)字。

    以下是百度百科說明:

    UUID由以下幾部分的組合:

    (1)UUID的第一個部分與時間有關(guān),如果你在生成一個UUID之后,過幾秒又生成一個UUID,則第一個部分不同,其余相同。

    (2)時鐘序列。

    (3)全局唯一的IEEE機(jī)器識別號,如果有網(wǎng)卡,從網(wǎng)卡MAC地址獲得,沒有網(wǎng)卡以其他方式獲得。

    UUID的唯一缺陷在于生成的結(jié)果串會比較長。關(guān)于UUID這個標(biāo)準(zhǔn)使用最普遍的是微軟的GUID(Globals Unique Identifiers)。在ColdFusion中可以用CreateUUID()函數(shù)很簡單地生成UUID,其格式為:xxxxxxxx-xxxx- xxxx-xxxxxxxxxxxxxxxx(8-4-4-16),其中每個 x 是 0-9 或 a-f 范圍內(nèi)的一個十六進(jìn)制的數(shù)字。而標(biāo)準(zhǔn)的UUID格式為:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12),可以從cflib 下載CreateGUID() UDF進(jìn)行轉(zhuǎn)換。 [2]

    (4)在 hibernate(Java orm框架)中, 采用 IP-JVM啟動時間-當(dāng)前時間右移32位-當(dāng)前時間-內(nèi)部計數(shù)(8-8-4-8-4)來組成UUID

    要想重復(fù),兩臺完全相同的虛擬機(jī),開機(jī)時間一致,隨機(jī)種子一致,同一時間生成uuid,才有極小的概率會重復(fù),因此我們可認(rèn)為,理論上會重復(fù),實際不可能重復(fù)!!!

    uuid優(yōu)點:

    • 性能好,效率高
    • 不用網(wǎng)絡(luò)請求,直接本地生成
    • 不同的機(jī)器個干個的,不會重復(fù)

    uuid 這么好,難不成是銀彈?當(dāng)然缺點也很突出:

    • 沒辦法保證遞增趨勢,沒法排序
    • uuid太長了,存儲占用空間大,特別落在數(shù)據(jù)庫,對建立索引不友好
    • 沒有業(yè)務(wù)屬性,這東西就是一串?dāng)?shù)字,沒啥意義,或者說規(guī)律

    當(dāng)然也有人想要改進(jìn)這家伙,比如不可讀性改造,用uuid to int64,把它轉(zhuǎn)成 long 類型:

    byte[] bytes=Guid.NewGuid().ToByteArray();
    return BitConverter.ToInt64(bytes, 0);
    

    又比如,改造無序性,比如 NHibernateComb 算法,把 uuid 的前 20 個字符保留下來,后面 12 個字符用 guid 生成的時間,時間是大致有序的,是一種小改進(jìn)。

    點評:UUID不存在數(shù)據(jù)庫當(dāng)索引,作為一些日志,上下文的識別,還是挺香的,但是要是這玩意用來當(dāng)訂單號,真是令人崩潰

    數(shù)據(jù)庫自增序列

    單機(jī)的數(shù)據(jù)庫

    數(shù)據(jù)庫的主鍵本身就擁有一個自增的天然特性,只要設(shè)置ID為主鍵并且自增,我們就可以向數(shù)據(jù)庫中插入一條記錄,可以返回自增的ID,比如以下的建表語句:

    CREATE DATABASE `test`;
    use test;
    CREATE TABLE id_table (
        id bigint(20) unsigned NOT NULL auto_increment, 
        value char(10) NOT NULL default '',
        PRIMARY KEY (id),
    ) ENGINE=MyISAM;
    

    插入語句:

    insert into id_table(value)  VALUES ('v1');
    

    優(yōu)點:

    • 單機(jī),簡單,速度也很快
    • 天然自增,原子性
    • 數(shù)字id排序,搜索,分頁都比較有利

    缺點也很明顯:

    • 單機(jī),掛了就要提桶跑路了
    • 一臺機(jī)器,高并發(fā)也不可能

    集群的數(shù)據(jù)庫

    既然單機(jī)高并發(fā)和高可用搞不定,那就加機(jī)器,搞集群模式的數(shù)據(jù)庫,既然集群模式,如果有多個master,那肯定不能每臺機(jī)器自己生成自己的id,這樣會導(dǎo)致重復(fù)的id。

    這個時候,每臺機(jī)器設(shè)置起始值步長,就尤為重要。比如三臺機(jī)器V1,V2,V3:

    統(tǒng)一步長:3
    V1起始值:1
    V2起始值:2
    V3起始值:3
    

    生成的ID:

    V1:1, 4, 7, 10...
    V2:2, 5, 8, 11...
    V3:3, 6, 9, 12...
    

    設(shè)置命令行可以使用:

    set @@auto_increment_offset=1;     // 起始值
    set @@auto_increment_increment=3;  // 步長
    

    這樣確實在master足夠多的情況下,高性能保證了,就算有的機(jī)器宕機(jī)了,slave 也可以補(bǔ)充上來,基于主從復(fù)制就可以,可以大大降低對單臺機(jī)器的壓力。但是這樣做還是有缺點:

    • 主從復(fù)制延遲了,master宕機(jī)了,從節(jié)點切換成為主節(jié)點之后,可能會重復(fù)發(fā)號。
    • 起始值和步長設(shè)置好之后,要是后面需要增加機(jī)器(水平拓展),要調(diào)整很麻煩,很多時候可能需要停機(jī)更新

    批量號段式數(shù)據(jù)庫

    上面的訪問數(shù)據(jù)庫太頻繁了,并發(fā)量一上來,很多小概率問題都可能發(fā)生,那為什么我們不直接一次性拿出一段id呢?直接放在內(nèi)存里,以供使用,用完了再申請一段就可以了。同樣也可以保留集群模式的優(yōu)點,每次從數(shù)據(jù)庫取出一個范圍的id,比如3臺機(jī)器,發(fā)號:

    每次取1000,每臺步長3000
    V1:1-1000,3001-4000,
    V2:1001-2000,4001-5000
    V3:2001-3000,5001-6000
    

    當(dāng)然,如果不搞多臺機(jī)器,也是可以的,一次申請10000個號碼,用樂觀鎖實現(xiàn),加一個版本號,

    CREATE TABLE id_table (
      id int(10) NOT NULL,
      max_id bigint(20) NOT NULL COMMENT '當(dāng)前最大id',
      step int(20) NOT NULL COMMENT '號段的步長',
      version int(20) NOT NULL COMMENT '版本號',
      `create_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
      `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
      PRIMARY KEY (`id`)
    ) 
    

    只有用完的時候,才會重新去數(shù)據(jù)庫申請,競爭的時候樂觀鎖保證只能一個請求成功,其他的直接等著別人取出來放在應(yīng)用內(nèi)存里面,再取就可以了,取的時候其實就是一個update操作:

    update id_table set max_id=#{max_id+step}, version=version + 1 where version=# {version}
    

    重點:

    • 批量獲取,減少數(shù)據(jù)庫請求
    • 樂觀鎖,保證數(shù)據(jù)準(zhǔn)確
    • 獲取只能從數(shù)據(jù)庫中獲取,批量獲取可以做成異步定時任務(wù),發(fā)現(xiàn)少于某個閾值,自動補(bǔ)充

    Redis自增

    redis有一個原子命令incr,原子自增,redis速度快,基于內(nèi)存:

    127.0.0.1:6379> set id 1
    OK
    127.0.0.1:6379> incr id      
    (integer) 2
    

    當(dāng)然,redis 如果單機(jī)有問題,也可以上集群,同樣可以用初始值 + 步長,可以用 INCRBY 命令,搞幾臺機(jī)器基本能抗住高并發(fā)。

    優(yōu)點:

    • 基于內(nèi)存,速度快
    • 天然排序,自增,有利于排序搜索

    缺點:

    • 步長確定之后,增加機(jī)器也比較難調(diào)整
    • 需要關(guān)注持久化,可用性等,增加系統(tǒng)復(fù)雜度

    redis持久化如果是RDB,一段時間打一個快照,那么可能會有數(shù)據(jù)沒來得及被持久化到磁盤,就掛掉了,重啟可能會出現(xiàn)重復(fù)的ID,同時要是主從延遲,主節(jié)點掛掉了,主從切換,也可能出現(xiàn)重復(fù)的ID。如果使用AOF,一條命令持久化一次,可能會拖慢速度,一秒鐘持久化一次,那么就可能最多丟失一秒鐘的數(shù)據(jù),同時,數(shù)據(jù)恢復(fù)也會比較慢,這是一個取舍的過程。

    Zookeeper生成唯一ID

    zookeeper其實是可以用來生成唯一ID的,但是大家不用,因為性能不高。znode有數(shù)據(jù)版本,可以生成32或者64位的序列號,這個序列號是唯一的,但是如果競爭比較大,還需要加分布式鎖,不值得,效率低。

    美團(tuán)的Leaf

    下面均來自美團(tuán)的官方文檔:https://tech.meituan.com/2019/03/07/open-source-project-leaf.html

    Leaf在設(shè)計之初就秉承著幾點要求:

    全局唯一,絕對不會出現(xiàn)重復(fù)的ID,且ID整體趨勢遞增。高可用,服務(wù)完全基于分布式架構(gòu),即使MySQL宕機(jī),也能容忍一段時間的數(shù)據(jù)庫不可用。高并發(fā)低延時,在CentOS 4C8G的虛擬機(jī)上,遠(yuǎn)程調(diào)用QPS可達(dá)5W+,TP99在1ms內(nèi)。接入簡單,直接通過公司RPC服務(wù)或者HTTP調(diào)用即可接入。

    文檔里面講得很清晰,一共有兩個版本:

    • V1:預(yù)分發(fā)的方式提供ID,也就是前面說的號段式分發(fā),表設(shè)計也差不多,意思就是批量的拉取id

    這樣做的缺點就是更新號段的時候,耗時比較高,還有就是如果這時候宕機(jī)或者主從復(fù)制,就不可用。

    優(yōu)化:

    • 1.先做了一個雙Buffer優(yōu)化,就是異步更新,意思就是搞兩個號段出來,一個號段比如被消耗10%的時候,就開始分配下一個號段,有種提前分配的意思,而且異步線程更新
    • 2.上面的方案,號段可能固定,跨度可能太大或者太小,那就做成動態(tài)變化,根據(jù)流量來決定下一次的號段的大小,動態(tài)調(diào)整
    • V2:Leaf-snowflake,Leaf提供了Java版本的實現(xiàn),同時對Zookeeper生成機(jī)器號做了弱依賴處理,即使Zookeeper有問題,也不會影響服務(wù)。Leaf在第一次從Zookeeper拿取workerID后,會在本機(jī)文件系統(tǒng)上緩存一個workerID文件。即使ZooKeeper出現(xiàn)問題,同時恰好機(jī)器也在重啟,也能保證服務(wù)的正常運(yùn)行。這樣做到了對第三方組件的弱依賴,一定程度上提高了SLA。

    snowflake(雪花算法)

    snowflake 是 twitter 公司內(nèi)部分布式項目采用的 ID 生成算法,開源后廣受歡迎,它生成的ID是 Long 類型,8個字節(jié),一共64位,從左到右:

    • 1位:不使用,二進(jìn)制中最高位是為1都是負(fù)數(shù),但是要生成的唯一ID都是正整數(shù),所以這個1位固定為0。
    • 41位:記錄時間戳(毫秒),這個位數(shù)可以用 $(2^{41}-1) / (1000 * 60 * 60 * 24 * 365)=69$年
    • 10位:記錄工作機(jī)器的ID,可以機(jī)器ID,也可以機(jī)房ID + 機(jī)器ID
    • 12位:序列號,就是某個機(jī)房某臺機(jī)器上這一毫秒內(nèi)同時生成的 id 序號

    那么每臺機(jī)器按照上面的邏輯去生成ID,就會是趨勢遞增的,因為時間在遞增,而且不需要搞個分布式的,簡單很多。

    可以看出 snowflake 是強(qiáng)依賴于時間的,因為時間理論上是不斷往前的,所以這一部分的位數(shù),也是趨勢遞增的。但是有一個問題,是時間回?fù)埽簿褪菚r間突然間倒退了,可能是故障,也可能是重啟之后時間獲取出問題了。那我們該如何解決時間回?fù)軉栴}呢?

    • 第一種方案:獲取時間的時候判斷,如果小于上一次的時間戳,那么就不要分配,繼續(xù)循環(huán)獲取時間,直到時間符合條件。
    • 第二種方案:上面的方案只適合時鐘回?fù)茌^小的,如果間隔過大,阻塞等待,肯定是不可取的,因此要么超過一定大小的回?fù)苤苯訄箦e,拒絕服務(wù),或者有一種方案是利用拓展位,回?fù)苤笤谕卣刮簧霞?就可以了,這樣ID依然可以保持唯一。

    Java代碼實現(xiàn):

    public class SnowFlake {
    
        // 數(shù)據(jù)中心(機(jī)房) id
        private long datacenterId;
        // 機(jī)器ID
        private long workerId;
        // 同一時間的序列
        private long sequence;
    
        public SnowFlake(long workerId, long datacenterId) {
            this(workerId, datacenterId, 0);
        }
    
        public SnowFlake(long workerId, long datacenterId, long sequence) {
            // 合法判斷
            if (workerId > maxWorkerId || workerId < 0) {
                throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
            }
            if (datacenterId > maxDatacenterId || datacenterId < 0) {
                throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
            }
            System.out.printf("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d",
                    timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId);
    
            this.workerId=workerId;
            this.datacenterId=datacenterId;
            this.sequence=sequence;
        }
    
        // 開始時間戳
        private long twepoch=1420041600000L;
    
        // 機(jī)房號,的ID所占的位數(shù) 5個bit 最大:11111(2進(jìn)制)--> 31(10進(jìn)制)
        private long datacenterIdBits=5L;
    
        // 機(jī)器ID所占的位數(shù) 5個bit 最大:11111(2進(jìn)制)--> 31(10進(jìn)制)
        private long workerIdBits=5L;
    
        // 5 bit最多只能有31個數(shù)字,就是說機(jī)器id最多只能是32以內(nèi)
        private long maxWorkerId=-1L ^ (-1L << workerIdBits);
    
        // 5 bit最多只能有31個數(shù)字,機(jī)房id最多只能是32以內(nèi)
        private long maxDatacenterId=-1L ^ (-1L << datacenterIdBits);
    
        // 同一時間的序列所占的位數(shù) 12個bit 111111111111=4095  最多就是同一毫秒生成4096個
        private long sequenceBits=12L;
    
        // workerId的偏移量
        private long workerIdShift=sequenceBits;
    
        // datacenterId的偏移量
        private long datacenterIdShift=sequenceBits + workerIdBits;
    
        // timestampLeft的偏移量
        private long timestampLeftShift=sequenceBits + workerIdBits + datacenterIdBits;
    
        // 序列號掩碼 4095 (0b111111111111=0xfff=4095)
        // 用于序號的與運(yùn)算,保證序號最大值在0-4095之間
        private long sequenceMask=-1L ^ (-1L << sequenceBits);
    
        // 最近一次時間戳
        private long lastTimestamp=-1L;
    
    
        // 獲取機(jī)器ID
        public long getWorkerId() {
            return workerId;
        }
    
    
        // 獲取機(jī)房ID
        public long getDatacenterId() {
            return datacenterId;
        }
    
    
        // 獲取最新一次獲取的時間戳
        public long getLastTimestamp() {
            return lastTimestamp;
        }
    
    
        // 獲取下一個隨機(jī)的ID
        public synchronized long nextId() {
            // 獲取當(dāng)前時間戳,單位毫秒
            long timestamp=timeGen();
    
            if (timestamp < lastTimestamp) {
                System.err.printf("clock is moving backwards.  Rejecting requests until %d.", lastTimestamp);
                throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds",
                        lastTimestamp - timestamp));
            }
    
            // 去重
            if (lastTimestamp==timestamp) {
    
                sequence=(sequence + 1) & sequenceMask;
    
                // sequence序列大于4095
                if (sequence==0) {
                    // 調(diào)用到下一個時間戳的方法
                    timestamp=tilNextMillis(lastTimestamp);
                }
            } else {
                // 如果是當(dāng)前時間的第一次獲取,那么就置為0
                sequence=0;
            }
    
            // 記錄上一次的時間戳
            lastTimestamp=timestamp;
    
            // 偏移計算
            return ((timestamp - twepoch) << timestampLeftShift) |
                    (datacenterId << datacenterIdShift) |
                    (workerId << workerIdShift) |
                    sequence;
        }
    
        private long tilNextMillis(long lastTimestamp) {
            // 獲取最新時間戳
            long timestamp=timeGen();
            // 如果發(fā)現(xiàn)最新的時間戳小于或者等于序列號已經(jīng)超4095的那個時間戳
            while (timestamp <=lastTimestamp) {
                // 不符合則繼續(xù)
                timestamp=timeGen();
            }
            return timestamp;
        }
    
        private long timeGen() {
            return System.currentTimeMillis();
        }
    
        public static void main(String[] args) {
            SnowFlake worker=new SnowFlake(1, 1);
            long timer=System.currentTimeMillis();
            for (int i=0; i < 100; i++) {
                worker.nextId();
            }
            System.out.println(System.currentTimeMillis());
            System.out.println(System.currentTimeMillis() - timer);
        }
    
    }
      
    

    百度 uid-generator

    換湯不換藥,百度開發(fā)的,基于Snowflake算法,不同的地方是可以自己定義每部分的位數(shù),也做了不少優(yōu)化和拓展:https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md

    UidGenerator是Java實現(xiàn)的, 基于Snowflake算法的唯一ID生成器。UidGenerator以組件形式工作在應(yīng)用項目中, 支持自定義workerId位數(shù)和初始化策略, 從而適用于docker等虛擬化環(huán)境下實例自動重啟、漂移等場景。 在實現(xiàn)上, UidGenerator通過借用未來時間來解決sequence天然存在的并發(fā)限制; 采用RingBuffer來緩存已生成的UID, 并行化UID的生產(chǎn)和消費, 同時對CacheLine補(bǔ)齊,避免了由RingBuffer帶來的硬件級「偽共享」問題. 最終單機(jī)QPS可達(dá)600萬。

    秦懷の觀點

    不管哪一種uid生成器,保證唯一性是核心,在這個核心上才能去考慮其他的性能,或者高可用等問題,總體的方案分為兩種:

    • 中心化:第三方的一個中心,比如 Mysql,Redis,Zookeeper
      • 優(yōu)點:趨勢自增
      • 缺點:增加復(fù)雜度,一般得集群,提前約定步長之類
    • 無中心化:直接本地機(jī)器上生成,snowflake,uuid
      • 優(yōu)點:簡單,高效,沒有性能瓶頸
      • 缺點:數(shù)據(jù)比較長,自增屬性較弱

    沒有哪一種是完美的,只有符合業(yè)務(wù)以及當(dāng)前體量的方案,技術(shù)方案里面,沒有最優(yōu)解。


    來源:https://www.cnblogs.com/Damaer/p/15531317.html

網(wǎng)站首頁   |    關(guān)于我們   |    公司新聞   |    產(chǎn)品方案   |    用戶案例   |    售后服務(wù)   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區(qū)    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權(quán)所有