github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/engine/pkg/p2p/server.go (about)

     1  // Copyright 2022 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package p2p
    15  
    16  import (
    17  	"context"
    18  	"net"
    19  	"time"
    20  
    21  	"github.com/pingcap/log"
    22  	"github.com/pingcap/tiflow/pkg/errors"
    23  	"github.com/pingcap/tiflow/pkg/logutil"
    24  	p2pImpl "github.com/pingcap/tiflow/pkg/p2p"
    25  	"github.com/pingcap/tiflow/pkg/security"
    26  	"github.com/pingcap/tiflow/proto/p2p"
    27  	"go.uber.org/zap"
    28  	"golang.org/x/sync/errgroup"
    29  	"google.golang.org/grpc"
    30  )
    31  
    32  // Re-export some types
    33  type (
    34  	// Topic alias to p2pImpl.Topic
    35  	Topic = p2pImpl.Topic
    36  	// NodeID alias to p2pImpl.NodeID
    37  	NodeID = p2pImpl.NodeID
    38  	// Config alias to p2pImpl.MessageServerConfig
    39  	Config = p2pImpl.MessageServerConfig
    40  )
    41  
    42  type (
    43  	// TypeInformation is used to hold type data
    44  	TypeInformation = interface{}
    45  	// MessageValue is used to hold message object
    46  	MessageValue = interface{}
    47  	// HandlerFunc alias to message handler function
    48  	HandlerFunc = func(sender NodeID, value MessageValue) error
    49  )
    50  
    51  type (
    52  	// MessageServerOpt alias to the option setter function
    53  	MessageServerOpt = func(*Config)
    54  )
    55  
    56  // read only
    57  // TODO: should we expose a default config from p2pImpl package
    58  var defaultServerConfig = Config{
    59  	MaxPendingMessageCountPerTopic:       256,
    60  	MaxPendingTaskCount:                  102400,
    61  	SendChannelSize:                      16,
    62  	AckInterval:                          time.Millisecond * 200,
    63  	WorkerPoolSize:                       4,
    64  	MaxPeerCount:                         1024,
    65  	WaitUnregisterHandleTimeoutThreshold: time.Millisecond * 100,
    66  	SendRateLimitPerStream:               1024.0,
    67  }
    68  
    69  // MessageRPCService is a background service wrapping a MessageServer instance.
    70  type MessageRPCService struct {
    71  	messageServer *p2pImpl.MessageServer
    72  	grpcServer    *grpc.Server
    73  
    74  	noNeedToRunGRPCServer bool
    75  }
    76  
    77  // NewMessageServer creates a new message server from given configs
    78  func NewMessageServer(
    79  	selfID NodeID,
    80  	_credential *security.Credential,
    81  	opts ...MessageServerOpt,
    82  ) *p2pImpl.MessageServer {
    83  	// Deep copy
    84  	config := defaultServerConfig
    85  	// Apply opts
    86  	for _, opt := range opts {
    87  		opt(&config)
    88  	}
    89  	return p2pImpl.NewMessageServer(selfID, &config)
    90  }
    91  
    92  // NewMessageRPCServiceWithRPCServer creates a new MessageRPCService with an
    93  // existing gRPC server.
    94  func NewMessageRPCServiceWithRPCServer(
    95  	selfID NodeID,
    96  	_credential *security.Credential,
    97  	grpcSvr *grpc.Server,
    98  	opts ...MessageServerOpt,
    99  ) *MessageRPCService {
   100  	// Deep copy
   101  	config := defaultServerConfig
   102  	// Apply opts
   103  	for _, opt := range opts {
   104  		opt(&config)
   105  	}
   106  	messageServer := p2pImpl.NewMessageServer(selfID, &config)
   107  	// TODO: support accepting TLS connections.
   108  	return &MessageRPCService{
   109  		messageServer: messageServer,
   110  		grpcServer:    grpcSvr,
   111  	}
   112  }
   113  
   114  // NewMessageRPCService creates a new MessageRPCService.
   115  // Note: TLS is not supported for now.
   116  func NewMessageRPCService(
   117  	selfID NodeID,
   118  	_credential *security.Credential,
   119  	opts ...MessageServerOpt,
   120  ) (*MessageRPCService, error) {
   121  	grpcSvr := grpc.NewServer()
   122  	service := NewMessageRPCServiceWithRPCServer(selfID, _credential, grpcSvr, opts...)
   123  	p2p.RegisterCDCPeerToPeerServer(grpcSvr, service.messageServer)
   124  	return service, nil
   125  }
   126  
   127  // NewDependentMessageRPCService creates a new MessageRPCService
   128  // that DOES NOT own a `grpc.Server`.
   129  // TODO refactor the design.
   130  func NewDependentMessageRPCService(
   131  	selfID NodeID,
   132  	_credential *security.Credential,
   133  	grpcSvr *grpc.Server,
   134  	opts ...MessageServerOpt,
   135  ) (*MessageRPCService, error) {
   136  	service := NewMessageRPCServiceWithRPCServer(selfID, _credential, grpcSvr, opts...)
   137  	p2p.RegisterCDCPeerToPeerServer(grpcSvr, service.messageServer)
   138  	service.noNeedToRunGRPCServer = true
   139  	return service, nil
   140  }
   141  
   142  // Serve listens on `l` and creates the background goroutine for the message server.
   143  func (s *MessageRPCService) Serve(ctx context.Context, l net.Listener) error {
   144  	defer func() {
   145  		if l == nil {
   146  			return
   147  		}
   148  		err := l.Close()
   149  		if err != nil {
   150  			log.Warn("failed to close Listener", zap.Error(err))
   151  		}
   152  	}()
   153  
   154  	wg, ctx := errgroup.WithContext(ctx)
   155  
   156  	wg.Go(func() (err error) {
   157  		defer logutil.ErrorFilterContextCanceled(log.L(), "message server exited", zap.Error(err))
   158  		return errors.Trace(s.messageServer.Run(ctx, nil))
   159  	})
   160  
   161  	// TODO redesign MessageRPCService to avoid this branch
   162  	if s.noNeedToRunGRPCServer {
   163  		return wg.Wait()
   164  	}
   165  
   166  	wg.Go(func() (err error) {
   167  		defer func() {
   168  			// TODO (zixiong) filter out expected harmless errors.
   169  			log.Debug("grpc server exited", zap.Error(err))
   170  		}()
   171  		return errors.Trace(s.grpcServer.Serve(l))
   172  	})
   173  
   174  	// We need a separate goroutine for canceling the gRPC server
   175  	// because the `Serve` method provides by the library does not
   176  	// support canceling by contexts, which is a more idiomatic way.
   177  	wg.Go(func() error {
   178  		<-ctx.Done()
   179  		log.Debug("context canceled, stopping the gRPC server")
   180  
   181  		s.grpcServer.Stop()
   182  		return nil
   183  	})
   184  
   185  	return wg.Wait()
   186  }
   187  
   188  // GetMessageServer returns the internal message server
   189  func (s *MessageRPCService) GetMessageServer() *p2pImpl.MessageServer {
   190  	return s.messageServer
   191  }
   192  
   193  // MakeHandlerManager returns a MessageHandlerManager
   194  func (s *MessageRPCService) MakeHandlerManager() MessageHandlerManager {
   195  	return newMessageHandlerManager(s.messageServer)
   196  }