前言
第一篇只要介绍了nano 库的一些概念,这篇主要讲解代码部分。因为这个库作者还是不断完善中,所以后续可能会有变动。作者已经在最初版本上加入了cluster,集群等概念。
结构
cluster集群
cluster 包含有多个nano节点
每个nano都提供一组不同的服务。
所有服务需求从客户端开始,并向前推进到适当的节点。
// cluster represents a nano cluster, which contains a bunch of nano nodes
// and each of them provide a group of different services. All services requests
// from client will send to gate firstly and be forwarded to appropriate node.
type cluster struct {
// If cluster is not large enough, use slice is OK
currentNode *Node
rpcClient *rpcClient
mu sync.RWMutex
members []*Member
}
node 节点:
Node表示nano集群中的一个节点,该节点将包含一组服务。
所有服务都将注册到群集,消息将转发到节点
提供各自的服务
// Node represents a node in nano cluster, which will contains a group of services.
// All services will register to cluster and messages will be forwarded to the node
// which provides respective service
type Node struct {
Options // current node options
ServiceAddr string // current server service address (RPC)
cluster *cluster
handler *LocalHandler
server *grpc.Server
rpcClient *rpcClient
mu sync.RWMutex
sessions map[int64]*session.Session
}
listen 函数 --启动一个node 并配置属性
定义
listen 是启动一个node的主要函数,设置监听端口,并且通过可变参数进行对node一下属性进行配置。
//Listen listens on the TCP network address addr and then calls Serve with handler to handle requests on incoming connections.
func Listen(addr string, opts …Option)
第二个参数是函数定义
type Option func(*cluster.Options)
//node.go
type Options struct {
Pipeline pipeline.Pipeline
IsMaster bool //是否是master服务器
AdvertiseAddr string //需要连接的ip和port
RetryInterval time.Duration
ClientAddr string
Components *component.Components //注册服务
Label string
IsWebsocket bool //是否websocket
TSLCertificate string
TSLKey string
}
配置函数
func listen 通过参数进行配置,代理中也提供了配置函数
1. func WithMaster
WithMaster设置指示当前节点是否为主节点的选项
// options.go
func WithMaster() Option
// WithMaster sets the option to indicate whether the current node is master node
func WithMaster() Option {
return func(opt *cluster.Options) {
opt.IsMaster = true
}
}
2. func WithComponents
设置功能组件
func WithComponents(components *component.Components) Option {
return func(opt *cluster.Options) {
opt.Components = components
}
}
3. func WithAdvertiseAddr
设置AdvertiseAddr变量。其实是master node 的ip地址,端口和超时重连,用于连接master node。
master node 不用设置。
func WithAdvertiseAddr(addr string, retryInterval ...time.Duration) Option {
return func(opt *cluster.Options) {
opt.AdvertiseAddr = addr
if len(retryInterval) > 0 {
opt.RetryInterval = retryInterval[0]
}
}
}
4. func WithClientAddr
设置用于在群集成员之间建立连接的侦听地址。如果没有成员地址设置,将自动选择可用端口;如果没有可用端口,将panic (我理解的还不是很清楚这个函数)
func WithClientAddr(addr string) Option {
return func(opt *cluster.Options) {
opt.ClientAddr = addr
}
}
5. func WithHeartbeatInterval
设置心跳时间
func WithHeartbeatInterval(d time.Duration) Option {
return func(_ *cluster.Options) {
env.Heartbeat = d
}
}
6. func WithIsWebsocket
指示当前节点WebSocket是否已启用
func WithIsWebsocket(enableWs bool) Option {
return func(opt *cluster.Options) {
opt.IsWebsocket = enableWs
}
}
7. func WithDebugMode
设置debug模式
func WithDebugMode() Option {
return func(_ *cluster.Options) {
env.Debug = true
}
}
8. func WithSerializer
自定义应用程序序列化过程,它自动封送和解除封送处理程序
func WithSerializer(serializer serialize.Serializer) Option {
return func(opt *cluster.Options) {
env.Serializer = serializer
}
}
listen函数实现
// interface.go
// Listen listens on the TCP network address addr
// and then calls Serve with handler to handle requests
// on incoming connections.
func Listen(addr string, opts ...Option) {
if atomic.AddInt32(&running, 1) != 1 {
log.Println("Nano has running")
return
}
// application initialize
app.name = strings.TrimLeft(filepath.Base(os.Args[0]), "/")
app.startAt = time.Now()
// environment initialize
if wd, err := os.Getwd(); err != nil {
panic(err)
} else {
env.Wd, _ = filepath.Abs(wd)
}
opt := cluster.Options{
Components: &component.Components{},
}
for _, option := range opts {
option(&opt)
}
// Use listen address as client address in non-cluster mode
if !opt.IsMaster && opt.AdvertiseAddr == "" && opt.ClientAddr == "" {
log.Println("The current server running in singleton mode")
opt.ClientAddr = addr
}
// Set the retry interval to 3 secondes if doesn't set by user
if opt.RetryInterval == 0 {
opt.RetryInterval = time.Second * 3
}
node := &cluster.Node{
Options: opt,
ServiceAddr: addr,
}
err := node.Startup()
if err != nil {
log.Fatalf("Node startup failed: %v", err)
}
runtime.CurrentNode = node
if node.ClientAddr != "" {
log.Println(fmt.Sprintf("Startup *Nano gate server* %s, client address: %v, service address: %s",
app.name, node.ClientAddr, node.ServiceAddr))
} else {
log.Println(fmt.Sprintf("Startup *Nano backend server* %s, service address %s",
app.name, node.ServiceAddr))
}
go scheduler.Sched()
sg := make(chan os.Signal)
signal.Notify(sg, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGTERM)
select {
case <-env.Die:
log.Println("The app will shutdown in a few seconds")
case s := <-sg:
log.Println("Nano server got signal", s)
}
log.Println("Nano server is stopping...")
node.Shutdown()
runtime.CurrentNode = nil
scheduler.Close()
atomic.StoreInt32(&running, 0)
}
cluster关闭
// Shutdown send a signal to let 'nano' shutdown itself.
func Shutdown() {
close(env.Die)
}
备注
这是一些基本的,还有其他的设置函数,比如重新设置日志系统,TSL加密等等,大家可以去看源码。