-
Notifications
You must be signed in to change notification settings - Fork 5.3k
matching: introduce consistent hashing matcher #14875
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
cc9c79c
b875edf
180ef64
7fb2b5f
4a91bb5
ab01c61
5b8eb7b
6e1f7a1
09bef8e
1103ce1
00ec10b
d328029
caa6629
81a21eb
558f469
aa4dd9b
1ebce21
61a13bd
9794836
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| # DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. | ||
|
|
||
| load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") | ||
|
|
||
| licenses(["notice"]) # Apache 2 | ||
|
|
||
| api_proto_package( | ||
| deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"], | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| syntax = "proto3"; | ||
|
|
||
| package envoy.extensions.matching.input_matchers.consistent_hashing.v3; | ||
|
|
||
| import "udpa/annotations/migrate.proto"; | ||
| import "udpa/annotations/status.proto"; | ||
| import "udpa/annotations/versioning.proto"; | ||
| import "validate/validate.proto"; | ||
|
|
||
| option java_package = "io.envoyproxy.envoy.extensions.matching.input_matchers.consistent_hashing.v3"; | ||
| option java_outer_classname = "ConsistentHashingProto"; | ||
| option java_multiple_files = true; | ||
| option (udpa.annotations.file_status).package_version_status = ACTIVE; | ||
|
|
||
| // [#protodoc-title: Consistent Hashing Matcher] | ||
| // [#extension: envoy.matching.input_matchers.consistent_hashing] | ||
|
|
||
| // The consistent hashing matchers computes a consistent hash from the input and matches if the resulting hash | ||
| // is within the configured threshold. | ||
| // More specifically, this matcher evaluates to true if hash(input, seed) % modulo >= threshold. | ||
| // Note that the consistency of the match result relies on the internal hash function (xxhash) remaining | ||
| // unchanged. While this is unlikely to happen intentionally, this could cause inconsistent match results | ||
| // between deployments. | ||
| message ConsistentHashing { | ||
| // The threshold the resulting hash must be over in order for this matcher to evaluate to true. | ||
| // This value must be below the configured modulo value. | ||
| // Setting this to 0 is equivalent to this matcher always matching. | ||
| uint32 threshold = 1; | ||
|
|
||
| // The value to use for the modulus in the calculation. This effectively bounds the hash output, | ||
| // specifying the range of possible values. | ||
| // This value must be above the configured threshold. | ||
| uint32 modulo = 2 [(validate.rules).uint32 = {gt: 0}]; | ||
|
|
||
| // Optional seed passed through the hash function. This allows using additional information when computing | ||
| // the hash value: by changing the seed value, a different partition of matching and non-matching inputs will | ||
| // be created that remains consistent for that seed value. | ||
| uint64 seed = 3; | ||
| } |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| load( | ||
| "//bazel:envoy_build_system.bzl", | ||
| "envoy_cc_extension", | ||
| "envoy_cc_library", | ||
| "envoy_extension_package", | ||
| ) | ||
|
|
||
| licenses(["notice"]) # Apache 2 | ||
|
|
||
| envoy_extension_package() | ||
|
|
||
| envoy_cc_library( | ||
| name = "consistent_hashing_lib", | ||
| hdrs = ["matcher.h"], | ||
| deps = [ | ||
| "//include/envoy/matcher:matcher_interface", | ||
| "//include/envoy/upstream:retry_interface", | ||
| "//source/common/common:hash_lib", | ||
| ], | ||
| ) | ||
|
|
||
| envoy_cc_extension( | ||
| name = "config", | ||
| srcs = ["config.cc"], | ||
| hdrs = ["config.h"], | ||
| category = "envoy.matching.input_matchers", | ||
| security_posture = "robust_to_untrusted_downstream", | ||
| deps = [ | ||
| ":consistent_hashing_lib", | ||
| "//include/envoy/matcher:matcher_interface", | ||
| "//include/envoy/registry", | ||
| "//include/envoy/server:factory_context_interface", | ||
| "@envoy_api//envoy/extensions/matching/input_matchers/consistent_hashing/v3:pkg_cc_proto", | ||
| ], | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| #include "extensions/matching/input_matchers/consistent_hashing/config.h" | ||
|
|
||
| namespace Envoy { | ||
| namespace Extensions { | ||
| namespace Matching { | ||
| namespace InputMatchers { | ||
| namespace ConsistentHashing { | ||
|
|
||
| Envoy::Matcher::InputMatcherPtr ConsistentHashingConfig::createInputMatcher( | ||
| const Protobuf::Message& config, Server::Configuration::FactoryContext& factory_context) { | ||
| const auto& consistent_hashing_config = | ||
| MessageUtil::downcastAndValidate<const envoy::extensions::matching::input_matchers:: | ||
| consistent_hashing::v3::ConsistentHashing&>( | ||
| config, factory_context.messageValidationVisitor()); | ||
|
|
||
| if (consistent_hashing_config.threshold() > consistent_hashing_config.modulo()) { | ||
| throw EnvoyException(fmt::format("threshold cannot be greater than modulo: {} > {}", | ||
| consistent_hashing_config.threshold(), | ||
| consistent_hashing_config.modulo())); | ||
| } | ||
|
|
||
| return std::make_unique<Matcher>(consistent_hashing_config.threshold(), | ||
| consistent_hashing_config.modulo(), | ||
| consistent_hashing_config.seed()); | ||
| } | ||
| /** | ||
| * Static registration for the consistent hashing matcher. @see RegisterFactory. | ||
| */ | ||
| REGISTER_FACTORY(ConsistentHashingConfig, Envoy::Matcher::InputMatcherFactory); | ||
|
|
||
| } // namespace ConsistentHashing | ||
| } // namespace InputMatchers | ||
| } // namespace Matching | ||
| } // namespace Extensions | ||
| } // namespace Envoy |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| #pragma once | ||
|
|
||
| #include "envoy/extensions/matching/input_matchers/consistent_hashing/v3/consistent_hashing.pb.h" | ||
| #include "envoy/extensions/matching/input_matchers/consistent_hashing/v3/consistent_hashing.pb.validate.h" | ||
| #include "envoy/matcher/matcher.h" | ||
| #include "envoy/server/factory_context.h" | ||
|
|
||
| #include "common/protobuf/utility.h" | ||
|
|
||
| #include "extensions/matching/input_matchers/consistent_hashing/matcher.h" | ||
|
|
||
| namespace Envoy { | ||
| namespace Extensions { | ||
| namespace Matching { | ||
| namespace InputMatchers { | ||
| namespace ConsistentHashing { | ||
|
|
||
| class ConsistentHashingConfig : public Envoy::Matcher::InputMatcherFactory { | ||
| public: | ||
| Envoy::Matcher::InputMatcherPtr | ||
| createInputMatcher(const Protobuf::Message& config, | ||
| Server::Configuration::FactoryContext& factory_context) override; | ||
|
|
||
| std::string name() const override { return "envoy.matching.matchers.consistent_hashing"; } | ||
|
|
||
| ProtobufTypes::MessagePtr createEmptyConfigProto() override { | ||
| return std::make_unique< | ||
| envoy::extensions::matching::input_matchers::consistent_hashing::v3::ConsistentHashing>(); | ||
| } | ||
| }; | ||
| } // namespace ConsistentHashing | ||
| } // namespace InputMatchers | ||
| } // namespace Matching | ||
| } // namespace Extensions | ||
| } // namespace Envoy |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| #pragma once | ||
|
|
||
| #include "envoy/matcher/matcher.h" | ||
|
|
||
| #include "common/common/hash.h" | ||
|
|
||
| namespace Envoy { | ||
| namespace Extensions { | ||
| namespace Matching { | ||
| namespace InputMatchers { | ||
| namespace ConsistentHashing { | ||
|
|
||
| class Matcher : public Envoy::Matcher::InputMatcher { | ||
| public: | ||
| Matcher(uint32_t threshold, uint32_t modulo, uint64_t seed) | ||
| : threshold_(threshold), modulo_(modulo), seed_(seed) {} | ||
| bool match(absl::optional<absl::string_view> input) override { | ||
| // Only match if the value is present. | ||
| if (!input) { | ||
| return false; | ||
| } | ||
|
|
||
| // Otherwise, match if (hash(input) % modulo) >= threshold. | ||
| return HashUtil::xxHash64(*input, seed_) % modulo_ >= threshold_; | ||
| } | ||
|
|
||
| private: | ||
| const uint32_t threshold_; | ||
| const uint32_t modulo_; | ||
| const uint64_t seed_; | ||
| }; | ||
| } // namespace ConsistentHashing | ||
| } // namespace InputMatchers | ||
| } // namespace Matching | ||
| } // namespace Extensions | ||
| } // namespace Envoy |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| load( | ||
| "//bazel:envoy_build_system.bzl", | ||
| "envoy_package", | ||
| ) | ||
| load( | ||
| "//test/extensions:extensions_build_system.bzl", | ||
| "envoy_extension_cc_test", | ||
| ) | ||
|
|
||
| licenses(["notice"]) # Apache 2 | ||
|
|
||
| envoy_package() | ||
|
|
||
| envoy_extension_cc_test( | ||
| name = "config_test", | ||
| srcs = ["config_test.cc"], | ||
| extension_name = "envoy.matching.input_matchers.consistent_hashing", | ||
| deps = [ | ||
| "//source/extensions/matching/input_matchers/consistent_hashing:config", | ||
| "//test/mocks/server:factory_context_mocks", | ||
| ], | ||
| ) | ||
|
|
||
| envoy_extension_cc_test( | ||
| name = "matcher_test", | ||
| srcs = ["matcher_test.cc"], | ||
| extension_name = "envoy.matching.input_matchers.consistent_hashing", | ||
| deps = [ | ||
| "//source/extensions/matching/input_matchers/consistent_hashing:consistent_hashing_lib", | ||
| ], | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍