Scale bootstrap connections based on load. (#552)
This commit is contained in:
parent
b07167a90d
commit
551412128c
5 changed files with 56 additions and 8 deletions
|
@ -1459,3 +1459,24 @@ TEST (node, balance_observer)
|
|||
ASSERT_GT (200, iterations);
|
||||
}
|
||||
}
|
||||
|
||||
TEST (node, bootstrap_connection_scaling)
|
||||
{
|
||||
rai::system system (24000, 1);
|
||||
auto & node1 (*system.nodes[0]);
|
||||
node1.bootstrap_initiator.bootstrap ();
|
||||
auto & attempt = node1.bootstrap_initiator.attempt;
|
||||
ASSERT_EQ (34, attempt->target_connections (25000));
|
||||
ASSERT_EQ (4, attempt->target_connections (0));
|
||||
ASSERT_EQ (64, attempt->target_connections (50000));
|
||||
ASSERT_EQ (64, attempt->target_connections (10000000000));
|
||||
node1.config.bootstrap_connections = 128;
|
||||
ASSERT_EQ (64, attempt->target_connections (0));
|
||||
ASSERT_EQ (64, attempt->target_connections (50000));
|
||||
node1.config.bootstrap_connections_max = 256;
|
||||
ASSERT_EQ (128, attempt->target_connections (0));
|
||||
ASSERT_EQ (256, attempt->target_connections (50000));
|
||||
node1.config.bootstrap_connections_max = 0;
|
||||
ASSERT_EQ (1, attempt->target_connections (0));
|
||||
ASSERT_EQ (1, attempt->target_connections (50000));
|
||||
}
|
||||
|
|
|
@ -5,9 +5,14 @@
|
|||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
// Updated 1-27-18
|
||||
constexpr double bootstrap_connection_scale_target = 50000.0;
|
||||
constexpr double bootstrap_connection_warmup_time = 5.0;
|
||||
constexpr double bootstrap_minimum_block_rate = 10.0;
|
||||
constexpr double bootstrap_minimum_termination_time = 30.0;
|
||||
constexpr unsigned bootstrap_max_new_connections = 10;
|
||||
constexpr unsigned bootstrap_peer_frontier_minimum = rai::rai_network == rai::rai_networks::rai_live_network ? 339000 : 0;
|
||||
|
||||
|
||||
rai::block_synchronization::block_synchronization (boost::log::sources::logger_mt & log_a) :
|
||||
log (log_a)
|
||||
{
|
||||
|
@ -971,12 +976,26 @@ struct block_rate_cmp
|
|||
}
|
||||
};
|
||||
|
||||
unsigned rai::bootstrap_attempt::target_connections (size_t pulls_remaining)
|
||||
{
|
||||
if (node->config.bootstrap_connections >= node->config.bootstrap_connections_max) {
|
||||
return std::max(1U, node->config.bootstrap_connections_max);
|
||||
}
|
||||
|
||||
// Only scale up to bootstrap_connections_max for large pulls.
|
||||
double step = std::min (1.0, std::max (0.0, (double)pulls_remaining / bootstrap_connection_scale_target));
|
||||
double target = (double)node->config.bootstrap_connections + (double)(node->config.bootstrap_connections_max - node->config.bootstrap_connections) * step;
|
||||
return std::max(1U, (unsigned)(target + 0.5f));
|
||||
}
|
||||
|
||||
void rai::bootstrap_attempt::populate_connections ()
|
||||
{
|
||||
double rate_sum = 0.0;
|
||||
size_t num_pulls = 0;
|
||||
std::priority_queue<std::shared_ptr<rai::bootstrap_client>, std::vector<std::shared_ptr<rai::bootstrap_client>>, block_rate_cmp> sorted_connections;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock (mutex);
|
||||
num_pulls = pulls.size ();
|
||||
for (auto & c : clients)
|
||||
{
|
||||
if (auto client = c.lock ())
|
||||
|
@ -984,13 +1003,13 @@ void rai::bootstrap_attempt::populate_connections ()
|
|||
double elapsed = client->elapsed_seconds ();
|
||||
auto rate = client->block_rate ();
|
||||
rate_sum += rate;
|
||||
if (client->elapsed_seconds () > 5.0 && client->block_count > 0)
|
||||
if (client->elapsed_seconds () > bootstrap_connection_warmup_time && client->block_count > 0)
|
||||
{
|
||||
sorted_connections.push (client);
|
||||
}
|
||||
// Force-stop the slowest peers, since they can take the whole bootstrap hostage by dribbling out blocks on the last remaining pull.
|
||||
// This is ~1.5kilobits/sec.
|
||||
if (elapsed > 30.0 && rate < 10.0)
|
||||
if (elapsed > bootstrap_minimum_termination_time && rate < bootstrap_minimum_block_rate)
|
||||
{
|
||||
client->stop (true);
|
||||
}
|
||||
|
@ -998,12 +1017,14 @@ void rai::bootstrap_attempt::populate_connections ()
|
|||
}
|
||||
}
|
||||
|
||||
auto target = target_connections (num_pulls);
|
||||
|
||||
// We only want to drop slow peers when more than 2/3 are active. 2/3 because 1/2 is too aggressive, and 100% rarely happens.
|
||||
// Probably needs more tuning.
|
||||
if (sorted_connections.size () >= (node->config.bootstrap_connections * 2) / 3 && node->config.bootstrap_connections >= 4)
|
||||
if (sorted_connections.size () >= (target * 2) / 3 && target >= 4)
|
||||
{
|
||||
// 4 -> 1, 8 -> 2, 16 -> 4, arbitrary, but seems to work well.
|
||||
auto drop = (int)roundf (sqrtf ((float)node->config.bootstrap_connections - 2.0f));
|
||||
auto drop = (int)roundf (sqrtf ((float)target - 2.0f));
|
||||
for (int i = 0; i < drop; i++)
|
||||
{
|
||||
auto client = sorted_connections.top ();
|
||||
|
@ -1018,9 +1039,9 @@ void rai::bootstrap_attempt::populate_connections ()
|
|||
BOOST_LOG (node->log) << boost::str (boost::format ("Bulk pull connections: %1%, rate: %2% blocks/sec, remaining account pulls: %3%, total blocks: %4%") % connections.load () % (int)rate_sum % pulls.size () % (int)total_blocks.load ());
|
||||
}
|
||||
|
||||
if (connections < node->config.bootstrap_connections)
|
||||
if (connections < target)
|
||||
{
|
||||
auto delta = std::min ((node->config.bootstrap_connections - connections) * 2, 10U);
|
||||
auto delta = std::min ((target - connections) * 2, bootstrap_max_new_connections);
|
||||
// TODO - tune this better
|
||||
// Not many peers respond, need to try to make more connections than we need.
|
||||
for (int i = 0; i < delta; i++)
|
||||
|
|
|
@ -88,6 +88,7 @@ public:
|
|||
void add_pull (rai::pull_info const &);
|
||||
bool still_pulling ();
|
||||
void process_fork (MDB_txn *, std::shared_ptr<rai::block>);
|
||||
unsigned target_connections (size_t pulls_remaining);
|
||||
std::deque<std::weak_ptr<rai::bootstrap_client>> clients;
|
||||
std::weak_ptr<rai::bootstrap_client> connection_frontier_request;
|
||||
std::weak_ptr<rai::frontier_req_client> frontiers;
|
||||
|
|
|
@ -750,7 +750,8 @@ password_fanout (1024),
|
|||
io_threads (std::max<unsigned> (4, std::thread::hardware_concurrency ())),
|
||||
work_threads (std::max<unsigned> (4, std::thread::hardware_concurrency ())),
|
||||
enable_voting (true),
|
||||
bootstrap_connections (16),
|
||||
bootstrap_connections (4),
|
||||
bootstrap_connections_max (64),
|
||||
callback_port (0),
|
||||
lmdb_max_dbs (128)
|
||||
{
|
||||
|
@ -822,6 +823,7 @@ void rai::node_config::serialize_json (boost::property_tree::ptree & tree_a) con
|
|||
tree_a.put ("work_threads", std::to_string (work_threads));
|
||||
tree_a.put ("enable_voting", enable_voting);
|
||||
tree_a.put ("bootstrap_connections", bootstrap_connections);
|
||||
tree_a.put ("bootstrap_connections_max", bootstrap_connections_max);
|
||||
tree_a.put ("callback_address", callback_address);
|
||||
tree_a.put ("callback_port", std::to_string (callback_port));
|
||||
tree_a.put ("callback_target", callback_target);
|
||||
|
@ -966,6 +968,7 @@ bool rai::node_config::deserialize_json (bool & upgraded_a, boost::property_tree
|
|||
auto work_threads_l (tree_a.get<std::string> ("work_threads"));
|
||||
enable_voting = tree_a.get<bool> ("enable_voting");
|
||||
auto bootstrap_connections_l (tree_a.get<std::string> ("bootstrap_connections"));
|
||||
auto bootstrap_connections_max_l (tree_a.get<std::string> ("bootstrap_connections_max"));
|
||||
callback_address = tree_a.get<std::string> ("callback_address");
|
||||
auto callback_port_l (tree_a.get<std::string> ("callback_port"));
|
||||
callback_target = tree_a.get<std::string> ("callback_target");
|
||||
|
@ -979,6 +982,7 @@ bool rai::node_config::deserialize_json (bool & upgraded_a, boost::property_tree
|
|||
io_threads = std::stoul (io_threads_l);
|
||||
work_threads = std::stoul (work_threads_l);
|
||||
bootstrap_connections = std::stoul (bootstrap_connections_l);
|
||||
bootstrap_connections_max = std::stoul (bootstrap_connections_max_l);
|
||||
lmdb_max_dbs = std::stoi (lmdb_max_dbs_l);
|
||||
result |= peering_port > std::numeric_limits<uint16_t>::max ();
|
||||
result |= logging.deserialize_json (upgraded_a, logging_l);
|
||||
|
|
|
@ -400,6 +400,7 @@ public:
|
|||
unsigned work_threads;
|
||||
bool enable_voting;
|
||||
unsigned bootstrap_connections;
|
||||
unsigned bootstrap_connections_max;
|
||||
std::string callback_address;
|
||||
uint16_t callback_port;
|
||||
std::string callback_target;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue