Illustration Image

Cassandra.Link

The best knowledge base on Apache Cassandra®

Helping platform leaders, architects, engineers, and operators build scalable real time data platforms.

1/5/2018

Reading time:4 min

cyngn/ChronoServer

by John Doe

README.md A test server for sampling how long it takes mobile & web clients to make various types of requests to a server doing common request patterns. The idea is you can set this server up in various locations (think DCs) around the globe or country and test what the latency and experience for users will be as you vary the size and style of requests. You can also use the server to see how different CDNs might perform when sitting in front of your server and caching content.The basic flow is as follows:Client gets a collection of URLs to call from server, a mix of GET & POST calls.Client executes the URLs timing each one.Client reports back to server all the timing data for each call and metadata about the client's connection.Getting Started####Clone the repo & build./gradlew clean shadowJar####Setup the Cassandra DBOptions:run standalonerun ccmpoint at your internal clusterExecute the scheme file in db/scheme.cql on your setup.####ConfigurationThe server takes the following config{ "port" : <port>, "default_test_base_url" : "<default http://localhost>", "data_retention_seconds" : <default 86400>, "cassandra": { "seeds": ["localhost"], "reconnect": { "name": "exponential", "base_delay": 1000, "max_delay": 10000 } }}For example:{ "port" : 7345, "default_test_base_url" : "http://localhost", "data_retention_seconds" : 86400, "cassandra": { "seeds": ["localhost"], "reconnect": { "name": "exponential", "base_delay": 1000, "max_delay": 10000 } }}Field breakdown:port the port the server listens ondefault_test_base_url the base url used in creating the bootstrap sample datadata_retention_seconds the seconds to allow the upload test data from users to live in the DB, this defaults to a day.cassandra The config to initialize the Cassandra driver with, see vertx-cassandra for more details.####Running Server#start the serverjava -jar build/libs/ChronoServer-0.5.0-fat.jar -conf conf.json -instances 2REST APIs/api/v1/test_endpoints - GETGets a set of URLs for the client to execute.Parameters:test_batch - a named collection of URLs you want to pass back to a client to run. Defaults to the bootstrap collection if not specified.Response:See ConfigResponse.java####/api/v1/report - POSTAllows a user to upload detailed information on the timings for all the calls it made.Parameters:See MetricReport.java####/api/v1/timing - GETSub APIs/static - grabs N data from memory/static_cached - grabs N data from memory and puts the appropriate cache headers on/dynamic - grabs N data from the DB/dynamic_cached - grabs N data from the DB and puts the appropriate cache headers onRequired Common Parameters:unit - the unit of the data to get, either kb or mbsize - the size of data to get backResponse:{ "data" : "<a bunch of random data matching your parameters>"}####/api/v1/timing - POSTSub APIs/store - upload N amount data to the DB, server returns after it is successfully written to Cassandra/store_mem - upload N amount data to server memory, server returns after it gets the full body of the postParameters:See StorageRequest.java####/healthcheck - GETStandard health check for things like a LB to hit.####/api/v1/timing_streaming - SockJS interfaceSee: streaming namespace and sample client below.ExamplesPiping curl output to something like jsonpp makes it much more readable.###curl requests#start the serverjava -jar build/libs/ChronoServer-0.5.0-fat.jar -conf conf.json -instances 2#grab a sample config package, take note of the api_keycurl -v "http://localhost:7345/api/v1/test_endpoints" | jsonpp#grab static data with no cachingcurl -v --header "X-API-Key: [api_key here]" "http://localhost:7345/api/v1/timing/static?unit=kb&size=1" | jsonpp#grab static data with cachingcurl -v --header "X-API-Key: [api_key here]" "http://localhost:7345/api/v1/timing/static_cached?unit=kb&size=1" | jsonpp#grab data from the DB with no cachingcurl -v --header "X-API-Key: [api_key here]" "http://localhost:7345/api/v1/timing/dynamic?unit=kb&size=1" | jsonpp#grab data from the DB with cachingcurl -v --header "X-API-Key: [api_key here]" "http://localhost:7345/api/v1/timing/dynamic_cached?unit=kb&size=1" | jsonppFor testing POST calls via the store api Postman is great for this.###sample SockJS client<html> <script src="http:////cdn.jsdelivr.net/sockjs/0.3.4/sockjs.min.js"></script> <script src="vertxbus-3.0.0.js"></script> <!-- You're going to want to turn off security in your browser when running this probably --> <script> // this is acquired from the server var apiKey = "" var sock = new SockJS('http://localhost:7345/api/v1/timing_streaming'); // download via socket var getData = function(address, unit, size) { sock.send(JSON.stringify({address: address, "api_key": apiKey, body : {unit : unit, size: size}})); }; // helper func for generating fake data var getKb = function(number) { var data = ['a', 'b', 'c', 'd', 'e', '1', '2', '3', '4', '5']; var str = ""; var totalKb = 1024 * number; for(var i = 0; i < totalKb; i++) { str += data[Math.floor((Math.random() * 10))]; } return str; }; // upload via socket var putData = function(size) { sock.send(JSON.stringify({address: "streaming.store", "api_key": apiKey, body : {test_batch: "some_batch", unit : "kb", size: size, data: getKb(size)}})); }; // get the config, ie api key var getApiKey = function() { sock.send(JSON.stringify({address: "streaming.config", "api_key": "", body : {}})); } sock.onopen = function() { console.log('connected to server'); getApiKey(); }; sock.onmessage = function(e) { console.log('message', e.data); var data = JSON.parse(e.data); // once we have the api key make some test calls if(data.type == "streaming.config") { apiKey = data.api_key; getData('streaming.static', "kb", 1); getData('streaming.dynamic', "kb", 5); putData(5); } }; sock.onclose = function() { console.log('lost connection to server'); }; </script> <body> </body></html>

Illustration Image

README.md

Build Status

A test server for sampling how long it takes mobile & web clients to make various types of requests to a server doing common request patterns. The idea is you can set this server up in various locations (think DCs) around the globe or country and test what the latency and experience for users will be as you vary the size and style of requests. You can also use the server to see how different CDNs might perform when sitting in front of your server and caching content.

The basic flow is as follows:

  • Client gets a collection of URLs to call from server, a mix of GET & POST calls.
  • Client executes the URLs timing each one.
  • Client reports back to server all the timing data for each call and metadata about the client's connection.

Getting Started

####Clone the repo & build

./gradlew clean shadowJar

####Setup the Cassandra DB

Options:

  • run standalone
  • run ccm
  • point at your internal cluster

Execute the scheme file in db/scheme.cql on your setup.

####Configuration

The server takes the following config

{
    "port" : <port>,
    "default_test_base_url" : "<default http://localhost>",
    "data_retention_seconds" : <default 86400>,
    "cassandra": {
        "seeds": ["localhost"],
        "reconnect": {
            "name": "exponential",
            "base_delay": 1000,
            "max_delay": 10000
        }
    }
}

For example:

{
    "port" : 7345,
    "default_test_base_url" : "http://localhost",
    "data_retention_seconds" : 86400,
    "cassandra": {
        "seeds": ["localhost"],
        "reconnect": {
            "name": "exponential",
            "base_delay": 1000,
            "max_delay": 10000
        }
    }
}

Field breakdown:

  • port the port the server listens on
  • default_test_base_url the base url used in creating the bootstrap sample data
  • data_retention_seconds the seconds to allow the upload test data from users to live in the DB, this defaults to a day.
  • cassandra The config to initialize the Cassandra driver with, see vertx-cassandra for more details.

####Running Server

#start the server
java -jar build/libs/ChronoServer-0.5.0-fat.jar -conf conf.json -instances 2

REST APIs

/api/v1/test_endpoints - GET

Gets a set of URLs for the client to execute.

Parameters:

  • test_batch - a named collection of URLs you want to pass back to a client to run. Defaults to the bootstrap collection if not specified.

Response:

See ConfigResponse.java

####/api/v1/report - POST

Allows a user to upload detailed information on the timings for all the calls it made.

Parameters:

See MetricReport.java

####/api/v1/timing - GET Sub APIs

  • /static - grabs N data from memory
  • /static_cached - grabs N data from memory and puts the appropriate cache headers on
  • /dynamic - grabs N data from the DB
  • /dynamic_cached - grabs N data from the DB and puts the appropriate cache headers on

Required Common Parameters:

  • unit - the unit of the data to get, either kb or mb
  • size - the size of data to get back

Response:

{
  "data" : "<a bunch of random data matching your parameters>"
}

####/api/v1/timing - POST Sub APIs

  • /store - upload N amount data to the DB, server returns after it is successfully written to Cassandra
  • /store_mem - upload N amount data to server memory, server returns after it gets the full body of the post

Parameters:

See StorageRequest.java

####/healthcheck - GET

Standard health check for things like a LB to hit.

####/api/v1/timing_streaming - SockJS interface

See: streaming namespace and sample client below.

Examples

Piping curl output to something like jsonpp makes it much more readable.

###curl requests

#start the server
java -jar build/libs/ChronoServer-0.5.0-fat.jar -conf conf.json -instances 2
#grab a sample config package, take note of the api_key
curl -v "http://localhost:7345/api/v1/test_endpoints" | jsonpp
#grab static data with no caching
curl -v --header "X-API-Key: [api_key here]" "http://localhost:7345/api/v1/timing/static?unit=kb&size=1" | jsonpp
#grab static data with caching
curl -v --header "X-API-Key: [api_key here]" "http://localhost:7345/api/v1/timing/static_cached?unit=kb&size=1" | jsonpp
#grab data from the DB with no caching
curl -v --header "X-API-Key: [api_key here]" "http://localhost:7345/api/v1/timing/dynamic?unit=kb&size=1" | jsonpp
#grab data from the DB with caching
curl -v --header "X-API-Key: [api_key here]" "http://localhost:7345/api/v1/timing/dynamic_cached?unit=kb&size=1" | jsonpp

For testing POST calls via the store api Postman is great for this.

###sample SockJS client

<html>
    <script src="http:////cdn.jsdelivr.net/sockjs/0.3.4/sockjs.min.js"></script>
    <script src="vertxbus-3.0.0.js"></script>
    <!-- You're going to want to turn off security in your browser when running this probably -->
    <script>
        // this is acquired from the server
        var apiKey = ""
        var sock = new SockJS('http://localhost:7345/api/v1/timing_streaming');
        // download via socket
        var getData = function(address, unit, size) {
            sock.send(JSON.stringify({address: address, "api_key": apiKey,
                        body : {unit : unit, size: size}}));
        };
        // helper func for generating fake data
        var getKb = function(number) {
            var data = ['a', 'b', 'c', 'd', 'e', '1', '2', '3', '4', '5'];
            var str = "";
            var totalKb = 1024 * number;
            for(var i = 0; i < totalKb; i++) {
                str += data[Math.floor((Math.random() * 10))];
            }
            return str;
        };
        // upload via socket
        var putData = function(size) {
            sock.send(JSON.stringify({address: "streaming.store", "api_key": apiKey,
                        body : {test_batch: "some_batch", unit : "kb", size: size, data: getKb(size)}}));
        };
        // get the config, ie api key
        var getApiKey = function() {
            sock.send(JSON.stringify({address: "streaming.config", "api_key": "", body : {}}));
        }
        sock.onopen = function() {
            console.log('connected to server');
            getApiKey();
        };
        sock.onmessage = function(e) {
            console.log('message', e.data);
            var data = JSON.parse(e.data);
            // once we have the api key make some test calls
            if(data.type == "streaming.config") {
                apiKey = data.api_key;
                getData('streaming.static', "kb", 1);
                getData('streaming.dynamic', "kb", 5);
                putData(5);
            }
        };
        sock.onclose = function() {
            console.log('lost connection to server');
        };
    </script>
    <body>
    </body>
</html>

Related Articles

spring
angular
rest

GitHub - jhipster/jhipster-sample-app-cassandra: This is a sample application created with JHipster, with the Cassandra option

jhipster

3/7/2024

Checkout Planet Cassandra

Claim Your Free Planet Cassandra Contributor T-shirt!

Make your contribution and score a FREE Planet Cassandra Contributor T-Shirt! 
We value our incredible Cassandra community, and we want to express our gratitude by sending an exclusive Planet Cassandra Contributor T-Shirt you can wear with pride.

Join Our Newsletter!

Sign up below to receive email updates and see what's going on with our company

Explore Related Topics

AllKafkaSparkScyllaSStableKubernetesApiGithubGraphQl

Explore Further

rest