Deploying an Nchan-Powered PubSub Server on ECS
You won't need to learn JavaScript to get real-time updates with this module.
Join the DZone community and get the full member experience.
Join For FreeThe modern app is real-time. It doesn't matter whether it's a web app, desktop or mobile app. The notion of "Please refresh to see changes" is ancient history. Today, the fact that an app can show new comments, or similar actions as they happen — without a page refresh — is considered by many a minimum standard feature.
This means that developers must find ways to efficiently enable real-time, bi-directional communication between app clients and backend servers. One of the most used concepts to accomplish this task is the Publish-Subscribe pattern.
The Publish–Subscribe pattern, popularly abbreviated as pub/sub, is a messaging pattern where senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called subscribers, but instead categorize published messages into classes without knowledge of which subscribers, if any, there may be. Similarly, subscribers express interest in one or more classes and only receive messages that are of interest, without knowledge of which publishers there are, if any.
There are already a plethora of libraries that can help developers set up a quick PubSub server, especially within the Node.js and npm ecosystems. The highly popular socket.io quickly comes to mind as well as others like primus. But they all contain one potential drawback: they are all JavaScript-based!
This means, whether your backend is written primarily in PHP, Python, Java or Go, adding real-time communication using one of the popular libraries forces you to use and perhaps learn JavaScript.
For many developers, learning a whole new language just to add one feature can be a potential deal-breaker. For this reason, and others that we'll dive into, let me introduce you to Nchan, a non-JavaScript based pub/sub server.
Nchan is a scalable, flexible pub/sub server for the modern web, built as a module for the NGINX web server. It can be configured as a standalone server, or as a shim between your application and hundreds, thousands, or millions of live subscribers. It can buffer messages in memory, on-disk, or via Redis. All connections are handled asynchronously and distributed among any number of worker processes. It can also scale to many NGINX servers with Redis.
Convinced? Without further ado let's dive into how to deploy Nchan on an Alibaba Cloud Elastic Compute Service (ECS) instance.
Prerequisite: Elastic Compute Service (ECS) Instance
First, we'll require an up and running ECS instance. If you haven't already, sign up on Alibaba Cloud. You can use this link to get $300 worth of free trial products.
As you set up your ECS instance, let's have a brief look into some key considerations to make, in order to have the best performance possible for our pub/sub server.
The first key component is the deployment region. For best performance, select a region closest to your clients. This is because each client would have to connect to our pub/sub server and keep that connection alive to receive real-time messages. So you would rather have many low latency connections to clients (subscribers) and one high one back to your application server (publisher) than many high latency connections to clients and one low latency one back to your server. Interestingly, Nchan has a built-in ability to deploy many NGINX servers and sync all pub/sub messages via Redis. But this is an advanced scenario that most won't need.
Another thing to consider is the ECS instance type. Nchan is an NGINX module, so it naturally inherits NGINX's resource requirements, which is surprisingly minuscule – 128MB of RAM is enough to run the tiniest NGINX server! So literally any ECS instance can run an Nchan pub/sub server, right from the smallest to the largest. Feel free to choose whatever suits you well.
Another critical component is storage. The default is an Ultra Cloud Disk drive, which is fast enough for any pub/sub server. If you chose to buffer pub/sub messages in memory, then the storage chosen hardly matters. However, if your application is serving tens of thousands of connected pub/sub clients and you lack enough RAM, then you should consider switching to disk-based buffering and use the more performant SSD Cloud Disk.
Lastly, the system configuration. Alibaba Cloud's security will restrict ingress and outgoing traffic to a few ports. Make sure the NGINX port is one of them. Typically NGINX uses port 80 for unsecured HTTP traffic or 433 for the SSL secured equivalent.
With all the above taken into consideration, our new ECS instance is ready to go. Time to connect to it and prepare it for an Nchan deployment. If you are on windows, you can use Putty.
Preparing the Server
When I'm the only tenant on a CentOS server, one of the first things I do is to disable SELinux – permanently. With it on, you may sometimes run into weird bugs here and there that are a pain to debug. I normally use this command
sudo sed -i 's/enforcing/disabled/g' /etc/selinux/config /etc/selinux/config
Next thing is to install and enable the epel repository. This enables us to download and install the latest software for our Centos version. It's good practice to always use the latest versions of software, for many reasons, chiefly security, performance, and feature enhancements. Let's type these commands to do so.
sudo yum -y install wget
sudo wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
sudo rpm -Uvh epel-release-latest-7.noarch.rpm
The last steps we'll take in setting up the server is to download and install the git, zip and unzip libraries and thereafter update all software on our server. We'll use these commands.
sudo yum -y install git zip unzip
sudo yum -y update
From here on in, our server is ready to have NGINX and Nchan deployed. If need be, you can opt to restart the server, to ensure that all settings are picked up, and that some of them persist on reboots – like the potentially annoying selinux. You can use this command.
sudo shutdown -r now
Compiling NGINX with the Nchan Module
To use Nchan with NGINX, you would need to build NGINX from source and configure it with the Nchan module. The Nchan website has an overview of how to do it from various Linux flavors, however, in this article, we'll dive into details of how to do it from a CentOS 7.x server on ECS.
First, ensure that you have all the necessary build tools installed. If not, you can quickly install them using this command. By the way, even if you have them installed, running these commands should produce no side-effects.
sudo yum -y install git gcc gcc-c++ make zlib-devel pcre-devel openssl-devel
Clone the latest Nchan source code from its GitHub repository. This places the module under a folder called nchan.
git clone https://github.com/slact/nchan.git
Fetch the latest version of NGINX from its download page, v1.15.3 at the time of writing. You may opt to override it and fetch previous versions if you so wish.
wget http://nginx.org/download/nginx-1.15.3.tar.gz
Uncompress the tar file and cd into it.
tar xzvf nginx-1.15.3.tar.gz
cd nginx-1.15.3
Now for the main focus of this article. Build NGINX from the sources specifying Nchan as an added module.
sudo ./configure --add-module=../nchan --user=root --group=root --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid
sudo make
sudo make install
Check to make sure NGINX is properly installed by asking for its version. Run this command.
sudo /usr/local/nginx/sbin/nginx –v
This command should output something like this.
nginx version: nginx/1.15.3
Configuring NGINX
Now that we can confirm that the custom build worked. Let's proceed to configure NGINX and Nchan.
First, create a symlink from our custom NGINX folder to the folder where NGINX would have been installed to should we have done so using the more common yum commands or rpm. Why? Almost any tutorial you find online will reference these places so it helps in getting assistance or debugging any issue. To do so, run these commands.
sudo ln -s /usr/local/nginx/conf/ /etc/nginx
sudo ln -s /usr/local/nginx/sbin/nginx /usr/sbin/nginx
Next, let's create a system init script that can register our custom built NGINX as a CentOS service. To do so, create a file in folder /etc/init.d let's name is NGINX.
sudo vi /etc/init.d/nginx
In it, paste the following content.
#!/bin/sh
#
# nginx - this script starts and stops the nginx daemon
#
# chkconfig: - 85 15
# description: NGINX is an HTTP(S) server, HTTP(S) reverse \
# proxy and IMAP/POP3 proxy server
# processname: nginx
# config: /etc/nginx/nginx.conf
# config: /etc/sysconfig/nginx
# pidfile: /var/run/nginx.pid
# Source function library.
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0
nginx="/usr/sbin/nginx"
prog=$(basename $nginx)
NGINX_CONF_FILE="/etc/nginx/nginx.conf"
[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx
lockfile=/var/lock/subsys/nginx
make_dirs() {
# make required directories
user=`$nginx -V 2>&1 | grep "configure arguments:.*--user=" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -`
if [ -n "$user" ]; then
if [ -z "`grep $user /etc/passwd`" ]; then
useradd -M -s /bin/nologin $user
fi
options=`$nginx -V 2>&1 | grep 'configure arguments:'`
for opt in $options; do
if [ `echo $opt | grep '.*-temp-path'` ]; then
value=`echo $opt | cut -d "=" -f 2`
if [ ! -d "$value" ]; then
# echo "creating" $value
mkdir -p $value && chown -R $user $value
fi
fi
done
fi
}
start() {
[ -x $nginx ] || exit 5
[ -f $NGINX_CONF_FILE ] || exit 6
make_dirs
echo -n $"Starting $prog: "
daemon $nginx -c $NGINX_CONF_FILE
retval=$?
echo
[ $retval -eq 0 ] && touch $lockfile
return $retval
}
stop() {
echo -n $"Stopping $prog: "
killproc $prog -QUIT
retval=$?
echo
[ $retval -eq 0 ] && rm -f $lockfile
return $retval
}
restart() {
configtest || return $?
stop
sleep 1
start
}
reload() {
configtest || return $?
echo -n $"Reloading $prog: "
killproc $nginx -HUP
RETVAL=$?
echo
}
force_reload() {
restart
}
configtest() {
$nginx -t -c $NGINX_CONF_FILE
}
rh_status() {
status $prog
}
rh_status_q() {
rh_status >/dev/null 2>&1
}
case "$1" in
start)
rh_status_q && exit 0
$1
;;
stop)
rh_status_q || exit 0
$1
;;
restart|configtest)
$1
;;
reload)
rh_status_q || exit 7
$1
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q || exit 0
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
exit 2
esac
Make sure the init script has the correct permissions to run. Run this command to do so.
sudo chmod +x /etc/init.d/nginx
Now we can reload the system daemon and tell our NGINX powered Nchan pub/sub server to start on system boot. Use these commands.
sudo systemctl daemon-reload
sudo systemctl start nginx
sudo service nginx status
sudo chkconfig nginx on
Now, NGINX is fully configured with a custom module and built. Now, it's time to configure its pub/sub paramters.
sudo service nginx restart
With the above configuration, you can now publish messages to channels by sending a post request with data to /pub?id=channel_id , and subscribe by pointing Websocket, EventSource, or NchanSubscriber.js to sub/?id=channel_id.
For browser implementations, I'd greatly advocate using NchanSubscriber.js, a companion Nchan JavaScript library. I've contributed code to it, so trust me when I say, it's that simple!
Enjoy building modern real-time apps with Nchan, NGINX and Alibaba Cloud ECS!
Opinions expressed by DZone contributors are their own.
Comments