Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DEPRECATED.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The following features have been DEPRECATED and will be removed in the specified
A logged warning is expected for each deprecated item that is in deprecation window.

## Version 1.11.0 (Pending)
* Use of `cluster`, found in [redis-proxy.proto](https://github.com/envoyproxy/envoy/blob/master/api/envoy/config/filter/network/redis_proxy/v2/redis_proxy.proto) is deprecated. Set a `PrefixRoutes.catch_all_cluster` instead.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please merge master, this was moved into deprecated.rst. (You can now ref link also.)


## Version 1.10.0 (Apr 5, 2019)
* Use of `use_alpha` in [Ext-Authz Authorization Service](https://github.com/envoyproxy/envoy/blob/master/api/envoy/service/auth/v2/external_auth.proto) is deprecated. It should be used for a short time, and only when transitioning from alpha to V2 release version.
Expand Down
63 changes: 61 additions & 2 deletions api/envoy/config/filter/network/redis_proxy/v2/redis_proxy.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ message RedisProxy {
// Name of cluster from cluster manager. See the :ref:`configuration section
// <arch_overview_redis_configuration>` of the architecture overview for recommendations on
// configuring the backing cluster.
string cluster = 2 [(validate.rules).string.min_bytes = 1];
//
// .. attention::
//
// This field is deprecated. Use a :ref:`catch-all
// cluster<envoy_api_field_config.filter.network.redis_proxy.v2.RedisProxy.PrefixRoutes.catch_all_cluster>`
// instead.
string cluster = 2 [deprecated = true];

// Redis connection pool settings.
message ConnPoolSettings {
Expand Down Expand Up @@ -55,10 +61,63 @@ message RedisProxy {
bool enable_redirection = 3;
}

// Network settings for the connection pool to the upstream cluster.
// Network settings for the connection pool to the upstream clusters.
ConnPoolSettings settings = 3 [(validate.rules).message.required = true];

// Indicates that latency stat should be computed in microseconds. By default it is computed in
// milliseconds.
bool latency_in_micros = 4;

message PrefixRoutes {
message Route {
// String prefix that must match the beginning of the keys. Envoy will always favor the
// longest match.
string prefix = 1 [(validate.rules).string.min_bytes = 1];

// Indicates if the prefix needs to be removed from the key when forwarded.
bool remove_prefix = 2;

// Upstream cluster to forward the command to.
string cluster = 3 [(validate.rules).string.min_bytes = 1];
}

// List of prefix routes.
repeated Route routes = 1 [(gogoproto.nullable) = false];

// Indicates that prefix matching should be case insensitive.
bool case_insensitive = 2;

// Optional catch-all route to forward commands that doesn't match any of the routes. The
// catch-all route becomes required when no routes are specified.
string catch_all_cluster = 3;
}

// List of **unique** prefixes used to separate keys from different workloads to different
// clusters. Envoy will always favor the longest match first in case of overlap. A catch-all
// cluster can be used to forward commands when there is no match. Time complexity of the
// lookups are in O(min(longest key prefix, key length)).
//
// Example:
//
// .. code-block:: yaml
//
// prefix_routes:
// routes:
// - prefix: "ab"
// cluster: "cluster_a"
// - prefix: "abc"
// cluster: "cluster_b"
//
// When using the above routes, the following prefixes would be sent to:
//
// * 'get abc:users' would retrive the key 'abc:users' from cluster_b.
// * 'get ab:users' would retrive the key 'ab:users' from cluster_a.
// * 'get z:users' would return a NoUpstreamHost error. A :ref:`catch-all
// cluster<envoy_api_field_config.filter.network.redis_proxy.v2.RedisProxy.PrefixRoutes.catch_all_cluster>`
// would have retrieved the key from that cluster instead.
//
// See the :ref:`configuration section
// <arch_overview_redis_configuration>` of the architecture overview for recommendations on
// configuring the backing clusters.
PrefixRoutes prefix_routes = 5 [(gogoproto.nullable) = false];
}
5 changes: 4 additions & 1 deletion docs/root/intro/arch_overview/redis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ In this mode, the goals of Envoy are to maintain availability and partition tole
over consistency. This is the key point when comparing Envoy to `Redis Cluster
<https://redis.io/topics/cluster-spec>`_. Envoy is designed as a best-effort cache,
meaning that it will not try to reconcile inconsistent data or keep a globally consistent
view of cluster membership.
view of cluster membership. It also supports routing commands from different workload to
different to different upstream clusters based on their access patterns, eviction, or isolation
requirements.

The Redis project offers a thorough reference on partitioning as it relates to Redis. See
"`Partitioning: how to split data among multiple Redis instances
Expand All @@ -22,6 +24,7 @@ The Redis project offers a thorough reference on partitioning as it relates to R
* Detailed command statistics.
* Active and passive healthchecking.
* Hash tagging.
* Prefix routing.

**Planned future enhancements**:

Expand Down
1 change: 1 addition & 0 deletions docs/root/intro/version_history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Version history
* ratelimit: removed deprecated rate limit configuration from bootstrap.
* redis: added :ref:`hashtagging <envoy_api_field_config.filter.network.redis_proxy.v2.RedisProxy.ConnPoolSettings.enable_hashtagging>` to guarantee a given key's upstream.
* redis: added :ref:`latency stats <config_network_filters_redis_proxy_per_command_stats>` for commands.
* redis: added :ref:`prefix routing <envoy_api_field_config.filter.network.redis_proxy.v2.RedisProxy.prefix_routes>` to enable routing commands based on their key's prefix to different upstream.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move to this to the 1.11.0 section.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping on this

* redis: added :ref:`success and error stats <config_network_filters_redis_proxy_per_command_stats>` for commands.
* redis: migrate hash function for host selection to `MurmurHash2 <https://sites.google.com/site/murmurhash>`_ from std::hash. MurmurHash2 is compatible with std::hash in GNU libstdc++ 3.4.20 or above. This is typically the case when compiled on Linux and not macOS.
* redis: added :ref:`latency_in_micros <envoy_api_field_config.filter.network.redis_proxy.v2.RedisProxy.latency_in_micros>` to specify the redis commands stats time unit in microseconds.
Expand Down
34 changes: 33 additions & 1 deletion source/common/common/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,8 +568,11 @@ template <class Value> struct TrieLookupTable {
* Adds an entry to the Trie at the given Key.
* @param key the key used to add the entry.
* @param value the value to be associated with the key.
* @param overwrite_existing will overwrite the value when the value for a given key already
* exists.
* @return false when a value already exists for the given key.
*/
void add(const char* key, Value value) {
bool add(const char* key, Value value, bool overwrite_existing = true) {
TrieEntry<Value>* current = &root_;
while (uint8_t c = *key) {
if (!current->entries_[c]) {
Expand All @@ -578,7 +581,11 @@ template <class Value> struct TrieLookupTable {
current = current->entries_[c].get();
key++;
}
if (current->value_ && !overwrite_existing) {
return false;
}
current->value_ = value;
return true;
}

/**
Expand All @@ -599,6 +606,31 @@ template <class Value> struct TrieLookupTable {
return current->value_;
}

/**
* Finds the entry associated with the longest prefix. Complexity is O(min(longest key prefix, key
* length))
* @param key the key used to find.
* @return the value matching the longest prefix based on the key.
*/
Value findLongestPrefix(const char* key) const {
const TrieEntry<Value>* current = &root_;
const TrieEntry<Value>* result = nullptr;
while (uint8_t c = *key) {
if (current->value_) {
result = current;
}

// https://github.com/facebook/mcrouter/blob/master/mcrouter/lib/fbi/cpp/Trie-inl.h#L126-L143
current = current->entries_[c].get();
if (current == nullptr) {
return result ? result->value_ : nullptr;
}

key++;
}
return current ? current->value_ : result->value_;
}

TrieEntry<Value> root_;
};

Expand Down
28 changes: 25 additions & 3 deletions source/extensions/filters/network/redis_proxy/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,22 @@ envoy_cc_library(
],
)

envoy_cc_library(
name = "router_interface",
hdrs = ["router.h"],
deps = [
":conn_pool_interface",
"@envoy_api//envoy/config/filter/network/redis_proxy/v2:redis_proxy_cc",
],
)

envoy_cc_library(
name = "command_splitter_lib",
srcs = ["command_splitter_impl.cc"],
hdrs = ["command_splitter_impl.h"],
deps = [
":command_splitter_interface",
":conn_pool_interface",
":router_interface",
"//include/envoy/stats:stats_macros",
"//include/envoy/stats:timespan",
"//source/common/common:assert_lib",
Expand All @@ -54,7 +63,6 @@ envoy_cc_library(
hdrs = ["conn_pool_impl.h"],
deps = [
":conn_pool_interface",
"//include/envoy/router:router_interface",
"//include/envoy/thread_local:thread_local_interface",
"//include/envoy/upstream:cluster_manager_interface",
"//source/common/buffer:buffer_lib",
Expand Down Expand Up @@ -97,7 +105,21 @@ envoy_cc_library(
"//source/extensions/filters/network/common:factory_base_lib",
"//source/extensions/filters/network/common/redis:codec_lib",
"//source/extensions/filters/network/redis_proxy:command_splitter_lib",
"//source/extensions/filters/network/redis_proxy:conn_pool_lib",
"//source/extensions/filters/network/redis_proxy:proxy_filter_lib",
"//source/extensions/filters/network/redis_proxy:router_lib",
],
)

envoy_cc_library(
name = "router_lib",
srcs = ["router_impl.cc"],
hdrs = ["router_impl.h"],
deps = [
":router_interface",
"//include/envoy/thread_local:thread_local_interface",
"//include/envoy/upstream:cluster_manager_interface",
"//source/common/common:to_lower_table_lib",
"//source/extensions/filters/network/redis_proxy:conn_pool_lib",
"@envoy_api//envoy/config/filter/network/redis_proxy/v2:redis_proxy_cc",
],
)
Loading