You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

392 line
11 KiB

  1. /*
  2. *
  3. * Copyright 2016 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * 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 grpc
  19. import (
  20. "context"
  21. "net"
  22. "sync"
  23. "google.golang.org/grpc/codes"
  24. "google.golang.org/grpc/credentials"
  25. "google.golang.org/grpc/grpclog"
  26. "google.golang.org/grpc/naming"
  27. "google.golang.org/grpc/status"
  28. )
  29. // Address represents a server the client connects to.
  30. //
  31. // Deprecated: please use package balancer.
  32. type Address struct {
  33. // Addr is the server address on which a connection will be established.
  34. Addr string
  35. // Metadata is the information associated with Addr, which may be used
  36. // to make load balancing decision.
  37. Metadata interface{}
  38. }
  39. // BalancerConfig specifies the configurations for Balancer.
  40. //
  41. // Deprecated: please use package balancer.
  42. type BalancerConfig struct {
  43. // DialCreds is the transport credential the Balancer implementation can
  44. // use to dial to a remote load balancer server. The Balancer implementations
  45. // can ignore this if it does not need to talk to another party securely.
  46. DialCreds credentials.TransportCredentials
  47. // Dialer is the custom dialer the Balancer implementation can use to dial
  48. // to a remote load balancer server. The Balancer implementations
  49. // can ignore this if it doesn't need to talk to remote balancer.
  50. Dialer func(context.Context, string) (net.Conn, error)
  51. }
  52. // BalancerGetOptions configures a Get call.
  53. //
  54. // Deprecated: please use package balancer.
  55. type BalancerGetOptions struct {
  56. // BlockingWait specifies whether Get should block when there is no
  57. // connected address.
  58. BlockingWait bool
  59. }
  60. // Balancer chooses network addresses for RPCs.
  61. //
  62. // Deprecated: please use package balancer.
  63. type Balancer interface {
  64. // Start does the initialization work to bootstrap a Balancer. For example,
  65. // this function may start the name resolution and watch the updates. It will
  66. // be called when dialing.
  67. Start(target string, config BalancerConfig) error
  68. // Up informs the Balancer that gRPC has a connection to the server at
  69. // addr. It returns down which is called once the connection to addr gets
  70. // lost or closed.
  71. // TODO: It is not clear how to construct and take advantage of the meaningful error
  72. // parameter for down. Need realistic demands to guide.
  73. Up(addr Address) (down func(error))
  74. // Get gets the address of a server for the RPC corresponding to ctx.
  75. // i) If it returns a connected address, gRPC internals issues the RPC on the
  76. // connection to this address;
  77. // ii) If it returns an address on which the connection is under construction
  78. // (initiated by Notify(...)) but not connected, gRPC internals
  79. // * fails RPC if the RPC is fail-fast and connection is in the TransientFailure or
  80. // Shutdown state;
  81. // or
  82. // * issues RPC on the connection otherwise.
  83. // iii) If it returns an address on which the connection does not exist, gRPC
  84. // internals treats it as an error and will fail the corresponding RPC.
  85. //
  86. // Therefore, the following is the recommended rule when writing a custom Balancer.
  87. // If opts.BlockingWait is true, it should return a connected address or
  88. // block if there is no connected address. It should respect the timeout or
  89. // cancellation of ctx when blocking. If opts.BlockingWait is false (for fail-fast
  90. // RPCs), it should return an address it has notified via Notify(...) immediately
  91. // instead of blocking.
  92. //
  93. // The function returns put which is called once the rpc has completed or failed.
  94. // put can collect and report RPC stats to a remote load balancer.
  95. //
  96. // This function should only return the errors Balancer cannot recover by itself.
  97. // gRPC internals will fail the RPC if an error is returned.
  98. Get(ctx context.Context, opts BalancerGetOptions) (addr Address, put func(), err error)
  99. // Notify returns a channel that is used by gRPC internals to watch the addresses
  100. // gRPC needs to connect. The addresses might be from a name resolver or remote
  101. // load balancer. gRPC internals will compare it with the existing connected
  102. // addresses. If the address Balancer notified is not in the existing connected
  103. // addresses, gRPC starts to connect the address. If an address in the existing
  104. // connected addresses is not in the notification list, the corresponding connection
  105. // is shutdown gracefully. Otherwise, there are no operations to take. Note that
  106. // the Address slice must be the full list of the Addresses which should be connected.
  107. // It is NOT delta.
  108. Notify() <-chan []Address
  109. // Close shuts down the balancer.
  110. Close() error
  111. }
  112. // RoundRobin returns a Balancer that selects addresses round-robin. It uses r to watch
  113. // the name resolution updates and updates the addresses available correspondingly.
  114. //
  115. // Deprecated: please use package balancer/roundrobin.
  116. func RoundRobin(r naming.Resolver) Balancer {
  117. return &roundRobin{r: r}
  118. }
  119. type addrInfo struct {
  120. addr Address
  121. connected bool
  122. }
  123. type roundRobin struct {
  124. r naming.Resolver
  125. w naming.Watcher
  126. addrs []*addrInfo // all the addresses the client should potentially connect
  127. mu sync.Mutex
  128. addrCh chan []Address // the channel to notify gRPC internals the list of addresses the client should connect to.
  129. next int // index of the next address to return for Get()
  130. waitCh chan struct{} // the channel to block when there is no connected address available
  131. done bool // The Balancer is closed.
  132. }
  133. func (rr *roundRobin) watchAddrUpdates() error {
  134. updates, err := rr.w.Next()
  135. if err != nil {
  136. grpclog.Warningf("grpc: the naming watcher stops working due to %v.", err)
  137. return err
  138. }
  139. rr.mu.Lock()
  140. defer rr.mu.Unlock()
  141. for _, update := range updates {
  142. addr := Address{
  143. Addr: update.Addr,
  144. Metadata: update.Metadata,
  145. }
  146. switch update.Op {
  147. case naming.Add:
  148. var exist bool
  149. for _, v := range rr.addrs {
  150. if addr == v.addr {
  151. exist = true
  152. grpclog.Infoln("grpc: The name resolver wanted to add an existing address: ", addr)
  153. break
  154. }
  155. }
  156. if exist {
  157. continue
  158. }
  159. rr.addrs = append(rr.addrs, &addrInfo{addr: addr})
  160. case naming.Delete:
  161. for i, v := range rr.addrs {
  162. if addr == v.addr {
  163. copy(rr.addrs[i:], rr.addrs[i+1:])
  164. rr.addrs = rr.addrs[:len(rr.addrs)-1]
  165. break
  166. }
  167. }
  168. default:
  169. grpclog.Errorln("Unknown update.Op ", update.Op)
  170. }
  171. }
  172. // Make a copy of rr.addrs and write it onto rr.addrCh so that gRPC internals gets notified.
  173. open := make([]Address, len(rr.addrs))
  174. for i, v := range rr.addrs {
  175. open[i] = v.addr
  176. }
  177. if rr.done {
  178. return ErrClientConnClosing
  179. }
  180. select {
  181. case <-rr.addrCh:
  182. default:
  183. }
  184. rr.addrCh <- open
  185. return nil
  186. }
  187. func (rr *roundRobin) Start(target string, config BalancerConfig) error {
  188. rr.mu.Lock()
  189. defer rr.mu.Unlock()
  190. if rr.done {
  191. return ErrClientConnClosing
  192. }
  193. if rr.r == nil {
  194. // If there is no name resolver installed, it is not needed to
  195. // do name resolution. In this case, target is added into rr.addrs
  196. // as the only address available and rr.addrCh stays nil.
  197. rr.addrs = append(rr.addrs, &addrInfo{addr: Address{Addr: target}})
  198. return nil
  199. }
  200. w, err := rr.r.Resolve(target)
  201. if err != nil {
  202. return err
  203. }
  204. rr.w = w
  205. rr.addrCh = make(chan []Address, 1)
  206. go func() {
  207. for {
  208. if err := rr.watchAddrUpdates(); err != nil {
  209. return
  210. }
  211. }
  212. }()
  213. return nil
  214. }
  215. // Up sets the connected state of addr and sends notification if there are pending
  216. // Get() calls.
  217. func (rr *roundRobin) Up(addr Address) func(error) {
  218. rr.mu.Lock()
  219. defer rr.mu.Unlock()
  220. var cnt int
  221. for _, a := range rr.addrs {
  222. if a.addr == addr {
  223. if a.connected {
  224. return nil
  225. }
  226. a.connected = true
  227. }
  228. if a.connected {
  229. cnt++
  230. }
  231. }
  232. // addr is only one which is connected. Notify the Get() callers who are blocking.
  233. if cnt == 1 && rr.waitCh != nil {
  234. close(rr.waitCh)
  235. rr.waitCh = nil
  236. }
  237. return func(err error) {
  238. rr.down(addr, err)
  239. }
  240. }
  241. // down unsets the connected state of addr.
  242. func (rr *roundRobin) down(addr Address, err error) {
  243. rr.mu.Lock()
  244. defer rr.mu.Unlock()
  245. for _, a := range rr.addrs {
  246. if addr == a.addr {
  247. a.connected = false
  248. break
  249. }
  250. }
  251. }
  252. // Get returns the next addr in the rotation.
  253. func (rr *roundRobin) Get(ctx context.Context, opts BalancerGetOptions) (addr Address, put func(), err error) {
  254. var ch chan struct{}
  255. rr.mu.Lock()
  256. if rr.done {
  257. rr.mu.Unlock()
  258. err = ErrClientConnClosing
  259. return
  260. }
  261. if len(rr.addrs) > 0 {
  262. if rr.next >= len(rr.addrs) {
  263. rr.next = 0
  264. }
  265. next := rr.next
  266. for {
  267. a := rr.addrs[next]
  268. next = (next + 1) % len(rr.addrs)
  269. if a.connected {
  270. addr = a.addr
  271. rr.next = next
  272. rr.mu.Unlock()
  273. return
  274. }
  275. if next == rr.next {
  276. // Has iterated all the possible address but none is connected.
  277. break
  278. }
  279. }
  280. }
  281. if !opts.BlockingWait {
  282. if len(rr.addrs) == 0 {
  283. rr.mu.Unlock()
  284. err = status.Errorf(codes.Unavailable, "there is no address available")
  285. return
  286. }
  287. // Returns the next addr on rr.addrs for failfast RPCs.
  288. addr = rr.addrs[rr.next].addr
  289. rr.next++
  290. rr.mu.Unlock()
  291. return
  292. }
  293. // Wait on rr.waitCh for non-failfast RPCs.
  294. if rr.waitCh == nil {
  295. ch = make(chan struct{})
  296. rr.waitCh = ch
  297. } else {
  298. ch = rr.waitCh
  299. }
  300. rr.mu.Unlock()
  301. for {
  302. select {
  303. case <-ctx.Done():
  304. err = ctx.Err()
  305. return
  306. case <-ch:
  307. rr.mu.Lock()
  308. if rr.done {
  309. rr.mu.Unlock()
  310. err = ErrClientConnClosing
  311. return
  312. }
  313. if len(rr.addrs) > 0 {
  314. if rr.next >= len(rr.addrs) {
  315. rr.next = 0
  316. }
  317. next := rr.next
  318. for {
  319. a := rr.addrs[next]
  320. next = (next + 1) % len(rr.addrs)
  321. if a.connected {
  322. addr = a.addr
  323. rr.next = next
  324. rr.mu.Unlock()
  325. return
  326. }
  327. if next == rr.next {
  328. // Has iterated all the possible address but none is connected.
  329. break
  330. }
  331. }
  332. }
  333. // The newly added addr got removed by Down() again.
  334. if rr.waitCh == nil {
  335. ch = make(chan struct{})
  336. rr.waitCh = ch
  337. } else {
  338. ch = rr.waitCh
  339. }
  340. rr.mu.Unlock()
  341. }
  342. }
  343. }
  344. func (rr *roundRobin) Notify() <-chan []Address {
  345. return rr.addrCh
  346. }
  347. func (rr *roundRobin) Close() error {
  348. rr.mu.Lock()
  349. defer rr.mu.Unlock()
  350. if rr.done {
  351. return errBalancerClosed
  352. }
  353. rr.done = true
  354. if rr.w != nil {
  355. rr.w.Close()
  356. }
  357. if rr.waitCh != nil {
  358. close(rr.waitCh)
  359. rr.waitCh = nil
  360. }
  361. if rr.addrCh != nil {
  362. close(rr.addrCh)
  363. }
  364. return nil
  365. }
  366. // pickFirst is used to test multi-addresses in one addrConn in which all addresses share the same addrConn.
  367. // It is a wrapper around roundRobin balancer. The logic of all methods works fine because balancer.Get()
  368. // returns the only address Up by resetTransport().
  369. type pickFirst struct {
  370. *roundRobin
  371. }