Skip to content
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

server: add support for range trigger overload actions #12352

Merged
merged 18 commits into from
Aug 12, 2020
Merged
Show file tree
Hide file tree
Changes from 13 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
20 changes: 16 additions & 4 deletions api/envoy/config/overload/v3/overload.proto
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,20 @@ message ThresholdTrigger {
"envoy.config.overload.v2alpha.ThresholdTrigger";

// If the resource pressure is greater than or equal to this value, the trigger
// will fire.
// will enter saturation.
double value = 1 [(validate.rules).double = {lte: 1.0 gte: 0.0}];
}

message RangeTrigger {
// If the resource pressure is greater than this value, the trigger will be in the
// :ref:`scaling <arch_overview_overload_manager-triggers-state>` state with value
// `(pressure - min_value) / (max_value - min_value)`.
double min_value = 1 [(validate.rules).double = {lte: 1.0 gte: 0.0}];
akonradi marked this conversation as resolved.
Show resolved Hide resolved

// If the resource pressure is greater than this value, the trigger will enter saturation.
double max_value = 2 [(validate.rules).double = {lte: 1.0 gte: 0.0}];
}

message Trigger {
option (udpa.annotations.versioning).previous_message_type =
"envoy.config.overload.v2alpha.Trigger";
Expand All @@ -65,6 +75,8 @@ message Trigger {
option (validate.required) = true;

ThresholdTrigger threshold = 2;

RangeTrigger range = 3;
}
}

Expand All @@ -77,9 +89,9 @@ message OverloadAction {
// DNS to ensure uniqueness.
string name = 1 [(validate.rules).string = {min_bytes: 1}];

// A set of triggers for this action. If any of these triggers fire the overload action
// is activated. Listeners are notified when the overload action transitions from
// inactivated to activated, or vice versa.
// A set of triggers for this action. The state of the action is the maximum
// state of all triggers, which can be scaling between 0 and 1 or saturated. Listeners
// are notified when the overload action changes state.
repeated Trigger triggers = 2 [(validate.rules).repeated = {min_items: 1}];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,24 @@ The overload manager uses Envoy's :ref:`extension <extending>` framework for def
resource monitors. Envoy's builtin resource monitors are listed
:ref:`here <config_resource_monitors>`.

Triggers
--------

Triggers connect resource monitors to actions. There are two types of triggers supported:

.. list-table::
:header-rows: 1
:widths: 1, 2

* - Type
- Description
* - :ref:`threshold <envoy_v3_api_msg_config.overload.v3.ThresholdTrigger>`
- Sets the action state to 1 (= *saturated*) when the resource pressure is above a threshold, and to 0 otherwise.
* - :ref:`range <envoy_v3_api_msg_config.overload.v3.RangeTrigger>`
- Sets the action state to 0 when the resource pressure is below the min threshold,
Copy link
Member

Choose a reason for hiding this comment

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

replace min/max with the new names and for bonus points ref link them

`(pressure - min)/(max - min)` when `min < pressure < max`,
and to 1 (*saturated*) when the pressure is above the max."

Overload actions
----------------

Expand Down Expand Up @@ -99,4 +117,5 @@ with the following statistics:
:header: Name, Type, Description
:widths: 1, 1, 2

active, Gauge, "Active state of the action (0=inactive, 1=active)"
active, Gauge, "Active state of the action (0=scaling, 1=saturated)"
scale_percent, Gauge, "Scaled value of the action as a percent (0-99=scaling, 100=saturated)"
41 changes: 41 additions & 0 deletions docs/root/intro/arch_overview/operations/overload_manager.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,44 @@ upstream services.
The overload manager is :ref:`configured <config_overload_manager>` by specifying a set of
resources to monitor and a set of overload actions that will be taken when some of those
resources exceed certain pressure thresholds.

Architecture
------------

The overload manager works by periodically polling the *pressure* of a set of **resources**,
feeding those through **triggers**, and taking **actions** based on the triggers. The set of
resource monitors, triggers, and actions are specified at startup.

Resources
~~~~~~~~~

A resource is a thing that can be monitored by the overload manager, and whose *pressure* is
represented by a real value in the range [0, 1]. The pressure of a resource is evaluated by a
*resource monitor*. See the :ref:`configuration page <config_overload_manager>` for setting up
resource monitors.

Triggers
~~~~~~~~

Triggers are evaluated on each resource pressure update, and convert a resource pressure value
into an action state. An action state has a value in the range [0, 1], and is categorized into one of two groups:

.. _arch_overview_overload_manager-triggers-state:

.. csv-table::
:header: action state, value, description
:widths: 1, 1, 2

scaling, "[0, 1)", the resource pressure is below the configured saturation point; action may be taken
saturated, 1, the resource pressure is at or above the configured saturation point; drastic action should be taken

When a resource pressure value is updated, the relevant triggers are reevaluated. For each action
with at least one trigger, the resulting action state is the maximum value over the configured
triggers. What effect the action state has depends on the action's configuration and implementation.

Actions
~~~~~~~

When a trigger changes state, the value is sent to registered actions, which can then affect how
connections and requests are processed. Each action interprets the input states differently, and
some may ignore the *scaling* state altogether, taking effect only when *saturated*.
20 changes: 16 additions & 4 deletions generated_api_shadow/envoy/config/overload/v3/overload.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 21 additions & 9 deletions include/envoy/server/overload_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,27 @@
namespace Envoy {
namespace Server {

enum class OverloadActionState {
/**
* Indicates that an overload action is active because at least one of its triggers has fired.
*/
Active,
/**
* Indicates that an overload action is inactive because none of its triggers have fired.
*/
Inactive
/**
* Tracks the state of an overload action. The state is a number between 0 and 1 that represents the
* level of saturation. The values are categorized in two groups:
* - Saturated (value = 1): indicates that an overload action is active because at least one of its
* triggers has reached saturation.
* - Scaling (0 <= value < 1): indicates that an overload action is not saturated.
Copy link
Contributor

Choose a reason for hiding this comment

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

The name of the function on L23 seems to imply that we refer to value = 0 as inactive, is this a useful distinction to make? Should that be included in this comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am planning to handle this in a follow-up PR. It does seem like a useful distinction at least conceptually.

*/
class OverloadActionState {
public:
static constexpr OverloadActionState inactive() { return OverloadActionState(0); }

static constexpr OverloadActionState saturated() { return OverloadActionState(1.0); }

explicit constexpr OverloadActionState(float value)
: action_value_(std::min(1.0f, std::max(0.0f, value))) {}

float value() const { return action_value_; }
bool isSaturated() const { return action_value_ == 1; }

private:
float action_value_;
Copy link
Member

Choose a reason for hiding this comment

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

const?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, because then OverloadActionState isn't assignable.

};

/**
Expand Down
5 changes: 2 additions & 3 deletions source/common/http/conn_manager_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -855,8 +855,7 @@ void ConnectionManagerImpl::ActiveStream::decodeHeaders(RequestHeaderMapPtr&& he
filter_manager_.maybeEndDecode(end_stream);

// Drop new requests when overloaded as soon as we have decoded the headers.
if (connection_manager_.overload_stop_accepting_requests_ref_ ==
Server::OverloadActionState::Active) {
if (connection_manager_.overload_stop_accepting_requests_ref_.isSaturated()) {
// In this one special case, do not create the filter chain. If there is a risk of memory
// overload it is more important to avoid unnecessary allocation than to create the filters.
state_.created_filter_chain_ = true;
Expand Down Expand Up @@ -1843,7 +1842,7 @@ void ConnectionManagerImpl::ActiveStream::encodeHeaders(ResponseHeaderMap& heade
}

if (connection_manager_.drain_state_ == DrainState::NotDraining &&
connection_manager_.overload_disable_keepalive_ref_ == Server::OverloadActionState::Active) {
connection_manager_.overload_disable_keepalive_ref_.isSaturated()) {
ENVOY_STREAM_LOG(debug, "disabling keepalive due to envoy overload", *this);
connection_manager_.drain_state_ = DrainState::Closing;
connection_manager_.stats_.named_.downstream_cx_overload_disable_keepalive_.inc();
Expand Down
7 changes: 3 additions & 4 deletions source/common/memory/heap_shrinker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ HeapShrinker::HeapShrinker(Event::Dispatcher& dispatcher, Server::OverloadManage
Stats::Scope& stats)
: active_(false) {
const auto action_name = Server::OverloadActionNames::get().ShrinkHeap;
if (overload_manager.registerForAction(action_name, dispatcher,
[this](Server::OverloadActionState state) {
active_ = (state == Server::OverloadActionState::Active);
})) {
if (overload_manager.registerForAction(
action_name, dispatcher,
[this](Server::OverloadActionState state) { active_ = state.isSaturated(); })) {
Envoy::Stats::StatNameManagedStorage stat_name(
absl::StrCat("overload.", action_name, ".shrink_count"), stats.symbolTable());
shrink_counter_ = &stats.counterFromStatName(stat_name.statName());
Expand Down
2 changes: 1 addition & 1 deletion source/server/admin/admin.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ class AdminImpl : public Admin,
struct NullThreadLocalOverloadState : public ThreadLocalOverloadState {
const OverloadActionState& getState(const std::string&) override { return inactive_; }

const OverloadActionState inactive_ = OverloadActionState::Inactive;
const OverloadActionState inactive_ = OverloadActionState::inactive();
};

NullOverloadManager(ThreadLocal::SlotAllocator& slot_allocator)
Expand Down
Loading