Skip to content

Commit f0d01aa

Browse files
jjbayerRiccardo Busetti
andauthored
feat(buffer): Spool compressed envelopes (#4171)
Enable compression for spooled envelopes (experimental spooler). As the results of [this PR](#4162) showed, avg. compression ratio is 4x on PoPs and 6x on processing relays. Average compression time is 10 microseconds and 30 microseconds, respectively. This PR also changes how disk writes are batched: It counts encoded bytes instead of number of envelopes to decide whether to write a batch to disk. For disk _reads_, still count the number of envelopes for now. Using bytes for read batching would require [window functions](https://www.sqlite.org/windowfunctions.html) or similar. --------- Co-authored-by: Riccardo Busetti <[email protected]>
1 parent 277c54d commit f0d01aa

File tree

8 files changed

+329
-248
lines changed

8 files changed

+329
-248
lines changed

relay-config/src/config.rs

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -872,14 +872,14 @@ fn spool_envelopes_unspool_interval() -> u64 {
872872
100
873873
}
874874

875-
/// Default batch size for the stack.
876-
fn spool_envelopes_stack_disk_batch_size() -> usize {
875+
/// Default number of envelope to read from disk at once.
876+
fn spool_envelopes_read_batch_size() -> usize {
877877
200
878878
}
879879

880-
/// Default maximum number of batches for the stack.
881-
fn spool_envelopes_stack_max_batches() -> usize {
882-
2
880+
/// Default number of encoded envelope bytes to cache before writing to disk.
881+
fn spool_envelopes_write_batch_bytes() -> ByteSize {
882+
ByteSize::kibibytes(10)
883883
}
884884

885885
fn spool_envelopes_max_envelope_delay_secs() -> u64 {
@@ -927,13 +927,16 @@ pub struct EnvelopeSpool {
927927
/// The interval in milliseconds to trigger unspool.
928928
#[serde(default = "spool_envelopes_unspool_interval")]
929929
unspool_interval: u64,
930-
/// Number of elements of the envelope stack that are flushed to disk.
931-
#[serde(default = "spool_envelopes_stack_disk_batch_size")]
932-
disk_batch_size: usize,
933-
/// Number of batches of size [`Self::disk_batch_size`] that need to be accumulated before
934-
/// flushing one batch to disk.
935-
#[serde(default = "spool_envelopes_stack_max_batches")]
936-
max_batches: usize,
930+
/// Number of envelopes that are read from disk at once.
931+
///
932+
/// Defaults to 10.
933+
#[serde(default = "spool_envelopes_read_batch_size")]
934+
read_batch_size: usize,
935+
/// Number of encoded envelope bytes that are spooled to disk at once.
936+
///
937+
/// Defaults to 10 KiB.
938+
#[serde(default = "spool_envelopes_write_batch_bytes")]
939+
write_batch_bytes: ByteSize,
937940
/// Maximum time between receiving the envelope and processing it.
938941
///
939942
/// When envelopes spend too much time in the buffer (e.g. because their project cannot be loaded),
@@ -953,7 +956,7 @@ pub struct EnvelopeSpool {
953956
/// This value should be lower than [`Health::max_memory_percent`] to prevent flip-flopping.
954957
///
955958
/// Warning: this threshold can cause the buffer service to deadlock when the buffer itself
956-
/// is using too much memory (influenced by [`Self::max_batches`] and [`Self::disk_batch_size`]).
959+
/// is using too much memory (influenced by [`Self::read_batch_size`] and [`Self::write_batch_bytes`]).
957960
///
958961
/// Defaults to 90% (5% less than max memory).
959962
#[serde(default = "spool_max_backpressure_memory_percent")]
@@ -989,9 +992,9 @@ impl Default for EnvelopeSpool {
989992
min_connections: spool_envelopes_min_connections(),
990993
max_disk_size: spool_envelopes_max_disk_size(),
991994
max_memory_size: spool_envelopes_max_memory_size(),
992-
unspool_interval: spool_envelopes_unspool_interval(), // 100ms
993-
disk_batch_size: spool_envelopes_stack_disk_batch_size(),
994-
max_batches: spool_envelopes_stack_max_batches(),
995+
unspool_interval: spool_envelopes_unspool_interval(),
996+
read_batch_size: spool_envelopes_read_batch_size(),
997+
write_batch_bytes: spool_envelopes_write_batch_bytes(),
995998
max_envelope_delay_secs: spool_envelopes_max_envelope_delay_secs(),
996999
disk_usage_refresh_frequency_ms: spool_disk_usage_refresh_frequency_ms(),
9971000
max_backpressure_envelopes: spool_max_backpressure_envelopes(),
@@ -2174,22 +2177,21 @@ impl Config {
21742177
self.values.spool.envelopes.max_memory_size.as_bytes()
21752178
}
21762179

2177-
/// Number of batches of size `stack_disk_batch_size` that need to be accumulated before
2178-
/// flushing one batch to disk.
2179-
pub fn spool_envelopes_stack_disk_batch_size(&self) -> usize {
2180-
self.values.spool.envelopes.disk_batch_size
2180+
/// Number of envelopes to read from disk at once.
2181+
pub fn spool_envelopes_read_batch_size(&self) -> usize {
2182+
self.values.spool.envelopes.read_batch_size
21812183
}
21822184

2183-
/// Number of batches of size `stack_disk_batch_size` that need to be accumulated before
2185+
/// Number of encoded envelope bytes that need to be accumulated before
21842186
/// flushing one batch to disk.
2185-
pub fn spool_envelopes_stack_max_batches(&self) -> usize {
2186-
self.values.spool.envelopes.max_batches
2187+
pub fn spool_envelopes_write_batch_bytes(&self) -> usize {
2188+
self.values.spool.envelopes.write_batch_bytes.as_bytes()
21872189
}
21882190

21892191
/// Returns `true` if version 2 of the spooling mechanism is used.
21902192
pub fn spool_v2(&self) -> bool {
21912193
matches!(
2192-
self.values.spool.envelopes.version,
2194+
&self.values.spool.envelopes.version,
21932195
EnvelopeSpoolVersion::V2
21942196
)
21952197
}

relay-server/benches/benches.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ fn benchmark_sqlite_envelope_stack(c: &mut Criterion) {
100100

101101
let stack = SqliteEnvelopeStack::new(
102102
envelope_store.clone(),
103+
10,
103104
disk_batch_size,
104-
2,
105105
ProjectKey::parse("e12d836b15bb49d7bbf99e64295d995b").unwrap(),
106106
ProjectKey::parse("e12d836b15bb49d7bbf99e64295d995b").unwrap(),
107107
true,
@@ -137,8 +137,8 @@ fn benchmark_sqlite_envelope_stack(c: &mut Criterion) {
137137

138138
let mut stack = SqliteEnvelopeStack::new(
139139
envelope_store.clone(),
140+
10,
140141
disk_batch_size,
141-
2,
142142
ProjectKey::parse("e12d836b15bb49d7bbf99e64295d995b").unwrap(),
143143
ProjectKey::parse("e12d836b15bb49d7bbf99e64295d995b").unwrap(),
144144
true,
@@ -178,8 +178,8 @@ fn benchmark_sqlite_envelope_stack(c: &mut Criterion) {
178178

179179
let stack = SqliteEnvelopeStack::new(
180180
envelope_store.clone(),
181+
10,
181182
disk_batch_size,
182-
2,
183183
ProjectKey::parse("e12d836b15bb49d7bbf99e64295d995b").unwrap(),
184184
ProjectKey::parse("e12d836b15bb49d7bbf99e64295d995b").unwrap(),
185185
true,

0 commit comments

Comments
 (0)