mirror of https://github.com/grpc/grpc.git
[xDS LB] xDS pick first support (#33540)
parent
867973b4c0
commit
e0bc8a2c85
28 changed files with 750 additions and 8 deletions
@ -0,0 +1,47 @@ |
||||
/* This file was generated by upbc (the upb compiler) from the input
|
||||
* file: |
||||
* |
||||
* envoy/extensions/load_balancing_policies/pick_first/v3/pick_first.proto |
||||
* |
||||
* Do not edit -- your changes will be discarded when the file is |
||||
* regenerated. */ |
||||
|
||||
#include <stddef.h> |
||||
#include "upb/collections/array_internal.h" |
||||
#include "upb/message/internal.h" |
||||
#include "upb/mini_table/enum_internal.h" |
||||
#include "envoy/extensions/load_balancing_policies/pick_first/v3/pick_first.upb.h" |
||||
#include "udpa/annotations/status.upb.h" |
||||
|
||||
// Must be last.
|
||||
#include "upb/port/def.inc" |
||||
|
||||
static const upb_MiniTableField envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst__fields[1] = { |
||||
{1, 0, 0, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, |
||||
}; |
||||
|
||||
const upb_MiniTable envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_msg_init = { |
||||
NULL, |
||||
&envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst__fields[0], |
||||
8, 1, kUpb_ExtMode_NonExtendable, 1, UPB_FASTTABLE_MASK(8), 0, |
||||
UPB_FASTTABLE_INIT({ |
||||
{0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, |
||||
{0x000000003f000008, &upb_psb1_1bt}, |
||||
}) |
||||
}; |
||||
|
||||
static const upb_MiniTable *messages_layout[1] = { |
||||
&envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_msg_init, |
||||
}; |
||||
|
||||
const upb_MiniTableFile envoy_extensions_load_balancing_policies_pick_first_v3_pick_first_proto_upb_file_layout = { |
||||
messages_layout, |
||||
NULL, |
||||
NULL, |
||||
1, |
||||
0, |
||||
0, |
||||
}; |
||||
|
||||
#include "upb/port/undef.inc" |
||||
|
@ -0,0 +1,93 @@ |
||||
/* This file was generated by upbc (the upb compiler) from the input
|
||||
* file: |
||||
* |
||||
* envoy/extensions/load_balancing_policies/pick_first/v3/pick_first.proto |
||||
* |
||||
* Do not edit -- your changes will be discarded when the file is |
||||
* regenerated. */ |
||||
|
||||
#ifndef ENVOY_EXTENSIONS_LOAD_BALANCING_POLICIES_PICK_FIRST_V3_PICK_FIRST_PROTO_UPB_H_ |
||||
#define ENVOY_EXTENSIONS_LOAD_BALANCING_POLICIES_PICK_FIRST_V3_PICK_FIRST_PROTO_UPB_H_ |
||||
|
||||
#include "upb/collections/array_internal.h" |
||||
#include "upb/collections/map_gencode_util.h" |
||||
#include "upb/message/accessors.h" |
||||
#include "upb/message/internal.h" |
||||
#include "upb/mini_table/enum_internal.h" |
||||
#include "upb/wire/decode.h" |
||||
#include "upb/wire/decode_fast.h" |
||||
#include "upb/wire/encode.h" |
||||
|
||||
// Must be last.
|
||||
#include "upb/port/def.inc" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
typedef struct envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst; |
||||
extern const upb_MiniTable envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_msg_init; |
||||
|
||||
|
||||
|
||||
/* envoy.extensions.load_balancing_policies.pick_first.v3.PickFirst */ |
||||
|
||||
UPB_INLINE envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst* envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_new(upb_Arena* arena) { |
||||
return (envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst*)_upb_Message_New(&envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_msg_init, arena); |
||||
} |
||||
UPB_INLINE envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst* envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_parse(const char* buf, size_t size, upb_Arena* arena) { |
||||
envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst* ret = envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_new(arena); |
||||
if (!ret) return NULL; |
||||
if (upb_Decode(buf, size, ret, &envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { |
||||
return NULL; |
||||
} |
||||
return ret; |
||||
} |
||||
UPB_INLINE envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst* envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_parse_ex(const char* buf, size_t size, |
||||
const upb_ExtensionRegistry* extreg, |
||||
int options, upb_Arena* arena) { |
||||
envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst* ret = envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_new(arena); |
||||
if (!ret) return NULL; |
||||
if (upb_Decode(buf, size, ret, &envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_msg_init, extreg, options, arena) != |
||||
kUpb_DecodeStatus_Ok) { |
||||
return NULL; |
||||
} |
||||
return ret; |
||||
} |
||||
UPB_INLINE char* envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_serialize(const envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst* msg, upb_Arena* arena, size_t* len) { |
||||
char* ptr; |
||||
(void)upb_Encode(msg, &envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_msg_init, 0, arena, &ptr, len); |
||||
return ptr; |
||||
} |
||||
UPB_INLINE char* envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_serialize_ex(const envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst* msg, int options, |
||||
upb_Arena* arena, size_t* len) { |
||||
char* ptr; |
||||
(void)upb_Encode(msg, &envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_msg_init, options, arena, &ptr, len); |
||||
return ptr; |
||||
} |
||||
UPB_INLINE void envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_clear_shuffle_address_list(envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst* msg) { |
||||
const upb_MiniTableField field = {1, 0, 0, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; |
||||
_upb_Message_ClearNonExtensionField(msg, &field); |
||||
} |
||||
UPB_INLINE bool envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_shuffle_address_list(const envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst* msg) { |
||||
bool default_val = false; |
||||
bool ret; |
||||
const upb_MiniTableField field = {1, 0, 0, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; |
||||
_upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret); |
||||
return ret; |
||||
} |
||||
|
||||
UPB_INLINE void envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst_set_shuffle_address_list(envoy_extensions_load_balancing_policies_pick_first_v3_PickFirst *msg, bool value) { |
||||
const upb_MiniTableField field = {1, 0, 0, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; |
||||
_upb_Message_SetNonExtensionField(msg, &field, &value); |
||||
} |
||||
|
||||
extern const upb_MiniTableFile envoy_extensions_load_balancing_policies_pick_first_v3_pick_first_proto_upb_file_layout; |
||||
|
||||
#ifdef __cplusplus |
||||
} /* extern "C" */ |
||||
#endif |
||||
|
||||
#include "upb/port/undef.inc" |
||||
|
||||
#endif /* ENVOY_EXTENSIONS_LOAD_BALANCING_POLICIES_PICK_FIRST_V3_PICK_FIRST_PROTO_UPB_H_ */ |
@ -0,0 +1,29 @@ |
||||
// Copyright 2023 The gRPC Authors |
||||
// |
||||
// Licensed 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. |
||||
|
||||
// Local copy of Envoy xDS proto file, used for testing only. |
||||
|
||||
syntax = "proto3"; |
||||
|
||||
package envoy.extensions.load_balancing_policies.pick_first.v3; |
||||
|
||||
// [#protodoc-title: Round Robin Load Balancing Policy] |
||||
|
||||
// This configuration allows the built-in PICK_FIRST LB policy to be configured |
||||
// via the LB policy extension point. |
||||
message PickFirst { |
||||
// If set to true, instructs the LB policy to shuffle the list of addresses |
||||
// received from the name resolver before attempting to connect to them. |
||||
bool shuffle_address_list = 1; |
||||
} |
@ -0,0 +1,132 @@ |
||||
// Copyright 2017 gRPC authors.
|
||||
//
|
||||
// Licensed 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.
|
||||
//
|
||||
|
||||
#include <unistd.h> |
||||
|
||||
#include <cstddef> |
||||
#include <optional> |
||||
#include <string> |
||||
#include <utility> |
||||
#include <vector> |
||||
|
||||
#include <gmock/gmock.h> |
||||
#include <gtest/gtest.h> |
||||
|
||||
#include "absl/strings/str_cat.h" |
||||
|
||||
#include <grpc/event_engine/endpoint_config.h> |
||||
#include <grpcpp/support/status.h> |
||||
|
||||
#include "src/core/ext/filters/client_channel/backup_poller.h" |
||||
#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h" |
||||
#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" |
||||
#include "src/core/lib/address_utils/sockaddr_utils.h" |
||||
#include "src/core/lib/config/config_vars.h" |
||||
#include "src/core/lib/gprpp/env.h" |
||||
#include "src/proto/grpc/testing/xds/v3/cluster.grpc.pb.h" |
||||
#include "src/proto/grpc/testing/xds/v3/pick_first.pb.h" |
||||
#include "test/core/util/scoped_env_var.h" |
||||
#include "test/core/util/test_config.h" |
||||
#include "test/cpp/end2end/connection_attempt_injector.h" |
||||
#include "test/cpp/end2end/xds/xds_end2end_test_lib.h" |
||||
|
||||
namespace grpc { |
||||
namespace testing { |
||||
namespace { |
||||
|
||||
using ::envoy::extensions::load_balancing_policies::pick_first::v3::PickFirst; |
||||
|
||||
class PickFirstTest : public XdsEnd2endTest { |
||||
protected: |
||||
// Sends RPCs until one of them lands on a backend in the specified range, in
|
||||
// which case it returns the index of that backend. Returns an error status if
|
||||
// any of the RPCs fails.
|
||||
absl::StatusOr<size_t> WaitForAnyBackendHit(size_t start, size_t end) { |
||||
absl::StatusOr<size_t> output; |
||||
SendRpcsUntil(DEBUG_LOCATION, [&](const RpcResult& result) -> bool { |
||||
if (!result.status.ok()) { |
||||
output = absl::Status( |
||||
static_cast<absl::StatusCode>(result.status.error_code()), |
||||
result.status.error_message()); |
||||
return false; |
||||
} |
||||
for (size_t i = start; i < end; ++i) { |
||||
if (backends_[i]->backend_service()->request_count() > 0) { |
||||
backends_[i]->backend_service()->ResetCounters(); |
||||
output = i; |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
}); |
||||
return output; |
||||
} |
||||
}; |
||||
|
||||
// Run both with and without load reporting, just for test coverage.
|
||||
INSTANTIATE_TEST_SUITE_P(XdsTest, PickFirstTest, |
||||
::testing::Values(XdsTestType()), &XdsTestType::Name); |
||||
|
||||
TEST_P(PickFirstTest, PickFirstConfigurationIsPropagated) { |
||||
grpc_core::testing::ScopedExperimentalEnvVar env_var( |
||||
"GRPC_EXPERIMENTAL_PICKFIRST_LB_CONFIG"); |
||||
CreateAndStartBackends(6); |
||||
// Change cluster to use pick_first with shuffle option.
|
||||
auto cluster = default_cluster_; |
||||
PickFirst pick_first; |
||||
pick_first.set_shuffle_address_list(true); |
||||
cluster.mutable_load_balancing_policy() |
||||
->add_policies() |
||||
->mutable_typed_extension_config() |
||||
->mutable_typed_config() |
||||
->PackFrom(pick_first); |
||||
balancer_->ads_service()->SetCdsResource(cluster); |
||||
size_t start_index = 0; |
||||
for (size_t i = 0; i < 100; ++i) { |
||||
// Update EDS resource. This will send a new address list update to the LB
|
||||
// policy.
|
||||
balancer_->ads_service()->SetEdsResource(BuildEdsResource( |
||||
EdsResourceArgs({{"locality0", CreateEndpointsForBackends( |
||||
start_index, start_index + 3)}}))); |
||||
auto result = WaitForAnyBackendHit(start_index, start_index + 3); |
||||
ASSERT_TRUE(result.ok()) << result.status(); |
||||
if (*result != start_index) return; |
||||
// Toggle between backends 0-2 and 3-5
|
||||
start_index = 3 - start_index; |
||||
} |
||||
FAIL() << "did not choose a different backend"; |
||||
} |
||||
} // namespace
|
||||
} // namespace testing
|
||||
} // namespace grpc
|
||||
|
||||
int main(int argc, char** argv) { |
||||
grpc::testing::TestEnvironment env(&argc, argv); |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
// Make the backup poller poll very frequently in order to pick up
|
||||
// updates from all the subchannels's FDs.
|
||||
grpc_core::ConfigVars::Overrides overrides; |
||||
overrides.client_channel_backup_poll_interval_ms = 1; |
||||
grpc_core::ConfigVars::SetOverrides(overrides); |
||||
#if TARGET_OS_IPHONE |
||||
// Workaround Apple CFStream bug
|
||||
grpc_core::SetEnv("grpc_cfstream", "0"); |
||||
#endif |
||||
grpc_init(); |
||||
grpc::testing::ConnectionAttemptInjector::Init(); |
||||
const auto result = RUN_ALL_TESTS(); |
||||
grpc_shutdown(); |
||||
return result; |
||||
} |
Loading…
Reference in new issue