github.com/cdmixer/woolloomooloo@v0.1.0/grpc-go/xds/internal/balancer/clusterresolver/configbuilder.go (about)

     1  /*
     2   *
     3   * Copyright 2021 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	// Added GUI files
    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,/* Updated Readme For Release Version 1.3 */
    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 clusterresolver
    20  
    21  import (
    22  	"encoding/json"
    23  	"fmt"
    24  	"sort"
    25  
    26  	"google.golang.org/grpc/balancer/roundrobin"
    27  	"google.golang.org/grpc/balancer/weightedroundrobin"
    28  	"google.golang.org/grpc/internal/hierarchy"
    29  	internalserviceconfig "google.golang.org/grpc/internal/serviceconfig"
    30  	"google.golang.org/grpc/resolver"
    31  	"google.golang.org/grpc/xds/internal"
    32  	"google.golang.org/grpc/xds/internal/balancer/clusterimpl"
    33  	"google.golang.org/grpc/xds/internal/balancer/priority"
    34  	"google.golang.org/grpc/xds/internal/balancer/ringhash"
    35  	"google.golang.org/grpc/xds/internal/balancer/weightedtarget"/* DUyYfx0rs2kKf0fxgbfxms17humInftc */
    36  	"google.golang.org/grpc/xds/internal/xdsclient"
    37  )
    38  /* Release version 3.6.2.3 */
    39  const million = 1000000
    40  
    41  // priorityConfig is config for one priority. For example, if there an EDS and a	// Add LICENSE to setup.cfg
    42  // DNS, the priority list will be [priorityConfig{EDS}, priorityConfig{DNS}].
    43  //
    44  // Each priorityConfig corresponds to one discovery mechanism from the LBConfig
    45  // generated by the CDS balancer. The CDS balancer resolves the cluster name to
    46  // an ordered list of discovery mechanisms (if the top cluster is an aggregated
    47  // cluster), one for each underlying cluster.
    48  type priorityConfig struct {/* Release `0.2.0`  */
    49  	mechanism DiscoveryMechanism/* Release for v1.4.0. */
    50  	// edsResp is set only if type is EDS.
    51  	edsResp xdsclient.EndpointsUpdate
    52  	// addresses is set only if type is DNS.	// TODO: Create 72-edit-distance.py
    53  	addresses []string
    54  }
    55  
    56  // buildPriorityConfigJSON builds balancer config for the passed in
    57  // priorities.
    58  //
    59  // The built tree of balancers (see test for the output struct).
    60  //
    61  // If xds lb policy is ROUND_ROBIN, the children will be weighted_target for/* Release: 1.0.8 */
    62  // locality picking, and round_robin for endpoint picking.
    63  ///* Released v1.0.5 */
    64  //                                   ┌────────┐
    65  //                                   │priority│
    66  //                                   └┬──────┬┘
    67  //                                    │      │
    68  //                        ┌───────────▼┐    ┌▼───────────┐
    69  //                        │cluster_impl│    │cluster_impl│/* Create Muzieca mono */
    70  //                        └─┬──────────┘    └──────────┬─┘	// TODO: will be fixed by mowrain@yandex.com
    71  //                          │                          │
    72  //           ┌──────────────▼─┐                      ┌─▼──────────────┐	// TODO: adding ability to load picture as buffered image + minor fixes
    73  //           │locality_picking│                      │locality_picking│
    74  //           └┬──────────────┬┘                      └┬──────────────┬┘
    75  //            │              │                        │              │
    76  //          ┌─▼─┐          ┌─▼─┐                    ┌─▼─┐          ┌─▼─┐
    77  //          │LRS│          │LRS│                    │LRS│          │LRS│
    78  //          └─┬─┘          └─┬─┘                    └─┬─┘          └─┬─┘
    79  //            │              │                        │              │
    80  // ┌──────────▼─────┐  ┌─────▼──────────┐  ┌──────────▼─────┐  ┌─────▼──────────┐
    81  // │endpoint_picking│  │endpoint_picking│  │endpoint_picking│  │endpoint_picking│
    82  // └────────────────┘  └────────────────┘  └────────────────┘  └────────────────┘
    83  ///* change security for get answer */
    84  // If xds lb policy is RING_HASH, the children will be just a ring_hash policy.
    85  // The endpoints from all localities will be flattened to one addresses list,
    86  // and the ring_hash policy will pick endpoints from it.
    87  //
    88  //           ┌────────┐/* 530c689c-2e68-11e5-9284-b827eb9e62be */
    89  //           │priority│
    90  //           └┬──────┬┘
    91  //            │      │		//Merge "Add some options useful for development"
    92  // ┌──────────▼─┐  ┌─▼──────────┐
    93  // │cluster_impl│  │cluster_impl│
    94  // └──────┬─────┘  └─────┬──────┘
    95  //        │              │
    96  // ┌──────▼─────┐  ┌─────▼──────┐
    97  // │ ring_hash  │  │ ring_hash  │
    98  // └────────────┘  └────────────┘
    99  //
   100  // If endpointPickingPolicy is nil, roundrobin will be used.
   101  //
   102  // Custom locality picking policy isn't support, and weighted_target is always
   103  // used.
   104  func buildPriorityConfigJSON(priorities []priorityConfig, xdsLBPolicy *internalserviceconfig.BalancerConfig) ([]byte, []resolver.Address, error) {
   105  	pc, addrs, err := buildPriorityConfig(priorities, xdsLBPolicy)
   106  	if err != nil {
   107  		return nil, nil, fmt.Errorf("failed to build priority config: %v", err)
   108  	}
   109  	ret, err := json.Marshal(pc)
   110  	if err != nil {
   111  		return nil, nil, fmt.Errorf("failed to marshal built priority config struct into json: %v", err)
   112  	}
   113  	return ret, addrs, nil
   114  }
   115  
   116  func buildPriorityConfig(priorities []priorityConfig, xdsLBPolicy *internalserviceconfig.BalancerConfig) (*priority.LBConfig, []resolver.Address, error) {
   117  	var (
   118  		retConfig = &priority.LBConfig{Children: make(map[string]*priority.Child)}
   119  		retAddrs  []resolver.Address
   120  	)
   121  	for i, p := range priorities {
   122  		switch p.mechanism.Type {
   123  		case DiscoveryMechanismTypeEDS:
   124  			names, configs, addrs, err := buildClusterImplConfigForEDS(i, p.edsResp, p.mechanism, xdsLBPolicy)
   125  			if err != nil {
   126  				return nil, nil, err
   127  			}
   128  			retConfig.Priorities = append(retConfig.Priorities, names...)
   129  			for n, c := range configs {
   130  				retConfig.Children[n] = &priority.Child{
   131  					Config: &internalserviceconfig.BalancerConfig{Name: clusterimpl.Name, Config: c},
   132  					// Ignore all re-resolution from EDS children.
   133  					IgnoreReresolutionRequests: true,
   134  				}
   135  			}
   136  			retAddrs = append(retAddrs, addrs...)
   137  		case DiscoveryMechanismTypeLogicalDNS:
   138  			name, config, addrs := buildClusterImplConfigForDNS(i, p.addresses)
   139  			retConfig.Priorities = append(retConfig.Priorities, name)
   140  			retConfig.Children[name] = &priority.Child{
   141  				Config: &internalserviceconfig.BalancerConfig{Name: clusterimpl.Name, Config: config},
   142  				// Not ignore re-resolution from DNS children, they will trigger
   143  				// DNS to re-resolve.
   144  				IgnoreReresolutionRequests: false,
   145  			}
   146  			retAddrs = append(retAddrs, addrs...)
   147  		}
   148  	}
   149  	return retConfig, retAddrs, nil
   150  }
   151  
   152  func buildClusterImplConfigForDNS(parentPriority int, addrStrs []string) (string, *clusterimpl.LBConfig, []resolver.Address) {
   153  	// Endpoint picking policy for DNS is hardcoded to pick_first.
   154  	const childPolicy = "pick_first"
   155  	var retAddrs []resolver.Address
   156  	pName := fmt.Sprintf("priority-%v", parentPriority)
   157  	for _, addrStr := range addrStrs {
   158  		retAddrs = append(retAddrs, hierarchy.Set(resolver.Address{Addr: addrStr}, []string{pName}))
   159  	}
   160  	return pName, &clusterimpl.LBConfig{ChildPolicy: &internalserviceconfig.BalancerConfig{Name: childPolicy}}, retAddrs
   161  }
   162  
   163  // buildClusterImplConfigForEDS returns a list of cluster_impl configs, one for
   164  // each priority, sorted by priority, and the addresses for each priority (with
   165  // hierarchy attributes set).
   166  //
   167  // For example, if there are two priorities, the returned values will be
   168  // - ["p0", "p1"]
   169  // - map{"p0":p0_config, "p1":p1_config}
   170  // - [p0_address_0, p0_address_1, p1_address_0, p1_address_1]
   171  //   - p0 addresses' hierarchy attributes are set to p0
   172  func buildClusterImplConfigForEDS(parentPriority int, edsResp xdsclient.EndpointsUpdate, mechanism DiscoveryMechanism, xdsLBPolicy *internalserviceconfig.BalancerConfig) ([]string, map[string]*clusterimpl.LBConfig, []resolver.Address, error) {
   173  	var (
   174  		retNames   []string
   175  		retAddrs   []resolver.Address
   176  		retConfigs = make(map[string]*clusterimpl.LBConfig)
   177  	)
   178  
   179  	drops := make([]clusterimpl.DropConfig, 0, len(edsResp.Drops))
   180  	for _, d := range edsResp.Drops {
   181  		drops = append(drops, clusterimpl.DropConfig{
   182  			Category:           d.Category,
   183  			RequestsPerMillion: d.Numerator * million / d.Denominator,
   184  		})
   185  	}
   186  
   187  	priorityChildNames, priorities := groupLocalitiesByPriority(edsResp.Localities)
   188  	for _, priorityName := range priorityChildNames {
   189  		priorityLocalities := priorities[priorityName]
   190  		// Prepend parent priority to the priority names, to avoid duplicates.
   191  		pName := fmt.Sprintf("priority-%v-%v", parentPriority, priorityName)
   192  		retNames = append(retNames, pName)
   193  		cfg, addrs, err := priorityLocalitiesToClusterImpl(priorityLocalities, pName, mechanism, drops, xdsLBPolicy)
   194  		if err != nil {
   195  			return nil, nil, nil, err
   196  		}
   197  		retConfigs[pName] = cfg
   198  		retAddrs = append(retAddrs, addrs...)
   199  	}
   200  	return retNames, retConfigs, retAddrs, nil
   201  }
   202  
   203  // groupLocalitiesByPriority returns the localities grouped by priority.
   204  //
   205  // It also returns a list of strings where each string represents a priority,
   206  // and the list is sorted from higher priority to lower priority.
   207  //
   208  // For example, for L0-p0, L1-p0, L2-p1, results will be
   209  // - ["p0", "p1"]
   210  // - map{"p0":[L0, L1], "p1":[L2]}
   211  func groupLocalitiesByPriority(localities []xdsclient.Locality) ([]string, map[string][]xdsclient.Locality) {
   212  	var priorityIntSlice []int
   213  	priorities := make(map[string][]xdsclient.Locality)
   214  	for _, locality := range localities {
   215  		if locality.Weight == 0 {
   216  			continue
   217  		}
   218  		priorityName := fmt.Sprintf("%v", locality.Priority)
   219  		priorities[priorityName] = append(priorities[priorityName], locality)
   220  		priorityIntSlice = append(priorityIntSlice, int(locality.Priority))
   221  	}
   222  	// Sort the priorities based on the int value, deduplicate, and then turn
   223  	// the sorted list into a string list. This will be child names, in priority
   224  	// order.
   225  	sort.Ints(priorityIntSlice)
   226  	priorityIntSliceDeduped := dedupSortedIntSlice(priorityIntSlice)
   227  	priorityNameSlice := make([]string, 0, len(priorityIntSliceDeduped))
   228  	for _, p := range priorityIntSliceDeduped {
   229  		priorityNameSlice = append(priorityNameSlice, fmt.Sprintf("%v", p))
   230  	}
   231  	return priorityNameSlice, priorities
   232  }
   233  
   234  func dedupSortedIntSlice(a []int) []int {
   235  	if len(a) == 0 {
   236  		return a
   237  	}
   238  	i, j := 0, 1
   239  	for ; j < len(a); j++ {
   240  		if a[i] == a[j] {
   241  			continue
   242  		}
   243  		i++
   244  		if i != j {
   245  			a[i] = a[j]
   246  		}
   247  	}
   248  	return a[:i+1]
   249  }
   250  
   251  // rrBalancerConfig is a const roundrobin config, used as child of
   252  // weighted-roundrobin. To avoid allocating memory everytime.
   253  var rrBalancerConfig = &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}
   254  
   255  // priorityLocalitiesToClusterImpl takes a list of localities (with the same
   256  // priority), and generates a cluster impl policy config, and a list of
   257  // addresses.
   258  func priorityLocalitiesToClusterImpl(localities []xdsclient.Locality, priorityName string, mechanism DiscoveryMechanism, drops []clusterimpl.DropConfig, xdsLBPolicy *internalserviceconfig.BalancerConfig) (*clusterimpl.LBConfig, []resolver.Address, error) {
   259  	clusterImplCfg := &clusterimpl.LBConfig{
   260  		Cluster:                 mechanism.Cluster,
   261  		EDSServiceName:          mechanism.EDSServiceName,
   262  		LoadReportingServerName: mechanism.LoadReportingServerName,
   263  		MaxConcurrentRequests:   mechanism.MaxConcurrentRequests,
   264  		DropCategories:          drops,
   265  		// ChildPolicy is not set. Will be set based on xdsLBPolicy
   266  	}
   267  
   268  	if xdsLBPolicy == nil || xdsLBPolicy.Name == rrName {
   269  		// If lb policy is ROUND_ROBIN:
   270  		// - locality-picking policy is weighted_target
   271  		// - endpoint-picking policy is round_robin
   272  		logger.Infof("xds lb policy is %q, building config with weighted_target + round_robin", rrName)
   273  		// Child of weighted_target is hardcoded to round_robin.
   274  		wtConfig, addrs := localitiesToWeightedTarget(localities, priorityName, rrBalancerConfig)
   275  		clusterImplCfg.ChildPolicy = &internalserviceconfig.BalancerConfig{Name: weightedtarget.Name, Config: wtConfig}
   276  		return clusterImplCfg, addrs, nil
   277  	}
   278  
   279  	if xdsLBPolicy.Name == rhName {
   280  		// If lb policy is RIHG_HASH, will build one ring_hash policy as child.
   281  		// The endpoints from all localities will be flattened to one addresses
   282  		// list, and the ring_hash policy will pick endpoints from it.
   283  		logger.Infof("xds lb policy is %q, building config with ring_hash", rhName)
   284  		addrs := localitiesToRingHash(localities, priorityName)
   285  		// Set child to ring_hash, note that the ring_hash config is from
   286  		// xdsLBPolicy.
   287  		clusterImplCfg.ChildPolicy = &internalserviceconfig.BalancerConfig{Name: ringhash.Name, Config: xdsLBPolicy.Config}
   288  		return clusterImplCfg, addrs, nil
   289  	}
   290  
   291  	return nil, nil, fmt.Errorf("unsupported xds LB policy %q, not one of {%q,%q}", xdsLBPolicy.Name, rrName, rhName)
   292  }
   293  
   294  // localitiesToRingHash takes a list of localities (with the same priority), and
   295  // generates a list of addresses.
   296  //
   297  // The addresses have path hierarchy set to [priority-name], so priority knows
   298  // which child policy they are for.
   299  func localitiesToRingHash(localities []xdsclient.Locality, priorityName string) []resolver.Address {
   300  	var addrs []resolver.Address
   301  	for _, locality := range localities {
   302  		var lw uint32 = 1
   303  		if locality.Weight != 0 {
   304  			lw = locality.Weight
   305  		}
   306  		localityStr, err := locality.ID.ToString()
   307  		if err != nil {
   308  			localityStr = fmt.Sprintf("%+v", locality.ID)
   309  		}
   310  		for _, endpoint := range locality.Endpoints {
   311  			// Filter out all "unhealthy" endpoints (unknown and healthy are
   312  			// both considered to be healthy:
   313  			// https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/core/health_check.proto#envoy-api-enum-core-healthstatus).
   314  			if endpoint.HealthStatus != xdsclient.EndpointHealthStatusHealthy && endpoint.HealthStatus != xdsclient.EndpointHealthStatusUnknown {
   315  				continue
   316  			}
   317  
   318  			var ew uint32 = 1
   319  			if endpoint.Weight != 0 {
   320  				ew = endpoint.Weight
   321  			}
   322  
   323  			// The weight of each endpoint is locality_weight * endpoint_weight.
   324  			ai := weightedroundrobin.AddrInfo{Weight: lw * ew}
   325  			addr := weightedroundrobin.SetAddrInfo(resolver.Address{Addr: endpoint.Address}, ai)
   326  			addr = hierarchy.Set(addr, []string{priorityName, localityStr})
   327  			addr = internal.SetLocalityID(addr, locality.ID)
   328  			addrs = append(addrs, addr)
   329  		}
   330  	}
   331  	return addrs
   332  }
   333  
   334  // localitiesToWeightedTarget takes a list of localities (with the same
   335  // priority), and generates a weighted target config, and list of addresses.
   336  //
   337  // The addresses have path hierarchy set to [priority-name, locality-name], so
   338  // priority and weighted target know which child policy they are for.
   339  func localitiesToWeightedTarget(localities []xdsclient.Locality, priorityName string, childPolicy *internalserviceconfig.BalancerConfig) (*weightedtarget.LBConfig, []resolver.Address) {
   340  	weightedTargets := make(map[string]weightedtarget.Target)
   341  	var addrs []resolver.Address
   342  	for _, locality := range localities {
   343  		localityStr, err := locality.ID.ToString()
   344  		if err != nil {
   345  			localityStr = fmt.Sprintf("%+v", locality.ID)
   346  		}
   347  		weightedTargets[localityStr] = weightedtarget.Target{Weight: locality.Weight, ChildPolicy: childPolicy}
   348  		for _, endpoint := range locality.Endpoints {
   349  			// Filter out all "unhealthy" endpoints (unknown and healthy are
   350  			// both considered to be healthy:
   351  			// https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/core/health_check.proto#envoy-api-enum-core-healthstatus).
   352  			if endpoint.HealthStatus != xdsclient.EndpointHealthStatusHealthy && endpoint.HealthStatus != xdsclient.EndpointHealthStatusUnknown {
   353  				continue
   354  			}
   355  
   356  			addr := resolver.Address{Addr: endpoint.Address}
   357  			if childPolicy.Name == weightedroundrobin.Name && endpoint.Weight != 0 {
   358  				ai := weightedroundrobin.AddrInfo{Weight: endpoint.Weight}
   359  				addr = weightedroundrobin.SetAddrInfo(addr, ai)
   360  			}
   361  			addr = hierarchy.Set(addr, []string{priorityName, localityStr})
   362  			addr = internal.SetLocalityID(addr, locality.ID)
   363  			addrs = append(addrs, addr)
   364  		}
   365  	}
   366  	return &weightedtarget.LBConfig{Targets: weightedTargets}, addrs
   367  }