Bioyino is a distributed statsd-protocol server with carbon backend.

Overview

Bioyino

The StatsD server written in Rust

Description

Bioyino is a distributed statsd-protocol server with carbon backend.

Features

  • all basic metric types supported (gauge, counter, diff-counter, timer), new types are easy to be added
  • fault tolerant: metrics are replicated to all nodes in the cluster
  • clustering: all nodes gather and replicate metrics, but only leader sends metrics to backend
  • precise: 64-bit floats, full metric set is stored in memory (for metric types that require post-processing), no approximation algorithms involved
  • standalone: can work without external services
  • safety and security: written in memory-safe language
  • networking tries to do it's best to avoid dropping UDP packets as much as possible
  • networking is asynchronous
  • small memory footprint and low CPU consumption

Status

Currently works in production at Avito, processing production-grade metric stream (~4M metrics per second on 3 nodes)

Installing

One of Bioyino's most powerful features - multimessage mode - require it to be working on GNU/Linux.

  • Install capnp compiler tool to generate schemas. It's usually downloaded using your distribution's package manager.
  • Do the usual Rust-program build-install cycle. Please note, that building is always tested on latest stable version of Rust. Rust 2018 edition is required.
$ git clone 
$ cargo build --release && strip target/release/bioyno

Build RPM package (for systemd-based distro)

  1. Install requirements (as root or with sudo)
    yum install -y capnproto capnproto-devel
    yum install -y ruby-devel
    gem install fpm
  1. Build
    bash contrib/fpm/create_package_rpm.sh

Build DEB package (for systemd-based distro)

  1. Install requirements (as root or with sudo)
    apt-get install -y capnproto libcapnp-dev
    apt-get install -y ruby-dev
    gem install fpm
  1. Build
    bash contrib/fpm/create_package_deb.sh

Configuring

To configure, please, see config.toml, all the options are listed there and all of them are commented.

Contributing

You can help project by doing the following:

  • find TODOs/FIXMEs and unwraps in the code fix them and create a PR
  • solve issues
  • create issues to request new features
  • add new features, like new metric types
  • test the server on your environment and creating new issues if/when bugs found
Comments
  • Sampling rate support

    Sampling rate support

    Hello! If I understand correctly, the sampling rate is not supported like in other statsd implementations. Bioyino does not "restore" the original value ​​in proportion to the sample rate? For example, after sending metric:1|c|@0.01 I expect to receive metric 100

    bug 
    opened by Karsonito 35
  • New prefix for metrics per type

    New prefix for metrics per type

    Hi, can I add prefix for metrics per type? For example: If metric type timer - add prefix stats.timers If metric type count - add prefix stats If gauges - add statsd.gauges

    Thanks!

    opened by colixxx 10
  • Corruption of last char in tag value

    Corruption of last char in tag value

    The last symbol of the last tag is chaotically replaced

    Sent tag values

    test_corrupted_tags;y=y;x=x
    test_corrupted_tags;y=yyyyyy;x=xxxx
    test_corrupted_tags;y=yyy;x=xxx
    

    Received

    test_corrupted_tags;x=x;y=x
    test_corrupted_tags;x=xxxx;y=yyyyyx
    test_corrupted_tags;x=xxx;y=yyx
    

    IMPORTANT: tags must be sent in reversed order (for example y before x)

    All versions affected: 0.6, 0.7.2, 0.8.0

    It's a little hard to reproduce and depends from some factors Here is config which makes it possible:

    bufsize = 1500
    multimessage = true
    mm-packets = 10
    buffer-flush-time = 0
    buffer-flush-length = 16384
    

    (It's possible with other values too, but needs more time to happens)

    Here some commands to save time and speed up testing

    while true; do for x in x xx xxx xxxx xxxxx xxxxxx xxxxxxx xxxxxxxx xxxxxxxxxx; do for y in y yy yyy yyyy yyyyy yyyyyy yyyyyyy yyyyyyyy yyyyyyyyy yyyyyyyyyy; do echo "test_corrupted_tags;y=$y;x=$x:1|c" | nc -u 127.0.0.1 8125; echo -n "."; done; done; echo; done
    
    nc -k -l -p 2003 | grep test_corrupted_tags | grep -v -P "test_corrupted_tags;x=x+;y=y+ "
    

    Please fix )

    opened by Karsonito 8
  • thread 'bioyino_udp0' panicked at 'assertion failed: self.remaining_mut() >= src.remaining()'

    thread 'bioyino_udp0' panicked at 'assertion failed: self.remaining_mut() >= src.remaining()'

    thread 'bioyino_udp0' panicked at 'assertion failed: self.remaining_mut() >= src.remaining()', /root/.cargo/registry/src/github.com-1ecc6299db9ec823/bytes-0.4.11/src/buf/buf_mut.rs:230:9
    note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
    stack backtrace:
       0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
                 at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
       1: std::sys_common::backtrace::print
                 at libstd/sys_common/backtrace.rs:71
                 at libstd/sys_common/backtrace.rs:59
       2: std::panicking::default_hook::{{closure}}
                 at libstd/panicking.rs:211
       3: std::panicking::default_hook
                 at libstd/panicking.rs:227
       4: std::panicking::rust_panic_with_hook
                 at libstd/panicking.rs:477
       5: std::panicking::begin_panic
       6: bytes::buf::buf_mut::BufMut::put
       7: <futures::future::chain::Chain<A, B, C>>::poll
       8: futures::task_impl::std::set
       9: tokio_current_thread::CurrentRunner::set_spawn
      10: <tokio_current_thread::scheduler::Scheduler<U>>::tick
      11: <tokio_current_thread::Entered<'a, P>>::block_on
      12: <std::thread::local::LocalKey<T>>::with
      13: <std::thread::local::LocalKey<T>>::with
      14: <std::thread::local::LocalKey<T>>::with
      15: <std::thread::local::LocalKey<T>>::with
      16: tokio::runtime::current_thread::runtime::Runtime::block_on
    

    I can reproduce the panic at my setup. Do you need some additional information to fix it up?

    opened by dmitryikh 5
  • Release 0.7.0

    Release 0.7.0

    This major release introduces more flexibility for choosing metric aggregates, a big internal async/await rewrite and some more features.

    See CHANGELOG for details.

    hacktoberfest-accepted 
    opened by Albibek 3
  • Valid example config

    Valid example config

    The current example of the config is incorrect by 50 percent. Can you give the minimum working config for building from the master? Maybe there is a key in to generate a configuration example? An interesting option with raft protocol.

    opened by ihard 3
  • One node sends to carbon more rarely when other node is physically turned off.

    One node sends to carbon more rarely when other node is physically turned off.

    Hello. We have cluster of three node: node1, node2, node3. Let's say, that statsd metrics are sent only to node1. When we turn off server node2, node1 start to send to carbon more rarely - one time per 1-2 minutes. When i commented option "nodes" in block "[network]" on node1, all started to be ok. I think, problem near tcp timeouts when node1 try to communicate with node2 for exchange (or aggregation) metrics. node1, node2 and node3 in different networks. So, tcp timeouts not limited by arp request timeouts.

    Here screenshot from graphite. Blue dots - it's all that's left from line. First time (11:50 - 12:05) - i try to understand, what happening. Second (12:11 - 12:17) - i commented "nodes" and trying to test the idea

    firefox_2019-01-22_16-35-16

    Config:

    verbosity = "warn"
    n-threads = 8
    w-threads = 8
    task-queue-size = 1024
    start-as-leader = false
    stats-interval = 10000
    stats-prefix = "resources.monitoring.bioyino"
    consensus = "internal"
    [metrics]
    count-updates = true
    update-counter-prefix = "resources.monitoring.bioyino.updates"
    update-counter-suffix = ""
    update-counter-threshold = 200
    fast-aggregation = false
    [carbon]
    address = "127.0.0.1:2003"
    interval = 10000
    connect-delay = 250
    connect-delay-multiplier = 2
    connect-delay-max = 10000
    send-retries = 30
    [network]
    listen = "0.0.0.0:8125"
    peer-listen = "0.0.0.0:8136"
    mgmt-listen = "0.0.0.0:8137"
    bufsize = 1500
    multimessage = true
    mm-packets = 100
    mm-async = false
    buffer-flush-time = 3000
    buffer-flush-length = 65536
    greens = 4
    async-sockets = 4
    nodes = ["192.168.2.2:8136", "192.168.3.3:8136"]
    snapshot-interval = 1000
    [raft]
    start-delay = 5000
    this-node = "192.168.1.1:8138"
    nodes = {"192.168.1.1:8138" = 1, "192.168.2.2:8138" = 2, "192.168.3.3:8138" = 3}
    [consul]
    start-as = "disabled"
    agent = "127.0.0.1:8500"
    session-ttl = 11000
    renew-time = 1000
    key-name = "service/bioyino/lock"
    
    opened by lexore 2
  • Feature request: allow change naming scheme for compability with different statsd implementations

    Feature request: allow change naming scheme for compability with different statsd implementations

    Different realization of StatsD has different naming scheme

    Add option for rename some names with regex or simple string pattern, like

    { "^percentile." = "p", "^min$" = "lower", "^max$" = "upper" }

    opened by msaf1980 2
  • Feature request: count per sec for metrics with

    Feature request: count per sec for metrics with "ms" type

    Hello. For metrics "XXX" with type "ms" bioyino generate metric "XXX.count". It send to carbon pure count of recieved packets every "interval" miliseconds. "interval" - setting from config file. I use it for get "packet per second" value this way: scale(XXX.count, 0.1) (i have interval = 10000). I ask to create another metric - count_ps (float) with value = count * 1000 / interval (from config). With it will no need to use "scale" for every "pps" metric. I think, it will be very usefull and handy - easy way to get "packets per second" value.

    opened by lexore 2
  • Cant compile 0.3.3.

    Cant compile 0.3.3.

    I am on 0.3.3 branch and during compiling I am getting next error:

    cargo build --release && strip target/release/bioyno
    
       Compiling tokio-reactor v0.1.6
    error[E0658]: use of unstable library feature 'thread_local_state': state querying was recently added (see issue #27716)
       --> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-reactor-0.1.6/src/sharded_rwlock.rs:158:18
        |
    158 |     REGISTRATION.try_with(|reg| reg.index).unwrap_or(0)
        |                  ^^^^^^^^
    
    error: aborting due to previous error
    
    error: Could not compile `tokio-reactor`.
    
    To learn more, run the command again with --verbose.
    

    I am on Ubuntu 16.04 with rustc 1.25.0 (standardf repo version). Do I need newer one?

    opened by ipeacocks 2
  • Build issues on nightly

    Build issues on nightly

    https://github.com/palfrey/bioyino/runs/3273000488?check_suite_focus=true running rustc 1.56.0-nightly (574d37568 2021-08-07)

    error: internal compiler error: unexpected concrete region in borrowck: ReEarlyBound(0, 'a)
    Error:    --> /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/bioyino-metric-0.3.1/src/parser.rs:48:1
        |
    48  | / pub fn metric_stream_parser<'a, I, F>(max_unparsed: usize, max_tags_len: usize) -> impl Parser<I, Output = ParsedPart<F>, PartialState = ...
    49  | | where
    50  | |     I: 'a + combine::StreamOnce<Token = u8, Range = &'a [u8], Position = PointerOffset<[u8]>> + std::fmt::Debug + RangeStream,
    51  | |     I::Error: ParseError<I::Token, I::Range, I::Position>,
    ...   |
    150 | |     ))
    151 | | }
        | |_^
        |
        = note: delayed at compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs:88:44
    
    thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', compiler/rustc_errors/src/lib.rs:1065:13
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    

    I think this is https://github.com/rust-lang/rust/issues/83190 and I've added a note about this there

    opened by palfrey 1
  • Gauge value after flush

    Gauge value after flush

    We have an issue with metric of gauge type. We expect behavior as described at statsd server's documentation

    If the gauge is not updated at the next flush, it will send the previous value.

    Expected behavior

    Let's say we send gaugor:5|g, so we would get gaugor metric with value of 5 on first flush. Later if we don't send any gaugor update we still would get gaugor metric with value of 5 on second flush. Or if we send gaugor:+10|g we would get gaugor metric with value of 15 at second flush.

    Actual behavior

    We send gaugor:5|g, we get gaugor metric with value of 5 at first flush. Later if we don't send any gaugor update we wouldn't get any gaugor metric on second flush at all. Or If we send gaugor:+10|g we would get gaugor metric with value of 10 on second flush.

    Consequence

    This behavior also affects gauge relative updates, i.e. sending gaugor:+5|g or gaugor:-5|g to update existing gaugor value by specified difference. It is impossible to update existing gauge, because it is forgotten after every flush.

    opened by sempasha 0
  • Using bioyino as statsd-agent

    Using bioyino as statsd-agent

    Hello!

    I want to clarify some details.

    1. Did I understand correctly that if we use bioyino as a statsd-agent, it can write its data to the cluster via the peer port over tcp? Maybe you have an example of bioyino configuration as agent?
    2. Now bioyino can only write to one carbon backend over tcp?
    question 
    opened by sti-jans 3
  • [question] Launch in kubernetes

    [question] Launch in kubernetes

    Hi! We plan to use bioyino in our infrastructure. And we have a couple of questions:

    1. What could be the problems if we put bioyino in kubernetes (besides consensus management)?
    2. Do you plan to make bioyino operator for kubernetes? Or maybe you have some ideas that we can use.
    question 
    opened by sti-jans 1
  • Dev docker conf

    Dev docker conf

    Hi. Is it possible to configure bioyino to send metrics every 10 seconds regardless buffers config, like original statsd ? I have problem on docker, metrics are not delivered to backend most often.

    question 
    opened by yuriyzinchenko 1
Releases(0.8.0)
  • 0.8.0(Dec 15, 2021)

  • 0.7.2(Mar 1, 2021)

  • 0.7.0(Oct 11, 2020)

  • 0.6.0(Jan 15, 2020)

  • 0.5.1(Oct 15, 2019)

  • 0.5.0(Jun 24, 2019)

  • 0.4.0(Nov 9, 2018)

  • 0.3.3(Jun 1, 2018)

    • moved to new tokio, excluding consul(hyper is not ready yet)
    • retry strategy has beed added to carbon backend
    • carbon backend now has it's own section in config.toml. To use new config:
      • move backend parameter to [carbon] section as address
      • move backend-interval parameter to [carbon] section as interval
      • also note that new parameters has been added for retrying send. See config.toml in this repo for more information
    • ingress(internal meric) now counts packets instead of packet chunks
    • egress(internal metric) counting is now more precise
    • new version of bincode is used for peer protocol. Showed not to work with previous one, so restart will most probably be required
    Source code(tar.gz)
    Source code(zip)
  • 0.3.2(Feb 26, 2018)

    Release 0.3.2

    This is mostly a bugfix release.

    Changes:

    • Fix to allow low volume of metrics to be sent
    • Fix for snapshot distribution bug for number of nodes reater than 2
    • Consul key name is now customizable
    • ms metric's leaf value is now suffixed as ".last", which is less confusing, more similar to statsd/brubeck and less random
    Source code(tar.gz)
    Source code(zip)
  • 0.3.1(Feb 14, 2018)

    Some statistics about metrics added to this release.

    One can be notified now if too much metrics come in aggregation period (thanks @errx for the patch). See config.toml for customizing such parameters. Also some minor performance optimizatons done(timestamp string replaced with Cow, which should reduce allocations during aggregation).

    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(Feb 5, 2018)

    All settings(and some new) are in configuration file now. Thought there are no significant changes in the way of work, extenal API has changed, so version bump was made

    Changes:

    • Multimsg mode is now cannot be run along with single msg
    • Some options are renamed
    • Commands to server are now sent using subcommand
    • Own stats can be turned off now
    Source code(tar.gz)
    Source code(zip)
Owner
avito.tech
Avito engineering team open source projects
avito.tech
Revolt backend API server, built with Rust.

Delta Description Delta is a blazing fast API server built with Rust for Revolt. Features: Robust and efficient API routes for running a chat platform

Revolt 741 Dec 26, 2022
A minimalistic encryption protocol for rust async streams/packets, based on noise protocol and snow.

Snowstorm A minimalistic encryption protocol for rust async streams / packets, based on noise protocol and snow. Quickstart Snowstorm allows you to se

Black Binary 19 Nov 22, 2022
Lightweight p2p library. Support build robust stable connection on p2p/distributed network.

Chamomile Build a robust stable connection on p2p network features Support build a robust stable connection between two peers on the p2p network. Supp

CympleTech 94 Jan 6, 2023
The open source distributed web search engine that searches by meaning.

DawnSearch DawnSearch is an open source distributed web search engine that searches by meaning. It uses semantic search (searching on meaning), using

DawnSearch 4 Aug 8, 2023
`prometheus` backend for `metrics` crate

metrics + prometheus = ❤️ API Docs | Changelog prometheus backend for metrics crate. Motivation Rust has at least two ecosystems regarding metrics col

Instrumentisto Team 2 Dec 17, 2022
axum-server is a hyper server implementation designed to be used with axum framework.

axum-server axum-server is a hyper server implementation designed to be used with axum framework. Features Conveniently bind to any number of addresse

null 79 Jan 4, 2023
Jex Compiler Server - Server that runs Jex code

Server that compiles and runs Jex code.

furetur 3 Nov 18, 2021
Dav-server-rs - Rust WebDAV server library. A fork of the webdav-handler crate.

dav-server-rs A fork of the webdav-handler-rs project. Generic async HTTP/Webdav handler Webdav (RFC4918) is defined as HTTP (GET/HEAD/PUT/DELETE) plu

messense 30 Dec 29, 2022
A simple web server(and library) to display server stats over HTTP and Websockets/SSE or stream it to other systems.

x-server-stats A simple web server(and library) to display server stats over HTTP and Websockets/SSE or stream it to other systems. x-server(in x-serv

Pratyaksh 11 Oct 17, 2022
DNS Server written in Rust for fun, see https://dev.to/xfbs/writing-a-dns-server-in-rust-1gpn

DNS Fun Ever wondered how you can write a DNS server in Rust? No? Well, too bad, I'm telling you anyways. But don't worry, this is going to be a fun o

Patrick Elsen 26 Jan 13, 2023
QUIC proxy that allows to use QUIC to connect to an SSH server without needing to patch the client or the server.

quicssh-rs ?? quicssh-rs is a QUIC proxy that allows to use QUIC to connect to an SSH server without needing to patch the client or the server. quicss

Jun Ouyang 18 May 5, 2023
Easy protocol definitions in Rust

protocol Documentation Easy protocol definitions in Rust. This crate adds a custom derive that can be added to types, allowing structured data to be s

Dylan McKay 157 Dec 30, 2022
A Constrained Application Protocol(CoAP) library implemented in Rust.

coap-rs A fast and stable Constrained Application Protocol(CoAP) library implemented in Rust. Features: CoAP core protocol RFC 7252 CoAP Observe optio

Covertness 170 Dec 19, 2022
🥧 Savoury implementation of the QUIC transport protocol and HTTP/3

quiche is an implementation of the QUIC transport protocol and HTTP/3 as specified by the IETF. It provides a low level API for processing QUIC packet

Cloudflare 7.1k Jan 8, 2023
🤖 brwrs is a new protocol running over TCP/IP that is intended to be a suitable candidate for terminal-only servers

brwrs is a new protocol running over TCP/IP that is intended to be a suitable candidate for terminal-only servers (plain text data). That is, although it can be accessed from a browser, brwrs will not correctly interpret the browser's GET request.

daCoUSB 3 Jul 30, 2021
A multi-protocol network relay

A multi-protocol network relay

zephyr 43 Dec 13, 2022
A Rust library for parsing the SOME/IP network protocol (without payload interpretation).

someip_parse A Rust library for parsing the SOME/IP network protocol (without payload interpretation). Usage Add the following to your Cargo.toml: [de

Julian Schmid 18 Oct 31, 2022
The Graph is a protocol for building decentralized applications (dApps) quickly on Ethereum and IPFS using GraphQL.

Graph Node The Graph is a protocol for building decentralized applications (dApps) quickly on Ethereum and IPFS using GraphQL. Graph Node is an open s

Mindy.wang 2 Jun 18, 2022
🤖 Autonomous Twitter bot that posts analytics of the APYs available on the Solend Protocol.

Solend APY Twitter Bot Solana Ignition Hackathon 2021 View Demo · Report Bug · Request Feature Table of Contents About The Project Motivation Challeng

Manuel Gil 4 Sep 23, 2022