哈爾濱網(wǎng)站建設(shè)1元錢2021年經(jīng)典營銷案例
1、UUID(通用唯一標(biāo)識(shí)符)
1、UUID本身
一種用于標(biāo)識(shí)信息的標(biāo)準(zhǔn)化方法。一個(gè)128位的數(shù)字,常表示為32個(gè)十六進(jìn)制數(shù)字,以連字符分隔成五組:8-4-4-4-12。
版本: UUID有不同的版本,最常見的是基于時(shí)間戳和隨機(jī)數(shù)生成的版本1和版本4。
唯一性: 由于UUID的長度和生成機(jī)制,可以保證在大多數(shù)情況下生成的UUID是唯一的。
應(yīng)用: 在各種系統(tǒng)中廣泛應(yīng)用,用于唯一標(biāo)識(shí)實(shí)體、會(huì)話、交易等。
2、設(shè)計(jì)方法:
時(shí)間戳: 將當(dāng)前時(shí)間戳作為UUID的一部分,以確保在同一時(shí)刻生成的UUID是唯一的。
節(jié)點(diǎn)標(biāo)識(shí): 在分布式系統(tǒng)中,將每個(gè)節(jié)點(diǎn)的唯一標(biāo)識(shí)符(如機(jī)器ID)納入U(xiǎn)UID的生成過程,以防止在不同節(jié)點(diǎn)上生成相同的UUID。
隨機(jī)數(shù)生成器: 將隨機(jī)數(shù)作為UUID的一部分,以增加唯一性,但在分布式系統(tǒng)中要確保隨機(jī)數(shù)生成器是足夠隨機(jī)的。
考慮時(shí)鐘回?fù)軉栴}: 如果使用時(shí)間戳作為UUID的一部分,需要考慮時(shí)鐘回?fù)芸赡軐?dǎo)致的重復(fù)UUID問題??梢圆捎靡恍C(jī)制來解決時(shí)鐘回?fù)軒淼臐撛趩栴},比如使用遞增序列號(hào)。
一致性哈希算法: 基于節(jié)點(diǎn)信息和數(shù)據(jù)內(nèi)容計(jì)算哈希值,然后將哈希值轉(zhuǎn)換為UUID。這樣可以確保相同的數(shù)據(jù)在不同節(jié)點(diǎn)上生成的UUID是一致的。
時(shí)鐘回?fù)軉栴}:
指在分布式系統(tǒng)中,當(dāng)某個(gè)節(jié)點(diǎn)的系統(tǒng)時(shí)間發(fā)生回?fù)?#xff08;即向過去跳躍)時(shí)可能導(dǎo)致的一系列問題。
引起的原因:手動(dòng)調(diào)整時(shí)間;網(wǎng)絡(luò)時(shí)間協(xié)議(NTP)校準(zhǔn);系統(tǒng)重啟或故障;虛擬機(jī)遷移;
解決方向:使用邏輯時(shí)鐘;增加容錯(cuò)機(jī)制;使用穩(wěn)定的時(shí)鐘;時(shí)間校正算法;設(shè)計(jì)時(shí)避免依賴絕對(duì)時(shí)間;
package mainimport ("fmt""github.com/google/uuid"
)func main() {// 生成一個(gè)新的 UUIDnewUUID := uuid.New()fmt.Printf("Generated UUID: %s\n", newUUID)
}
2、數(shù)據(jù)庫序列(自增ID)
簡(jiǎn)單,工作方式:基于中央數(shù)據(jù)庫的序列生成器,如自增ID,每次請(qǐng)求時(shí)遞增序列值。順序性:保證了生成ID的順序性和唯一性。
package mainimport ("database/sql""fmt"_ "github.com/mattn/go-sqlite3"
)func main() {// 連接到 SQLite 數(shù)據(jù)庫db, err := sql.Open("sqlite3", "test.db")if err != nil {fmt.Println(err)return}defer db.Close()// 創(chuàng)建一個(gè)包含自增ID的表_, err = db.Exec("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)")if err != nil {fmt.Println(err)return}fmt.Println("Table created successfully")
}
//連接到 SQLite 數(shù)據(jù)庫,并創(chuàng)建了一個(gè)名為 users 的表,該表包含一個(gè)自增的整數(shù)類型的ID列和一個(gè)文本類型的 name 列。
//不同的數(shù)據(jù)庫(如 MySQL、PostgreSQL 等)可能有不同的語法和方式來實(shí)現(xiàn)自動(dòng)遞增的ID列
3、雪花算法(Twitter Snowflake)
Twitter開發(fā)的一種生成64位ID的服務(wù),基于時(shí)間戳、機(jī)器ID和序列號(hào)。
時(shí)間戳(41位): 用于表示ID生成的時(shí)間戳,通常精確到毫秒級(jí)。
機(jī)器ID(10位): 標(biāo)識(shí)生成ID的機(jī)器的唯一標(biāo)識(shí),通常使用數(shù)據(jù)中心ID與機(jī)器ID的組合。
序列號(hào)(12位): 在同一毫秒內(nèi),通過累加的方式生成序列號(hào),確保在同一節(jié)點(diǎn)上生成的ID是唯一的。
雪花算法的優(yōu)點(diǎn)包括高性能、高可用性和ID趨勢(shì)遞增。在實(shí)際應(yīng)用中,可根據(jù)需求調(diào)整時(shí)間戳的位數(shù)、機(jī)器ID的位數(shù)和序列號(hào)的位數(shù)來適應(yīng)不同的場(chǎng)景。
一般用于替代傳統(tǒng)自增ID的方式。
package mainimport ("fmt""sync""time"
)const (epoch time.Duration = 1609459200000 // 2021-01-01 的時(shí)間戳,用于生成時(shí)間戳部分workerIDBits = 5 // 機(jī)器 ID 的位數(shù)sequenceBits = 12 // 序列號(hào)的位數(shù)maxWorkerID = -1 ^ (-1 << workerIDBits)maxSequence = -1 ^ (-1 << sequenceBits)
)type Snowflake struct {mu sync.MutexlastTime int64workerID uintsequence uint
}func NewSnowflake(workerID uint) *Snowflake {if workerID > maxWorkerID {panic("worker ID 超出范圍")}return &Snowflake{lastTime: 0,workerID: workerID,sequence: 0,}
}func (s *Snowflake) GenerateID() uint64 {s.mu.Lock()defer s.mu.Unlock()currentTime := time.Now().UnixNano() / 1e6 // 獲取當(dāng)前時(shí)間的毫秒數(shù)if s.lastTime == currentTime {s.sequence = (s.sequence + 1) & maxSequenceif s.sequence == 0 {for currentTime <= s.lastTime {currentTime = time.Now().UnixNano() / 1e6}}} else {s.sequence = 0}s.lastTime = currentTimeid := uint64((currentTime-epoch)<<22 | int64(s.workerID)<<17 | int64(s.sequence))return id
}func main() {sf := NewSnowflake(1) // 設(shè)定一個(gè)機(jī)器 IDid := sf.GenerateID()fmt.Println(id)
}
4、使用Redis實(shí)現(xiàn)分布式ID生成
Redis是一個(gè)高性能的鍵值數(shù)據(jù)庫,它可以用于生成分布式唯一標(biāo)識(shí)符。
不同Redis實(shí)例通過配置不同的起始步長來區(qū)分。
這個(gè)的實(shí)現(xiàn)原理利用了Redis的原子操作。
package mainimport ("fmt""github.com/go-redis/redis/v8""log""time"
)var redisClient *redis.Clientfunc init() {redisClient = redis.NewClient(&redis.Options{Addr: "localhost:6379", // Redis 服務(wù)器地址Password: "", // Redis 密碼,如果有的話DB: 0, // 選擇使用的數(shù)據(jù)庫})
}func generateID(key string) (int64, error) {val, err := redisClient.Incr(key).Result()if err != nil {return 0, err}return val, nil
}func main() {key := "distributed_id_generator" // Redis 中的鍵名// 生成 5 個(gè)分布式 IDfor i := 0; i < 5; i++ {id, err := generateID(key)if err != nil {log.Fatalf("Failed to generate ID: %v", err)}fmt.Printf("Generated ID: %d\n", id)time.Sleep(time.Millisecond) // 可選的延遲,以避免生成相同的 ID}
}
package mainimport ("fmt""github.com/go-redis/redis/v8""log""time"
)var redisClients map[string]*redis.Clientfunc init() {redisClients = make(map[string]*redis.Client)redisClients["instance1"] = redis.NewClient(&redis.Options{Addr: "localhost:6379", // Redis 實(shí)例1的地址Password: "", // Redis 密碼,如果有的話DB: 0, // 選擇使用的數(shù)據(jù)庫})redisClients["instance2"] = redis.NewClient(&redis.Options{Addr: "localhost:6380", // Redis 實(shí)例2的地址Password: "", // Redis 密碼,如果有的話DB: 0, // 選擇使用的數(shù)據(jù)庫})
}func generateID(key string, start int64) (int64, error) {val, err := redisClients[key].IncrBy(key, start).Result()if err != nil {return 0, err}return val, nil
}func main() {key1 := "distributed_id_generator_instance1" // Redis 實(shí)例1中的鍵名key2 := "distributed_id_generator_instance2" // Redis 實(shí)例2中的鍵名// 生成 5 個(gè)分布式 IDfor i := 0; i < 5; i++ {id1, err := generateID(key1, 1000) // 指定實(shí)例1的起始步長為1000if err != nil {log.Fatalf("Failed to generate ID: %v", err)}fmt.Printf("Instance 1 - Generated ID: %d\n", id1)id2, err := generateID(key2, 2000) // 指定實(shí)例2的起始步長為2000if err != nil {log.Fatalf("Failed to generate ID: %v", err)}fmt.Printf("Instance 2 - Generated ID: %d\n", id2)time.Sleep(time.Millisecond) // 可選的延遲,以避免生成相同的 ID}
}
5、使用數(shù)據(jù)庫分段(Database Segment)
6、分布式鍵生成服務(wù)(如Zookeeper、etcd)
分布式協(xié)調(diào)服務(wù)在集群中生成唯一ID。
也是利用這些服務(wù)提供的分布式鎖和原子性操作來生成唯一的ID。還有集群協(xié)調(diào)機(jī)制。