TribeDB 是一个MySQL分表分库数据中间件,实现MySQL数据的分布式集群储存管理。在处理海量数据、高并发访问时,获得更加优越的性能及横向扩展能力。它包含以下主要特性:
拥有以上特点意味着,可随时通过增加普通级别数据库服务器的方式,方便地扩展整体系统性能,而无需修改业务层架构和代码。理论上TribeDB的扩展能力上线在于主库单表插入性能和主从数据同步开销。通过合理设计“横向”和“纵向”分表和数据切分粒度,可轻松应对上亿级别的数据量和访问请求。
本文档包括 TribeDB 详细API说明和对应的最优数据库设计建议。
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)
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
});
dbname[string]:默认查询的数据库名称。
当未指定库时,查询默认使用的库,和未指定的数据表默认保存的库。如果不调用此函数进行设置,则第一个添加的数据库为默认。使用示例:
var config = require('tribedb').config;
// 用法示例:
config.default_db('db1');
db[string]: 数据库名称。
tables[string] or [array]:数据表
使用示例:
var config = require('tribedb').config;
// 用法示例:
config.dist('db1', ['user', 'post', 'comment', ...]);
// 或者逗号隔开的字符串
config.dist('db1', 'user, post, comment, ...');
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){
// 结果
});
table[string]:要执行操作的数据表名。也可以稍后调用
table()
函数指定。
Query
返回一个查询对象,包含一系列封装的方法,完成数据的增删改查操作。对象方法如下:
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[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"}
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
field:字段名。
list:有效值列表。
var db = new Query('user');
// 正确用法示例:
db.where_in("id", [1,2]) // WHERE id IN(1,2)
// 等同于:
db.where("id in(1,2)")
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%" ')
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
field:字段名。
var db = new Query('user');
// 正确用法示例:
db.group_by('id') // GROUP BY id
start:开始位置。
limit:数量。
var db = createQuery('user');
// 正确用法示例:
db.limit(1) // LIMIT 1
db.limit(2, 2) // LIMIT 2, 2
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
});
callback[function]:删除完成回调。与insert相同。
var db = new Query('user');
// 正确用法示例:
db.where({name: 'John Smith'}).delete(function(err, data, fidlds){
console.log(data);
});
callback[function]:删除完成回调。与insert相同。
var db = new Query('user');
// 正确用法示例:
db.where({name: 'John'}).data({name: 'John Smith'}).update(function(err, data){
console.log(data);
});
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 敬上 - - -