Grenache Command Line Interface (CLI) - The Bitfinex Blog
16170
post-template-default,single,single-post,postid-16170,single-format-standard,bridge-core-3.0.6,et_bloom,qode-page-transition-enabled,ajax_fade,page_not_loaded,,qode-title-hidden,qode_grid_1300,footer_responsive_adv,qode-content-sidebar-responsive,qode-child-theme-ver-1.0.0,qode-theme-ver-29.3,qode-theme-bridge,qode_header_in_grid,wpb-js-composer js-comp-ver-6.10.0,vc_responsive

Grenache CLI – Command Line Interface

Grenache CLI

 

Much of the infrastructure at Bitfinex is based on Grenache, a small high-performance framework built around Distributed Hashtables (DHT). Today we take a look at the Grenache Command Line Interface (CLI), a set of tools to interact with the Grenache-grape suite from your command line. Using Grenache CLI, you can create a number of unique scripts which communicate directly with the DHT. 

 

In this article we lay out a framework for how you can use Grenache to store sensor data in a distributed, scalable way.

 

Grenache

Grenache is a DHT based, high-performance microservices framework developed by Bitfinex. The framework is decentralised and optimized for performance, due in part to its simplicity and ease of setting up.  

Grenache

Grenache uses DHT, known from Bittorrent, to build networks between peers. Using Grenache, peers can send each other commands (RPC), sub/pub and store items on the DHT. For a more detailed look into Grenache, check out our piece titled “Microservices with Grenache”.

 

Installing Grenache CLI

Prerequisites

Prior to starting the installation, make sure that your version of grenache-grape supports mutable items (see pull request #35).

 

How to install

Briefly, the shell command should configure, build and install this package.

./configure && make && make install

 

Initializing Grenache CLI

Before you start using this set of tools you will need to initialize the grenache CLI environment.

To do this, use:

grenache-keygen

This will generate your key pair, which will be used when mutable items are stored on the DHT. This is a one-time task, but you can regenerate a new key pair at any time.

 

Storing items on the DHT

The grenache-put command writes an arbitrary payload to the DHT (see BEP 44 for more information). 

There are two types of items you can store on the DHT – immutable items and mutable items. In either case, you will receive the key under which the item has been stored.

 

  • Immutable Items

Immutable items cannot be modified, thus there is no need to authenticate the origin of them. This makes immutable items simple.

To write an immutable item to the DHT, simply run something like this:

grenache-put "$(uname -n)"

 

  • Mutable Items

Mutable items can be updated, without changing their DHT keys. In order to create your key pair, see grenache-keygen.

To write a mutable item to the DHT, run something like this:

grenache-put --mutable "$(uptime -p)"

 

In order to support a single key being used to store separate items on the DHT, an optional salt can be specified in the put request of mutable items:

grenache-put --mutable --salt 'sys:mem:available' \
  "$(awk '/^MemAvailable:/ { print $2 "Ki" }' < /proc/meminfo)"

 

Note: Grenache-put is agnostic, and will treat your payload as a single string. Other useful options are -n or –number that will let you set the sequence number to use in your request, and -c or –cas that let you use the compare and swap feature.

To retrieve the complete options list, use:

grenache-put --help

 

Retrieving items from the DHT

The grenache-get command reads a data record from the DHT (see BEP 44 for more information). There are no differences between retrieving a mutable or an immutable item; in either case, the key returned by the PUT request must be provided. 

grenache-get validates the payload it receives, working to ensure that the key provided truly matches the payload and, in the case of a mutable item, that the signature is correct. This protects you from evil nodes on the network. 

To read an item from the DHT, simply run something like this:

grenache-get '81c2a8157780989af9a16661324fafbd7803877d'

 

You can format the previously stored available memory amount using something like this:

numfmt --from=auto --to=iec-i < <(
  grenache-get '81c2a8157780989af9a16661324fafbd7803877d'
)

 

You can also retrieve the raw packet received from the network using the -r switch or its long form –raw.

To retrieve the complete options list, use:

grenache-get --help

 

An Illustration of Grenache CLI

Saving AWS server network statistics to the DHT:

grenache-put --mutable --salt "$(head -n1 < /etc/hostname):net:stats" \
 "$(curl \
   --silent \
   --compress \
   --connect-timeout 5 \
   --output '/dev/null' \
   --header 'Cache-Control: no-cache' \
   --write-out '%{time_connect}\t%{time_starttransfer}\t%{time_total}' \
   --resolve "www.myhostname.com:443:$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4 2>/dev/null)" \
     'https://www.myhostname.com/' 2>/dev/null | jq -cMR 'split("\t") | map(tonumber)' 2>/dev/null
 )"

 

This will save a JSON array under the salt <machine hostname>:net:stats, which contains:

  • The time, in seconds, it took until the TCP connect was completed.
  • The time, in seconds, it took until the first byte was just about to be transferred. This includes the time needed by the server to calculate the result.
  • The time, in seconds, that the full operation lasted.

A sample JSON array could look something like [0, 0.123, 0.125]

 

To ensure that we are testing the correct server, we use the local ipv4 from the AWS Instance Metadata and the internal curl cache (requires a curl version greater than or equal to 7.21.3). Install this sensor on each network server and run it periodically (e.g using a systemd timer); now we can retrieve all of these useful stats directly from DHT.

We can go further and create another process that controls all of these stats and warns all administrators if something is out of a certain threshold, using Twilio, Slack or a simple email.

For the sake of brevity and for the purpose of this document, we simply send a message to all users connected to the server:

jq -e '.[2] > 1' < <( \
 grenache-get '24061f201464af1ca50a65789c6f7c8d295e1300' \
) &>/dev/null && wall "Total connection time greater than 1 second!"

 

Now you can create other sensors. For example, you can easily republish the status of the graylog cluster health status by using something like:

grenache-put --mutable --salt "$(head -n1 < /etc/hostname):cluster:health" \
 "$(curl \
   --silent \
   --compress \
     'http://127.0.0.1:9200/_cluster/health'
 )"

 

Alternatively, save the MySQL replication lag using the Percona Toolkit:

grenache-put --mutable --salt "$(head -n1 < /etc/hostname):mysql:replica:lag" \
  "$(pt-heartbeat --check)"

 

Takeaways

In this article we used the Grenache Command Line Interface to communicate directly with the DHT. We stored sensor data using highly specialised scripts and made them available for other consumers. We hope you enjoyed this brief example on the fundamentals and potential of Grenache. Grenache is open-source, and can be found here

 

Resources

Tags: