| // |
| // Copyright 2015 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. |
| // |
| |
| #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_H |
| #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_H |
| |
| #include <grpc/support/port_platform.h> |
| |
| #include <functional> |
| #include <iterator> |
| |
| #include "absl/status/status.h" |
| #include "absl/status/statusor.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/types/variant.h" |
| |
| #include "src/core/ext/filters/client_channel/subchannel_interface.h" |
| #include "src/core/lib/gprpp/orphanable.h" |
| #include "src/core/lib/gprpp/ref_counted_ptr.h" |
| #include "src/core/lib/iomgr/polling_entity.h" |
| #include "src/core/lib/iomgr/work_serializer.h" |
| #include "src/core/lib/resolver/server_address.h" |
| #include "src/core/lib/transport/connectivity_state.h" |
| |
| namespace grpc_core { |
| |
| extern DebugOnlyTraceFlag grpc_trace_lb_policy_refcount; |
| |
| /// Interface for load balancing policies. |
| /// |
| /// The following concepts are used here: |
| /// |
| /// Channel: An abstraction that manages connections to backend servers |
| /// on behalf of a client application. The application creates a channel |
| /// for a given server name and then sends calls (RPCs) on it, and the |
| /// channel figures out which backend server to send each call to. A channel |
| /// contains a resolver, a load balancing policy (or a tree of LB policies), |
| /// and a set of one or more subchannels. |
| /// |
| /// Subchannel: A subchannel represents a connection to one backend server. |
| /// The LB policy decides which subchannels to create, manages the |
| /// connectivity state of those subchannels, and decides which subchannel |
| /// to send any given call to. |
| /// |
| /// Resolver: A plugin that takes a gRPC server URI and resolves it to a |
| /// list of one or more addresses and a service config, as described |
| /// in https://github.com/grpc/grpc/blob/master/doc/naming.md. See |
| /// resolver.h for the resolver API. |
| /// |
| /// Load Balancing (LB) Policy: A plugin that takes a list of addresses |
| /// from the resolver, maintains and manages a subchannel for each |
| /// backend address, and decides which subchannel to send each call on. |
| /// An LB policy has two parts: |
| /// - A LoadBalancingPolicy, which deals with the control plane work of |
| /// managing subchannels. |
| /// - A SubchannelPicker, which handles the data plane work of |
| /// determining which subchannel a given call should be sent on. |
| |
| /// LoadBalacingPolicy API. |
| /// |
| /// Note: All methods with a "Locked" suffix must be called from the |
| /// work_serializer passed to the constructor. |
| /// |
| /// Any I/O done by the LB policy should be done under the pollset_set |
| /// returned by \a interested_parties(). |
| // TODO(roth): Once we move to EventManager-based polling, remove the |
| // interested_parties() hooks from the API. |
| class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> { |
| public: |
| /// Interface for accessing per-call state. |
| /// Implemented by the client channel and used by the SubchannelPicker. |
| class CallState { |
| public: |
| CallState() = default; |
| virtual ~CallState() = default; |
| |
| /// Allocates memory associated with the call, which will be |
| /// automatically freed when the call is complete. |
| /// It is more efficient to use this than to allocate memory directly |
| /// for allocations that need to be made on a per-call basis. |
| virtual void* Alloc(size_t size) = 0; |
| |
| /// EXPERIMENTAL API. |
| /// Returns the value of the call attribute \a key. |
| /// Keys are static strings, so an attribute can be accessed by an LB |
| /// policy implementation only if it knows about the internal key. |
| /// Returns a null string_view if key not found. |
| virtual absl::string_view ExperimentalGetCallAttribute(const char* key) = 0; |
| }; |
| |
| /// Interface for accessing metadata. |
| /// Implemented by the client channel and used by the SubchannelPicker. |
| class MetadataInterface { |
| public: |
| virtual ~MetadataInterface() = default; |
| |
| ////////////////////////////////////////////////////////////////////////// |
| // TODO(ctiller): DO NOT MAKE THIS A PUBLIC API YET |
| // This needs some API design to ensure we can add/remove/replace metadata |
| // keys... we're deliberately not doing so to save some time whilst |
| // cleaning up the internal metadata representation, but we should add |
| // something back before making this a public API. |
| ////////////////////////////////////////////////////////////////////////// |
| |
| /// Adds a key/value pair. |
| /// Does NOT take ownership of \a key or \a value. |
| /// Implementations must ensure that the key and value remain alive |
| /// until the call ends. If desired, they may be allocated via |
| /// CallState::Alloc(). |
| virtual void Add(absl::string_view key, absl::string_view value) = 0; |
| |
| /// Produce a vector of metadata key/value strings for tests. |
| virtual std::vector<std::pair<std::string, std::string>> |
| TestOnlyCopyToVector() = 0; |
| |
| virtual absl::optional<absl::string_view> Lookup( |
| absl::string_view key, std::string* buffer) const = 0; |
| }; |
| |
| /// Arguments used when picking a subchannel for a call. |
| struct PickArgs { |
| /// The path of the call. Indicates the RPC service and method name. |
| absl::string_view path; |
| /// Initial metadata associated with the picking call. |
| /// The LB policy may use the existing metadata to influence its routing |
| /// decision, and it may add new metadata elements to be sent with the |
| /// call to the chosen backend. |
| MetadataInterface* initial_metadata; |
| /// An interface for accessing call state. Can be used to allocate |
| /// memory associated with the call in an efficient way. |
| CallState* call_state; |
| }; |
| |
| /// Interface for accessing backend metric data. |
| /// Implemented by the client channel and used by |
| /// SubchannelCallTrackerInterface. |
| class BackendMetricAccessor { |
| public: |
| // Represents backend metrics reported by the backend to the client. |
| struct BackendMetricData { |
| /// CPU utilization expressed as a fraction of available CPU resources. |
| double cpu_utilization; |
| /// Memory utilization expressed as a fraction of available memory |
| /// resources. |
| double mem_utilization; |
| /// Total requests per second being served by the backend. This |
| /// should include all services that a backend is responsible for. |
| uint64_t requests_per_second; |
| /// Application-specific requests cost metrics. Metric names are |
| /// determined by the application. Each value is an absolute cost |
| /// (e.g. 3487 bytes of storage) associated with the request. |
| std::map<absl::string_view, double> request_cost; |
| /// Application-specific resource utilization metrics. Metric names |
| /// are determined by the application. Each value is expressed as a |
| /// fraction of total resources available. |
| std::map<absl::string_view, double> utilization; |
| }; |
| |
| virtual ~BackendMetricAccessor() = default; |
| |
| /// Returns the backend metric data returned by the server for the call, |
| /// or null if no backend metric data was returned. |
| virtual const BackendMetricData* GetBackendMetricData() = 0; |
| }; |
| |
| /// Interface for tracking subchannel calls. |
| /// Implemented by LB policy and used by the channel. |
| class SubchannelCallTrackerInterface { |
| public: |
| virtual ~SubchannelCallTrackerInterface() = default; |
| |
| /// Called when a subchannel call is started after an LB pick. |
| virtual void Start() = 0; |
| |
| /// Called when a subchannel call is completed. |
| /// The metadata may be modified by the implementation. However, the |
| /// implementation does not take ownership, so any data that needs to be |
| /// used after returning must be copied. |
| struct FinishArgs { |
| absl::Status status; |
| MetadataInterface* trailing_metadata; |
| BackendMetricAccessor* backend_metric_accessor; |
| }; |
| virtual void Finish(FinishArgs args) = 0; |
| }; |
| |
| /// The result of picking a subchannel for a call. |
| struct PickResult { |
| /// A successful pick. |
| struct Complete { |
| /// The subchannel to be used for the call. Must be non-null. |
| RefCountedPtr<SubchannelInterface> subchannel; |
| |
| /// Optionally set by the LB policy when it wishes to be notified |
| /// about the resulting subchannel call. |
| /// Note that if the pick is abandoned by the channel, this may never |
| /// be used. |
| std::unique_ptr<SubchannelCallTrackerInterface> subchannel_call_tracker; |
| |
| explicit Complete( |
| RefCountedPtr<SubchannelInterface> sc, |
| std::unique_ptr<SubchannelCallTrackerInterface> tracker = nullptr) |
| : subchannel(std::move(sc)), |
| subchannel_call_tracker(std::move(tracker)) {} |
| }; |
| |
| /// Pick cannot be completed until something changes on the control |
| /// plane. The client channel will queue the pick and try again the |
| /// next time the picker is updated. |
| struct Queue {}; |
| |
| /// Pick failed. If the call is wait_for_ready, the client channel |
| /// will wait for the next picker and try again; otherwise, it |
| /// will immediately fail the call with the status indicated (although |
| /// the call may be retried if the client channel is configured to do so). |
| struct Fail { |
| absl::Status status; |
| |
| explicit Fail(absl::Status s) : status(s) {} |
| }; |
| |
| /// Pick will be dropped with the status specified. |
| /// Unlike FailPick, the call will be dropped even if it is |
| /// wait_for_ready, and retries (if configured) will be inhibited. |
| struct Drop { |
| absl::Status status; |
| |
| explicit Drop(absl::Status s) : status(s) {} |
| }; |
| |
| // A pick result must be one of these types. |
| // Default to Queue, just to allow default construction. |
| absl::variant<Complete, Queue, Fail, Drop> result = Queue(); |
| |
| PickResult() = default; |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| PickResult(Complete complete) : result(std::move(complete)) {} |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| PickResult(Queue queue) : result(queue) {} |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| PickResult(Fail fail) : result(std::move(fail)) {} |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| PickResult(Drop drop) : result(std::move(drop)) {} |
| }; |
| |
| /// A subchannel picker is the object used to pick the subchannel to |
| /// use for a given call. This is implemented by the LB policy and |
| /// used by the client channel to perform picks. |
| /// |
| /// Pickers are intended to encapsulate all of the state and logic |
| /// needed on the data plane (i.e., to actually process picks for |
| /// individual calls sent on the channel) while excluding all of the |
| /// state and logic needed on the control plane (i.e., resolver |
| /// updates, connectivity state notifications, etc); the latter should |
| /// live in the LB policy object itself. |
| /// |
| /// Currently, pickers are always accessed from within the |
| /// client_channel data plane mutex, so they do not have to be |
| /// thread-safe. |
| class SubchannelPicker { |
| public: |
| SubchannelPicker() = default; |
| virtual ~SubchannelPicker() = default; |
| |
| virtual PickResult Pick(PickArgs args) = 0; |
| }; |
| |
| /// A proxy object implemented by the client channel and used by the |
| /// LB policy to communicate with the channel. |
| // TODO(roth): Once insecure builds go away, add methods for accessing |
| // channel creds. By default, that should strip off the call creds |
| // attached to the channel creds, but there should also be a "use at |
| // your own risk" option to get the channel creds without stripping |
| // off the attached call creds. |
| class ChannelControlHelper { |
| public: |
| ChannelControlHelper() = default; |
| virtual ~ChannelControlHelper() = default; |
| |
| /// Creates a new subchannel with the specified channel args. |
| virtual RefCountedPtr<SubchannelInterface> CreateSubchannel( |
| ServerAddress address, const grpc_channel_args& args) = 0; |
| |
| /// Sets the connectivity state and returns a new picker to be used |
| /// by the client channel. |
| virtual void UpdateState(grpc_connectivity_state state, |
| const absl::Status& status, |
| std::unique_ptr<SubchannelPicker>) = 0; |
| |
| /// Requests that the resolver re-resolve. |
| virtual void RequestReresolution() = 0; |
| |
| /// Returns the channel authority. |
| virtual absl::string_view GetAuthority() = 0; |
| |
| /// Adds a trace message associated with the channel. |
| enum TraceSeverity { TRACE_INFO, TRACE_WARNING, TRACE_ERROR }; |
| virtual void AddTraceEvent(TraceSeverity severity, |
| absl::string_view message) = 0; |
| }; |
| |
| /// Interface for configuration data used by an LB policy implementation. |
| /// Individual implementations will create a subclass that adds methods to |
| /// return the parameters they need. |
| class Config : public RefCounted<Config> { |
| public: |
| ~Config() override = default; |
| |
| // Returns the load balancing policy name |
| virtual const char* name() const = 0; |
| }; |
| |
| /// Data passed to the UpdateLocked() method when new addresses and |
| /// config are available. |
| struct UpdateArgs { |
| /// A list of addresses, or an error indicating a failure to obtain the |
| /// list of addresses. |
| absl::StatusOr<ServerAddressList> addresses; |
| /// The LB policy config. |
| RefCountedPtr<Config> config; |
| /// A human-readable note providing context about the name resolution that |
| /// provided this update. LB policies may wish to include this message |
| /// in RPC failure status messages. For example, if the update has an |
| /// empty list of addresses, this message might say "no DNS entries |
| /// found for <name>". |
| std::string resolution_note; |
| |
| // TODO(roth): Before making this a public API, find a better |
| // abstraction for representing channel args. |
| const grpc_channel_args* args = nullptr; |
| |
| // TODO(roth): Remove everything below once channel args is |
| // converted to a copyable and movable C++ object. |
| UpdateArgs() = default; |
| ~UpdateArgs() { grpc_channel_args_destroy(args); } |
| UpdateArgs(const UpdateArgs& other); |
| UpdateArgs(UpdateArgs&& other) noexcept; |
| UpdateArgs& operator=(const UpdateArgs& other); |
| UpdateArgs& operator=(UpdateArgs&& other) noexcept; |
| }; |
| |
| /// Args used to instantiate an LB policy. |
| struct Args { |
| /// The work_serializer under which all LB policy calls will be run. |
| std::shared_ptr<WorkSerializer> work_serializer; |
| /// Channel control helper. |
| /// Note: LB policies MUST NOT call any method on the helper from |
| /// their constructor. |
| std::unique_ptr<ChannelControlHelper> channel_control_helper; |
| /// Channel args. |
| // TODO(roth): Find a better channel args representation for this API. |
| // TODO(roth): Clarify ownership semantics here -- currently, this |
| // does not take ownership of args, which is the opposite of how we |
| // handle them in UpdateArgs. |
| const grpc_channel_args* args = nullptr; |
| }; |
| |
| explicit LoadBalancingPolicy(Args args, intptr_t initial_refcount = 1); |
| ~LoadBalancingPolicy() override; |
| |
| // Not copyable nor movable. |
| LoadBalancingPolicy(const LoadBalancingPolicy&) = delete; |
| LoadBalancingPolicy& operator=(const LoadBalancingPolicy&) = delete; |
| |
| /// Returns the name of the LB policy. |
| virtual const char* name() const = 0; |
| |
| /// Updates the policy with new data from the resolver. Will be invoked |
| /// immediately after LB policy is constructed, and then again whenever |
| /// the resolver returns a new result. |
| // TODO(roth): Change this to return some indication as to whether the |
| // update has been accepted, so that we can indicate to the resolver |
| // whether it should go into backoff to retry the resolution. |
| virtual void UpdateLocked(UpdateArgs) = 0; // NOLINT |
| |
| /// Tries to enter a READY connectivity state. |
| /// This is a no-op by default, since most LB policies never go into |
| /// IDLE state. |
| virtual void ExitIdleLocked() {} |
| |
| /// Resets connection backoff. |
| virtual void ResetBackoffLocked() = 0; |
| |
| grpc_pollset_set* interested_parties() const { return interested_parties_; } |
| |
| // Note: This must be invoked while holding the work_serializer. |
| void Orphan() override; |
| |
| // A picker that returns PickResult::Queue for all picks. |
| // Also calls the parent LB policy's ExitIdleLocked() method when the |
| // first pick is seen. |
| class QueuePicker : public SubchannelPicker { |
| public: |
| explicit QueuePicker(RefCountedPtr<LoadBalancingPolicy> parent) |
| : parent_(std::move(parent)) {} |
| |
| ~QueuePicker() override { parent_.reset(DEBUG_LOCATION, "QueuePicker"); } |
| |
| PickResult Pick(PickArgs args) override; |
| |
| private: |
| RefCountedPtr<LoadBalancingPolicy> parent_; |
| bool exit_idle_called_ = false; |
| }; |
| |
| // A picker that returns PickResult::Fail for all picks. |
| class TransientFailurePicker : public SubchannelPicker { |
| public: |
| explicit TransientFailurePicker(absl::Status status) : status_(status) {} |
| |
| PickResult Pick(PickArgs /*args*/) override { |
| return PickResult::Fail(status_); |
| } |
| |
| private: |
| absl::Status status_; |
| }; |
| |
| protected: |
| std::shared_ptr<WorkSerializer> work_serializer() const { |
| return work_serializer_; |
| } |
| |
| // Note: LB policies MUST NOT call any method on the helper from their |
| // constructor. |
| ChannelControlHelper* channel_control_helper() const { |
| return channel_control_helper_.get(); |
| } |
| |
| /// Shuts down the policy. |
| virtual void ShutdownLocked() = 0; |
| |
| private: |
| /// Work Serializer under which LB policy actions take place. |
| std::shared_ptr<WorkSerializer> work_serializer_; |
| /// Owned pointer to interested parties in load balancing decisions. |
| grpc_pollset_set* interested_parties_; |
| /// Channel control helper. |
| std::unique_ptr<ChannelControlHelper> channel_control_helper_; |
| }; |
| |
| } // namespace grpc_core |
| |
| #endif // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_H |