Skip to content

Commit

Permalink
feat: 测试msg id的极限
Browse files Browse the repository at this point in the history
  • Loading branch information
zhixunjie committed Apr 21, 2024
1 parent f8aa44d commit 50b78f6
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 1 deletion.
2 changes: 1 addition & 1 deletion docs
Submodule docs updated from 215aca to 9e4a40
34 changes: 34 additions & 0 deletions pkg/gen_id/id_msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
"github.com/spf13/cast"
"strconv"
"time"
)
Expand Down Expand Up @@ -46,6 +47,39 @@ func genMsgId(ctx context.Context, mem *redis.Client, slotId uint64) (msgId uint
return
}

// genMsgId1 生成msg_id
// 如果 msgId 使用int64,可以支持偏移28年。
// 如果 msgId 使用uint64,可以支持偏移58年。
func genMsgId1(ctx context.Context, mem *redis.Client, slotId uint64, t time.Time, needType string) (msgId any, err error) {
// redis:每秒一个key,在key上执行原子操作+1
ts := t.Unix()
key := keyMsgId(ts)

// incr
afterIncr, err := incNum(ctx, mem, key, expireMsgKey)
if err != nil {
return
}

// msg_id的组成部分:[ 10位:相对时间戳 | 6位:自增id | 4位:槽id ]
timeOffset := ts - baseTimeStampOffset
idStr := fmt.Sprintf("%d%06d%04d", timeOffset, afterIncr%1000000, slotId%10000)

switch needType {
case "uint64":
//msgId = cast.ToUint64(idStr) 有bug,相当于cast.ToInt64的效果
msgId, _ = strconv.ParseUint(idStr, 10, 64)
case "int64":
msgId = cast.ToInt64(idStr)
msgId, _ = strconv.ParseInt(idStr, 10, 64)
case "uint32":
msgId = cast.ToUint32(idStr)
case "int32":
msgId = cast.ToInt32(idStr)
}
return
}

// incNum 每秒一个Key,进行累加
func incNum(ctx context.Context, mem *redis.Client, key string, expire time.Duration) (value int64, err error) {
value, err = mem.IncrBy(ctx, key, 1).Result()
Expand Down
71 changes: 71 additions & 0 deletions pkg/gen_id/id_msg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
"math"
"testing"
"time"
)

var client = redis.NewClient(&redis.Options{
Expand Down Expand Up @@ -36,3 +38,72 @@ func TestIdMsg(t *testing.T) {
msgId, err = MsgId(ctx, client, id3, id1)
fmt.Printf("群聊,msgId=%v,err=%v\n", msgId, err)
}

// 测试位数
// baseTimeStampOffset = 2023-02-22 02:31:47
func TestMsgIdBit(t *testing.T) {
ctx := context.Background()

// 结论:uint64 可以支持58年
typ := "uint64"
fmt.Printf("测试%v,最大值为: %v\n", typ, "18446744073709551615")
testGen(ctx, "2080-01-01", typ) // 输出:17942884930000011001 <nil>
testGen(ctx, "2081-01-01", typ) // 输出:18259108930000011001 <nil> 这里已经是极限了!!!
testGen(ctx, "2082-01-01", typ) // 输出:18446744073709551615 <nil>
testGen(ctx, "2083-01-01", typ) // 输出:18446744073709551615 <nil>
testGen(ctx, "2084-01-01", typ) // 输出:18446744073709551615 <nil>

// /////////////////////////////////////
// 结论:int64 可以支持28年
fmt.Println("======================================================")
typ = "int64"
fmt.Printf("测试%v,最大值为: %v\n", typ, math.MaxInt64)
testGen(ctx, "2050-01-01", typ) // 输出:8476036930000011001 <nil>
testGen(ctx, "2051-01-01", typ) // 输出:8791396930000011001 <nil>
testGen(ctx, "2052-01-01", typ) // 输出:9106756930000011001 <nil> 这里已经是极限了!!!
testGen(ctx, "2053-01-01", typ) // 输出:9223372036854775807 <nil>
testGen(ctx, "2054-01-01", typ) // 输出:9223372036854775807 <nil>

// /////////////////////////////////////
// 结论:uint32 可以支持20年
fmt.Println("======================================================")
typ = "uint32"
fmt.Printf("测试%v,最大值为: %v\n", typ, math.MaxUint32)
testGen(ctx, "2043-01-01", typ) // 输出:922763001 <nil> 这里已经是极限了!!!
testGen(ctx, "2044-01-01", typ) // 输出:4284366585 <nil>
testGen(ctx, "2045-01-01", typ) // 输出:1959935737 <nil>
testGen(ctx, "2046-01-01", typ) // 输出:1026572025 <nil>
testGen(ctx, "2047-01-01", typ) // 输出:93208313 <nil>

// /////////////////////////////////////
// 结论:int32 完全玩不了
fmt.Println("======================================================")
typ = "int32"
fmt.Printf("测试%v,最大值为: %v\n", typ, math.MaxInt32)
testGen(ctx, "2024-01-01", typ) // 输出:8476036930000011001 <nil> 这里已经是极限了!!!
testGen(ctx, "2025-01-01", typ) // 输出:8791396930000011001 <nil>
testGen(ctx, "2026-01-01", typ) // 输出:9106756930000011001 <nil>
testGen(ctx, "2027-01-01", typ) // 输出:9223372036854775807 <nil>
testGen(ctx, "2028-01-01", typ) // 输出:9223372036854775807 <nil>

}

func testGen(ctx context.Context, dateStr, typ string) {
loc, _ := time.LoadLocation("Asia/Shanghai")
date := getDate(dateStr, loc)
res, err := genMsgId1(ctx, client, 1001, date, typ)
fmt.Println("date: ", date, res, err)
}

// 解析日期字符串为时间对象
func getDate(dateStr string, loc *time.Location) (date time.Time) {
var err error
date, err = time.Parse("2006-01-02", dateStr)
if err != nil {
fmt.Println("解析日期失败:", err)
return
}
date = date.In(loc)

return
}

0 comments on commit 50b78f6

Please sign in to comment.