-
Notifications
You must be signed in to change notification settings - Fork 4.5k
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
Weight concurrent streams by stake #25993
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,15 @@ | ||
use { | ||
crate::quic::{configure_server, QuicServerError, StreamStats}, | ||
crate::{ | ||
quic::{configure_server, QuicServerError, StreamStats}, | ||
streamer::StakedNodes, | ||
}, | ||
crossbeam_channel::Sender, | ||
futures_util::stream::StreamExt, | ||
quinn::{Endpoint, EndpointConfig, Incoming, IncomingUniStreams, NewConnection}, | ||
quinn::{Endpoint, EndpointConfig, Incoming, IncomingUniStreams, NewConnection, VarInt}, | ||
solana_perf::packet::PacketBatch, | ||
solana_sdk::{ | ||
packet::{Packet, PACKET_DATA_SIZE}, | ||
quic::QUIC_MAX_UNSTAKED_CONCURRENT_STREAMS, | ||
signature::Keypair, | ||
timing, | ||
}, | ||
|
@@ -21,6 +25,8 @@ use { | |
tokio::{task::JoinHandle, time::timeout}, | ||
}; | ||
|
||
const QUIC_TOTAL_STAKED_CONCURRENT_STREAMS: f64 = 100_000f64; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How was this number chosen? With 383.3M SOL staked on mainnet, that means every 3833 SOL staked gives you a stream, which means that any node with less than that amount staked gets 0 streams and counts as unstaked. According to Solana Beach, on mainnet, the 1776th staked node has just about enough stake for one stream, which means that ~90% of validators on the network get a stream (including a long tail of delinquent or totally unstaked validators). So this number might even be a little too high, unless we know that a validator can handle a total of 100k concurrent streams. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 100k streams * 1280 bytes per packet would be ~128MB and ~81MB for unstaked (128 * 500 * 1280) so that sounds pretty conservative in terms of packet memory use. Each stream and connection has other additional overhead as well though. |
||
|
||
#[allow(clippy::too_many_arguments)] | ||
pub fn spawn_server( | ||
sock: UdpSocket, | ||
|
@@ -29,7 +35,7 @@ pub fn spawn_server( | |
packet_sender: Sender<PacketBatch>, | ||
exit: Arc<AtomicBool>, | ||
max_connections_per_ip: usize, | ||
staked_nodes: Arc<RwLock<HashMap<IpAddr, u64>>>, | ||
staked_nodes: Arc<RwLock<StakedNodes>>, | ||
max_staked_connections: usize, | ||
max_unstaked_connections: usize, | ||
stats: Arc<StreamStats>, | ||
|
@@ -59,7 +65,7 @@ pub async fn run_server( | |
packet_sender: Sender<PacketBatch>, | ||
exit: Arc<AtomicBool>, | ||
max_connections_per_ip: usize, | ||
staked_nodes: Arc<RwLock<HashMap<IpAddr, u64>>>, | ||
staked_nodes: Arc<RwLock<StakedNodes>>, | ||
max_staked_connections: usize, | ||
max_unstaked_connections: usize, | ||
stats: Arc<StreamStats>, | ||
|
@@ -97,18 +103,30 @@ pub async fn run_server( | |
|
||
let (mut connection_table_l, stake) = { | ||
let staked_nodes = staked_nodes.read().unwrap(); | ||
if let Some(stake) = staked_nodes.get(&remote_addr.ip()) { | ||
if let Some(stake) = staked_nodes.stake_map.get(&remote_addr.ip()) { | ||
let stake = *stake; | ||
let total_stake = staked_nodes.total_stake; | ||
drop(staked_nodes); | ||
let mut connection_table_l = staked_connection_table.lock().unwrap(); | ||
let num_pruned = connection_table_l.prune_oldest(max_staked_connections); | ||
stats.num_evictions.fetch_add(num_pruned, Ordering::Relaxed); | ||
connection.set_max_concurrent_uni_streams( | ||
VarInt::from_u64( | ||
((stake as f64 / total_stake as f64) | ||
* QUIC_TOTAL_STAKED_CONCURRENT_STREAMS) | ||
as u64, | ||
) | ||
.unwrap(), | ||
); | ||
(connection_table_l, stake) | ||
} else { | ||
drop(staked_nodes); | ||
let mut connection_table_l = connection_table.lock().unwrap(); | ||
let num_pruned = connection_table_l.prune_oldest(max_unstaked_connections); | ||
stats.num_evictions.fetch_add(num_pruned, Ordering::Relaxed); | ||
connection.set_max_concurrent_uni_streams( | ||
VarInt::from_u64(QUIC_MAX_UNSTAKED_CONCURRENT_STREAMS as u64).unwrap(), | ||
); | ||
(connection_table_l, 0) | ||
} | ||
}; | ||
|
@@ -449,7 +467,7 @@ pub mod test { | |
let keypair = Keypair::new(); | ||
let ip = "127.0.0.1".parse().unwrap(); | ||
let server_address = s.local_addr().unwrap(); | ||
let staked_nodes = Arc::new(RwLock::new(HashMap::new())); | ||
let staked_nodes = Arc::new(RwLock::new(StakedNodes::default())); | ||
let stats = Arc::new(StreamStats::default()); | ||
let t = spawn_server( | ||
s, | ||
|
@@ -648,7 +666,7 @@ pub mod test { | |
let keypair = Keypair::new(); | ||
let ip = "127.0.0.1".parse().unwrap(); | ||
let server_address = s.local_addr().unwrap(); | ||
let staked_nodes = Arc::new(RwLock::new(HashMap::new())); | ||
let staked_nodes = Arc::new(RwLock::new(StakedNodes::default())); | ||
let stats = Arc::new(StreamStats::default()); | ||
let t = spawn_server( | ||
s, | ||
|
@@ -678,7 +696,7 @@ pub mod test { | |
let keypair = Keypair::new(); | ||
let ip = "127.0.0.1".parse().unwrap(); | ||
let server_address = s.local_addr().unwrap(); | ||
let staked_nodes = Arc::new(RwLock::new(HashMap::new())); | ||
let staked_nodes = Arc::new(RwLock::new(StakedNodes::default())); | ||
let stats = Arc::new(StreamStats::default()); | ||
let t = spawn_server( | ||
s, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
use { | ||
crate::streamer::StakedNodes, | ||
crossbeam_channel::Sender, | ||
pem::Pem, | ||
pkcs8::{der::Document, AlgorithmIdentifier, ObjectIdentifier}, | ||
|
@@ -7,11 +8,10 @@ use { | |
solana_perf::packet::PacketBatch, | ||
solana_sdk::{ | ||
packet::PACKET_DATA_SIZE, | ||
quic::{QUIC_MAX_CONCURRENT_STREAMS, QUIC_MAX_TIMEOUT_MS}, | ||
quic::{QUIC_MAX_TIMEOUT_MS, QUIC_MAX_UNSTAKED_CONCURRENT_STREAMS}, | ||
signature::Keypair, | ||
}, | ||
std::{ | ||
collections::HashMap, | ||
error::Error, | ||
net::{IpAddr, UdpSocket}, | ||
sync::{ | ||
|
@@ -49,7 +49,7 @@ pub(crate) fn configure_server( | |
let config = Arc::get_mut(&mut server_config.transport).unwrap(); | ||
|
||
// QUIC_MAX_CONCURRENT_STREAMS doubled, which was found to improve reliability | ||
const MAX_CONCURRENT_UNI_STREAMS: u32 = (QUIC_MAX_CONCURRENT_STREAMS * 2) as u32; | ||
const MAX_CONCURRENT_UNI_STREAMS: u32 = (QUIC_MAX_UNSTAKED_CONCURRENT_STREAMS * 2) as u32; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. unrelated. i can't help but ask why this doubling is here rather than SDK where the variable is declared? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ryleung-solana can you please remove the doubling now that streams don't have head-of-line blocking? #26086 |
||
config.max_concurrent_uni_streams(MAX_CONCURRENT_UNI_STREAMS.into()); | ||
config.stream_receive_window((PACKET_DATA_SIZE as u32).into()); | ||
config.receive_window((PACKET_DATA_SIZE as u32 * MAX_CONCURRENT_UNI_STREAMS).into()); | ||
|
@@ -258,7 +258,7 @@ pub fn spawn_server( | |
packet_sender: Sender<PacketBatch>, | ||
exit: Arc<AtomicBool>, | ||
max_connections_per_ip: usize, | ||
staked_nodes: Arc<RwLock<HashMap<IpAddr, u64>>>, | ||
staked_nodes: Arc<RwLock<StakedNodes>>, | ||
max_staked_connections: usize, | ||
max_unstaked_connections: usize, | ||
stats: Arc<StreamStats>, | ||
|
@@ -306,7 +306,7 @@ mod test { | |
let keypair = Keypair::new(); | ||
let ip = "127.0.0.1".parse().unwrap(); | ||
let server_address = s.local_addr().unwrap(); | ||
let staked_nodes = Arc::new(RwLock::new(HashMap::new())); | ||
let staked_nodes = Arc::new(RwLock::new(StakedNodes::default())); | ||
let stats = Arc::new(StreamStats::default()); | ||
let t = spawn_server( | ||
s, | ||
|
@@ -361,7 +361,7 @@ mod test { | |
let keypair = Keypair::new(); | ||
let ip = "127.0.0.1".parse().unwrap(); | ||
let server_address = s.local_addr().unwrap(); | ||
let staked_nodes = Arc::new(RwLock::new(HashMap::new())); | ||
let staked_nodes = Arc::new(RwLock::new(StakedNodes::default())); | ||
let stats = Arc::new(StreamStats::default()); | ||
let t = spawn_server( | ||
s, | ||
|
@@ -403,7 +403,7 @@ mod test { | |
let keypair = Keypair::new(); | ||
let ip = "127.0.0.1".parse().unwrap(); | ||
let server_address = s.local_addr().unwrap(); | ||
let staked_nodes = Arc::new(RwLock::new(HashMap::new())); | ||
let staked_nodes = Arc::new(RwLock::new(StakedNodes::default())); | ||
let stats = Arc::new(StreamStats::default()); | ||
let t = spawn_server( | ||
s, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,13 @@ use { | |
thiserror::Error, | ||
}; | ||
|
||
// Total stake and nodes => stake map | ||
#[derive(Default)] | ||
pub struct StakedNodes { | ||
pub total_stake: f64, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: why is this an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess this is mostly due to its float arithmetic? Like?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should just flip the ops and drop the floats. floats are the devil |
||
pub stake_map: HashMap<IpAddr, u64>, | ||
} | ||
|
||
pub type PacketBatchReceiver = Receiver<PacketBatch>; | ||
pub type PacketBatchSender = Sender<PacketBatch>; | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What impact does this have on TPU clients? Are there some stats about TPS or network performance with and without this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not see a huge impact of w/o this change in my tpu-client test:
With this branch
2022-06-17T20:47:16.938332781Z INFO solana_bench_tps::bench] ---------------------+---------------+--------------------
[2022-06-17T20:47:16.938343148Z INFO solana_bench_tps::bench] http://35.247.120.58:8899 | 67938.42 | 1213244
[2022-06-17T20:47:16.938348907Z INFO solana_bench_tps::bench]
Average max TPS: 67938.42, 0 nodes had 0 TPS
[2022-06-17T20:47:16.938360601Z INFO solana_bench_tps::bench]
Highest TPS: 67938.42 sampling period 1s max transactions: 1213244 clients: 1 drop rate: 0.60
[2022-06-17T20:47:16.938367384Z INFO solana_bench_tps::bench] Average TPS: 19827.145
[2022-06-17T20:55:40.669179958Z INFO solana_bench_tps::bench] http://35.247.120.58:8899 | 55039.97 | 1311307
[2022-06-17T20:55:40.669184817Z INFO solana_bench_tps::bench]
Average max TPS: 55039.97, 0 nodes had 0 TPS
[2022-06-17T20:55:40.669194603Z INFO solana_bench_tps::bench]
Highest TPS: 55039.97 sampling period 1s max transactions: 1311307 clients: 1 drop rate: 0.29
[2022-06-17T20:55:40.669198742Z INFO solana_bench_tps::bench] Average TPS: 21661.62
[2022-06-18T01:07:46.093266884Z INFO solana_bench_tps::bench] Node address | Max TPS | Total Transactions
[2022-06-18T01:07:46.093280556Z INFO solana_bench_tps::bench] ---------------------+---------------+--------------------
[2022-06-18T01:07:46.093285691Z INFO solana_bench_tps::bench] http://35.247.120.58:8899 | 58969.85 | 1367411
[2022-06-18T01:07:46.093301930Z INFO solana_bench_tps::bench]
Average max TPS: 58969.85, 0 nodes had 0 TPS
[2022-06-18T01:07:46.093292778Z INFO solana_metrics::metrics] datapoint: bench-tps-lamport_balance balance=14373355930776120i
[2022-06-18T01:07:46.093311329Z INFO solana_bench_tps::bench]
Highest TPS: 58969.85 sampling period 1s max transactions: 1367411 clients: 1 drop rate: 0.76
[2022-06-18T01:07:46.093349226Z INFO solana_bench_tps::bench] Average TPS: 22578.842
Master
[2022-06-17T21:33:02.909510265Z INFO solana_bench_tps::bench] Node address | Max TPS | Total Transactions
[2022-06-17T21:33:02.909517556Z INFO solana_bench_tps::bench] ---------------------+---------------+--------------------
[2022-06-17T21:33:02.909520144Z INFO solana_bench_tps::bench] http://35.247.120.58:8899 | 44006.95 | 1102674
[2022-06-17T21:33:02.909535908Z INFO solana_bench_tps::bench]
Average max TPS: 44006.95, 0 nodes had 0 TPS
[2022-06-17T21:33:02.909548109Z INFO solana_bench_tps::bench]
Highest TPS: 44006.95 sampling period 1s max transactions: 1102674 clients: 1 drop rate: 0.35
[2022-06-17T21:33:02.909526414Z INFO solana_metrics::metrics] datapoint: bench-tps-lamport_balance balance=14373355930776120i
[2022-06-17T21:33:02.909555115Z INFO solana_bench_tps::bench] Average TPS: 18090.404
[2022-06-17T21:38:51.706520412Z INFO solana_bench_tps::bench] Token balance: 14373355930776120
[2022-06-17T21:38:51.706553141Z INFO solana_bench_tps::bench] Node address | Max TPS | Total Transactions
[2022-06-17T21:38:51.706559304Z INFO solana_bench_tps::bench] ---------------------+---------------+--------------------
[2022-06-17T21:38:51.706562073Z INFO solana_bench_tps::bench] http://35.247.120.58:8899 | 65728.62 | 1300790
[2022-06-17T21:38:51.706573521Z INFO solana_bench_tps::bench]
Average max TPS: 65728.62, 0 nodes had 0 TPS
[2022-06-17T21:38:51.706581605Z INFO solana_bench_tps::bench]
Highest TPS: 65728.62 sampling period 1s max transactions: 1300790 clients: 1 drop rate: 0.34
[2022-06-17T21:38:51.706595604Z INFO solana_bench_tps::bench] Average TPS: 21306.563