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

Delayed RPC Send Using Tokens #5923

Open
wants to merge 81 commits into
base: unstable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
0154359
trickle responses
ackintosh Jun 7, 2024
d5fe64e
pruning
ackintosh Jun 9, 2024
aab59f5
cargo fmt
ackintosh Jun 10, 2024
e00e679
Test that the receiver delays the responses
ackintosh Jun 10, 2024
670ec96
Add doc comments
ackintosh Jun 11, 2024
c0ae632
Fix typo
ackintosh Jun 13, 2024
7e0c630
Add inbound request size limiter
ackintosh Jun 14, 2024
6322210
Merge branch 'refs/heads/unstable' into delayed-rpc-response
ackintosh Jun 20, 2024
3947bf6
Fix compile error
ackintosh Jun 20, 2024
933dc00
Add doc comment and rename
ackintosh Jun 20, 2024
b62537f
Extract a function that calculates tau and t from the quota
ackintosh Jun 20, 2024
86cf8fb
unwrap
ackintosh Jun 22, 2024
8fd37c5
Remove unused limiter
ackintosh Jun 22, 2024
6c1015e
Restrict more than two requests from running simultaneously on the sa…
ackintosh Jun 26, 2024
817ce97
Rename from self_limiter to outbound_request_limiter
ackintosh Jun 29, 2024
7e42568
Fix clippy errors
ackintosh Jun 29, 2024
94c2493
Merge branch 'refs/heads/unstable' into delayed-rpc-response
ackintosh Jul 1, 2024
9ad4eb7
Fix import
ackintosh Jul 1, 2024
de9d943
Fix clippy errors
ackintosh Jul 6, 2024
7adb142
Merge branch 'refs/heads/unstable' into delayed-rpc-response
ackintosh Jul 7, 2024
627fd33
Merge branch 'refs/heads/unstable' into delayed-rpc-response
ackintosh Jul 11, 2024
b55ffca
Update request_id with AppRequestId
ackintosh Jul 11, 2024
73e9879
Merge branch 'unstable' into delayed-rpc-response
ackintosh Jul 13, 2024
cdef58d
Update beacon_node/lighthouse_network/src/rpc/active_requests_limiter.rs
ackintosh Jul 23, 2024
3190d9a
Update beacon_node/lighthouse_network/src/rpc/mod.rs
ackintosh Jul 23, 2024
19fe6b0
Merge branch 'unstable' into delayed-rpc-response
ackintosh Jul 25, 2024
5a9237f
Remove the RequestSizeLimiter and check if the count of requested blo…
ackintosh Jul 29, 2024
4609624
Revert extracting `tau_and_t()` because no longer need to do that
ackintosh Jul 29, 2024
a325438
Remove Instant from the requests field
ackintosh Sep 9, 2024
3b6edab
Remove unused field
ackintosh Sep 9, 2024
2ab853c
Merge branch 'unstable' into delayed-rpc-response
ackintosh Sep 9, 2024
2621ce8
Add DataColumnsBy***
ackintosh Sep 9, 2024
51247e3
Merge branch 'unstable' into delayed-rpc-response
ackintosh Sep 26, 2024
5ed47b7
Fix the mistakes made during the merge
ackintosh Sep 27, 2024
cbfb2ea
cargo fmt
ackintosh Sep 27, 2024
9f6177d
Update beacon_node/lighthouse_network/src/rpc/active_requests_limiter.rs
ackintosh Sep 27, 2024
9008d3e
Merge branch 'unstable' into delayed-rpc-response
ackintosh Oct 1, 2024
bd9f13c
merge unstable
ackintosh Oct 1, 2024
5dbac58
Move the response limiter logic from handler to behaviour
ackintosh Oct 5, 2024
ae67804
Remove Mutex from response_limiter
ackintosh Oct 5, 2024
4852b20
Fix clippy error
ackintosh Oct 7, 2024
156565c
Add the request back to active requests if the response is not a stre…
ackintosh Oct 7, 2024
0e1e58b
Add ResponseLimiter to make RPC cleaner
ackintosh Oct 10, 2024
cb87af0
Remove pending responses on disconnect
ackintosh Oct 11, 2024
023c542
Add ConnectionId to Request
ackintosh Oct 18, 2024
14ffeec
Add a comment
ackintosh Oct 20, 2024
5c9e063
Return early if the request is too large
ackintosh Oct 20, 2024
3c058b3
Remove ActiveRequestsLimiter
ackintosh Oct 21, 2024
a9a675a
Merge branch 'unstable' into delayed-rpc-response
ackintosh Oct 22, 2024
5d70573
Merge branch 'unstable' into delayed-rpc-response
ackintosh Oct 23, 2024
4e872a0
merge unstable
ackintosh Oct 23, 2024
450326c
Tweak for readability
ackintosh Oct 29, 2024
14fb84c
Merge branch 'unstable' into delayed-rpc-response
ackintosh Nov 19, 2024
636224c
Limit concurrent requests on self-limiter
ackintosh Nov 23, 2024
f6fd85b
Make the self-limiter mandatory, and make the rate-limiter optional w…
ackintosh Nov 23, 2024
95f8378
Inform the limiter that a response has been received
ackintosh Nov 25, 2024
9d2b263
Remove active requests belonging to the peer that disconnected
ackintosh Nov 26, 2024
2d7a679
Fix unused variable error
ackintosh Nov 27, 2024
b73a336
Fix clippy errors
ackintosh Nov 29, 2024
dfd092d
Merge branch 'unstable' into delayed-rpc-response
ackintosh Dec 1, 2024
810c5de
Fix clippy errors
ackintosh Dec 1, 2024
d46cbe8
Update test
ackintosh Dec 1, 2024
540436c
Adding a slight margin to the elapsed time check to account for poten…
ackintosh Dec 1, 2024
3d39f2c
Merge branch 'unstable' into delayed-rpc-response
ackintosh Dec 4, 2024
60c9900
Remove an active request when it ends with an error
ackintosh Dec 8, 2024
eec6b4a
Merge branch 'unstable' into delayed-rpc-response
ackintosh Dec 10, 2024
9a6eb72
Merge branch 'unstable' into delayed-rpc-response
ackintosh Feb 6, 2025
0d0f48d
Sync with further updates from unstable
ackintosh Feb 7, 2025
ce7ae4b
Sync with further updates from unstable
ackintosh Feb 7, 2025
cfea9d2
Remove RPC::is_request_size_too_large
ackintosh Feb 14, 2025
9850bce
Merge branch 'unstable' into delayed-rpc-response
ackintosh Feb 16, 2025
d859dad
Merge branch 'unstable' into delayed-rpc-response
ackintosh Feb 24, 2025
b0ce89d
Update beacon_node/lighthouse_network/src/rpc/mod.rs
ackintosh Feb 26, 2025
1f521d6
Fix a mistake when merging the unstable
ackintosh Feb 26, 2025
a09fc1a
Add a metric that records the time our own request remained in the se…
ackintosh Mar 7, 2025
5f6485a
Add a metric that records the time our response remained in the respo…
ackintosh Mar 8, 2025
14cf204
Update beacon_node/lighthouse_network/src/rpc/mod.rs
ackintosh Mar 11, 2025
9b1c180
Fix indentation
ackintosh Mar 11, 2025
c0c4459
Fix naming according to the naming conventions
ackintosh Mar 11, 2025
580f921
Add a comment and log
ackintosh Mar 11, 2025
a9910e4
Move the sub match to avoid the unreachable
ackintosh Mar 11, 2025
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
Prev Previous commit
Next Next commit
Add ResponseLimiter to make RPC cleaner
  • Loading branch information
ackintosh committed Oct 11, 2024
commit 0e1e58b5b6a02931b92d97adfa1a0ee808dbe8dc
117 changes: 0 additions & 117 deletions beacon_node/lighthouse_network/src/rpc/delayed_responses.rs

This file was deleted.

147 changes: 26 additions & 121 deletions beacon_node/lighthouse_network/src/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
//! direct peer-to-peer communication primarily for sending/receiving chain information for
//! syncing.

use futures::future::FutureExt;
use handler::RPCHandler;
use libp2p::core::transport::PortUse;
use libp2p::swarm::{
Expand All @@ -13,8 +12,7 @@ use libp2p::swarm::{
};
use libp2p::swarm::{ConnectionClosed, FromSwarm, SubstreamProtocol, THandlerInEvent};
use libp2p::PeerId;
use rate_limiter::RPCRateLimiter as RateLimiter;
use slog::{crit, debug, error, o, trace};
use slog::{debug, error, o, trace};
use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicUsize, Ordering};
Expand All @@ -33,8 +31,8 @@ use self::config::{InboundRateLimiterConfig, OutboundRateLimiterConfig};
use self::protocol::RPCProtocol;
use self::self_limiter::SelfRateLimiter;
use crate::rpc::active_requests_limiter::ActiveRequestsLimiter;
use crate::rpc::delayed_responses::DelayedResponses;
use crate::rpc::rate_limiter::{RateLimitedErr, RateLimiterItem};
use crate::rpc::rate_limiter::RateLimiterItem;
use crate::rpc::response_limiter::ResponseLimiter;
pub use handler::SubstreamId;
pub use methods::{
BlocksByRangeRequest, BlocksByRootRequest, GoodbyeReason, LightClientBootstrapRequest,
Expand All @@ -45,12 +43,12 @@ pub use protocol::{max_rpc_size, Protocol, RPCError};
mod active_requests_limiter;
pub(crate) mod codec;
pub mod config;
mod delayed_responses;
mod handler;
pub mod methods;
mod outbound;
mod protocol;
mod rate_limiter;
mod response_limiter;
mod self_limiter;

static NEXT_REQUEST_ID: AtomicUsize = AtomicUsize::new(1);
Expand Down Expand Up @@ -156,10 +154,8 @@ pub struct NetworkParams {
/// Implements the libp2p `NetworkBehaviour` trait and therefore manages network-level
/// logic.
pub struct RPC<Id: ReqId, E: EthSpec> {
/// Rate limiter for our responses. This is shared with RPCHandlers.
response_limiter: Option<RateLimiter>,
/// Responses queued for sending. These responses are stored when the response limiter rejects them.
delayed_responses: DelayedResponses<E>,
/// Rate limiter for our responses.
response_limiter: Option<ResponseLimiter<E>>,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
response_limiter: Option<ResponseLimiter<E>>,
inbound_rate_limiter: Option<ResponseLimiter<E>>,

I would keep the previous naming, to also still follow the naming of the configurations. But mostly what we are rate limiting are external requests right? Not our responses

/// Rate limiter for our own requests.
outbound_request_limiter: Option<SelfRateLimiter<Id, E>>,
/// Limiter for inbound requests, which restricts more than two requests from running
Expand Down Expand Up @@ -193,8 +189,7 @@ impl<Id: ReqId, E: EthSpec> RPC<Id, E> {

let response_limiter = inbound_rate_limiter_config.clone().map(|config| {
debug!(log, "Using response rate limiting params"; "config" => ?config);
RateLimiter::new_with_config(config.0)
.expect("Inbound limiter configuration parameters are valid")
ResponseLimiter::new(config, log.clone())
});

let outbound_request_limiter = outbound_rate_limiter_config.map(|config| {
Expand All @@ -203,7 +198,6 @@ impl<Id: ReqId, E: EthSpec> RPC<Id, E> {

RPC {
response_limiter,
delayed_responses: DelayedResponses::new(),
outbound_request_limiter,
active_inbound_requests_limiter: ActiveRequestsLimiter::new(),
active_inbound_requests: HashMap::new(),
Expand Down Expand Up @@ -241,38 +235,14 @@ impl<Id: ReqId, E: EthSpec> RPC<Id, E> {
}

if let Some(response_limiter) = self.response_limiter.as_mut() {
// First check that there are not already other responses waiting to be sent.
let protocol = request.r#type.protocol();
if self.delayed_responses.exists(peer_id, protocol) {
self.delayed_responses.add(
peer_id,
protocol,
connection_id,
request.substream_id,
event,
);
return;
}

match Self::try_response_limiter(
response_limiter,
&peer_id,
protocol,
if !response_limiter.allows(
peer_id,
request.r#type.protocol(),
connection_id,
request.substream_id,
event.clone(),
&self.log,
) {
Ok(()) => {}
Err(wait_time) => {
self.delayed_responses.push_back(
peer_id,
protocol,
connection_id,
request.substream_id,
event,
wait_time,
);
return;
}
return;
Copy link
Member

Choose a reason for hiding this comment

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

same here, we can return an Error for rate limited requests so that the caller can decide what to do if the request was not allowed, instead of silent ignoring it

Copy link
Member Author

Choose a reason for hiding this comment

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

In this case, where the response_limiter doesn’t allow the response, it is queued inside the limiter and will eventually be sent after a delay. So I don’t think it’s necessary to return an error.

Copy link
Member

Choose a reason for hiding this comment

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

yup, thanks for explaining Akihito

Copy link
Member

Choose a reason for hiding this comment

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

can we then leave a comment explain that Akihito, as we have on send_request?
Thanks!

}
}

Expand All @@ -289,36 +259,6 @@ impl<Id: ReqId, E: EthSpec> RPC<Id, E> {
});
}

/// Checks if the response limiter allows the response. If the response should be delayed, the
/// duration to wait is returned.
fn try_response_limiter(
limiter: &mut RateLimiter,
peer_id: &PeerId,
protocol: Protocol,
response: RpcResponse<E>,
log: &slog::Logger,
) -> Result<(), Duration> {
match limiter.allows(peer_id, &(response, protocol)) {
Ok(()) => Ok(()),
Err(e) => match e {
RateLimitedErr::TooLarge => {
// This should never happen with default parameters. Let's just send the response.
// Log a crit since this is a config issue.
crit!(
log,
"Response rate limiting error for a batch that will never fit. Sending response anyway. Check configuration parameters.";
"protocol" => %protocol
);
Ok(())
}
RateLimitedErr::TooSoon(wait_time) => {
debug!(log, "Response rate limiting"; "protocol" => %protocol, "wait_time_ms" => wait_time.as_millis(), "peer_id" => %peer_id);
Err(wait_time)
}
},
}
}

/// Submits an RPC request.
///
/// The peer must be connected for this to succeed.
Expand Down Expand Up @@ -616,56 +556,21 @@ where

fn poll(&mut self, cx: &mut Context) -> Poll<ToSwarm<Self::ToSwarm, THandlerInEvent<Self>>> {
if let Some(response_limiter) = self.response_limiter.as_mut() {
// let the rate limiter prune.
let _ = response_limiter.poll_unpin(cx);

let mut response_to_requeue = None;
let mut should_remove = false;
let mut key_to_remove = None;
if let Some(q) = self.delayed_responses.poll_next_response(cx) {
if let Some(response) = q.front() {
key_to_remove = Some((response.peer_id, response.protocol));
}
// Take delayed responses from the queue and send them, as long as the limiter allows it.
while let Some(response) = q.pop_front() {
match Self::try_response_limiter(
response_limiter,
&response.peer_id,
response.protocol,
response.response.clone(),
&self.log,
) {
Ok(()) => {
self.active_inbound_requests_limiter.remove_request(
response.peer_id,
&response.connection_id,
&response.substream_id,
);

self.events.push(ToSwarm::NotifyHandler {
peer_id: response.peer_id,
handler: NotifyHandler::One(response.connection_id),
event: RPCSend::Response(response.substream_id, response.response),
});
}
Err(wait_time) => {
response_to_requeue = Some((response, wait_time));
break;
}
}
}
should_remove = q.is_empty();
}
if should_remove {
// Remove the queue since now it's empty.
if let Some((peer_id, protocol)) = key_to_remove {
self.delayed_responses.remove(peer_id, protocol);
if let Poll::Ready(responses) = response_limiter.poll_ready(cx) {
for response in responses {
self.active_inbound_requests_limiter.remove_request(
response.peer_id,
&response.connection_id,
&response.substream_id,
);

self.events.push(ToSwarm::NotifyHandler {
peer_id: response.peer_id,
handler: NotifyHandler::One(response.connection_id),
event: RPCSend::Response(response.substream_id, response.response),
});
}
}
if let Some((response, wait_time)) = response_to_requeue {
// The response was taken from the queue, but the limiter didn't allow it.
self.delayed_responses.push_front(response, wait_time);
}
}

if let Some(self_limiter) = self.outbound_request_limiter.as_mut() {
Expand Down
Loading
Loading