|
|
|
@ -3,38 +3,51 @@ package main |
|
|
|
import ( |
|
|
|
import ( |
|
|
|
"context" |
|
|
|
"context" |
|
|
|
"encoding/base64" |
|
|
|
"encoding/base64" |
|
|
|
|
|
|
|
"encoding/json" |
|
|
|
"fmt" |
|
|
|
"fmt" |
|
|
|
"github.com/bytedance/sonic" |
|
|
|
"github.com/bytedance/sonic" |
|
|
|
"github.com/gorilla/websocket" |
|
|
|
"github.com/gorilla/websocket" |
|
|
|
|
|
|
|
clientv3 "go.etcd.io/etcd/client/v3" |
|
|
|
|
|
|
|
"google.golang.org/grpc" |
|
|
|
|
|
|
|
"google.golang.org/grpc/credentials/insecure" |
|
|
|
"google.golang.org/protobuf/proto" |
|
|
|
"google.golang.org/protobuf/proto" |
|
|
|
|
|
|
|
"io" |
|
|
|
"math/rand" |
|
|
|
"math/rand" |
|
|
|
"net" |
|
|
|
"net" |
|
|
|
|
|
|
|
"net/http" |
|
|
|
"runtime" |
|
|
|
"runtime" |
|
|
|
"sonet/api/gen/auth" |
|
|
|
"sonet/api/gen/auth" |
|
|
|
"sonet/api/gen/chat" |
|
|
|
"sonet/api/gen/chat" |
|
|
|
"sonet/pkg/config" |
|
|
|
"sonet/pkg/config" |
|
|
|
|
|
|
|
"sonet/pkg/grpc/discovery" |
|
|
|
"sonet/pkg/protocol" |
|
|
|
"sonet/pkg/protocol" |
|
|
|
|
|
|
|
"sonet/pkg/protocol/deliver" |
|
|
|
"sonet/pkg/utils/logger" |
|
|
|
"sonet/pkg/utils/logger" |
|
|
|
"sonet/pkg/utils/security" |
|
|
|
"sonet/pkg/utils/security" |
|
|
|
"sonet/pkg/utils/shutdown" |
|
|
|
"sonet/pkg/utils/shutdown" |
|
|
|
"strconv" |
|
|
|
"strconv" |
|
|
|
|
|
|
|
"strings" |
|
|
|
"sync" |
|
|
|
"sync" |
|
|
|
"sync/atomic" |
|
|
|
"sync/atomic" |
|
|
|
"time" |
|
|
|
"time" |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
var ( |
|
|
|
mockUsers = 100 |
|
|
|
benchmarkMode = "deliver" // deliver / groupDeliver
|
|
|
|
eachUserSend = 100000 |
|
|
|
mockUsers = 2000 |
|
|
|
|
|
|
|
eachUserSend = 100 |
|
|
|
mockNetUsers []*NetUser |
|
|
|
mockNetUsers []*NetUser |
|
|
|
sendCounter int64 = 0 |
|
|
|
sendCounter int64 = 0 |
|
|
|
receiverCounter int64 = 0 |
|
|
|
receiverCounter int64 = 0 |
|
|
|
wsUrls = []string{"ws://192.168.110.36:7001", "ws://192.168.110.36:7003"} |
|
|
|
//wsUrls = []string{"ws://192.168.110.36:7001", "ws://192.168.110.36:7003"}
|
|
|
|
seqId int32 |
|
|
|
gatewayHttp = "http://192.168.110.36:7000" |
|
|
|
callbacks map[int32]func(res any) |
|
|
|
httpClient *http.Client |
|
|
|
callbackMutex *sync.Mutex |
|
|
|
etcdClient *clientv3.Client |
|
|
|
useMsSum int64 |
|
|
|
seqId int32 |
|
|
|
useMsAvg int64 |
|
|
|
callbacks map[int32]func(res any) |
|
|
|
|
|
|
|
callbackMutex *sync.Mutex |
|
|
|
|
|
|
|
useMsSum int64 |
|
|
|
|
|
|
|
useMsAvg int64 |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
func init() { |
|
|
|
func init() { |
|
|
|
@ -42,10 +55,21 @@ func init() { |
|
|
|
|
|
|
|
|
|
|
|
callbacks = make(map[int32]func(res any), 128) |
|
|
|
callbacks = make(map[int32]func(res any), 128) |
|
|
|
callbackMutex = &sync.Mutex{} |
|
|
|
callbackMutex = &sync.Mutex{} |
|
|
|
|
|
|
|
httpClient = &http.Client{Timeout: 10 * time.Second} |
|
|
|
|
|
|
|
var err error |
|
|
|
|
|
|
|
etcdClient, err = clientv3.New(clientv3.Config{ |
|
|
|
|
|
|
|
Endpoints: []string{"124.222.131.236:3279"}, |
|
|
|
|
|
|
|
Username: "root", |
|
|
|
|
|
|
|
Password: "sopod@etcd", |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
panic(err) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func main() { |
|
|
|
func main() { |
|
|
|
benchmark() |
|
|
|
// benchmark()
|
|
|
|
|
|
|
|
benchmarkGroup() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func records(ctx context.Context) { |
|
|
|
func records(ctx context.Context) { |
|
|
|
@ -83,11 +107,15 @@ func benchmark() { |
|
|
|
// initial uids
|
|
|
|
// initial uids
|
|
|
|
for i := 0; i < mockUsers; i++ { |
|
|
|
for i := 0; i < mockUsers; i++ { |
|
|
|
uid := strconv.Itoa(110000 + i) |
|
|
|
uid := strconv.Itoa(110000 + i) |
|
|
|
conn, err := getConn() |
|
|
|
token, err := getToken(uid) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
panic(err) |
|
|
|
panic(err) |
|
|
|
} |
|
|
|
} |
|
|
|
err = handleConn(ctx, uid, conn) |
|
|
|
conn, err := getConn(token) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
panic(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
err = handleConn(ctx, uid, token, conn) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
panic(err) |
|
|
|
panic(err) |
|
|
|
} |
|
|
|
} |
|
|
|
@ -108,6 +136,75 @@ func benchmark() { |
|
|
|
logger.Infof("total receiver:%d, send:%d\n", receiverCounter, sendCounter) |
|
|
|
logger.Infof("total receiver:%d, send:%d\n", receiverCounter, sendCounter) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func benchmarkGroup() { |
|
|
|
|
|
|
|
benchmarkMode = "groupDeliver" |
|
|
|
|
|
|
|
runtime.GOMAXPROCS(runtime.NumCPU()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background()) |
|
|
|
|
|
|
|
shutdown.AddHook(cancel) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// postal group deliver
|
|
|
|
|
|
|
|
dis := discovery.NewEtcdDiscovery(etcdClient) |
|
|
|
|
|
|
|
picker := deliver.NewPostalPicker(dis, grpc.WithTransportCredentials(insecure.NewCredentials())) |
|
|
|
|
|
|
|
if err := picker.Init(ctx); err != nil { |
|
|
|
|
|
|
|
panic(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
groupDeliver := deliver.NewGroupDeliver(chat.Chat_ServiceDesc.ServiceName, picker, nil, nil) |
|
|
|
|
|
|
|
if err := groupDeliver.Init(ctx); err != nil { |
|
|
|
|
|
|
|
panic(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
groupId := "9527" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// initial mock users, join to postal group
|
|
|
|
|
|
|
|
mockNetUsers = make([]*NetUser, mockUsers) |
|
|
|
|
|
|
|
for i := 0; i < mockUsers; i++ { |
|
|
|
|
|
|
|
uid := strconv.Itoa(110000 + i) |
|
|
|
|
|
|
|
token, err := getToken(uid) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
panic(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
conn, err := getConn(token) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
panic(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
err = handleConn(ctx, uid, token, conn) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
panic(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
mockNetUsers[i] = &NetUser{ |
|
|
|
|
|
|
|
Uid: uid, |
|
|
|
|
|
|
|
Conn: conn, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// join group
|
|
|
|
|
|
|
|
err = groupDeliver.GroupJoin(context.Background(), uid, []string{groupId}) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
panic(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
shutdown.AddHook(func() { |
|
|
|
|
|
|
|
if err := groupDeliver.GroupDissolve(context.Background(), groupId); err != nil { |
|
|
|
|
|
|
|
logger.Error("dissolve group error: ", err) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
logger.Info("test group dissolved") |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
go records(ctx) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// send group message
|
|
|
|
|
|
|
|
message := &chat.ChatMessage{Sender: "100001", Content: "hello"} |
|
|
|
|
|
|
|
for i := 0; i < eachUserSend; i++ { |
|
|
|
|
|
|
|
err := groupDeliver.DeliverGroup(context.Background(), groupId, message) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
logger.Error("deliver group error:", err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
atomic.AddInt64(&sendCounter, 1) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
shutdown.Await() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func sendBatchChatMessage(ctx context.Context, uid string, conn *websocket.Conn, count int) { |
|
|
|
func sendBatchChatMessage(ctx context.Context, uid string, conn *websocket.Conn, count int) { |
|
|
|
r := rand.New(rand.NewSource(time.Now().UnixMilli())) |
|
|
|
r := rand.New(rand.NewSource(time.Now().UnixMilli())) |
|
|
|
for i := 0; i < count; i++ { |
|
|
|
for i := 0; i < count; i++ { |
|
|
|
@ -132,9 +229,30 @@ func sendBatchChatMessage(ctx context.Context, uid string, conn *websocket.Conn, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func getConn() (conn *websocket.Conn, err error) { |
|
|
|
func getConn(token string) (conn *websocket.Conn, err error) { |
|
|
|
wsUrl := wsUrls[rand.Intn(len(wsUrls))] |
|
|
|
req, err := http.NewRequest("GET", gatewayHttp+"/api/lb/ws", io.LimitReader(nil, 0)) |
|
|
|
conn, _, err = websocket.DefaultDialer.Dial(wsUrl+"/ws", nil) |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
req.Header.Set("Authorization", token) |
|
|
|
|
|
|
|
resp, err := httpClient.Do(req) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
logger.Error("get ws endpoint error: ", err) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
defer resp.Body.Close() |
|
|
|
|
|
|
|
bytes, err := io.ReadAll(resp.Body) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
body := make(map[string]any, 2) |
|
|
|
|
|
|
|
err = json.Unmarshal(bytes, &body) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
wsUrl := body["data"].(map[string]any)["ws"].(string) |
|
|
|
|
|
|
|
// wsUrl := wsUrls[rand.Intn(len(wsUrls))]
|
|
|
|
|
|
|
|
conn, _, err = websocket.DefaultDialer.Dial("ws://"+wsUrl+"/ws", nil) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
@ -161,14 +279,10 @@ func getToken(uid string) (token string, err error) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// handleConn listen and auth verify
|
|
|
|
// handleConn listen and auth verify
|
|
|
|
func handleConn(ctx context.Context, uid string, conn *websocket.Conn) (err error) { |
|
|
|
func handleConn(ctx context.Context, uid string, token string, conn *websocket.Conn) (err error) { |
|
|
|
go listen(ctx, conn) |
|
|
|
go listen(ctx, conn) |
|
|
|
|
|
|
|
|
|
|
|
// handshake
|
|
|
|
// handshake
|
|
|
|
token, err := getToken(uid) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
args := &auth.ReqVerify{Token: token} |
|
|
|
args := &auth.ReqVerify{Token: token} |
|
|
|
|
|
|
|
|
|
|
|
channel, err := send(conn, auth.Auth_ServiceDesc.ServiceName, "Verify", args) |
|
|
|
channel, err := send(conn, auth.Auth_ServiceDesc.ServiceName, "Verify", args) |
|
|
|
@ -186,7 +300,7 @@ func handleConn(ctx context.Context, uid string, conn *websocket.Conn) (err erro |
|
|
|
func listen(ctx context.Context, conn *websocket.Conn) { |
|
|
|
func listen(ctx context.Context, conn *websocket.Conn) { |
|
|
|
var e error |
|
|
|
var e error |
|
|
|
defer func() { |
|
|
|
defer func() { |
|
|
|
if e != nil { |
|
|
|
if e != nil && !strings.Contains(e.Error(), "close") { |
|
|
|
fmt.Println("conn error: ", e) |
|
|
|
fmt.Println("conn error: ", e) |
|
|
|
} |
|
|
|
} |
|
|
|
}() |
|
|
|
}() |
|
|
|
@ -221,6 +335,10 @@ func listen(ctx context.Context, conn *websocket.Conn) { |
|
|
|
} |
|
|
|
} |
|
|
|
header := payload.Header |
|
|
|
header := payload.Header |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if benchmarkMode == "groupDeliver" { |
|
|
|
|
|
|
|
atomic.AddInt64(&receiverCounter, 1) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if header.Type == 4 { |
|
|
|
if header.Type == 4 { |
|
|
|
callbackMutex.Lock() |
|
|
|
callbackMutex.Lock() |
|
|
|
callback, ok := callbacks[header.SeqId] |
|
|
|
callback, ok := callbacks[header.SeqId] |
|
|
|
|