A practical way
to generate unique id in Go
speaker := &Programmer{
Name: "Manh Dao Van",
Github: "manhdaovan",
Org: &Company{
Name: "Money Forward",
StockCode: "TYO:3994",
}
}
Slide 2
Slide 2 text
Disclaimer
All error handling, context params... of source code in this talk is reduced for representation the
idea purpose, not production-ready source code.
2
Slide 3
Slide 3 text
What?
❖ Microservices --(needs)-> Idempotency --(needs)-> Request ID (Unique ID)
❖ Some constrain about this Request ID:
➢ Sortable is NOT required
➢ Universal uniqueness
➢ Be generated "fastly enough" per service instance
➢ Independent to any setting as much as possible
➢ Human readable and understandable about the request from
requestID
3
Slide 4
Slide 4 text
Existing solutions
- Snowflake(1*):
- ID (64-bit) , sortable
- (unused 1-bit) | (timestamp 41-bit) | (machine ID 10-bit) | (sequence number 36-bit)
- Sonyflake(2*):
- ID (64-bit) , sortable
- (unused 1-bit) | (timestamp 39-bit) | (sequence number 8-bit) | (machine ID 16-bit)
- Instagram’s method(3*):
- ID (64-bit) , sortable
- (timestamp 41-bit) | (shard ID 13-bit) | (sequence number 10-bit)
- Pinterest’s method(4*):
- ID (64-bit) , unsortable
- (unused 2-bit) | (shard ID 16-bit) | (type ID 10-bit) | (local ID 36-bit)
4
Cons: Fixed info per
app/db instance
Slide 5
Slide 5 text
Our solution - Architecture
- Similar to Ticket Server(5*) algorithm
- Request ID: string (non-fixed length)
- IDPrefix (global unique id) + sequence number
- Generated by and per app instance
- IDPrefix = Service name + sequence number
- Generated by IDManager Service
- Flow: Service A -(requests)-> Service B -(requests) -> Service C
- 1. Get IDPrefix from IDManager Service immediately after started up
- Eg: “ServiceA-1” as IDPrefix for Service A, and “ServiceB-1” for Service B
- 2, 3. Create ID basing on IDPrefix and request to downstream services.
- Eg: “ServiceA-1-1” as Request ID from Service A to Service B
- and “ServiceB-1-1” from Service B to Service C
5
Service A
Service B Service C
IDManager
Service
1
1
2
3
Solving data race
- Method1: Using atomic operation
- Eg: using “sync/atomic”
- Method2: Using lock
- Eg: using sync.Mutex / sync.RWMutex
- Method3: Share data safety
- Eg: using go channel
8