TribeDB - 分布式集群储存框架 - Node.js

TribeDB 是一个MySQL分表分库数据中间件,实现MySQL数据的分布式集群储存管理。在处理海量数据、高并发访问时,获得更加优越的性能及横向扩展能力。它包含以下主要特性:

拥有以上特点意味着,可随时通过增加普通级别数据库服务器的方式,方便地扩展整体系统性能,而无需修改业务层架构和代码。理论上TribeDB的扩展能力上线在于主库单表插入性能和主从数据同步开销。通过合理设计“横向”和“纵向”分表和数据切分粒度,可轻松应对上亿级别的数据量和访问请求。

本文档包括 TribeDB 详细API说明和对应的最优数据库设计建议。

Fork me on GitHub

目录:

# 快速上手:

var tribe = require('tribedb')
  , Query = tribe.Query;
// 添加一个数据库配置
tribe.config.db('db1',{user:'root'});
// 直接执行sql
tribe.pool.query('SELECT 1+1 AS num', { db: 'db1' }, function(err, rows, fields){
  // 结果
});
//插入封装
new Query('post').data({title:'标题'}).insert(function(err, data){
  console.log(err);
  console.log(data);
});
//查询封装
new Query('post').where('title','标题').order_by('time','DESC').limit(1).select(function(err, data){
  console.log(err);
  console.log(data);
});

TribeDB 通过全局唯一的表名,自动连接对应的数据库,并通过分表配置,将操作映射到涉及的分表,同时完成读写分离。 一切都由 TribeDB 自动完成,业务层不必关心数据的位置。当数据库负载过高需要添加服务器时,只需简单修改配置文件而不必修改业务代码,甚至将整个架构推倒重来。继续阅读本文档详细了解如何使用。

# 安装

推荐采用 NPM 方式安装 TribeDB。也可以 下载源码,但需要自己处理依赖。

$ npm install tribedb

#tribedb@0.2.1 node_modules\tribedb
#└── mysql@2.5.2 (require-all@0.0.8, bignumber.js@1.4.1, readable-stream@1.1.13)

# config 数据库配置

# db(name, conf) 设置数据库

name[string]: 数据库名称。

conf[object] or [array]:连接配置

设置一个或多个数据库,并可配置查询从库。使用示例:

var config = require('tribedb').config;
// 用法示例:
// [host,user,password,port,slave] , slave 表示是否为从库
config.db('db1', ['localhost', 'root', ...]);
// 对象形式,并设置为 db1 的从库
config.db('db1', {
  host: 'localhost',
  user: 'root',
  ...
  slave: true
});

# default_db(dbname) 数据表与数据库的从属关系

dbname[string]:默认查询的数据库名称。

当未指定库时,查询默认使用的库,和未指定的数据表默认保存的库。如果不调用此函数进行设置,则第一个添加的数据库为默认。使用示例:

var config = require('tribedb').config;
// 用法示例:
config.default_db('db1');
  

# dist(db, tables) 数据表与数据库的从属关系

db[string]: 数据库名称。

tables[string] or [array]:数据表

使用示例:

var config = require('tribedb').config;
// 用法示例:
config.dist('db1', ['user', 'post', 'comment', ...]);
// 或者逗号隔开的字符串
config.dist('db1', 'user, post, comment, ...');

# pool 数据库连接池

# query(sql, [opts,] callback) 在连接池中取一条连接并执行 sql 语句

sql[string]: MySQL 语句。

opts[object]:配置项,包含:

 ·db[string]:要连接的数据库名称,不设置使用默认的库

 ·table[string]从表名称自动映射到对应的库

 ·slave[bool]是否优先使用从库(没有则使用主库)

callback[function]:执行结果回调

。使用示例:

var pool = require('tribedb').pool;
// 用法示例(使用默认库):
pool.query('select * from tag;', function(err, rows, fields){
    // 结果
});
// 连接 user 表 所在的库
pool.query('select * from user;', {table: 'user'}, function(err, rows, fields){
    // 结果
});

# destroy() 销毁所有数据库连接

# Query([table]) 数据库处理对象

table[string]:要执行操作的数据表名。也可以稍后调用 table()函数指定。

Query返回一个查询对象,包含一系列封装的方法,完成数据的增删改查操作。对象方法如下:

# table(table) 指定进行操作的数据表

table[string]:要执行操作的数据表名。

可在Query()中指定数据表。

# field(cols) 设置查询的字段

cols=[string] or [array]:查询时要返回的内容(包含字段名或统计等)。

var db = new Query('user');
// 正确用法示例
db.field('count(*)')
db.field('id as uid , name')
db.field(['id','name'])
db.field('id as uid','name')
db.field(['id','name as nick'])
      

# data(data) 插入或修改数据

data[object]:要插入或修改的数据。

var db = new Query('user');
// 正确用法示例:
db.data({id: 1})              // 设置 {id:1} 
db.data({key: "value"})       // 追加 {id:1, key: "value"}
db.data({id: 2})              // 覆盖 {id:2, key: "value"}
db.data("foo", "bar")         // 追加 {id:2, key: "value", foo: "bar"}

# where(whe [, ...]) 筛选条件

whe:筛选条件。

var db = new Query('user');
// 正确用法示例:
db.where("id", 1)              // WHERE id = 1
db.where("id", 1, ">")         // WHERE id > 1
db.where("id", 1, ">" ,'or')         // WHERE OR id > 1
db.where("id=1")               // WHERE id = 1
db.where({'id':1, 'num':2})  // WHERE id > 1 AND num = 2
      

# where_in(field, list) WHERE IN()条件

field:字段名。

list:有效值列表。

var db = new Query('user');
// 正确用法示例:
db.where_in("id", [1,2])              // WHERE id IN(1,2)
// 等同于:
db.where("id in(1,2)")
      

# like(field, value, side) WHERE LIKE 条件

field:字段名。

value:匹配值。

var db = createQuery('user');
// 正确用法示例:
db.like('name', 'sam')          // WHERE name LIKE "%sam%"
db.like('name', 'sam', 'both')     // WHERE name LIKE "%sam%"
db.like('name', 'sam', 'left')     // WHERE name LIKE "sam%"
db.like('name', 'sam', 'right')    // WHERE name LIKE "%sam"
// 等同于:
db.where('name like "%sam%" ')
      

# or_like(field, value, side) WHERE LIKE OR 条件

# not_like(field, value, side) WHERE NOT LIKE 条件

# or_not_like(field, value, side) WHERE NOT LIKE OR 条件

# order_by(field [, desc]) 排序

field:字段名。

desc:是否为降序。

var db = new Query('user');
// 正确用法示例:
db.order_by('id')          // ORDER BY id
db.order_by('id', true)    // ORDER BY id DESC
db.order_by('id', 'DESC')    // ORDER BY id DESC
db.order_by('id', 'ASC')    // ORDER BY id ASC
      

# group_by(field) 分组

field:字段名。

var db = new Query('user');
// 正确用法示例:
db.group_by('id')          // GROUP BY id
      

# limit([start], limit) 分页数量

start:开始位置。

limit:数量。

var db = createQuery('user');
// 正确用法示例:
db.limit(1)          // LIMIT 1
db.limit(2, 2)          // LIMIT 2, 2
      

# insert(callback) 插入(新增)数据

callback[function]:插入完成回调。callback(err, data, fidlds)接受两个参数:err为解析或执行时可能出现的错误(无错则为null)。data操作成功后返回的数据。

var db = new Query('user');
// 正确用法示例:
db.data({name: "John"}).insert(function(err, data, fidlds){
  // console.log(err);
  console.log(data);
  /*
  { fieldCount: 0,
    affectedRows: 1,
    insertId: 8,
    serverStatus: 2,
    warningCount: 1,
    message: '',
    protocol41: true,
    changedRows: 0 }
  */
},{
  //obj: true
  //db: true
  //sql: true
});
      

# delete(callback) 删除

callback[function]:删除完成回调。与insert相同。

var db = new Query('user');
// 正确用法示例:
db.where({name: 'John Smith'}).delete(function(err, data, fidlds){
  console.log(data);
});
      

# update(callback) 修改(更新)数据

callback[function]:删除完成回调。与insert相同。

var db = new Query('user');
// 正确用法示例:
db.where({name: 'John'}).data({name: 'John Smith'}).update(function(err, data){
  console.log(data);
});
      

# select(callback) 查询数据

callback[function]:删除完成回调。与insert相同。

var db = new Query('user');
// 正确用法示例:
db.where('name', 'John Smith').select(function(err, data){
  console.log(data);
  /*
  [ { id: 1, name: 'John Smith', create_time: 0 } ]
  */
});
      

# 数据库设计

对数据表名称进行简单的修改,就能使用 TribeDB 的分表功能。数据表的扩容,分表定位查询,一切将自动完成。

将需要“横向”切分的数据表名称后面,添加 "_0" 后缀,并在配置文件中指出。

例如:将 user 表切分为每一百万用户一个表,只需设置两处:

  一、则在数据库新建 "user_0" 表。( _0 后缀)

  二、在配置文件中的[table]项下添加:user = 100w, id

当 user_0 表数据满一百万时,TribeDB 将自动拷贝 user_0 的表结构新建名为 "user_1" 的表。用户超过两百万时,新建 "user_2",依此类推。

【注意】:只需要新建数据表时添加 "_0" 后缀,在代码里查询更新时,不加后缀:

// user 表“横向”拆分
// 正确:
db.table('user').select(...);
// 错误:
db.table('user_0').select(...);

如果需要对指定分表进行查询或维护,使用query()函数:

// user 表“横向”拆分,查询维护指定分表
// 正确:
tribe.query('select * from user_0',function(){...}); // 需要加后缀,使用真实表名称。
// 错误:
tribe.query('select * from user',function(){...}); // 不存在user表

一些建议

合理规划数据切分粒度,将可以为后期系统升级预留更多的空间。

比如,对于用户user表的切分,每个分表保存十万至一百万用户,是一个比较合理的划分。但对于“用户关注”表,一百万用户一个表就显得太多了,关注是一对多的关系,最终数据行数将远大于一百万。(具体数值试关注的用户量而定)。

再比如,可将一个一个超大的用户表划分为 user 、user_info 、user_conf 、user_data 四个表,用于储存不同类型或不同使用频率的用户数据。

具体实际情况需要视数据库服务器性能和产品业务需要而定。


- - - TribeDB 敬上 - - -