Sugr Server Development From Scratch

666 查看

This article is about the way we choosing frameworks during Sugr Server development.

We change the frameworks many times until we found the best one, which helps us on coding, deploying, debugging, and saving the cost of VPS.

SQL, NoSQL, QueryBuilder, ORM

At first, We tried Postgres and NoSQL.

Use NoSQL Database saves a lot of time wasted in writing SQL. There is no SQL statements anymore.

Table will be created at the first time we use it. Without any SQL like CREATE TABLE ... before using it.

db.inventory.find( {} )
db.inventory.find( { type: "snacks" } )

For example. In mongodb, table inventory will be created after line 1.

You can save and load any fields in any type as you want.

db.inventory.insert({
 item: "ABC1",
 details: {
    model: "14Q3",
    manufacturer: "XYZ Company"
 },
 stock: [ { size: "S", qty: 25 }, { size: "M", qty: 50 } ],
 category: "clothing"
})

db.inventory.insert({
 item: "ABC2",
 details: "description of ABC@",
})

In the above 2 records. detail have different types. But it also works fine.

However, NoSQL performance worse than traditional SQL.

Mongodb always wastes more than 2G memory and produces huge amount I/O operations.

We don't want to pay more for VPS, So we must make a compromise.

QueryBuilder can build SQL Query quickly.

knex.avg('sum_column1').from(function() {
  this.sum('column1 as sum_column1')
  .from('t1').groupBy('column1').as('t1')
}).as('ignored_alias')

>>>>

select avg(`sum_column1`) from (
    select sum(`column1`) as `sum_column1` from `t1` group by `column1`) as `t1`

knex.js make traditional SQL can be written in tree-struct like JSON. much better than the original way. PHP's laravel framework did the same thing.

But it's still not the most agile way dealing with database. I still need to write knex.update / knex.select / knex.delete / knex.insert to perform CURD (Create / Update / Read / Delete).

Finally we found BackboneORM.

var Project = Backbone.Model.extend({
  urlRoot: 'sqlite://dbpath',

  schema: {
    created_at: 'DateTime',
    type: ['Integer', {nullable: false}],
    name: ['String', {unique: true, indexed: true}]
  }    
});

It can create table and tranform field types automatically like NoSQL, even if the database is using traditional SQL like PostgresSQL, SQLite, MySQL, etc.

This is a feature of RubyOnRails, but node.js is quite lightweight and easy to use.

BackboneHTTP in BackboneORM make front-end using backbone.js framework access database easily, which may help us writing front-end pages later.

LeanCloud

LeanCloud is a Cloud API Platform founded in China, focus on small start-up company like us developing Server APIs rapidly.

It gathers node.js, express.js, BackboneORM, Apple Push API, iOS APP Publish and Analysis API, etc. into one platform.

It also integrates Promise.js in BackboneORM and many other APIs, which is very important for node.js.

LeanCloud's Apple Push API is easily to use. The only thing you need to do is to upload the Apple Push Notify P12 Certificate and integrate AVOSCloud iOS SDK in Cocopods.

Here are some screenshots of LeanCloud's Console Panel.

iOS APP Analysis

Database View

Cloud code logger

HTTP Comet Server

Comet server is using to exchange message between hardware. Hardware always keeps a long polling HTTP connection with comet server.

At first we use nginx_http_push_module. Its problem is:

  • has no API getting current online id list
  • uses date string in Last-Modified header field, which can't deal with 2 requests in the same second

So we write our own comet server using node.js instead.

Supervisord & lighttpd

lighttpd can forward HTTP request with specific Host to specific localhost ports running node.js process. We don't need a big and powerfull server like apache or nginx, a lightweight server is better.

supervisord keeps track of node.js process, captures and rotates stdout and stderr log.

Docker

Docker is an open platform for distributed applications for developers and sysadmins.

In Sugr Server. Docker likes the binary version of git.

If lighttpd configuration, sqlite database, node.js modules, etc. is modified, Docker will consider it as a 'commit' like a commit in git.

So everything can be save and load like "Time Machine" in OS X.

Another great feature of docker is, it can "hide" ports in docker image. For example, port 2234,2235,2236,2237 in used in node.js process. port 80 is used for lighttpd and request may forward to 223x. I can pack a image and export port 80 only, then 223x ports is invisible in host, which avoids port duplicate problems.

Future

In future we will release our own comet server as a npm package.