github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/peer/node/grpc_limiters.go (about)

     1  /*
     2  Copyright hechain. 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/hechain20/hechain/common/semaphore"
    14  	"github.com/hechain20/hechain/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  	gatewayConcurrency := config.LimitsConcurrencyGatewayService
    24  
    25  	// Currently concurrency limit is applied to endorser service, deliver service and gateway service.
    26  	// These services are defined in fabric-protos and fabric-protos-go (generated from fabric-protos).
    27  	// Below service names must match their definitions.
    28  	if endorserConcurrency != 0 {
    29  		logger.Infof("concurrency limit for endorser service is %d", endorserConcurrency)
    30  		semaphores["/protos.Endorser"] = semaphore.New(endorserConcurrency)
    31  	}
    32  	if deliverConcurrency != 0 {
    33  		logger.Infof("concurrency limit for deliver service is %d", deliverConcurrency)
    34  		semaphores["/protos.Deliver"] = semaphore.New(deliverConcurrency)
    35  	}
    36  	if gatewayConcurrency != 0 {
    37  		logger.Infof("concurrency limit for gateway service is %d", gatewayConcurrency)
    38  		semaphores["/gateway.Gateway"] = semaphore.New(gatewayConcurrency)
    39  	}
    40  
    41  	return semaphores
    42  }
    43  
    44  func unaryGrpcLimiter(semaphores map[string]semaphore.Semaphore) grpc.UnaryServerInterceptor {
    45  	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    46  		serviceName := getServiceName(info.FullMethod)
    47  		sema, ok := semaphores[serviceName]
    48  		if !ok {
    49  			return handler(ctx, req)
    50  		}
    51  		if !sema.TryAcquire() {
    52  			logger.Errorf("Too many requests for %s, exceeding concurrency limit (%d)", serviceName, cap(sema))
    53  			return nil, errors.Errorf("too many requests for %s, exceeding concurrency limit (%d)", serviceName, cap(sema))
    54  		}
    55  		defer sema.Release()
    56  		return handler(ctx, req)
    57  	}
    58  }
    59  
    60  func streamGrpcLimiter(semaphores map[string]semaphore.Semaphore) grpc.StreamServerInterceptor {
    61  	return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
    62  		serviceName := getServiceName(info.FullMethod)
    63  		sema, ok := semaphores[serviceName]
    64  		if !ok {
    65  			return handler(srv, ss)
    66  		}
    67  		if !sema.TryAcquire() {
    68  			logger.Errorf("Too many requests for %s, exceeding concurrency limit (%d)", serviceName, cap(sema))
    69  			return errors.Errorf("too many requests for %s, exceeding concurrency limit (%d)", serviceName, cap(sema))
    70  		}
    71  		defer sema.Release()
    72  		return handler(srv, ss)
    73  	}
    74  }
    75  
    76  func getServiceName(methodName string) string {
    77  	index := strings.LastIndex(methodName, "/")
    78  	return methodName[:index]
    79  }