github.com/true-sqn/fabric@v2.1.1+incompatible/internal/peer/node/grpc_limiters.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package node
     8  
     9  import (
    10  	"context"
    11  	"strings"
    12  
    13  	"github.com/hyperledger/fabric/common/semaphore"
    14  	"github.com/hyperledger/fabric/core/peer"
    15  	"github.com/pkg/errors"
    16  	"google.golang.org/grpc"
    17  )
    18  
    19  func initGrpcSemaphores(config *peer.Config) map[string]semaphore.Semaphore {
    20  	semaphores := make(map[string]semaphore.Semaphore)
    21  	endorserConcurrency := config.LimitsConcurrencyEndorserService
    22  	deliverConcurrency := config.LimitsConcurrencyDeliverService
    23  
    24  	// Currently concurrency limit is applied to endorser service and deliver service.
    25  	// These services are defined in fabric-protos and fabric-protos-go (generated from fabric-protos).
    26  	// Below service names must match their definitions.
    27  	if endorserConcurrency != 0 {
    28  		logger.Infof("concurrency limit for endorser service is %d", endorserConcurrency)
    29  		semaphores["/protos.Endorser"] = semaphore.New(endorserConcurrency)
    30  	}
    31  	if deliverConcurrency != 0 {
    32  		logger.Infof("concurrency limit for deliver service is %d", deliverConcurrency)
    33  		semaphores["/protos.Deliver"] = semaphore.New(deliverConcurrency)
    34  	}
    35  
    36  	return semaphores
    37  }
    38  
    39  func unaryGrpcLimiter(semaphores map[string]semaphore.Semaphore) grpc.UnaryServerInterceptor {
    40  	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    41  		serviceName := getServiceName(info.FullMethod)
    42  		sema, ok := semaphores[serviceName]
    43  		if !ok {
    44  			return handler(ctx, req)
    45  		}
    46  		if !sema.TryAcquire() {
    47  			logger.Errorf("Too many requests for %s, exceeding concurrency limit (%d)", serviceName, cap(sema))
    48  			return nil, errors.Errorf("too many requests for %s, exceeding concurrency limit (%d)", serviceName, cap(sema))
    49  		}
    50  		defer sema.Release()
    51  		return handler(ctx, req)
    52  	}
    53  }
    54  
    55  func streamGrpcLimiter(semaphores map[string]semaphore.Semaphore) grpc.StreamServerInterceptor {
    56  	return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
    57  		serviceName := getServiceName(info.FullMethod)
    58  		sema, ok := semaphores[serviceName]
    59  		if !ok {
    60  			return handler(srv, ss)
    61  		}
    62  		if !sema.TryAcquire() {
    63  			logger.Errorf("Too many requests for %s, exceeding concurrency limit (%d)", serviceName, cap(sema))
    64  			return errors.Errorf("too many requests for %s, exceeding concurrency limit (%d)", serviceName, cap(sema))
    65  		}
    66  		defer sema.Release()
    67  		return handler(srv, ss)
    68  	}
    69  }
    70  
    71  func getServiceName(methodName string) string {
    72  	index := strings.LastIndex(methodName, "/")
    73  	return methodName[:index]
    74  }