dubbo.apache.org/dubbo-go/v3@v3.1.1/remoting/getty/pool.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package getty 19 20 import ( 21 "crypto/tls" 22 "fmt" 23 "math/rand" 24 "net" 25 "sync" 26 "sync/atomic" 27 "time" 28 ) 29 30 import ( 31 getty "github.com/apache/dubbo-getty" 32 33 "github.com/dubbogo/gost/log/logger" 34 35 perrors "github.com/pkg/errors" 36 ) 37 38 type gettyRPCClient struct { 39 once sync.Once 40 addr string // protocol string 41 active int64 // zero, not create or be destroyed 42 43 rpcClient *Client 44 45 lock sync.RWMutex 46 gettyClient getty.Client 47 sessions []*rpcSession 48 } 49 50 func newGettyRPCClientConn(rpcClient *Client, addr string) (*gettyRPCClient, error) { 51 var ( 52 gettyClient getty.Client 53 sslEnabled bool 54 ) 55 sslEnabled = rpcClient.conf.SSLEnabled 56 clientOpts := []getty.ClientOption{ 57 getty.WithServerAddress(addr), 58 getty.WithConnectionNumber((int)(rpcClient.conf.ConnectionNum)), 59 getty.WithReconnectInterval(rpcClient.conf.ReconnectInterval), 60 } 61 if sslEnabled { 62 logger.Infof("Getty client initialized the TLS configuration") 63 clientOpts = append(clientOpts, getty.WithClientSslEnabled(sslEnabled), getty.WithClientTlsConfigBuilder(rpcClient.conf.TLSBuilder)) 64 } 65 66 if clientGrPool != nil { 67 clientOpts = append(clientOpts, getty.WithClientTaskPool(clientGrPool)) 68 } 69 70 gettyClient = getty.NewTCPClient(clientOpts...) 71 c := &gettyRPCClient{ 72 addr: addr, 73 rpcClient: rpcClient, 74 gettyClient: gettyClient, 75 } 76 go c.gettyClient.RunEventLoop(c.newSession) 77 78 idx := 1 79 start := time.Now() 80 connectTimeout := rpcClient.opts.ConnectTimeout 81 for { 82 idx++ 83 if c.isAvailable() { 84 break 85 } 86 87 if time.Since(start) > connectTimeout { 88 c.gettyClient.Close() 89 return nil, perrors.New(fmt.Sprintf("failed to create client connection to %s in %s", addr, connectTimeout)) 90 } 91 92 interval := time.Millisecond * time.Duration(idx) 93 if interval > time.Duration(100e6) { 94 interval = 100e6 // 100 ms 95 } 96 time.Sleep(interval) 97 } 98 logger.Debug("client init ok") 99 c.updateActive(time.Now().Unix()) 100 101 return c, nil 102 } 103 104 func (c *gettyRPCClient) updateActive(active int64) { 105 atomic.StoreInt64(&c.active, active) 106 } 107 108 func (c *gettyRPCClient) getActive() int64 { 109 return atomic.LoadInt64(&c.active) 110 } 111 112 func (c *gettyRPCClient) newSession(session getty.Session) error { 113 var ( 114 ok bool 115 tcpConn *net.TCPConn 116 conf ClientConfig 117 sslEnabled bool 118 ) 119 conf = c.rpcClient.conf 120 sslEnabled = c.rpcClient.sslEnabled 121 if conf.GettySessionParam.CompressEncoding { 122 session.SetCompressType(getty.CompressZip) 123 } 124 if sslEnabled { 125 if _, ok = session.Conn().(*tls.Conn); !ok { 126 panic(fmt.Sprintf("%s, session.conn{%#v} is not tls connection\n", session.Stat(), session.Conn())) 127 } 128 session.SetName(conf.GettySessionParam.SessionName) 129 session.SetMaxMsgLen(conf.GettySessionParam.MaxMsgLen) 130 session.SetPkgHandler(NewRpcClientPackageHandler(c.rpcClient)) 131 session.SetEventListener(NewRpcClientHandler(c)) 132 session.SetReadTimeout(conf.GettySessionParam.tcpReadTimeout) 133 session.SetWriteTimeout(conf.GettySessionParam.tcpWriteTimeout) 134 session.SetCronPeriod((int)(conf.heartbeatPeriod.Nanoseconds() / 1e6)) 135 session.SetWaitTime(conf.GettySessionParam.waitTimeout) 136 logger.Debugf("client new session:%s\n", session.Stat()) 137 return nil 138 } 139 if tcpConn, ok = session.Conn().(*net.TCPConn); !ok { 140 panic(fmt.Sprintf("%s, session.conn{%#v} is not tcp connection\n", session.Stat(), session.Conn())) 141 } 142 143 if err := tcpConn.SetNoDelay(conf.GettySessionParam.TcpNoDelay); err != nil { 144 logger.Error("tcpConn.SetNoDelay() = error:%v", err) 145 } 146 if err := tcpConn.SetKeepAlive(conf.GettySessionParam.TcpKeepAlive); err != nil { 147 logger.Error("tcpConn.SetKeepAlive() = error:%v", err) 148 } 149 if conf.GettySessionParam.TcpKeepAlive { 150 if err := tcpConn.SetKeepAlivePeriod(conf.GettySessionParam.keepAlivePeriod); err != nil { 151 logger.Error("tcpConn.SetKeepAlivePeriod() = error:%v", err) 152 } 153 } 154 if err := tcpConn.SetReadBuffer(conf.GettySessionParam.TcpRBufSize); err != nil { 155 logger.Error("tcpConn.SetReadBuffer() = error:%v", err) 156 } 157 if err := tcpConn.SetWriteBuffer(conf.GettySessionParam.TcpWBufSize); err != nil { 158 logger.Error("tcpConn.SetWriteBuffer() = error:%v", err) 159 } 160 161 session.SetName(conf.GettySessionParam.SessionName) 162 session.SetMaxMsgLen(conf.GettySessionParam.MaxMsgLen) 163 session.SetPkgHandler(NewRpcClientPackageHandler(c.rpcClient)) 164 session.SetEventListener(NewRpcClientHandler(c)) 165 session.SetReadTimeout(conf.GettySessionParam.tcpReadTimeout) 166 session.SetWriteTimeout(conf.GettySessionParam.tcpWriteTimeout) 167 session.SetCronPeriod((int)(conf.heartbeatPeriod.Nanoseconds() / 1e6)) 168 session.SetWaitTime(conf.GettySessionParam.waitTimeout) 169 logger.Debugf("client new session:%s\n", session.Stat()) 170 return nil 171 } 172 173 func (c *gettyRPCClient) selectSession() getty.Session { 174 c.lock.RLock() 175 defer c.lock.RUnlock() 176 177 if c.sessions == nil { 178 return nil 179 } 180 count := len(c.sessions) 181 if count == 0 { 182 return nil 183 } 184 return c.sessions[rand.Int31n(int32(count))].session 185 } 186 187 func (c *gettyRPCClient) addSession(session getty.Session) { 188 logger.Debugf("add session{%s}", session.Stat()) 189 if session == nil { 190 return 191 } 192 193 c.lock.Lock() 194 defer c.lock.Unlock() 195 if c.sessions == nil { 196 c.sessions = make([]*rpcSession, 0, 16) 197 } 198 c.sessions = append(c.sessions, &rpcSession{session: session}) 199 } 200 201 func (c *gettyRPCClient) removeSession(session getty.Session) { 202 if session == nil { 203 return 204 } 205 206 var removeFlag bool 207 func() { 208 c.lock.Lock() 209 defer c.lock.Unlock() 210 if c.sessions == nil { 211 return 212 } 213 214 for i, s := range c.sessions { 215 if s.session == session { 216 c.sessions = append(c.sessions[:i], c.sessions[i+1:]...) 217 logger.Debugf("delete session{%s}, its index{%d}", session.Stat(), i) 218 break 219 } 220 } 221 logger.Infof("after remove session{%s}, left session number:%d", session.Stat(), len(c.sessions)) 222 if len(c.sessions) == 0 { 223 removeFlag = true 224 } 225 }() 226 if removeFlag { 227 c.rpcClient.resetRpcConn() 228 c.close() 229 } 230 } 231 232 func (c *gettyRPCClient) updateSession(session getty.Session) { 233 if session == nil { 234 return 235 } 236 237 var rs *rpcSession 238 func() { 239 c.lock.RLock() 240 defer c.lock.RUnlock() 241 if c.sessions == nil { 242 return 243 } 244 245 for i, s := range c.sessions { 246 if s.session == session { 247 rs = c.sessions[i] 248 break 249 } 250 } 251 }() 252 if rs != nil { 253 rs.AddReqNum(1) 254 } 255 } 256 257 func (c *gettyRPCClient) getClientRpcSession(session getty.Session) (rpcSession, error) { 258 var ( 259 err error 260 rs rpcSession 261 ) 262 c.lock.RLock() 263 defer c.lock.RUnlock() 264 if c.sessions == nil { 265 return rs, errClientClosed 266 } 267 268 err = errSessionNotExist 269 for _, s := range c.sessions { 270 if s.session == session { 271 rs = *s 272 err = nil 273 break 274 } 275 } 276 277 return rs, perrors.WithStack(err) 278 } 279 280 func (c *gettyRPCClient) isAvailable() bool { 281 return c.selectSession() != nil 282 } 283 284 func (c *gettyRPCClient) close() error { 285 closeErr := perrors.Errorf("close gettyRPCClient{%#v} again", c) 286 c.once.Do(func() { 287 var ( 288 gettyClient getty.Client 289 sessions []*rpcSession 290 ) 291 func() { 292 c.lock.Lock() 293 defer c.lock.Unlock() 294 295 gettyClient = c.gettyClient 296 c.gettyClient = nil 297 298 sessions = make([]*rpcSession, 0, len(c.sessions)) 299 sessions = append(sessions, c.sessions...) 300 c.sessions = c.sessions[:0] 301 }() 302 303 c.updateActive(0) 304 305 go func() { 306 if gettyClient != nil { 307 gettyClient.Close() 308 } 309 for _, s := range sessions { 310 logger.Infof("close client session{%s, last active:%s, request number:%d}", 311 s.session.Stat(), s.session.GetActive().String(), s.GetReqNum()) 312 s.session.Close() 313 } 314 }() 315 316 closeErr = nil 317 }) 318 return closeErr 319 }