github.com/kubewharf/katalyst-core@v0.5.3/pkg/custom-metric/store/remote/sharding.go (about)

     1  /*
     2  Copyright 2022 The Katalyst Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package remote
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"net/http"
    23  
    24  	"k8s.io/klog/v2"
    25  
    26  	katalystbase "github.com/kubewharf/katalyst-core/cmd/base"
    27  	metricconf "github.com/kubewharf/katalyst-core/pkg/config/metric"
    28  	"github.com/kubewharf/katalyst-core/pkg/custom-metric/store/local"
    29  	sd "github.com/kubewharf/katalyst-core/pkg/util/service-discovery"
    30  )
    31  
    32  const httpMetricURL = "http://%v"
    33  
    34  // ShardingController is responsible to separate the metric store into
    35  // several sharding pieces to tolerant single node failure, as well as
    36  // avoiding memory pressure in single node.
    37  //
    38  // todo: currently, it not really a valid
    39  type ShardingController struct {
    40  	ctx context.Context
    41  
    42  	sdManager  sd.ServiceDiscoveryManager
    43  	totalCount int
    44  }
    45  
    46  func NewShardingController(ctx context.Context, baseCtx *katalystbase.GenericContext,
    47  	storeConf *metricconf.StoreConfiguration,
    48  ) (*ShardingController, error) {
    49  	sdManager, err := sd.GetSDManager(ctx, baseCtx, storeConf.ServiceDiscoveryConf)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	// since collector will define its own pod/node label selectors, so we will construct informer separately
    55  	s := &ShardingController{
    56  		ctx:        ctx,
    57  		totalCount: storeConf.StoreServerReplicaTotal,
    58  		sdManager:  sdManager,
    59  	}
    60  
    61  	return s, nil
    62  }
    63  
    64  func (s *ShardingController) Start() error {
    65  	return s.sdManager.Run()
    66  }
    67  
    68  func (s *ShardingController) Stop() error {
    69  	return nil
    70  }
    71  
    72  // GetRWCount returns the quorum read/write counts
    73  func (s *ShardingController) GetRWCount() (int, int) {
    74  	r := (s.totalCount + 1) / 2
    75  	w := s.totalCount - r + 1
    76  	return r, w
    77  }
    78  
    79  // GetRequests returns the pre-generated http requests
    80  func (s *ShardingController) GetRequests(ctx context.Context, path string) ([]*http.Request, error) {
    81  	endpoints, err := s.sdManager.GetEndpoints()
    82  	if err != nil {
    83  		return nil, fmt.Errorf("failed get endpoints from serviceDiscoveryManager: %v", err)
    84  	}
    85  	klog.V(6).Infof("%v current endpoints is %v", s.sdManager.Name(), endpoints)
    86  
    87  	requests := make([]*http.Request, 0, len(endpoints))
    88  	for _, endpoint := range endpoints {
    89  		req, err := s.generateRequest(ctx, endpoint, path)
    90  		if err != nil {
    91  			klog.Errorf("failed to generate request err: %v", err)
    92  			continue
    93  		}
    94  		requests = append(requests, req)
    95  	}
    96  
    97  	return requests, nil
    98  }
    99  
   100  func (s *ShardingController) generateRequest(ctx context.Context, endpoint, path string) (*http.Request, error) {
   101  	url := fmt.Sprintf(httpMetricURL, endpoint+path)
   102  
   103  	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
   104  	if err != nil {
   105  		return nil, fmt.Errorf("new http request for %v err: %v", url, err)
   106  	}
   107  
   108  	req.Header.Add("Accept-Encoding", "gzip")
   109  	req.Header.Set("User-Agent", "remote-store")
   110  
   111  	switch path {
   112  	case local.ServingGetPath:
   113  		req.Method = "GET"
   114  	case local.ServingSetPath:
   115  		req.Method = "POST"
   116  	case local.ServingListPath:
   117  		req.Method = "GET"
   118  	}
   119  
   120  	return req, nil
   121  }