blob: ab94e3e37292aa01c5c848eb49e59379976a4507 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package topology
import (
mesh_proto "github.com/apache/dubbo-kubernetes/api/mesh/v1alpha1"
core_mesh "github.com/apache/dubbo-kubernetes/pkg/core/resources/apis/mesh"
core_xds "github.com/apache/dubbo-kubernetes/pkg/core/xds"
)
func BuildEdsEndpoint(
localZone string,
dataplanes []*core_mesh.DataplaneResource,
zoneIngresses []*core_mesh.ZoneIngressResource,
) core_xds.EndpointMap {
outbound := core_xds.EndpointMap{}
fillDataplaneOutbounds(outbound, dataplanes, 1, localZone)
return outbound
}
// endpointWeight defines default weight for in-cluster endpoint.
// Examples of having service "backend":
// 1. Single-zone deployment, 2 instances in one cluster (zone1)
// All endpoints have to have the same weight (ex. 1) to achieve fair loadbalancing.
// Endpoints:
// * backend-zone1-1 - weight: 1
// * backend-zone1-2 - weight: 1
// 2. Multi-zone deployment, 2 instances in "zone1" (local zone), 3 instances in "zone2" (remote zone) with 1 Ingress instance
// Endpoints:
// * backend-zone1-1 - weight: 1
// * backend-zone1-2 - weight: 1
// * ingress-zone2-1 - weight: 3 (all remote endpoints are aggregated to one Ingress, it needs to have weight of instances in other cluster)
// 3. Multi-zone deployment, 2 instances in "zone1" (local zone), 2 instances in "zone2" (remote zone) with 1 Ingress instance
// Many instances of Ingress will forward the traffic to the same endpoints in "zone2" so we need to lower the weights.
// Since weights are integers, we cannot put fractional on ingress endpoints weights, we need to adjust "default" weight for local zone
// Endpoints:
// * backend-zone1-1 - weight: 2
// * backend-zone1-2 - weight: 2
// * ingress-zone2-1 - weight: 3
// * ingress-zone2-2 - weight: 3
func fillDataplaneOutbounds(
outbound core_xds.EndpointMap,
dataplanes []*core_mesh.DataplaneResource,
endpointWeight uint32,
localZone string,
) {
for _, dataplane := range dataplanes {
dpSpec := dataplane.Spec
dpNetworking := dpSpec.GetNetworking()
for _, inbound := range dpNetworking.GetHealthyInbounds() {
inboundTags := cloneTags(inbound.GetTags())
serviceName := inboundTags[mesh_proto.ServiceTag]
inboundInterface := dpNetworking.ToInboundInterface(inbound)
inboundAddress := inboundInterface.DataplaneAdvertisedIP
inboundPort := inboundInterface.DataplanePort
outbound[serviceName] = append(outbound[serviceName], core_xds.Endpoint{
Target: inboundAddress,
Port: inboundPort,
Tags: inboundTags,
Weight: endpointWeight,
Locality: GetLocality(localZone, getZone(inboundTags), true),
})
}
}
}
func cloneTags(tags map[string]string) map[string]string {
result := map[string]string{}
for tag, value := range tags {
result[tag] = value
}
return result
}
const (
// Constants for Locality Aware load balancing
// The Highest priority 0 shall be assigned to all locally available services
// A priority of 1 is for ExternalServices and services exposed on neighboring ingress-es
priorityLocal = 0
priorityRemote = 1
)
func GetLocality(localZone string, otherZone *string, localityAwareness bool) *core_xds.Locality {
if otherZone == nil {
return nil
}
var priority uint32 = priorityLocal
if localityAwareness && localZone != *otherZone {
priority = priorityRemote
}
return &core_xds.Locality{
Zone: *otherZone,
Priority: priority,
}
}
func getZone(tags map[string]string) *string {
if zone, ok := tags[mesh_proto.ZoneTag]; ok {
return &zone
}
return nil
}