Lessons building a JMeter/Caliper benchmarking system

Remote SSH access

  • While it seemed convenient at first, actually we can’t use remote access libraries like JSch http://www.jcraft.com/jsch/ or sshj https://github.com/hierynomus/sshj
    • These libraries re-implemented the ssh protocol and is based upon bouncy castle https://www.bouncycastle.org/
    • Bouncy castle, in turn requires a highly randomized source from the OS. But Amazon EC2 are virtual environment and thus have very little randomness
    • As a result, these libraries will hang for a long time, and may never complete
    • Solution: simply call the os’ natively installed ssh executable. It seems this has been modified to accomodate the environment and work much faster. This also reduced dependency on external libraries (don’t have to download jsch or sshj from maven)
    • Downside: while Jetmeter is written in java, dependency on ssh and scp means it can only run on MacOS or Linux

JMeter

  • While JMeter can be embedded as a library https://mvnrepository.com/artifact/org.apache.jmeter , this approach have the following downsides
    • You need to download external libraries
    • If you use JMeter plugins, you need to include those plugins as libraries, increasing the size of the build a lot
    • You’ll still need to include the JMeter binary and extension directory (yes, you need both build time and run time access)
    • This is due to historical reasons. JMeter has been developed a long time ago and they couldn’t break old conventions.
    • Including JMeter in our application will affect
      • Security. Any JMeter vulnerability will affect our application too
      • JMeter has a tendency to hang. Once we hand over control to the JMeter library it’s hard to take back, the only way is to fork a new process.
    • When we go with process forking, it’s hard to monitor the progress of JMeter (you need to constantly check for result files as JMeter provide no internal method for this)
    • JMeter was built to be mainly run from the command line. To do even basic operation like launching remote controller would require convoluted object instantiation and reflection to access JMeter’s internal types
    • Solution: Since we need to include JMeter library anyway, just call it as an external application and wait for it to finish

Caliper

  • When running Caliper via a remote session, caliper sometimes end the session during test (after around 5 seconds), but still running on the remote host
    • Can’t depend on caliper output
    • Can’t depend on the time caliper exit thread for control flow
    • Need to periodically pool caliper report file on remote host
    • Need to parse said file instead of console output

Find and block unsafe content on your wordpress installation

For some reason, my WP installation decided to load some files via http instead of https

Screen Shot 2018-11-12 at 3.28.59 PM.png

To find out which file it is, I used the Javascript consoleScreen Shot 2018-11-12 at 3.29.39 PM.png

It’s wp-emoji in this case, and I don’t use emojis on my site, so I decided to block it by adding this to my theme’s functions.php

 

remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'wp_print_styles', 'print_emoji_styles' );

 

How to connect to MySQL / MariaDB using Node.JS (the right way)

Use a connection pool. It helps

  • Conserve resource, connections got recycled
  • Better reliability: it automatically reconnects when there’s a problem

How? Simple, instead of creating a connection, just create a pool. It’s designed as a drop in replacement for client.query()

var mysql = require('mysql');
var pool  = mysql.createPool({
  connectionLimit : 10,
  host            : 'example.org',
  user            : 'bob',
  password        : 'secret',
  database        : 'my_db'
});

pool.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
  if (error) throw error;
  console.log('The solution is: ', results[0].solution);
});

is a shorthand for

var mysql = require('mysql');
var pool  = mysql.createPool(...);

pool.getConnection(function(err, connection) {
  if (err) throw err; // not connected!

  // Use the connection
  connection.query('SELECT something FROM sometable', function (error, results, fields) {
    // When done with the connection, release it.
    connection.release();

    // Handle error after the release.
    if (error) throw error;

    // Don't use the connection here, it has been returned to the pool.
  });
});

Work around to make sub-subdomain useful on Cloudflare

As any seasoned webmaster may have known, Cloudflare’s free SSL certificate while convenient for most use cases, are very restrictive in edge cases. For example when you want to have.a.vanity.url.com for your website, Cloudflare won’t work (only vanity.url.com part is permitted).

What can you do? Other than paying cloudflare $10 / month and get a custom-made edge certificate?

You can set up URL forwarding rule like


  1. Log into your Cloudflare account.
  2. From the dropdown menu on the top left, select your domain.
  3. Click the Page Rules app in the top menu.
  4. When adding a new page rule, enable Forwarding.
  5. Enter the destination URL and select the forwarding type.

Forwarding examples:

Example forwarding to Google+:

Imagine you have a Google+ profile and you want to make it easy for anyone coming to get to simply by going to a URL like:

    *www.example.com/+

    *example.com/+

This pattern will match:

    http://example.com/+
    http://www.example.com/+
    https://www.example.com/+
    https://blog.example.com/+
    https://www.blog.example.com/+
    Etc…

It will not match:

    http://www.example.com/blog/+  [extra directory before the +]
    http://www.example.com+  [no trailing slash]

Once you have  created the pattern that matches what you want, click the Forwarding toggle. That exposes a field where you can enter the address I want requests forwarded to. 

https://plus.google.com/yourid

If I enter that in the forwarding box and click the Add Rule button within a few seconds any requests that match the pattern I entered will automatically be forwarded with a 302 Redirect to the new URL. 

Advanced forwarding options:

If you use a basic redirect, such as forwarding the root domain to www.yourdomain.com,  then you lose anything else in the URL. For example, you could setup the pattern:

    example.com

And have it forward to:

http://www.example.com

But then if someone entered:

    example.com/some-particular-page.html

Then they’d be redirected to:

    www.example.com

Not where you’d want them to go:

    www.example.com/some-particular-page.html

The solution is to use variables. Each wildcard corresponds to a variable when can be referenced in the forwarding address. The variables are represented by a $ followed by a number. To refer to the first wildcard you’d use $1, to refer to the second wildcard you’d use $2, and so on. To fix the forwarding from the root to www in the above example, you could use the same pattern:

    example.com/*

You’d then setup the following URL for traffic to forward to:

http://www.example.com/$1

In this case, if someone went to:

    example.com/some-particular-page.html

They’d be redirected to:

http://www.example.com/some-particular-page.html

Using this and set up a rule like

$1.$2.yourdomain/$3

and forward it to

yourdomain/$1.$2/$3

You can redirect it somewhere else or create a website for it

How to install zip extension for PHP7

Specifically for LAMP stack / webmin

First, install the module

sudo apt-get install php7.0-zip

Then restart the web server

sudo service apache2 restart
sudo service nginx restart

That’s it!