GithubHelp home page GithubHelp logo

meteorhacks / cluster Goto Github PK

View Code? Open in Web Editor NEW
631.0 35.0 80.0 666 KB

Clustering solution for Meteor with load balancing and service discovery

Home Page: https://meteorhacks.com/cluster-a-different-kind-of-load-balancer-for-meteor.html

License: MIT License

JavaScript 100.00%

cluster's Introduction

Cluster Build Status

Clustering solution for Meteor with load balancing and service discovery.

TLDR; With cluster, we can scale Meteor apps by simply installing a Meteor package. No need to use tools like Nginx or HaProxy. It's built for Meteor and you don't need to worry about configuring IP addresses and so on. Just add more instances and let cluster take care of load balancing.

Cluster also has first class support for MicroServices.

Table of Contents

Concept

When we need to scale Meteor, it's about scaling DDP requests since that's where the traffic flows. When we need to do horizontal scaling, we generally put a load balancer like Ngnix or HaProxy in front of Meteor. Then, it'll do the load balancing.

Okay, what happens when we need to add another instance? We'd need to reconfigure the load balancer again. That will reset all the existing DDP connections.

Then what if the load balancer goes down? To fix that, we'd need to add a load balancer working parentally. That makes the setup more complex.


Cluster has an interesting way to solve this problem. It turns your Meteor app into a load balancer and you don't need to use a separate tool for that. When you add a new server (or an instance), you wouldn't even need to reconfigure cluster. Cluster will simply detect new instances and route traffic to them.

Any of the instances within the cluster can act as a load balancer. So, even if one server goes down, you don't need to worry much. Also, it's configured specially for Meteor.

Cluster can do these things because it acts as a service discovery solution. Currently, that is implemented using MongoDB, but we can have more implementations later.

Since cluster is a service discovery solution, it's perfect for MicroServices. Read to the end :)

Getting Started

Simply add cluster into your app.

meteor add meteorhacks:cluster

Then when you are deploying or starting your app, export the following environment variables.

# You can use your existing MONGO_URL for this
export CLUSTER_DISCOVERY_URL=mongodb://host:port/db,
# this is the direct URL to your server (it could be a private URL)
export CLUSTER_ENDPOINT_URL=http://ipaddress
# mark your server as a web service (you can set any name for this)
export CLUSTER_SERVICE=web

Now start as many servers as you like and DDP traffic will be sent to each of the instances randomly. You can also remove instances anytime without affecting the cluster or your app.

Live Demo - How to use cluster to scale your app

API

We have a very simple API and there are two version of the API:

  1. JavaScript API
  2. Environment Variables based API

For a production app, it's recommended to use the Environment Variables based API.

JS API

// Connect to the cluster with a MongoDB URL. Better if it's a replica set
var connectOptions = {
  // Value of 0 to 1, mentioning which portion of requestes to process here or proxy
  // If 1, all the requests allocated to this host will get processed
  // If 0.5 half of the requsted allocated to this host will get processed, others will get proxied
  // If 0, only do proxying 
  selfWeight: 1 // optional
};

Cluster.connect("mongodb://mongo-url", connectOptions)

// Register a service to the cluster
var options = {
  endpoint: "a direct url to the instance",
  balancer: "balancer URL, if this is a balancer" // optional
  uiService: "service to proxy UI" // (optional) read to the end for more info
};

Cluster.register("serviceName", options);

// Expose services to the public
Cluster.allowPublicAccess(["service1", "service2"]);

// Discover a DDP connection
// > This is available on both the client and the server
Cluster.discoverConnection("serviceName");

Environment Variables based API

# Connect to the cluster with a MongoDB URL. Better if it's a replica set
export CLUSTER_DISCOVERY_URL=mongodb://mongo-url

# Register a service to the cluster
export CLUSTER_ENDPOINT_URL="a direct url to the instance"
export CLUSTER_SERVICE="serviceName"

export CLUSTER_BALANCER_URL="balancer URL, if this is a balancer" #optional
export CLUSTER_UI_SERVICE="ui-service-name" #optional - read to the end for more info

# Expose services to the public
export CLUSTER_PUBLIC_SERVICES="service1, service2"

# Check JS API's connectOptions.selfWeight for docs
export CLUSTER_SELF_WEIGHT="0.6"

Multi-Core Support

Cluster has the multi-core support as well. You can run your Meteor app utilizing all the cores in your server as follows:

Make sure you've added the meteorhacks:cluster package.

Then expose following environment variable:

export CLUSTER_WORKERS_COUNT=auto

That’s all you have to do. Now your Meteor app will use all the cores available on your server.

You can also specify the number of workers explicitly like this:

export CLUSTER_WORKERS_COUNT=2

For more information follow this article.

If you are using Meteor Up to deploy your app, make sure you've the latest version.

MicroServices

With Microservices, we build apps as a set of tiny services rather than create a monolithic app. These services can be deployed independently.

Cluster is a tool which has built-in support for Microservices. With cluster, you can manage a set of Microservices very easily. Cluster has many features that are perfect for Microservices:

  • Register and Discover Services
  • Discover DDP Connections in both client and server
  • Load Balancing and Failovers

A Simple app based on Microservices

For example, if we want to build our own version of Atmosphere to search Meteor packages and we decided to build it with Microservices. In this case, we'd have two such services:

  • search - handles searching
  • web - has the UI

Each of these services is it's own Meteor app.

Service Registration & Discovery

First we need a Mongo URL for the cluster. That's how cluster communicates with each node. It's better if you can create a separate MongoDB ReplicaSet for that. It doesn't need to have oplog support.

Next, we add the following configuration to the search service inside server/app.js.

Cluster.connect("mongodb://mongo-url");
Cluster.register("search");

// Meteor methods
Meteor.methods({
  "searchPackages": function(searchText) {
    return ["a list of packages"];
  }
});

Then we add the following configuration to server/app.js to the web service.

Cluster.connect("mongodb://mongo-url");
Cluster.register("web");
Cluster.allowPublicAccess("search");

var searchConn = Cluster.discoverConnection("search");
var packagesFromMeteorHacks = searchConn.call("searchPackages", "meteorhacks");
console.log("here is list of", packagesFromMeteorHacks);

In the above example, you can see how we made a connection to the "search" service from the "web" service.

We've also allowed clients to connect directly to the search service from the browser (or from cordova apps). That was done with a single line:

Cluster.allowPublicAccess("search");

This way, you can access the "search" service from the client side of the "web" service as shown below:

var searchConn = Cluster.discoverConnection("search");
searchConn.call("searchPackages", "meteorhacks", function(err, packages) {
  if(err) throw err;
  console.log("here is list of", packages);
});

Learn More about Microservices

If you'd like to learn more, here are a few resources for you.

Multiple Balancers

The setup we discussed earlier in the getting-started section still has one issue. All the DDP connections are routing through a single instance which is normally the server you pointed your domain name to via DNS.

But that's not ideal. If it goes down you lose access to the whole cluster. Additionally, you will likely be facing scaling issues as well since all traffic is routing through that single server.

Cluster has a built in solution for that. It's called Balancers. A Balancer is an instance of your cluster which acts as a load balancer. You can add or remove them as needed.

Making your instance a Balancer is pretty simple. Just export the following environment variable.

export CLUSTER_BALANCER_URL=https://subdomain.domainname.com

This URL is open to public and it should point to this instance. Now configure your instances to run as Balancers and your cluster will start to load balance DDP connections through them.

Demo & Presentation - Learn more about Balancers

UI Service

In cluster, there is a special concept called "UI Service". By default, if you visit a service, it's UI will be served to you. For an example, let's say we've two services:

  • web - the user inteface of our app (on port 7000)
  • search - the service which expose a search API (on port 8000)

So, if you visit the web app on port 7000, you'll get the UI of the web app. If you visit the search app on port 8000, you'll get the UI of the search app.

But it's possible, search apps to give the UI of the "web" app as well. With that we can make sure, all the services in the cluster exposes the same UI. For that, simply expose following environment variable.

export CLUSTER_UI_SERVICE="web"

Practical Setup

Let's see how you could setup Cluster in a practical scenario. BulletProof Meteor is already running Cluster so I will show you an excerpt of its setup. (I've changed some information for the educational purposes)

We have four Servers and three of them are Balancers. This is how they are structured.

{
  "ip-1": {
    "endpointUrl": "http://ip-1",
    "balancerUrl": "https://one.bulletproofmeteor.com"
  },
  "ip-2": {
    "endpointUrl": "http://ip-2",
    "balancerUrl": "https://two.bulletproofmeteor.com"
  },
  "ip-3": {
    "endpointUrl": "http://ip-3",
    "balancerUrl": "https://three.bulletproofmeteor.com"
  },
  "ip-4": {
    "endpointUrl": "http://ip-4"
  }
}

I'm using Meteor Up to deploy and here's a sample configuration file. With Meteor Up, you don't need to expose CLUSTER_ENDPOINT_URL. It'll automatically do that by itself.

Make sure you install the latest version of Meteor Up.

DNS & SSL

We'll use cloudflare for DNS and SSL setup.

We turn off WebSockets since cloudflare does not support SSL with WebSockets yet!

As this setup, ip-1 and ip-2 will take care of load balancing for static content while ip-1, ip-2 and ip-3 is take care of load balancing DDP connections.

All 4 servers process DDP and provide Static Content.

cluster's People

Contributors

arunoda avatar jasonnathan avatar okland avatar orion- avatar tigransloyan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cluster's Issues

Error: write after end

Sometimes my app throws that error:

Cluster: Exiting worker 2 with exitCode=7 signalCode=null
Error: write after end
    at writeAfterEnd (_stream_writable.js:133:12)
    at Socket.Writable.write (_stream_writable.js:181:5)
    at Socket.write (net.js:616:40)
    at Socket.Writable.end (_stream_writable.js:341:10)
    at Socket.end (net.js:397:31)
    at App.exports.GenericApp.GenericApp.handle_error (/opt/easydrop/app/programs/server/npm/ddp/node_modules/sockjs/lib/webjs.js:148:13)
    at execute_request (/opt/easydrop/app/programs/server/npm/ddp/node_modules/sockjs/lib/webjs.js:33:30)
    at Object.req.next_filter (/opt/easydrop/app/programs/server/npm/ddp/node_modules/sockjs/lib/webjs.js:105:18)
    at Listener.webjs_handler (/opt/easydrop/app/programs/server/npm/ddp/node_modules/sockjs/lib/webjs.js:107:13)
    at Listener.handler (/opt/easydrop/app/programs/server/npm/ddp/node_modules/sockjs/lib/sockjs.js:147:12)

What IP addresses make requests to 3rd party Oauth?

Hi, I am using Cluster on AWS Opsworks... thanks to the great help of folks Sunsama.com as per https://blog.sunsama.com/meteor-docker-opsworks/

One thing I am not sure on is if I am using 3rd party Oauth (via accounts-facebook etc) the require that I put in the requesting domain and server IP (whitelist).

I have setup cluster to handle requests at mydomain.com ... I have not used the load balancer option. I have two servers

I have setup Facebook app to allow login from mydomain.com. If Cluster redirects me to the actual machine of my domain I can login. But when Cluster sends me to one of the other machines in the Cluster I get the following error:

Exception while invoking method 'login' Error: Failed to complete OAuth handshake with Facebook. failed [400] {"error":{"message":"This IP can't make requests for that application.","type":"OAuthException","code":5}} 

So this makes sense as the second machine in the cluster would have an IP that Facebook does not know.

As the system may autoscale, the IPs may not be known to Facebook.

I there some way to have Cluster have all requests seem like they're from one IP?

WebSocket is closed before the connection is established.

WebSocket connection to 'wss://domain/sockjs/163/h0c16r5q/websocket' failed: WebSocket is closed before the connection is established.

I suspect cluster could be the blame, but have no proof just yet.

This happens 3-4 times per hour in meteor run mode

Question: Is there a way in app that we can detect current running core?

I'm running to an issue that I have an Mongo update query in startup code of server:

if (Meteor.isServer) {
 Meteor.startup(function(){
    Posts.find().observeChanges({
        added: function(id, fields) {
            Authors.update({_id: fields.authorId}, {$inc: {count: 1}});
        }
    })
 });
}

I run app with 4 cores server and this added event run 4 times which I expected just 1.
Is there a way in app that we can detect current running core? Or any other best practices to run observerChanges in multicore environment?

meteorhacks:cluster + velocity with jasmine doesn't work

Below problems are occured:

  • Logged in user logged out autmatically.
  • Method not found 404 on
  • Uncaught SyntaxError: Unexpected token <

If I remove below cluster code section, everything is ok. I think velocity client integration test and cluster can't work together.

Cluster.connect('mongodb://localhost/discovery-conn');
Cluster.register('main');

var conn = Cluster.discoverConnection('service');

Meteor.methods({
  getMessage: function (name) {
    check(name, String);
    return conn.call('greet', name);
  }
});

Reproducing repo: https://github.com/boldkhuu/cluster-with-velocity

Manage errors when cluster unavailable

Hi,

I have a main microservice who request some others microservices, I would like to display an error on my UI when a microservice is unavailable.

For the moment I have the message -> "Cluster: no such endpoint for service:name" in the server console.

How can I do ?

Thanks :)

Workers Keep Crashing Randomly

Randomly all of the workers will kill them selves with an error similar to these:

[104.236.27.101] Error: write after end
    at writeAfterEnd (_stream_writable.js:133:12)[104.236.27.101] 
    at Socket.Writable.write (_stream_writable.js:181:5)
    at Socket.write (net.js:616:40)
    at Socket.Writable.end (_stream_writable.js:341:10)
    at Socket.end (net.js:397:31)
    at App.exports.GenericApp.GenericApp.handle_error (/opt/meteor/app/programs/server/npm/ddp/node_modules/sockjs/lib/webjs.js:148:13)
    at execute_request (/opt/meteor/app/programs/server/npm/ddp/node_modules/sockjs/lib/webjs.js:33:30)
    at Object.req.next_filter (/opt/meteor/app/programs/server/npm/ddp/node_modules/sockjs/lib/webjs.js:105:18)
    at Listener.webjs_handler (/opt/meteor/app/programs/server/npm/ddp/node_modules/sockjs/lib/webjs.js:107:13)
    at Listener.handler (/opt/meteor/app/programs/server/npm/ddp/node_modules/sockjs/lib/sockjs.js:147:12)
Cluster: Exiting worker 7 with exitCode=7 signalCode=null
[104.236.27.101] TypeError: Cannot read property 'writeHead' of undefined
    at Listener.webjs_handler (/opt/meteor/app/programs/server/npm/ddp/node_modules/sockjs/lib/webjs.js:78:21)
    at Listener.handler (/opt/meteor/app/programs/server/npm/ddp/node_modules/sockjs/lib/sockjs.js:147:12)
    at Listener.handler (/opt/meteor/app/programs/server/npm/ddp/node_modules/sockjs/lib/sockjs.js:6:61)
    at Server.<anonymous> (/opt/meteor/app/programs/server/npm/ddp/node_modules/sockjs/lib/sockjs.js:154:24)
    at Server.new_handler (/opt/meteor/app/programs/server/npm/ddp/node_modules/sockjs/lib/utils.js:86:19)
    at packages/ddp/stream_server.js:133:1
    at Array.forEach (native)
    at Function._.each._.forEach (packages/underscore/underscore.js:105:1)
    at Server.newListener (packages/ddp/stream_server.js:132:1)
    at packages/meteorhacks:cluster/lib/server/utils.js:11:1

This error may be unrelated

[104.236.27.101]     at Object.Meteor._nodeCodeMustBeInFiber (packages/meteor/dynamics_nodejs.js:9:1)
    at [object Object]._.extend.get (packages/meteor/dynamics_nodejs.js:21:1)
    at [object Object].RouteController.lookupOption (packages/iron:router/lib/route_controller.js:66:1)
    at new Controller.extend.constructor (packages/iron:router/lib/route_controller.js:26:1)
    at [object Object].ctor (packages/iron:core/lib/iron_core.js:88:1)
    at Function.Router.createController (packages/iron:router/lib/router.js:201:1)
    at Function.Router.dispatch (packages/iron:router/lib/router_server.js:39:1)
    at Object.router (packages/iron:router/lib/router.js:15:1)
    at next (/opt/meteor/app/programs/server/npm/webapp/node_modules/connect/lib/proto.js:190:15)
    at Object.Package [as handle] (packages/cfs:http-methods/http.methods.server.api.js:420:1)

It is causing instability on our website is there a known fix for this?

Firefox Block CORS/XHR

So, I have two systems: backend.site.com and client.site.com
But in Firefox the Cross-Origin blocks the content of the backend. I configured the package browser-policy but the error continues.

But I can't see this error in: https://bulletproofmeteor.com/
@arunoda What did you do to resolve this?

PS: I'm sorry to open this issue, but after hours trying and searching was not a solution, so I have to ask for those who already have it resolved. Thank You!

Client connection IP is reported as 127.0.0.1

Is this something cluster and/or mup is doing, or is it a problem with some other package?

Accounts.onLogin (info) ->
  console.log('onLogin', info.connection.clientAddress)
  console.log(info.connection.httpHeaders)
[parlay.io] onLogin 127.0.0.1[parlay.io] 
[parlay.io] { host: 'parlay.io',[parlay.io] 
[parlay.io]   'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36',[parlay.io] 
[parlay.io]   'accept-language': 'en-US,en;q=0.8' }[parlay.io]

Question: How to do versioning for services

Hi @arunoda,

if you have a lot of serivces and one changes from 1.0.0 to 2.0.0 including breaking "API" changes. How can I control that?

By naming conventions of the service?

Cluster.register('ServiceA.v1')
Cluster.register('ServiceA.v2')
...

Or would it be an idea to register like

// register service
Cluster.register('ServiceA', {version: '1.0.1'})

// connect to service
serviceConnection = Cluster.discoverConnection("mlServiceTest", {version: '1.0.1'});

Cluster and MeteorIonic Integration (shows no data in mobile app version)

Has anyone tried that before?

I built my meteor-ionic app for IOS and Android, which works just fine when I run it in the browser ( Chrome ) on mac and when I run it in Chrome from my android phone.

I am running the ionic version on port 5000, and web version on port 3000. All the publishers are part of the web version and so is the database. Ionic app at 3000 connects to the server and database using Meteor Cluster solution.

When I launch the app as an Android app, it does not connect to the server and does not show any data.

Command to run meteor-ionic mobile app -
sudo MONGO_URL=mongodb://localhost:3001/meteor CLUSTER_ENDPOINT_URL=http://localhost:3000 meteor run android-device --verbose --port 5000 --settings settings.json

discovering connection from mobile app -
SearchConn = Cluster.discoverConnection('qollserver');

Declaring the mongo-collection in the mobile app -
QbSummary = new Mongo.Collection('qbank_summary', SearchConn);

Subscribing to the server side data from mobile app -
SearchConn.subscribe('QBANK_SUMMARY_PUBLISHER', {userId: userId});

Query for the data in the mobile app -
QbSummary.find();

On the server side, I have the following in app.js
Cluster.connect("mongodb://localhost:3001/meteor");
Cluster.register("qollserver");

Run the web version server running the following command -
sudo meteor --port 3000

Concerns about recommending `cluster` over existing solutions

I think this is a great concept, especially because it's so easy to implement. But I'm wondering if it should be recommended for serious production use. If you would make that recommendation, it would be nice to see a comparison between cluster and the other solutions in the docs--

  1. The docs mention that using cluster is as easy as adding a Meteor package. So I'm guessing that it puts the request handling and load balancing on Meteor applications and uses the application's database? If not, it's a bit more complicated.
  2. There are good existing solutions that auto-scale load balancers, and I know you're aware of them--what are they, and why is cluster better for Meteor apps?
  3. If DDP connections are dropped as a load balancer is manually scaled (for the very short period of time it takes to restart the load balancer), as long as there are sticky sessions, is that a problem? What happens?
  4. The load balancers in question, like HAProxy, are battle-tested in production and have been under development for years. HAProxy supports SSL, HTTP compression, health checks, redispatching, and has a very useful ACL feature, and supports complex redirects, among other features. It's written in C, and can handle upwards to 40K hits per second. At what point does someone decide to use cluster instead of HAProxy, or vice-versa?

These points aren't meant to criticize your package--as I said, it's really cool. And of course, running a real-time Meteor app is much different than running an HTTP request/response-style app.

Exiting worker with exitCode=0 signalCode=null

I managed to deploy my app after adding cluster and I set "CLUSTER_WORKERS_COUNT":2 in my mup.json.

My app is working fine but when I check the logs, cluster seems to be trying to initialize new workers all the time because they are exiting immediately for some reason:

...
Cluster: Initializing worker 55 on port 4810
Cluster: Exiting worker 55 with exitCode=0 signalCode=null
Cluster: Initializing worker 56 on port 4828
Cluster: Exiting worker 56 with exitCode=0 signalCode=null
Cluster: Initializing worker 57 on port 15815
Cluster: Exiting worker 57 with exitCode=0 signalCode=null
...

MicroServices separation by folder naming convetions

Hi, Is it possible
to separate the microservices by folder naming convention?
Or by a service.json file, inside a folder, which would describe the (to compile) code scope and limit the execution only to a special service environment.

It could be something like the already implemented balancer solution:
"Every node can be a balancer"
This would be:
"Every Node can be any of the possible services inside one project"

This could also simplifie the code base, because we could share code between services without copy & paste of files between different meteor projects, because we would have only one project. And it would be very easy to start using services for existing projects.

So my question is, is it possible and are there some limitations to solve it?
This would also make possible of a MotherShip solution, because we would know about all the microservices in a project ;)

And a lot of thanks, to Arunoda and all the MeteorHacks Guys which are helping a lot to improve meteor.
Really great work all that stuff!

Observe cursors

HI! I had a problem. When a document is added to the collection, my observers are triggered on all servers (2 clusters with 4 cores = 8 workers). How can i prevent this behavior?

For example:

Items.find().observeChanges({
  added: function(id, fields) {
    HTTP.get(fields.url, function() {
      // DO SOMETHING
    })
  }
})

Its fired on ALL workers, but i want it to only run on one worker (most are not loaded).

Geo based balancing

This is just something that came to my head. Do you thing it could be possible to route traffic to the nearest server? Like when you have servers in the US and Europe, the system should prefer near servers. Something like geo based load-balancing.

Error 503 on Docker Container

If the apps are running inside a container and are on the same server they do not communicate as it should.

I'm using Docker-compose, and here is a reproduction:
Frontend App: https://bitbucket.org/jadsonlourenco/todo-frontend
Backend App: https://bitbucket.org/jadsonlourenco/todo-backend
Need install Docker and Docker-compose, then:
docker-compose up
(need run this command in each folder, will start two containers, for each app, access "localhost:3031" to see the frontend app running)

In this case I have two Apps, frontend (that subscribe the collection from backend) and the backend (that just publish the collection). The Cluster package works fine and I can subscribe the collection, I have it working in production, using Docker too. But I don't know why not work any more in Docker, I install a new server and did the same installation, and get this problem.

This is not a problem of network, because I did the same test using different server, and various cloud services with valid domain. As I said this only happens if the applications are on the same server (or in the same cluster, when tested with CoreOS).

And in last case I try subscribe the collection in frontend app using the DDP.connect and works, yes! Because of this I think is some thing on Cluster package or on Docker (container network).

PS: @arunoda I ask about it on twitter, but just open it now because I try everything before make sure the cause of problem; thank you!

Displaying cluster data in client

I'm wanting to build a status/admin UI page to display information on the cluster (maybe even as a standalone service in the cluster). I'm firstly just wanting to list the endpoints grouped by service. I was hoping to get access to the documents via a find on Cluster.discovery._endpointsColl, but I see the client has a different API limited to discoverConnection. Have would you achieve this?

404s from /cluster-ddp

Hi, I'm using meteor-cluster in the following scenario:

  • AWS
  • 2 instances running meteor-cluster as normal app-servers (e.g. not balancers)
  • Deployment using mup
  • ELB
  • SSL termination on ELB
  • DISABLE_WEBSOCKETS (since ELB+SSL)
  • The site itself (if you want to test) is https://gormim.com
    Most of the time things work well, but since I have an alert on ELB looking for 4xx I noticed that every once in awhile the calls to POST /cluster-ddp are 404ing

Here's just one screenshot of the 404s on my ELB.
http://cl.ly/image/17083P0j2x07
And I recorded the access logs, so here's an example request that 404s

2015-02-28T17:41:57.787697Z web 66.249.78.7:60042 172.31.38.90:80 0.00012 0.003284 0.000023 404 404 417 26 "POST https://gormim.com:443/cluster-ddp/f4a987ea4fac27bdc2f00df9dd01a691e23f29b8/web/352/etyjoyb4/xhr_send HTTP/1.1"

Most of the /cluster-ddp calls end with 200 (or 204), but occasionally they 404.
Here are just a few examples or 2xx lines:

2015-02-28T17:41:18.573685Z web 109.64.50.27:53781 172.31.12.222:80 0.000073 30.001697 0.000045 200 200 0 24 "POST https://gormim.com:443/cluster-ddp/f4a987ea4fac27bdc2f00df9dd01a691e23f29b8/web/607/lqhhw6rh/xhr HTTP/1.1"
2015-02-28T17:41:49.567741Z web 109.64.50.27:53761 172.31.12.222:80 0.000116 0.004414 0.000032 204 204 22 0 "POST https://gormim.com:443/cluster-ddp/f4a987ea4fac27bdc2f00df9dd01a691e23f29b8/web/607/lqhhw6rh/xhr_send HTTP/1.1"

As far as I can tell, this does not interfere in the sense that users are bothered by it, but it does make monitoring really hard (b/c it's hard to say what's a real error and that's just 404 from /cluster-ddp).

I wonder if you had seen this before or could guide me towards a solution?

Thanks!

One instance overloaded while another one is much less

I'm using 4 EC2 instances with Meteor-Up + Cluster for setup. This is my Meteor-up configuration:

"servers": [
    {
      "host": "server-1.myserver.com",
      "username": "ubuntu",
      "pem": "./ssh.pem",
      "env": {
        "CLUSTER_BALANCER_URL": "https://server-1.myserver.com",
        "CLUSTER_ENDPOINT_URL": "https://server-1.myserver.com"
      }
    },
    {
      "host": "server-2.myserver.com",
      "username": "ubuntu",
      "pem": "./ssh.pem",
      "env": {
        "CLUSTER_BALANCER_URL": "https://server-2.myserver.com",
        "CLUSTER_ENDPOINT_URL": "https://server-2.myserver.com"
      }
    },
    {
      "host": "server-3.myserver.com",
      "username": "ubuntu",
      "pem": "./ssh.pem",
      "env": {
        "CLUSTER_BALANCER_URL": "https://server-3.myserver.com",
        "CLUSTER_ENDPOINT_URL": "https://server-3.myserver.com"
      }
    },
    {
      "host": "server-4.myserver.com",
      "username": "ubuntu",
      "pem": "./ssh.pem",
      "env": {
        "CLUSTER_BALANCER_URL": "https://server-4.myserver.com",
        "CLUSTER_ENDPOINT_URL": "https://server-4.myserver.com"
      }
    }
]

But when I check the 4 instances, the instance-1 CPU usage is much more than instance-2 (34% compared to 5%), instance-3 & 4 consumes about 10%.

I've also checked the server log and see that log from instance-1 is much more than the other's.

Is there anything wrong with my configuration?
Thank you so much for your help.

Determine master process

how can I know which is the master process to perform actions that should only be performed once ?
thx

How to set up round robin for microservices?

I'm experimenting with cluster and what I want to achieve is to be able to round robin requests between multiple instances of a particular micro service.

E.g. I have a "log" service which provides logging functionality to the cluster:

Cluster.register('log');

and a web service which connects to that log service:

var logConn = Cluster.discoverConnection('log');

As a test I start 2 instances of the log service (let's call them log1 and log2), both on a different port:

~/apps/demo-log1$ MONGO_URL=mongodb://localhost:27017/demo meteor --port 2001
~/apps/demo-log2$ MONGO_URL=mongodb://localhost:27017/demo meteor --port 2002

And 1 instance of the web service:

~/apps/demo-web$ MONGO_URL=mongodb://localhost:27017/demo meteor --port 2000

The web service can send log messages to the log service, but it's always the same instance (let's say log1) that's receiving the messages.
When I stop this instance (log1), the messages are being sent to the other one (log2).
So the failover is working, but in addition to this I also want some kind of load balancing between the two log instances so that they can both accept messages from the web service in a round robin fashion.

What am I doing wrong?

Complete nginx / HaProxy replacement ?

Hi, I posted this question on SO:

Basically is meteor:cluster able yet to route different dns to the right meteor app ? This would involve the main meteor service to know the URL origin and then to redirect to the right meteor app instance. A bit like what we are doing with a reverse proxy.

Autoscaling/ Cluster Events

It would be nice if we could run code on certain events. For example, if the average load is more than 90%, launch a new server (I think DigitalOcean & friends allow this using their APIs). Or at least notify the admin. Or remove a server, if the load goes below a certain value. And having a number of current servers would be nice, so we could scale but check before removing servers so that we keep at least three servers or so.

I'm not sure what events and data would be helpful, but basically a cluster API would be nice :)

Please publish your package meteorhacks:cluster for Windows

Hi!

This package has binary dependencies, and we wanted to give you a heads up that Meteor 1.1, with support for Windows will be released in a few days.

Now is the time to publish your package for Windows!

It should be very straightforward -- we've added new build machines that run Windows that you can access with the meteor admin get-machine command. This is the same as you've done before for the other architectures we support.

For complete directions on how to publish your package for Windows, visit https://github.com/meteor/meteor/wiki/Publishing-a-package-with-binary-dependencies-for-the-Windows-preview

On behalf of the Meteor team,
@stubailo, @Slava and @avital.

P.S. This is an automated message based on our database of package authors.

HTTPS doesn't work on Cloudflare

If I go through the "deploying a highly available meteor cluster" tutorial and enter the url in with https the page loads but the cluster does not work. If I open the console i'm getting this in Chrome:

Mixed Content: The page at 'https://mydomain.net/' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://162.xxx.xx.xxx/cluster-ddp/3ad40d3dc87940b5724b52c633d860b3be071630/search/631/nkhc327e/xhr'. This request has been blocked; the content must be served over HTTPS.

If I set the "CLUSTER_BALANCER" to "//162.xxx.xx.xx" (or https) I get an error:

POST https://45.xx.xxx.xxx/cluster-ddp/9807e97fb619e150c77a30f653b521d75033eac1/web/494/lk53znrn/xhr net::ERR_CONNECTION_REFUSED

Is there an easy way to accept https on all of the nodes that are not balancers?

Update Cloudflare websocket info

Readme says:

We turn off WebSockets since cloudflare does not support SSL with WebSockets yet!

They support both ws:// and wss:// if you have an enterprise account.

Use DNS to resolve balancers and endpoints

Now we are doing an info hit to explore balancers and endpoints. If we could use DNS, we can support external apps without much issue.

May be we don't need to go with this approach.

service's name caused an error on client

Hello,

I tried this in my repo (https://github.com/darkship/test_cluster_client_error) :

if (Meteor.isServer) {
      Cluster.connect("mongodb://localhost:27017/discovery");
      Cluster.register("test-test");
}

But on the client I have an error (that was not expected and killed other connexions):

 Firefox could not connect to ws://localhost:5001/cluster-ddp/8d6a5062c883e6d079209864a3fbeec534018d1e/test-test/866/10ypgijw/websocket.

And sometimes on the server too :

Cluster: no such endpoint for service:test-test

Replacing test-test by test solved the issue.
I tried with test_test and it didn't work either.So what are the service's name limitations ?

What's the impact of not running with Websockets

@arunoda this sounds really interesting. I noticed that you are not running with Websockets. Anyway, I was wondering if you have any high-level guidance on what sort of performance impact could we expect on falling back to HTTP (vs TCP/Websockets), please?

autoreconnect to the service

My microservices allocated on DigicalOcean droplets. Sometimes cluster throw this errors.

stream error Network error: ws://10.133.235.201:3000/websocket: connect ECONNREFUSED

Re-initializing/cleanup of cluster DB?

Hi,

Does Cluster clean itself up or do I need to delete old entries that in the discovery database?

I am worried that there are some "old" IPs in there that are still working as part of a separate test environment and cluster is redirecting to it... I just wanted to re-initialize the DB and make sure. Do I need to do this or will Cluster clean itself up?

thanks

Infinite loop

I use multicore cluster mode. When reload page ( i use ironrouter) the web enter in a loop reload infinite.
When disable cluster workers, the web work fine

Is it possible to have multiple cores share a variable?

Hey! I'm loving all the things you guys are building for meteor!
I was using cluster up until a few days ago when I realized it breaks my current job que!

I have a custom job handler running on my server that looks like this:

Jobs = new Mongo.Collection('jobs')

var throttle = [];
var running = false;

Meteor.setInterval(function(){
    if (!(running)) {
        running = true;
        var now = new Date();
        var time = now.getTime();
        var unfinishedJobs = Jobs.find({_id: { $nin: throttle }, date: {$lt: time} });
        unfinishedJobs.map(function (job) {
            throttle.push(job._id);
            if (job.name === 'setTime') {
                setTime(job.campaign);
            }else if (job.name === 'matchLimit') {
                matchLimitReached(job.match);
            }

            /* kill throttle */
            var index = throttle.indexOf(job._id);
            if (index > -1) {
                throttle.splice(index, 1);
            }
            Jobs.remove({_id: job._id});
        });
        running = false;
    }
}, 500);

The issue is that this code gets ran on both cores... so a second one can run before the first one is completed and cause problems.

Is there a way for the separate instances to share a variable?
I want them to be able to share var running = false; so that way this isn't an issue!

Is this possible?
Can I just set the environment variables to do this or?

Any examples for using node-usage for load-balancing?

Thank you for this great meteor package! I also noticed your great (a bit older) node library node-usage.

So, is there any way of integrating these two? In the way that the system-resources are being taken into account for the balancing logic? I think that would be the ultimate goal, pointing the visitor to the most idle server, and ultimately alerting some system administrators when all servers become to heavily loaded (so he can spawn a new server).

cluster and cordova integration

Hi @arunoda,
first of all, thanks for all the great work you are doing for the meteor community ;)

We are trying to build an app and would like to use the cluster package for service-discovery.

As soon as we run the app in the ios simulator or device we get following error:

Uncaught Error: SyntaxError: JSON Parse error: Unrecognized token '<':2087:http://meteor.local/packages/ddp.js?41b62dcceb3ce0de6ca79c6aed088cccde6a44d8

Basically the ddp call returns the raw html.

I have created a small demo project here https://github.com/banglashi/meteor-cordova-cluster to reproduce the issue. Just edit the CLUSTER_DISCOVERY_URL in the dev and mobile shell scripts.
Than lunch the ./dev script for the search service and the ./mobile script for the web service.

It could be possible that I am doing/setting something wrong. Could it be related to the endpoint being localhost?

Any hint or suggestions is really appreciated.

Best regards

Some questions

Hello,

I like the idea of mini-services using cluster. It makes my application more modular and as an added benefit I can scale out DDP traffic.
Now, I actually made a separate build process using gulp to separate my front-end from my back-end (as we have some specific requirements on how to serve the front-end).
Therefore I do not need webapp (since I do not want autoupdate etc either).
Clusters package.js specifies it needs webapp. Therefore my first question is how hard this dependency is between cluster and webapp.

My second question is how session data is handled. If I make mini services using cluster and use the accounts package is session and authentication data shared between these services?

Also,

Load balancing support

Create a way to load balance services. Come up with a pattern to completely ignore Nginx

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.