在Windows中可以使用 事件查看器 來查看相關(guān)日志,并結(jié)合日志ID進(jìn)行日志篩選。常見的日志有:
下面以查看遠(yuǎn)程連接的日志為例展示事件查看器的使用。
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)限已更改
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)
分布式系統(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的核心是唯一性,其他的都是附加屬性,一般來說,一個優(yōu)秀的全局唯一ID方案有以下的特點,僅供參考:
寫過 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)點:
uuid 這么好,難不成是銀彈?當(dāng)然缺點也很突出:
當(dāng)然也有人想要改進(jìn)這家伙,比如不可讀性改造,用uuid to int64,把它轉(zhuǎn)成 long 類型:
byte[] bytes=Guid.NewGuid().ToByteArray();
return BitConverter.ToInt64(bytes, 0);
又比如,改造無序性,比如 NHibernate 的 Comb 算法,把 uuid 的前 20 個字符保留下來,后面 12 個字符用 guid 生成的時間,時間是大致有序的,是一種小改進(jìn)。
點評:UUID不存在數(shù)據(jù)庫當(dāng)索引,作為一些日志,上下文的識別,還是挺香的,但是要是這玩意用來當(dāng)訂單號,真是令人崩潰
數(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ī)高并發(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ī)器的壓力。但是這樣做還是有缺點:
上面的訪問數(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}
重點:
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)點:
缺點:
redis持久化如果是RDB,一段時間打一個快照,那么可能會有數(shù)據(jù)沒來得及被持久化到磁盤,就掛掉了,重啟可能會出現(xiàn)重復(fù)的ID,同時要是主從延遲,主節(jié)點掛掉了,主從切換,也可能出現(xiàn)重復(fù)的ID。如果使用AOF,一條命令持久化一次,可能會拖慢速度,一秒鐘持久化一次,那么就可能最多丟失一秒鐘的數(shù)據(jù),同時,數(shù)據(jù)恢復(fù)也會比較慢,這是一個取舍的過程。
zookeeper其實是可以用來生成唯一ID的,但是大家不用,因為性能不高。znode有數(shù)據(jù)版本,可以生成32或者64位的序列號,這個序列號是唯一的,但是如果競爭比較大,還需要加分布式鎖,不值得,效率低。
下面均來自美團(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)用即可接入。
文檔里面講得很清晰,一共有兩個版本:
這樣做的缺點就是更新號段的時候,耗時比較高,還有就是如果這時候宕機(jī)或者主從復(fù)制,就不可用。
優(yōu)化:
snowflake 是 twitter 公司內(nèi)部分布式項目采用的 ID 生成算法,開源后廣受歡迎,它生成的ID是 Long 類型,8個字節(jié),一共64位,從左到右:
那么每臺機(jī)器按照上面的邏輯去生成ID,就會是趨勢遞增的,因為時間在遞增,而且不需要搞個分布式的,簡單很多。
可以看出 snowflake 是強(qiáng)依賴于時間的,因為時間理論上是不斷往前的,所以這一部分的位數(shù),也是趨勢遞增的。但是有一個問題,是時間回?fù)埽簿褪菚r間突然間倒退了,可能是故障,也可能是重啟之后時間獲取出問題了。那我們該如何解決時間回?fù)軉栴}呢?
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);
}
}
換湯不換藥,百度開發(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生成器,保證唯一性是核心,在這個核心上才能去考慮其他的性能,或者高可用等問題,總體的方案分為兩種:
沒有哪一種是完美的,只有符合業(yè)務(wù)以及當(dāng)前體量的方案,技術(shù)方案里面,沒有最優(yōu)解。
來源:https://www.cnblogs.com/Damaer/p/15531317.html