|
Node.js
|
|
Monday, 28 March 2011 23:27 |
|
Can Node.js beat the big players in the industry? The key strength of Node.js is that it is efficient. Node.js is not faster than other platforms, at least not by orders of magnitude. It's not going to get a request completed and back to the client perceptibly faster than anything else. The only thing it's going to do that is really amazing is to do it all more efficiently so you need fewer servers. And it will only do that if your app is I/O intensive.
Where Node.js is headed, it is going to plateau. It's got a lot of popularity, I think because the efficiency excites developers and it's fun to develop in JavaScript. That will only take it so far. To play with the big boys, this thing needs to find it's niche. What will take Node.js to the next level is a business model where highly efficient, I/O intensive applications can create a huge competitive edge or perhaps even makes something possible that wasn't possible before.
The first thing that comes to mind is shared website hosting. The efficiency Node.js should make it possible to provide hosting of Node.js powered applications cheaper than anything before it. Oh, ya, that sounds a lot like Joyent. :)
The second thing that comes to mind is improving the efficiency of huge server farms, like Wal-Mart's ecommerce infrastructure. But what does that really do for them? It doesn't help with horizontal scalability. It doesn't make anything possible that wasn't possible before. It merely makes it so they can save some money on servers. Is that enough to win them over? Considering the downsides they would face (small developer pool, immature platform, etc.) there's no way it would be worth it. We've got a chicken and the egg problem here. The platform won't fully mature without major adoption, but nobody major is going to adopt it until it is mature.
So, was Node.js dead before it ever got started? I suppose that depends on what you come up with next. Happy hacking!
|
|
Node.js
|
|
Monday, 13 December 2010 13:45 |
|
Just want to point people to this interview with Ryan Dahl. It's basically a status update for Node.js and where it's headed.
|
|
Node.js
|
|
Tuesday, 05 October 2010 20:58 |
|
Just watched a video of Ryah Dahl (creator of node.js) from JSConf. It's very interesting to hear about the project's motivations and design goals directly from the author. Check it out.
|
|
Node.js
|
|
Tuesday, 05 October 2010 11:05 |
|
I heard about a new website today called noatta.ch on #Node.js. This sweet app uses the new File API to store files locally and allows you to send uploaded files by sharing your unique URL. This is so simple and elegant and it has long lasting value. I'll bet I end up using this service regularly for a long time. Nice work Astro!
|
|
Node.js
|
|
Wednesday, 29 September 2010 12:43 |
|
There are two Twilio client libraries available for Node.js (that I could find). The first is aaronblohowiak's Twilio-Node and the second is guille's node.twilio.js. What I needed to do was to send an SMS message and neither library provided an example of how to do this. I'm not sure if they just neglected it or if they figured that a library wasn't necessary for accessing a simple REST interface.
So here is my implementation of a simple module for sending SMS messages through Twilio from a Node.js application. I would have just used the http module except that the Twilio API leverages HTTP Basic Authentication which you can manually do using the http module, but it is a pain. restler makes it must easier.
var rest = require('./vend/restler/lib/restler'),
sys = require('sys'),
config = require('../config');
var sendSMS = function(opt, callback) {
var accountSid = config.twilio.accountSid,
authToken = config.twilio.authToken,
apiVersion = '2010-04-01',
uri = '/'+apiVersion+'/Accounts/'+accountSid+'/SMS/Messages',
host = 'api.twilio.com',
fullURL = 'https://'+accountSid+':'+authToken+'@'+host+uri,
from = opt.from || config.twilio.fromPhoneNumber,
to = opt.to,
body = opt.body;
rest.post(fullURL, {
data: { From:from, To:to, Body:body }
}).addListener('complete', function(data, response) {
callback();
});
};
exports.sendSMS = sendSMS;
|
|
Node.js
|
|
Wednesday, 29 September 2010 12:09 |
|
One thing I love about MongoDB's document-oriented approach is that there is no longer a need for an ORM (object relational mapper) because there is nothing to map. You can just store your object directly. However, I would still like a layer to reduce the complexity of interfacing with MongoDB. For example, working with MongoDB requires quite a few layers of nested callbacks and I don't want to deal with that everywhere.
The first library I came across to ease use of MongoDB was mongoose. It seems to be quite nice, but it has one problem. It is trying to be an ORM where an ORM is not needed! I don’t want to create my model using the ORM tool. I shouldn’t have to do that with MongoDB. I should be able to create my models completely separate and if I want to I might not even make a model in some cases.
So what I really want is just a simple layer over MongoDB to take care of connections, reduce the number of callbacks I have to deal with and make error handling more simple. Not an ORM. So I started to write a class called DataProvider that does just this. It works with models by defining an interface they must implement in order to work with it (a very simple interface). Keep in mind this is very incomplete. I only implemented what I need at the moment.
DataProvider.js
var mongodb = require('mongodb'),
sys = require('sys');
var DataProvider = function(cfg) {
cfg = cfg || {};
if (!cfg.host) { throw new Error('Missing host config.'); }
cfg.port = cfg.port || 27017;
if (!cfg.dbname) { throw new Error('Missing dbname config.'); }
this.cfg = cfg;
};
DataProvider.prototype.save = function(persistable, callback) {
var db = new mongodb.Db(
this.cfg.dbname,
new mongodb.Server(this.cfg.host, this.cfg.port, {auto_reconnect:true}),
{strict:false}
);
db.addListener('error', callback);
db.open(function(err, db) {
if (err) { return callback(err) }
db.createCollection(persistable.getCollectionName(), function(err, collection) {
if (err) { return callback(err) }
collection.insert(persistable.toObject(), function(err, docs) {
db.close();
callback(null, persistable);
});
});
});
};
exports.DataProvider = DataProvider;
Persistable.js
var Persistable = function(){};
Persistable.prototype.getCollectionName = function() { throw new Error('not implemented') };
Persistable.prototype.toObject = function() { throw new Error('not implemented') };
Persistable.prototype.initFromObject = function() { throw new Error('not implemented') };
exports.Persistable = Persistable;
|
|
Node.js
|
|
Monday, 06 September 2010 20:59 |
Since Node.js runs in a single process with no threads by default, your application will not be capable of leveraging multiple CPUs. On the Node.js home page, they state Processes are necessary to scale to multi-core computers, not memory-sharing threads. The fundamentals of scalable systems are fast networking and non-blocking design—the rest is message passing. In future versions, Node will be able to fork new processes (using the Web Workers API ) which fits well into the current design. I checked into the timeline for this promise and found a few interesting things.
First, there is now an implementation of the Web Workers API called node-webworker, which is built on node-websocket-server/client. Although I haven't tried it out myself, I get the impression that it needs some work before being ready for prime time, but it looks promising.
Second, there is a way to manually spawn child processes is Node.js, and from what I can tell, this is fully baked. The API call looks like "require('child_process').spawn()." One noted downside of this method is that the child process is not well integrated into the main processess, so messaging between the processes is a bit painful and things like output to stdout won't work as you might hope. My reaction to this method is that I wanted something much more transparent. I want my app to "just work" on a multi-cpu server, without modifications to my application. The response I got to this concern was that the CPU is rarely the bottleneck for socket applications, but rather I/O. Yeah, but what if you have a particularly CPU intensive application? Well, in that case, it might make sense to spawn a child process just for the CPU intensive logic, as opposed to all of your application constantly dealing with the overhead of process context switching when CPU isn't the bottleneck anyway. And, if tons of code in your application is CPU intensive, then perhaps the Web Workers API implementation above is right for you.
So, in summary, CPU probably won't be your bottleneck. You can manually spawn child processes for CPU intensive activities as needed and you can use node-webworker if you really need it. It all makes quite a bit of sense to me now. It is somewhat annoying that there's an extra layer of complexity here that you wouldn't normally have to think about, but the design has good reasoning and, once more, since CPU is typically not the bottleneck in socket applictions, this is a moot point in most cases and therefore isn't something you need to constantly be thinking about as you develop Node.js applications.
So I should just let my other CPU's run idle???
Absolutely not. I'm merely saying that you don't need a single instance of your app to leverage multiple CPUs. You should write your app in such a way that multiple instances of it can be run at once. A notable gotcha here is if you have some in-memory variables that must be global to your app. Really this is just bad design anyway because doing this will limit you to one server whether you use Node.js or not. Spark and Spark2 are my favorite means of running multiple instances of an app in an organized manner.
|
|
Node.js
|
|
Monday, 06 September 2010 19:44 |
When we launch projects at Backcountry.com, one of the questions we ask ourselves is "what are the risks of launching this?" Sometimes it is tempting to say "this is a small project that doesn't touch any core functionality, so the risk is low." The problem is that our current stack is synchronous, has blocking IO and is fairly monolithic. The result of this is that most any problem can bring down the entire application. For example, if you create a query that is too slow, the Apache process that is executing that query is waiting a long time for that response. If you check your system stats, you'll see that CPU usage is low on your app servers, but you might see memory start to get eaten up. What? Memory is getting eaten up on the app servers that are just waiting around? Yup, that's right. Although your app servers aren't doing much, the threads or child process are building up because they can't complete while they are waiting for a response from the database. If you're running Apache prefork-MPM, you've got processes taking up around 1MB or more, one per request, just sitting around.
Now let's see how this looks in an evented, non-blocking I/O design (such as Node.js, but there are others too such as EventMachine). In Node.js, there is, for the most part, only one process and no threads (there are exceptions to that, but nothing that will affect this example). As client conenctions are made, they are added to the event loop, which is basically just a queue of stuff to do. When the database query get's executed, the code will say "hey, i'm executing a query, which might take a while, so please just throw me back in the event loop and call me again when the query is finished." So, what happens on the app server when the query takes a long time to execute? Well, that one request won't get a response for a while, but that's about it. Barely any memory is tied up and no processing time is wasted on waiting around.
Furthermore, in situations where you will have large amounts of socket connections to clients, because Node.js requires so little memory for each connection and handles idle connections so gracefully, it can handle a phenominal amount of concurrent connections. You can see some roungh numbers at Node.js Has a Bright Future, an article I wrote when I first discovered Node.js. Those examples were oriented toward normal HTTP connections. It would be even more interested to see how something like Faye (running on Node.js) would stack up against the proven CometD/Jetty.
Lean more at nodejs.org.
|
|