forked from iopsystems/rpc-perf
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add blabber protocol support (iopsystems#136)
Adds support for the `blabber` protocol in which the server will periodically publish messages to subscribers. This is implemented as a pubsub protocol. Adds latency distribution information to the dataspec for pubsub.
- Loading branch information
Showing
14 changed files
with
457 additions
and
161 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# An example configuration for a Pelikan Blabber client which is unidirectional | ||
# publishing of small messages to all clients. | ||
|
||
[general] | ||
# specify the protocol to be used | ||
protocol = "blabber" | ||
# the interval for stats integration and reporting | ||
interval = 1 | ||
# the number of intervals to run the test for | ||
duration = 300 | ||
# optionally, we can write some detailed stats to a file during the run | ||
#json_output = "stats.json" | ||
# run the admin thread with a HTTP listener at the address provided, this allows | ||
# stats exposition via HTTP | ||
admin = "127.0.0.1:9090" | ||
# optionally, set an initial seed for the PRNGs used to generate the workload. | ||
# The default is to intialize from the OS entropy pool. | ||
#initial_seed = "0" | ||
|
||
[debug] | ||
# choose from: error, warn, info, debug, trace | ||
log_level = "info" | ||
# optionally, log to the file below instead of standard out | ||
# log_file = "rpc-perf.log" | ||
# backup file name for use with log rotation | ||
log_backup = "rpc-perf.log.old" | ||
# trigger log rotation when the file grows beyond this size (in bytes). Set this | ||
# option to '0' to disable log rotation. | ||
log_max_size = 1073741824 | ||
|
||
[target] | ||
# specify one or more endpoints as IP:PORT pairs | ||
endpoints = ["127.0.0.1:12321"] | ||
|
||
[pubsub] | ||
# the connect timeout in milliseconds | ||
connect_timeout = 10000 | ||
publish_timeout = 1000 | ||
publisher_threads = 1 | ||
subscriber_threads = 6 | ||
publisher_poolsize = 1 | ||
publisher_concurrency = 20 | ||
|
||
[workload] | ||
# the number of threads that will be used to generate requests | ||
threads = 1 | ||
# the global ratelimit | ||
ratelimit = 1 | ||
|
||
# An example set of topics using a low number of subscribers per topic. | ||
[[workload.topics]] | ||
topics = 1 | ||
topic_len = 1 | ||
message_len = 64 | ||
weight = 1 | ||
# the total number of clients that will subscribe to this set of topics | ||
subscriber_poolsize = 100 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
use super::*; | ||
use crate::net::Connector; | ||
use bytes::Buf; | ||
use bytes::BufMut; | ||
use session::Buffer; | ||
use std::borrow::Borrow; | ||
use std::borrow::BorrowMut; | ||
use tokio::io::AsyncReadExt; | ||
|
||
use tokio::time::timeout; | ||
|
||
// blabber has a header before the standard pubsub message | ||
// | ||
// ___________________________________ | ||
// | 0 .. | 4 .. | 8 .. length | | ||
// | | | | | ||
// | length | padding | pubsub message | | ||
// |________|_________|________________| | ||
|
||
const HEADER_LEN: u32 = 8; | ||
|
||
/// Launch tasks with one conncetion per task as ping protocol is not mux-enabled. | ||
pub fn launch_subscribers( | ||
runtime: &mut Runtime, | ||
config: Config, | ||
workload_components: &[Component], | ||
) { | ||
debug!("launching blabber subscriber tasks"); | ||
|
||
for component in workload_components { | ||
if let Component::Topics(topics) = component { | ||
let connections = topics.subscriber_poolsize() * topics.subscriber_concurrency(); | ||
|
||
// create one task per "connection" | ||
// note: these may be channels instead of connections for multiplexed protocols | ||
for _ in 0..connections { | ||
for endpoint in config.target().endpoints() { | ||
runtime.spawn(subscriber_task(endpoint.clone(), config.clone())); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
// a task for blabber servers (eg: Pelikan Blabber) | ||
#[allow(clippy::slow_vector_initialization)] | ||
async fn subscriber_task(endpoint: String, config: Config) -> Result<()> { | ||
let validator = MessageValidator::new(); | ||
|
||
let connector = Connector::new(&config)?; | ||
|
||
// this unwrap will succeed because we wouldn't be creating these tasks if | ||
// there wasn't a client config. | ||
let pubsub_config = config.pubsub().unwrap(); | ||
|
||
let mut stream = None; | ||
let mut read_buffer = Buffer::new(pubsub_config.read_buffer_size()); | ||
|
||
while RUNNING.load(Ordering::Relaxed) { | ||
if stream.is_none() { | ||
CONNECT.increment(); | ||
PUBSUB_SUBSCRIBE.increment(); | ||
|
||
stream = match timeout( | ||
pubsub_config.connect_timeout(), | ||
connector.connect(&endpoint), | ||
) | ||
.await | ||
{ | ||
Ok(Ok(s)) => { | ||
CONNECT_OK.increment(); | ||
CONNECT_CURR.increment(); | ||
PUBSUB_SUBSCRIBER_CURR.add(1); | ||
PUBSUB_SUBSCRIBE_OK.increment(); | ||
|
||
Some(s) | ||
} | ||
Ok(Err(_)) => { | ||
CONNECT_EX.increment(); | ||
PUBSUB_SUBSCRIBE_EX.increment(); | ||
|
||
sleep(Duration::from_millis(100)).await; | ||
continue; | ||
} | ||
Err(_) => { | ||
CONNECT_TIMEOUT.increment(); | ||
PUBSUB_SUBSCRIBE_EX.increment(); | ||
|
||
sleep(Duration::from_millis(100)).await; | ||
continue; | ||
} | ||
} | ||
} | ||
|
||
let mut s = stream.take().unwrap(); | ||
|
||
// read until response or timeout | ||
loop { | ||
match s.read(read_buffer.borrow_mut()).await { | ||
Ok(n) => { | ||
unsafe { | ||
read_buffer.advance_mut(n); | ||
} | ||
{ | ||
loop { | ||
let consumed = { | ||
let rbuf: &[u8] = read_buffer.borrow(); | ||
|
||
if rbuf.len() >= HEADER_LEN as usize { | ||
let len = | ||
u32::from_be_bytes(rbuf[0..4].try_into().unwrap()) as usize; | ||
|
||
// check if we have only a partial message | ||
if rbuf.len() < len { | ||
break; | ||
} | ||
|
||
let mut mbuf = rbuf[8..len].to_owned(); | ||
|
||
let _ = validator.validate(&mut mbuf); | ||
|
||
// return the number of bytes consumed | ||
len | ||
} else { | ||
break; | ||
} | ||
}; | ||
|
||
read_buffer.advance(consumed); | ||
} | ||
} | ||
} | ||
Err(_) => { | ||
PUBSUB_RECEIVE.increment(); | ||
PUBSUB_RECEIVE_EX.increment(); | ||
PUBSUB_SUBSCRIBER_CURR.sub(1); | ||
} | ||
} | ||
} | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Launch tasks with one channel per task as gRPC is mux-enabled. | ||
pub fn launch_publishers( | ||
_runtime: &mut Runtime, | ||
_config: Config, | ||
_work_receiver: Receiver<WorkItem>, | ||
) { | ||
// note: there are no publish tasks for blabber, instead the server is | ||
// expected to publish compatible messages to the subscribers | ||
debug!("skipping blabber publisher tasks"); | ||
} |
Oops, something went wrong.