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 }