Varnish supports sticky session and websockets, so it can be configured as a load balancer for Meteor apps.
Here’s the sample Varnish configuration to distribute both web page requests and REST API requests to two Meteor servers.
Meteor Server #1:
Full content of Varnish configuration file /etc/varnish/default.vcl:
backend api_svr1 {
.host = "192.168.1.1";
.port = "3000";
.probe = {
/* You can change to use your own light weight request for probing */
.url = "/api/version";
.interval = 5s;
.timeout = 5s;
.window = 5;
.threshold = 3;
}
}
backend api_svr2 {
.host = "192.168.1.2";
.port = "3000";
.probe = {
/* You can change to use your own light weight request for probing */
.url = "/api/version";
.interval = 5s;
.timeout = 5s;
.window = 5;
.threshold = 3;
}
}
backend web_svr1 {
.host = "192.168.1.1";
.port = "3000";
.probe = {
.url = "/";
.interval = 5s;
.timeout = 5s;
.window = 5;
.threshold = 3;
}
}
backend web_svr2 {
.host = "192.168.1.2";
.port = "3000";
.probe = {
.url = "/";
.interval = 5s;
.timeout = 5s;
.window = 5;
.threshold = 3;
}
}
director api_be client {
{
.backend = api_svr1;
.weight = 1;
}
{
.backend = api_svr2;
.weight = 1;
}
}
director web_be client {
{
.backend = web_svr1;
.weight = 1;
}
{
.backend = web_svr2;
.weight = 1;
}
}
#pipe for websocket
sub vcl_pipe {
if (req.http.upgrade) {
set bereq.http.upgrade = req.http.upgrade;
}
}
sub vcl_recv {
if (req.http.Upgrade ~ "(?i)websocket") {
set req.backend = web_be;
return (pipe);
}
/* Default load balance by client IP */
set client.identity = client.ip;
if (req.url ~ "^/api") {
/* dispatch /api to api backend */
/* you can even use other balance strategy other than client ip, */
/* e.g by request url path */
set client.identity = req.url;
set req.backend = api_be;
} else {
/* dispatch web request to web backend. */
/* must use sticky balance strategy, e.g. by default client ip */
set req.backend = web_be;
return (pipe);
}
}
Here’s the sample Varnish configuration to distribute both web page requests and REST API requests to two Meteor servers.
Meteor Server #1:
Web Server: http://192.168.1.1:3000/
REST API: http://192.168.1.1:3000/api/
Meteor Server #2:
Web Server: http://192.168.1.2:3000/
REST API: http://192.168.1.2:3000/api/
You shall have noticed we have dual-purpose Meteor server here – the
web server and REST API are actually pointed to the same Meteor
instance. Requests made to /api get routed at Meteor server side by
using Meteor.Router or RestStop2.Full content of Varnish configuration file /etc/varnish/default.vcl:
backend api_svr1 {
.host = "192.168.1.1";
.port = "3000";
.probe = {
/* You can change to use your own light weight request for probing */
.url = "/api/version";
.interval = 5s;
.timeout = 5s;
.window = 5;
.threshold = 3;
}
}
backend api_svr2 {
.host = "192.168.1.2";
.port = "3000";
.probe = {
/* You can change to use your own light weight request for probing */
.url = "/api/version";
.interval = 5s;
.timeout = 5s;
.window = 5;
.threshold = 3;
}
}
backend web_svr1 {
.host = "192.168.1.1";
.port = "3000";
.probe = {
.url = "/";
.interval = 5s;
.timeout = 5s;
.window = 5;
.threshold = 3;
}
}
backend web_svr2 {
.host = "192.168.1.2";
.port = "3000";
.probe = {
.url = "/";
.interval = 5s;
.timeout = 5s;
.window = 5;
.threshold = 3;
}
}
director api_be client {
{
.backend = api_svr1;
.weight = 1;
}
{
.backend = api_svr2;
.weight = 1;
}
}
director web_be client {
{
.backend = web_svr1;
.weight = 1;
}
{
.backend = web_svr2;
.weight = 1;
}
}
#pipe for websocket
sub vcl_pipe {
if (req.http.upgrade) {
set bereq.http.upgrade = req.http.upgrade;
}
}
sub vcl_recv {
if (req.http.Upgrade ~ "(?i)websocket") {
set req.backend = web_be;
return (pipe);
}
/* Default load balance by client IP */
set client.identity = client.ip;
if (req.url ~ "^/api") {
/* dispatch /api to api backend */
/* you can even use other balance strategy other than client ip, */
/* e.g by request url path */
set client.identity = req.url;
set req.backend = api_be;
} else {
/* dispatch web request to web backend. */
/* must use sticky balance strategy, e.g. by default client ip */
set req.backend = web_be;
return (pipe);
}
}
Comments