-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
721 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# sharding | ||
|
||
## sid-64-bit | ||
// +----------+-------------------+------------+----------------+----------------------+---------------+ | ||
// | signed 1 | millis (39) | worker(2) | db-sharding(10)| table-rotate(2) | sequence(10) | | ||
// +----------+-------------------+------------+----------------+----------------------+---------------+ | ||
39 = 17 years 2 = 4 10=1024 0: none :table 10=1024 | ||
1: monthly :table-[YYYYMM] | ||
2: weekly :table-[YYYY0XX] | ||
3: daily :table-[YYYYMMDD] | ||
- signed(1): sid is always positive number | ||
- millis(39): 2^39 (17years) unix milliseconds since 2024-02-19 00:00:00 | ||
- workers(4): 2^4(16) workers | ||
- db-sharding(10): 2^10 (1024) db instances | ||
- table-rotate(2): 2^2(4) table rotate: none/by year/by month/by day | ||
- sequence(10): 2^10(1024) per milliseconds | ||
|
||
## TPS: | ||
- ID: 1000(ms)*1024(seq)*4 = 4096000 409.6W/s | ||
1000*1024 = 1024000 102.4W/s | ||
|
||
- DB : | ||
10 * 1000 = 10000 1W/s | ||
1024 * 1000 = 1024000 102.4W/s | ||
|
||
10 * 2000 = 20000 2W/s | ||
1024 * 2000 = 2048000 204.8W/s | ||
|
||
10 * 3000 = 30000 3W/s | ||
1024 * 3000 = 3072000 307.2W/s | ||
|
||
## mysql-benchmark | ||
- https://docs.aws.amazon.com/whitepapers/latest/optimizing-mysql-on-ec2-using-amazon-ebs/mysql-benchmark-observations-and-considerations.html | ||
- https://github.com/MinervaDB/MinervaDB-Sysbench | ||
- https://www.percona.com/blog/assessing-mysql-performance-amongst-aws-options-part-one/ | ||
|
||
## issues | ||
- Overflow capacity | ||
waiting for next microsecond. | ||
|
||
- System Clock Dependency | ||
You should use NTP to keep your system clock accurate. | ||
|
||
- Time move backwards | ||
+ if sequence doesn't overflow, let's use last timestamp and next sequence. system clock might moves forward and greater than last timestamp on next id generation | ||
+ if sequence overflows, and has to be reset. let's built-in clock to get timestamp till system clock moves forward and greater than built-in clock | ||
|
||
- Built-in clock | ||
record last timestamp in memory/database, increase it when it is requested to send current timestamp instead of system clock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package sharding | ||
|
||
import ( | ||
"sync" | ||
"time" | ||
) | ||
|
||
type Generator struct { | ||
sync.Mutex | ||
_ noCopy // nolint: unused | ||
|
||
workerID int8 | ||
databaseTotal int16 | ||
tableRotate TableRotate | ||
now func() time.Time | ||
|
||
lastMillis int64 | ||
nextSequence int16 | ||
nextDatabaseID int16 | ||
} | ||
|
||
func New(options ...Option) *Generator { | ||
g := &Generator{ | ||
now: time.Now, | ||
databaseTotal: 1, | ||
tableRotate: None, | ||
workerID: acquireWorkerID(), | ||
} | ||
for _, option := range options { | ||
option(g) | ||
} | ||
return g | ||
} | ||
|
||
func (g *Generator) Next() int64 { | ||
g.Lock() | ||
|
||
defer func() { | ||
g.nextSequence++ | ||
g.Unlock() | ||
}() | ||
|
||
nowMillis := g.now().UnixMilli() | ||
if nowMillis < g.lastMillis { | ||
if g.nextSequence > MaxSequence { | ||
// time move backwards,and sequence overflows capacity, waiting system clock to move forward | ||
g.nextSequence = 0 | ||
nowMillis = g.tillNextMillis() | ||
} else { | ||
// time move backwards,but sequence doesn't overflow capacity, use Built-in clock to move forward | ||
nowMillis = g.moveNextMillis() | ||
} | ||
} | ||
|
||
// sequence overflows capacity | ||
if g.nextSequence > MaxSequence { | ||
if nowMillis == g.lastMillis { | ||
nowMillis = g.tillNextMillis() | ||
} | ||
|
||
g.nextSequence = 0 | ||
} | ||
|
||
g.lastMillis = nowMillis | ||
|
||
return Build(nowMillis, g.workerID, g.getNextDatabaseID(), g.tableRotate, g.nextSequence) | ||
|
||
} | ||
|
||
func (g *Generator) getNextDatabaseID() int16 { | ||
if g.databaseTotal <= 1 { | ||
return 0 | ||
} | ||
|
||
defer func() { | ||
g.nextDatabaseID++ | ||
}() | ||
|
||
if g.nextDatabaseID < g.databaseTotal { | ||
return g.nextDatabaseID | ||
} | ||
|
||
g.nextDatabaseID = 0 | ||
return 0 | ||
} | ||
|
||
func (g *Generator) tillNextMillis() int64 { | ||
lastMillis := g.now().UnixMilli() | ||
for { | ||
if lastMillis > g.lastMillis { | ||
break | ||
} | ||
|
||
lastMillis = g.now().UnixMilli() | ||
} | ||
|
||
return lastMillis | ||
} | ||
func (g *Generator) moveNextMillis() int64 { | ||
return g.lastMillis + 1 | ||
} |
Oops, something went wrong.