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 }