mazzi.github.com

Deploying node 29 / 01 / 2014

All good. You wrote your first node app using express as your web application framework and everything looks amazing locally. Now the big question: how we deploy this live?

First of all, I had to do it in a DigitalOcean VPS using Ubuntu 12.04 TLS, so my first idea was to install node using apt-get install nodejs. No problems at all, except that was an extremely old version. Node ecosystem is changing day by day so if you are not aware of that you can end with an edge version in development and a stable in production. To get then the latest version, I suggest to use Chris Lea’s repository

$ sudo apt-get install python-software-properties
$ sudo apt-add-repository ppa:chris-lea/node.js
$ sudo apt-get update
$ sudo apt-get install nodejs

So far, so good. Next will be install npm, the node package manager with apt-get install npm.

Your node + express app will have a package.json file with all the project dependencies. In a good day doing npm install in your project root folder will be enough. npm on ubuntu has a differnt way to handle source repositories, so to be able to download all the dependencies we need to change an npm configuration setting.

npm config set registry http://registry.npmjs.org

The above command will tell npm were to go to download dependencies then. Re-executing npm install will download then all the dependencies.

Fair enough. Our application will be running without problems at this point. Now is time to configure nginx to serve the app.

When using node + express, executing node app.js in the project root folder will be enough to server the app in http://localhost:3000. Now we need to do the same but as a service in our Ubuntu box. For this task I’ve used upstart. Creating an file /etc/init/myapp.conf with the following content will do the trick.

description     "My Express App"

env HOME=/var/www/myexpressapp

start on runlevel [2345]
stop on runlevel [!2345]

respawn

env NODE_ENV=production
exec start-stop-daemon --start --umask 000 --exec /usr/bin/node -- /var/www/myexpressapp/app.js >>/var/log/myexpressapp.sys.log

It’s important to execute env NODE_ENV=production so the express app is able to run in production with different setting than development. In some upstart versions this command is not compatible. Excecuting then service myapp start will start the service.

Finally, we can create a virtual host in nginx to serve the app to the ouside world in a good way.

upstream nodejs {
      server 127.0.0.1:3000 max_fails=0; 
} 
server { 
  server_name mynodeapp.com; 

  add_header Strict-Transport-Security max-age=500; 

  location / { 
    proxy_pass  http://nodejs; 
    proxy_redirect off; 
    proxy_set_header Host $host ; 
    proxy_set_header X-Real-IP $remote_addr ; 
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; 
    proxy_set_header X-Forwarded-Proto https; 
  }     }

Like this, nginx is acting as a proxy with the express service. Do not forget to set up logs at nginx level to see what’s going on!

Profiling PHP with Facebook xhprof 16 / 09 / 2013

To improve speed of our sites (or scripts) we need to detect bottlenecks. How we can accomplish that? profiling. What’s profiling? It’s form of dynamic programing that analyzes and measures different aspects of software like memory usage, time, cyclomatic complexity, usage of functions and other useful metrics. Without metrics we cannot see improvement.

As a long time user of Zend extension Xdebug I wanted to try something different. With a little bit of research I found Facebook Zend extension XHprof and I must say that is an excellent tool.

The installation was straight away. You need to compile the module and add it to your php.ini file.

What’s next then? Just configure your application to load the extension if it’s available. Something like this…

if ( extension_loaded ( 'xhprof' ) )
{
	include_once '/usr/share/php/xhprof_lib/utils/xhprof_runs.php';
	include_once '/usr/share/php/xhprof_lib/utils/xhprof_lib.php';

	xhprof_enable ( XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY );

	Logger::info ( "Profiler ENABLED" );
}

Now, choose your favourite HTTP server (Apache, Nginx, whatever) and configure the UI that is provided with Xhprof. In there, there’s a list of all the existing runs that were executed. Basically one for each HTTP request in this example.

xhprof flat view

In the flat view, there is values for each method/function call with the ammount of them, processor and memory usage. I’m more a photographic person, so I prefer to see a callgraph of these values.

xhprof callgraph

In red and yellow are being displayed critial function calls in terms of memory, cpu usage and ammount of calls. Useful for detecting low performance in algorithms.

But what’s so good in comparission with the original zend extension? I found this extension way more easy to use (it’s just a virtual host in your dev environment) and can be easily integrated in a test enviroment so the whole team can see the results. In my experience saved a lot of headaches when optimizing concrete algorithms. Give it a try.

Nginx alias, virtual hosts and debugging 21 / 08 / 2013

Searching on The Internets about “How to configure one virtual host in nginx with multiple subdirs” I found a lot of different answers (mostly wrong or misconfigured) so I decided to write some (more) on my humble blog.

What’s the objective of the configuration? Being able to serve different folders under the same virtual host.

www.domain.com               == served in ==>   /srv/htdocs/domain.com/
www.domain.com/folder01/     == served in ==>   /srv/htdocs/deployment01/
www.domain.com/folder02/     == served in ==>   /srv/htdocs/deployment02/

The most common solution for this scenario would be changing the root under different location directives. This could lead to different problems; especially knowing that Nginx processes virtual hosts configuration files from top to bottom. If some other location relies on the root value and we change it after the first definition we are not going to get the desired result (global variables anyone?).

What’s the solution then? Using the alias directive.

server {
    listen      80;
    server_name www.domain.com;
    root        /srv/htdocs/domain.com;
    set         $alternate_folder01 /srv/htdocs/deployment01

    location /
    {
       index index.html index.htm index.php;
    }

    location ~ /folder01/(.*)$
    {
        alias $alternate_folder01/index.php;

        rewrite "^/folder01/(.*)$"      /folder01/index.php?$1;

        include       /etc/nginx/fastcgi_params;

        fastcgi_pass  127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $request_filename;

        break;
    }

We also need to change the way that fastcgi_parm SCRIPT_FILENAME is called. It’s important to use $request_filename instead of $document_root/$fastcgi_script_name (It’s the most common error when using alias).

In the example I used a variable called $alternate_folder01. This is the best way to keep the configuration modular and easy to read/configure if we have several sublocations added to that location later on.

One of the best ways of debugging the variables (and other stuff) in Nginx is to install HttpEchoModule. It’s so easy to debug like doing this:

 	location ~ /folder01/(.*)$
    {
        alias /srv/htdocs/deployment01/index.php;

        rewrite "^/folder01/(.*)$"      /folder01/index.php?$1;

        include       /etc/nginx/fastcgi_params;

        fastcgi_pass  127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $request_filename;

        echo $uri

        break;
    }

To see the results it’s better to use curl instead of a normal browser (we get rid of caches, cookies, whatever). You’ll receive as an answer the $uri variable and also you are going to be sure where your request was processed.

curl http://www.domain.com/folder01/

Probably you need to complile HttpEchoModule for Nginx (like I had to). But beleive me, it is worth it.

Some MySQL handy tips 07 / 08 / 2013

This post is kind of a “copy paste memo” to myself. Oldies but goldies.

How to check a my.cnf file syntax without restarting the service?

sudo /opt/mysql/server-5.6/bin/mysqld --help --verbose --skip-networking --pid-file=/tmp/deleteme.pid 1>/dev/null

All the things that appear in the console are useful (of course, syntax errors included).

From mysql 5.6, the syntax to log slow queries and queries that perform full table scans (bad for performance!) changed. Here they are the new options.

[mysqld]
slow-query-log = ON
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 10
log_queries_not_using_indexes = ON

Don’t forget to do chmod the log file!

This settings can also be changed without restarting the service in mysql versions bigger than 5.3 (you probably want to do that on a live system). To do that, execute the following commands using a mysql client.

SET @@GLOBAL.long_query_time=1;
SET @@GLOBAL.log_queries_not_using_indexes = 'ON';
SET @@GLOBAL.slow_query_log_file ='/var/log/mysql/slow-query.log';

To check that the settings that we just changed have succeeded:

SHOW GLOBAL VARIABLES LIKE "%slow%";
SHOW GLOBAL VARIABLES LIKE "%long%";

Finally, the log is being activated.

SET @@GLOBAL.slow_query_log = 'ON';

How to analyze and optimize SQL queries is a subject for another post ;)

Playing around with Haproxy 27 / 04 / 2013

As part of the infrastructure at work, we use Haproxy as a load balancer and Nginx as webserver. Here is a nice layout made with Gliffy

Network Layout

As a requirement we had the necessity to redirect all the traffic received to only one of our servers depending on the format of the received request. The problem that we had was that all our traffic had to be over a secure connection (HTTPS) so the HTTP message received could not be analyzed because is encrypted.

The latest version of Haproxy (1.5-dev18) supports native SSL. It’s not an stable version but does the trick. Following a configuration example.

listen  https_server
    bind            127.0.0.1:443 ssl crt /etc/haproxy/ssl
    mode            http
    balance         source
    option          abortonclose
    
    option          forwardfor
    option          http-server-close
    option          originalto

In the folder /etc/haproxy/ssl we need to copy all of our certificates. Alternatively you can use a specific certificate. To be able to analyze HTTP headers the key here is to specify mode http. If we use mode tcp (like in a standard https configuration for Haproxy) we are not able to analyze the headers. You must take a peek at the OSI layer model to understand why.

Regarding the balancing, it’s quick and easy to configure Haproxy using the listen directive instead of backend and fronted ones. Here’s the rest of the configuration in the listen https_server.

    # Routing for operation with files
    acl             path01  path_reg        ^/api/upload/(.*)$
    acl             path02  path_reg        ^/api/download/(.*)$
    use-server      srv01 if path01 or path02

    server          srv01 192.168.0.1:8080 weight 1 maxconn 1000 check inter 10000 rise 1 fall 2
    server          srv02 192.168.0.2:8080 weight 1 maxconn 1000 check inter 10000 rise 1 fall 2

It’s important not to include option ssl-hello-chk to this configuration because if we do so, haproxy will consider them down because of the rise and fall directives. Haproxy will not be able to receive an answer status because we are checking HTTP servers instead of HTTPS.

The path_reg directive is not the optimum regarding speed, but it depends on how many requests per second we need to analyze.

For automatic redirection to HTTPS we need to specify another listen directive in Haproxy.

listen  http_server     127.0.0.1:80
    	redirect scheme https if !{ ssl_fc }

Last but not least, it’s important to know that the webservers are now listening for incoming traffic in a non secure way (HTTP). If it’s going to receive only requests from Haproxy maybe is a good idea to use the allow and deny all directives.