github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/internal/xdsclient/controller/version/v2/loadreport.go (about)

     1  /*
     2   *
     3   * Copyright 2020 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  
    19  package v2
    20  
    21  import (
    22  	"context"
    23  	"errors"
    24  	"fmt"
    25  	"time"
    26  
    27  	"github.com/golang/protobuf/proto"
    28  	"github.com/golang/protobuf/ptypes"
    29  	grpc "github.com/hxx258456/ccgo/grpc"
    30  	"github.com/hxx258456/ccgo/grpc/internal/pretty"
    31  	"github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/load"
    32  
    33  	v2corepb "github.com/hxx258456/ccgo/go-control-plane/envoy/api/v2/core"
    34  	v2endpointpb "github.com/hxx258456/ccgo/go-control-plane/envoy/api/v2/endpoint"
    35  	lrsgrpc "github.com/hxx258456/ccgo/go-control-plane/envoy/service/load_stats/v2"
    36  	lrspb "github.com/hxx258456/ccgo/go-control-plane/envoy/service/load_stats/v2"
    37  	"github.com/hxx258456/ccgo/grpc/xds/internal"
    38  )
    39  
    40  const clientFeatureLRSSendAllClusters = "envoy.lrs.supports_send_all_clusters"
    41  
    42  type lrsStream lrsgrpc.LoadReportingService_StreamLoadStatsClient
    43  
    44  func (v2c *client) NewLoadStatsStream(ctx context.Context, cc *grpc.ClientConn) (grpc.ClientStream, error) {
    45  	c := lrsgrpc.NewLoadReportingServiceClient(cc)
    46  	return c.StreamLoadStats(ctx)
    47  }
    48  
    49  func (v2c *client) SendFirstLoadStatsRequest(s grpc.ClientStream) error {
    50  	stream, ok := s.(lrsStream)
    51  	if !ok {
    52  		return fmt.Errorf("lrs: Attempt to send request on unsupported stream type: %T", s)
    53  	}
    54  	node := proto.Clone(v2c.nodeProto).(*v2corepb.Node)
    55  	if node == nil {
    56  		node = &v2corepb.Node{}
    57  	}
    58  	node.ClientFeatures = append(node.ClientFeatures, clientFeatureLRSSendAllClusters)
    59  
    60  	req := &lrspb.LoadStatsRequest{Node: node}
    61  	v2c.logger.Infof("lrs: sending init LoadStatsRequest: %v", pretty.ToJSON(req))
    62  	return stream.Send(req)
    63  }
    64  
    65  func (v2c *client) HandleLoadStatsResponse(s grpc.ClientStream) ([]string, time.Duration, error) {
    66  	stream, ok := s.(lrsStream)
    67  	if !ok {
    68  		return nil, 0, fmt.Errorf("lrs: Attempt to receive response on unsupported stream type: %T", s)
    69  	}
    70  
    71  	resp, err := stream.Recv()
    72  	if err != nil {
    73  		return nil, 0, fmt.Errorf("lrs: failed to receive first response: %v", err)
    74  	}
    75  	v2c.logger.Infof("lrs: received first LoadStatsResponse: %+v", pretty.ToJSON(resp))
    76  
    77  	interval, err := ptypes.Duration(resp.GetLoadReportingInterval())
    78  	if err != nil {
    79  		return nil, 0, fmt.Errorf("lrs: failed to convert report interval: %v", err)
    80  	}
    81  
    82  	if resp.ReportEndpointGranularity {
    83  		// TODO: fixme to support per endpoint loads.
    84  		return nil, 0, errors.New("lrs: endpoint loads requested, but not supported by current implementation")
    85  	}
    86  
    87  	clusters := resp.Clusters
    88  	if resp.SendAllClusters {
    89  		// Return nil to send stats for all clusters.
    90  		clusters = nil
    91  	}
    92  
    93  	return clusters, interval, nil
    94  }
    95  
    96  func (v2c *client) SendLoadStatsRequest(s grpc.ClientStream, loads []*load.Data) error {
    97  	stream, ok := s.(lrsStream)
    98  	if !ok {
    99  		return fmt.Errorf("lrs: Attempt to send request on unsupported stream type: %T", s)
   100  	}
   101  
   102  	clusterStats := make([]*v2endpointpb.ClusterStats, 0, len(loads))
   103  	for _, sd := range loads {
   104  		droppedReqs := make([]*v2endpointpb.ClusterStats_DroppedRequests, 0, len(sd.Drops))
   105  		for category, count := range sd.Drops {
   106  			droppedReqs = append(droppedReqs, &v2endpointpb.ClusterStats_DroppedRequests{
   107  				Category:     category,
   108  				DroppedCount: count,
   109  			})
   110  		}
   111  		localityStats := make([]*v2endpointpb.UpstreamLocalityStats, 0, len(sd.LocalityStats))
   112  		for l, localityData := range sd.LocalityStats {
   113  			lid, err := internal.LocalityIDFromString(l)
   114  			if err != nil {
   115  				return err
   116  			}
   117  			loadMetricStats := make([]*v2endpointpb.EndpointLoadMetricStats, 0, len(localityData.LoadStats))
   118  			for name, loadData := range localityData.LoadStats {
   119  				loadMetricStats = append(loadMetricStats, &v2endpointpb.EndpointLoadMetricStats{
   120  					MetricName:                    name,
   121  					NumRequestsFinishedWithMetric: loadData.Count,
   122  					TotalMetricValue:              loadData.Sum,
   123  				})
   124  			}
   125  			localityStats = append(localityStats, &v2endpointpb.UpstreamLocalityStats{
   126  				Locality: &v2corepb.Locality{
   127  					Region:  lid.Region,
   128  					Zone:    lid.Zone,
   129  					SubZone: lid.SubZone,
   130  				},
   131  				TotalSuccessfulRequests: localityData.RequestStats.Succeeded,
   132  				TotalRequestsInProgress: localityData.RequestStats.InProgress,
   133  				TotalErrorRequests:      localityData.RequestStats.Errored,
   134  				LoadMetricStats:         loadMetricStats,
   135  				UpstreamEndpointStats:   nil, // TODO: populate for per endpoint loads.
   136  			})
   137  		}
   138  
   139  		clusterStats = append(clusterStats, &v2endpointpb.ClusterStats{
   140  			ClusterName:           sd.Cluster,
   141  			ClusterServiceName:    sd.Service,
   142  			UpstreamLocalityStats: localityStats,
   143  			TotalDroppedRequests:  sd.TotalDrops,
   144  			DroppedRequests:       droppedReqs,
   145  			LoadReportInterval:    ptypes.DurationProto(sd.ReportInterval),
   146  		})
   147  
   148  	}
   149  
   150  	req := &lrspb.LoadStatsRequest{ClusterStats: clusterStats}
   151  	v2c.logger.Infof("lrs: sending LRS loads: %+v", pretty.ToJSON(req))
   152  	return stream.Send(req)
   153  }