Skip to content

Commit

Permalink
Rate limit ascending bootstrap requests
Browse files Browse the repository at this point in the history
  • Loading branch information
pwojcikdev committed Oct 30, 2024
1 parent 37ee220 commit 5f31cb1
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 17 deletions.
2 changes: 2 additions & 0 deletions nano/node/bootstrap/bootstrap_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ nano::error nano::bootstrap_config::deserialize (nano::tomlconfig & toml)
toml.get ("enable_frontier_scan", enable_frontier_scan);

toml.get ("channel_limit", channel_limit);
toml.get ("rate_limit", rate_limit);
toml.get ("database_rate_limit", database_rate_limit);
toml.get ("database_warmup_ratio", database_warmup_ratio);
toml.get ("max_pull_count", max_pull_count);
Expand Down Expand Up @@ -64,6 +65,7 @@ nano::error nano::bootstrap_config::serialize (nano::tomlconfig & toml) const
toml.put ("enable_frontier_scan", enable_frontier_scan, "Enable or disable the 'frontier scan` strategy for the ascending bootstrap.\ntype:bool");

toml.put ("channel_limit", channel_limit, "Maximum number of un-responded requests per channel.\nNote: changing to unlimited (0) is not recommended.\ntype:uint64");
toml.put ("rate_limit", rate_limit, "Rate limit on requests.\nNote: changing to unlimited (0) is not recommended as this operation competes for resources with realtime traffic.\ntype:uint64");
toml.put ("database_rate_limit", database_rate_limit, "Rate limit on scanning accounts and pending entries from database.\nNote: changing to unlimited (0) is not recommended as this operation competes for resources on querying the database.\ntype:uint64");
toml.put ("database_warmup_ratio", database_warmup_ratio, "Ratio of the database rate limit to use for the initial warmup.\ntype:uint64");
toml.put ("max_pull_count", max_pull_count, "Maximum number of requested blocks for bootstrap request.\ntype:uint64");
Expand Down
3 changes: 2 additions & 1 deletion nano/node/bootstrap/bootstrap_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ class bootstrap_config final

// Maximum number of un-responded requests per channel, should be lower or equal to bootstrap server max queue size
std::size_t channel_limit{ 16 };
std::size_t database_rate_limit{ 256 };
std::size_t rate_limit{ 500 };
std::size_t database_rate_limit{ 250 };
std::size_t frontier_rate_limit{ 8 };
std::size_t database_warmup_ratio{ 10 };
std::size_t max_pull_count{ nano::bootstrap_server::max_blocks };
Expand Down
28 changes: 14 additions & 14 deletions nano/node/bootstrap/bootstrap_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ nano::bootstrap_service::bootstrap_service (nano::node_config const & node_confi
frontiers{ config.frontier_scan, stats },
throttle{ compute_throttle_size () },
scoring{ config, node_config_a.network_params.network },
limiter{ config.rate_limit },
database_limiter{ config.database_rate_limit },
frontiers_limiter{ config.frontier_rate_limit },
workers{ 1, nano::thread_role::name::bootstrap_worker }
Expand Down Expand Up @@ -301,14 +302,6 @@ void nano::bootstrap_service::wait (std::function<bool ()> const & predicate) co
}
}

void nano::bootstrap_service::wait_tags () const
{
wait ([this] () {
debug_assert (!mutex.try_lock ());
return tags.size () < config.max_requests;
});
}

void nano::bootstrap_service::wait_blockprocessor () const
{
wait ([this] () {
Expand All @@ -318,9 +311,19 @@ void nano::bootstrap_service::wait_blockprocessor () const

std::shared_ptr<nano::transport::channel> nano::bootstrap_service::wait_channel ()
{
// Limit the number of in-flight requests
wait ([this] () {
return tags.size () < config.max_requests;
});

// Wait until more requests can be sent
wait ([this] () {
return limiter.should_pass (1);
});

// Wait until a channel is available
std::shared_ptr<nano::transport::channel> channel;
wait ([this, &channel] () {
debug_assert (!mutex.try_lock ());
channel = scoring.channel ();
return channel != nullptr; // Wait until a channel is available
});
Expand Down Expand Up @@ -528,7 +531,6 @@ bool nano::bootstrap_service::request_frontiers (nano::account start, std::share

void nano::bootstrap_service::run_one_priority ()
{
wait_tags ();
wait_blockprocessor ();
auto channel = wait_channel ();
if (!channel)
Expand Down Expand Up @@ -559,7 +561,6 @@ void nano::bootstrap_service::run_priorities ()

void nano::bootstrap_service::run_one_database (bool should_throttle)
{
wait_tags ();
wait_blockprocessor ();
auto channel = wait_channel ();
if (!channel)
Expand Down Expand Up @@ -590,8 +591,7 @@ void nano::bootstrap_service::run_database ()

void nano::bootstrap_service::run_one_blocking ()
{
wait_tags ();
wait_blockprocessor ();
// No need to wait for blockprocessor, as we are not processing blocks
auto channel = wait_channel ();
if (!channel)
{
Expand Down Expand Up @@ -619,6 +619,7 @@ void nano::bootstrap_service::run_dependencies ()

void nano::bootstrap_service::run_one_frontier ()
{
// No need to wait for blockprocessor, as we are not processing blocks
wait ([this] () {
return !accounts.priority_half_full ();
});
Expand All @@ -628,7 +629,6 @@ void nano::bootstrap_service::run_one_frontier ()
wait ([this] () {
return workers.queued_tasks () < config.frontier_scan.max_pending;
});
wait_tags ();
auto channel = wait_channel ();
if (!channel)
{
Expand Down
4 changes: 2 additions & 2 deletions nano/node/bootstrap/bootstrap_service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,6 @@ class bootstrap_service
/* Waits for a condition to be satisfied with incremental backoff */
void wait (std::function<bool ()> const & predicate) const;

/* Avoid too many in-flight requests */
void wait_tags () const;
/* Ensure there is enough space in blockprocessor for queuing new blocks */
void wait_blockprocessor () const;
/* Waits for a channel that is not full */
Expand Down Expand Up @@ -191,6 +189,8 @@ class bootstrap_service
// clang-format on
ordered_tags tags;

// Rate limiter for all types of requests
nano::rate_limiter limiter;
// Requests for accounts from database have much lower hitrate and could introduce strain on the network
// A separate (lower) limiter ensures that we always reserve resources for querying accounts from priority queue
nano::rate_limiter database_limiter;
Expand Down

0 comments on commit 5f31cb1

Please sign in to comment.