go-pitaya学习笔记(4)-clusterdemo分析

14 篇文章 3 订阅

 学习笔记: 我家别墅靠大海/pitaya-learn

尝试集成功能:我家别墅靠大海/pitaya-game

如果你正在看此笔记,请你左边放笔记,右边放chatdemo的代码!!

我是按代码的顺序记的笔记

和之前一样,把demo拿过来

cluster

看一下main.go

映入眼帘的就是是否是前端服务器。。第二节有记到

那我们猜着运行一个前端服务器和一个后端服务器。

估计默认参数就是前端,改了参数就是后端

前端:

后端:

go run main.go -port=3251 -type=room -frontend=false

 启动完成后端以后,前端好像检测到了集群,好像启动成功了

html测试不了了,用官方cli测试一下

安装

go get github.com/topfreegames/pitaya-cli

如果出现了

在mod里面把grpc降到1.26 

这个包拉完,命令就可以用了

我们先改一下demo里room.go的源码

他这个有点问题

所有人的uid都是一样的,不太好测试,改成chatdemo一样的。

 这个entry类似于打开网页自动分配个uid。

只不过chatdemo集成在join里面了

别忘了你的main.go引入的还是线上的services,需要改成本地的。

重新启动一下全部服务器。

按照火龙果cli的demo链接一下

示例:https://github.com/topfreegames/pitaya-cli

我这边启动了多个cli,

测起来是可以的,好像没啥问题。

message没测试,没找到怎么传proto。反正测不测也无所谓了

可以看到,我们实际链接的服务器是前端服务器

我们跳过前端,连下后端服务器room试试

 连不过去,好了,我们分析下源码

源码分析1

源码有点太乱了,我们只保留room基础的源码,后续我们再分析别的。

删除 connector.go

main.go代码如下

package main

import (
	"context"
	"flag"
	"fmt"

	"game/demo/cluster/services"
	"strings"

	"github.com/topfreegames/pitaya/v2"
	"github.com/topfreegames/pitaya/v2/acceptor"
	"github.com/topfreegames/pitaya/v2/cluster"
	"github.com/topfreegames/pitaya/v2/component"
	"github.com/topfreegames/pitaya/v2/config"

	// "github.com/topfreegames/pitaya/v2/examples/demo/cluster/services"
	"github.com/topfreegames/pitaya/v2/groups"
	"github.com/topfreegames/pitaya/v2/route"
)

var app pitaya.Pitaya

func configureBackend() {
	room := services.NewRoom(app)
	app.Register(room,
		component.WithName("room"),
		component.WithNameFunc(strings.ToLower),
	)

	app.RegisterRemote(room,
		component.WithName("room"),
		component.WithNameFunc(strings.ToLower),
	)
}

func configureFrontend(port int) {

	err := app.AddRoute("room", func(
		ctx context.Context,
		route *route.Route,
		payload []byte,
		servers map[string]*cluster.Server,
	) (*cluster.Server, error) {
		// will return the first server
		for k := range servers {
			return servers[k], nil
		}
		return nil, nil
	})

	if err != nil {
		fmt.Printf("error adding route %s\n", err.Error())
	}
}

func main() {
	port := flag.Int("port", 3250, "the port to listen")
	svType := flag.String("type", "connector", "the server type")
	isFrontend := flag.Bool("frontend", true, "if server is frontend")

	flag.Parse()

	builder := pitaya.NewDefaultBuilder(*isFrontend, *svType, pitaya.Cluster, map[string]string{}, *config.NewDefaultBuilderConfig())
	if *isFrontend {
		tcp := acceptor.NewTCPAcceptor(fmt.Sprintf(":%d", *port))
		builder.AddAcceptor(tcp)
	}
	builder.Groups = groups.NewMemoryGroupService(*config.NewDefaultMemoryGroupConfig())
	app = builder.Build()

	//TODO: Oelze pitaya.SetSerializer(protobuf.NewSerializer())

	defer app.Shutdown()

	if !*isFrontend {
		configureBackend()
	} else {
		configureFrontend(*port)
	}

	app.Start()
}

room.go 如下

package services

import (
	"context"
	"fmt"
	"strconv"
	"time"

	"github.com/topfreegames/pitaya/v2"
	"github.com/topfreegames/pitaya/v2/component"
	"github.com/topfreegames/pitaya/v2/examples/demo/protos"
	"github.com/topfreegames/pitaya/v2/timer"
)

type (
	// Room represents a component that contains a bundle of room related handler
	// like Join/Message
	Room struct {
		component.Base
		timer *timer.Timer
		app   pitaya.Pitaya
		Stats *protos.Stats
	}

	// UserMessage represents a message that user sent
	UserMessage struct {
		Name    string `json:"name"`
		Content string `json:"content"`
	}

	// Stats exports the room status
	Stats struct {
		outboundBytes int
		inboundBytes  int
	}

	// NewUser message will be received when new user join room
	NewUser struct {
		Content string `json:"content"`
	}

	// AllMembers contains all members uid
	AllMembers struct {
		Members []string `json:"members"`
	}

	// JoinResponse represents the result of joining room
	JoinResponse struct {
		Code   int    `json:"code"`
		Result string `json:"result"`
	}
)

// NewRoom returns a new room
func NewRoom(app pitaya.Pitaya) *Room {
	return &Room{
		app:   app,
		Stats: &protos.Stats{},
	}
}

// Init runs on service initialization
func (r *Room) Init() {
	r.app.GroupCreate(context.Background(), "room")
}

// AfterInit component lifetime callback
func (r *Room) AfterInit() {
	r.timer = pitaya.NewTimer(time.Minute, func() {
		count, err := r.app.GroupCountMembers(context.Background(), "room")
		println("UserCount: Time=>", time.Now().String(), "Count=>", count, "Error=>", err)
		println("OutboundBytes", r.Stats.OutboundBytes)
		println("InboundBytes", r.Stats.OutboundBytes)
	})
}

// Entry is the entrypoint
func (r *Room) Entry(ctx context.Context, msg []byte) (*protos.JoinResponse, error) {

	logger := pitaya.GetDefaultLoggerFromCtx(ctx) // The default logger contains a requestId, the route being executed and the sessionId
	s := r.app.GetSessionFromCtx(ctx)

	// err := s.Bind(ctx, "banana")

	fakeUID := s.ID()                              // just use s.ID as uid !!!
	err := s.Bind(ctx, strconv.Itoa(int(fakeUID))) // binding session uid

	if err != nil {
		logger.Error("Failed to bind session")
		logger.Error(err)
		return nil, pitaya.Error(err, "RH-000", map[string]string{"failed": "bind"})
	}
	return &protos.JoinResponse{Result: "ok"}, nil
}

// Join room
func (r *Room) Join(ctx context.Context) (*protos.JoinResponse, error) {
	logger := pitaya.GetDefaultLoggerFromCtx(ctx)
	s := r.app.GetSessionFromCtx(ctx)
	err := r.app.GroupAddMember(ctx, "room", s.UID())
	if err != nil {
		logger.Error("Failed to join room")
		logger.Error(err)
		return nil, err
	}
	members, err := r.app.GroupMembers(ctx, "room")
	if err != nil {
		logger.Error("Failed to get members")
		logger.Error(err)
		return nil, err
	}
	s.Push("onMembers", &protos.AllMembers{Members: members})
	// err = r.app.GroupBroadcast(ctx, "connector", "room", "onNewUser", &protos.NewUser{Content: fmt.Sprintf("New user: %d", s.ID())})
	err = r.app.GroupBroadcast(ctx, "connector", "room", "onNewUser", &protos.NewUser{Content: fmt.Sprintf("New user: %s", s.UID())})
	if err != nil {
		logger.Error("Failed to broadcast onNewUser")
		logger.Error(err)
		return nil, err
	}
	return &protos.JoinResponse{Result: "success"}, nil
}

// Message sync last message to all members
func (r *Room) Message(ctx context.Context, msg *protos.UserMessage) {
	logger := pitaya.GetDefaultLoggerFromCtx(ctx)
	err := r.app.GroupBroadcast(ctx, "connector", "room", "onMessage", msg)
	if err != nil {
		logger.Error("Error broadcasting message")
		logger.Error(err)
	}
}

代码干净了,再测一下

其实发现整套代码和之前的地方没什么不同。

先看一下配置后端

是注册模块,不同的是,分布式要注册一个远程模块。

注册方法和之前注册本地模块一样。

他这个demo是通过转发消息实现的。

后面其实是可以通过rpc实现

文档:Pitaya API — Pitaya documentation

 

 再看看注册前端。

app有个addroute方法,添加一个分布式模块路由 ,消息由 pitaya 转发到适当的服务器类型

“room” 服务器类型

"第二个参数是路由方法"

 

 文档:Pitaya API — Pitaya documentation

路由方法

ctx上下文

route 路由实例

payload 不知道啥玩意

cluster.Server 当前服务器的集群map

返还

一个服务器句柄

demo里面是只要在集群中找到了这个类型的服务器,就返回这个服务器

 

 当然可以我们可以实现其他的负载算法

笔记5:

https://blog.csdn.net/qq_37962920/article/details/122350196

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值