From e44e753e66e98f7ad4a624e9696aa85c2b9c005e Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Thu, 4 Feb 2016 13:06:27 -0800 Subject: [PATCH] pkg/idutil: reduce conflict rate from 1% to 0.005% Perviously, we only use 8bits from member identification in id generation. The conflict rate is A(256,3)/256^3, which is around 1%. Now we use 16bites to reduce the rate to 0.005%. We can attach the full member id into id generation if needed... --- etcdserver/server.go | 2 +- pkg/idutil/id.go | 12 ++++++------ pkg/idutil/id_test.go | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/etcdserver/server.go b/etcdserver/server.go index 020ed3687..ab737c167 100644 --- a/etcdserver/server.go +++ b/etcdserver/server.go @@ -358,7 +358,7 @@ func NewServer(cfg *ServerConfig) (*EtcdServer, error) { lstats: lstats, SyncTicker: time.Tick(500 * time.Millisecond), peerRt: prt, - reqIDGen: idutil.NewGenerator(uint8(id), time.Now()), + reqIDGen: idutil.NewGenerator(uint16(id), time.Now()), forceVersionC: make(chan struct{}), msgSnapC: make(chan raftpb.Message, maxInFlightMsgSnap), } diff --git a/pkg/idutil/id.go b/pkg/idutil/id.go index 0ba570cff..50d80d963 100644 --- a/pkg/idutil/id.go +++ b/pkg/idutil/id.go @@ -24,7 +24,7 @@ import ( const ( tsLen = 5 * 8 - cntLen = 2 * 8 + cntLen = 8 suffixLen = tsLen + cntLen ) @@ -32,7 +32,7 @@ const ( // High order byte is memberID, next 5 bytes are from timestamp, // and low order 2 bytes are 0s. // | prefix | suffix | -// | 1 byte | 5 bytes | 2 bytes | +// | 2 bytes | 5 bytes | 1 byte | // | memberID | timestamp | cnt | // // The timestamp 5 bytes is different when the machine is restart @@ -42,16 +42,16 @@ const ( // The count field may overflow to timestamp field, which is intentional. // It helps to extend the event window to 2^56. This doesn't break that // id generated after restart is unique because etcd throughput is << -// 65536req/ms. +// 256req/ms(250k reqs/second). type Generator struct { mu sync.Mutex - // high order byte + // high order 2 bytes prefix uint64 - // low order 7 bytes + // low order 6 bytes suffix uint64 } -func NewGenerator(memberID uint8, now time.Time) *Generator { +func NewGenerator(memberID uint16, now time.Time) *Generator { prefix := uint64(memberID) << suffixLen unixMilli := uint64(now.UnixNano()) / uint64(time.Millisecond/time.Nanosecond) suffix := lowbit(unixMilli, tsLen) << cntLen diff --git a/pkg/idutil/id_test.go b/pkg/idutil/id_test.go index b5249883f..19e2a8ff1 100644 --- a/pkg/idutil/id_test.go +++ b/pkg/idutil/id_test.go @@ -22,7 +22,7 @@ import ( func TestNewGenerator(t *testing.T) { g := NewGenerator(0x12, time.Unix(0, 0).Add(0x3456*time.Millisecond)) id := g.Next() - wid := uint64(0x1200000034560001) + wid := uint64(0x12000000345601) if id != wid { t.Errorf("id = %x, want %x", id, wid) } @@ -45,7 +45,7 @@ func TestNewGeneratorUnique(t *testing.T) { func TestNext(t *testing.T) { g := NewGenerator(0x12, time.Unix(0, 0).Add(0x3456*time.Millisecond)) - wid := uint64(0x1200000034560001) + wid := uint64(0x12000000345601) for i := 0; i < 1000; i++ { id := g.Next() if id != wid+uint64(i) {