SPHiveDB: 基于 sqlite 的数据库服务器
盛柏
2023-12-01
在 share nothing 的架构中,如果数据规模很大,为了提高可用性,通常采用数据库分片(database sharding)的策略。常见的分片策略是按主键把数据分散到不同的数据库中。在使用常规的 RDBMS 的场景中,分片策略中使用的数据库个数通常在100以下。在某些特殊的场景中,可能希望采用更极端的分片方法,比如在类似地址本这种应用中,可以为每个用户创建一个数据库。
SPHiveDB 就是为这种极端的分片方法而实现的一个数据库服务器。SPHiveDB 基于 sqlite ,用 JSONRPC over HTTP 为 sqlite 提供了网络访问接口。为了能够支持大量的数据库实例,SPHiveDB 把多个 sqlite 数据库合并保存到一个文件中;支持同时使用多个数据库文件。
[url]http://code.google.com/p/sphivedb/[/url]
[url]http://freshmeat.net/urls/01b9b3be9ec4e19ebd6a8e6208f3a0a1[/url]
[url]http://sphivedb.googlecode.com/files/spmemvfs-0.2.src.tar.gz[/url]
×× 内部结构示意图
[img]/upload/attachment/107054/5b3ab8f3-8cdb-339e-bdc1-02df1b8b4db9.bmp[/img]
SPHiveDB 使用 Tokyo Cabinet 作为最终的物理存储,每个用户对应的 sqlite 数据库以用户名为 key 保存在 Cabinet 中。为了支持能够从 Cabinet 中加载 sqlite 数据库,为 sqlite 实现了一个 memvfs 。通过 memvfs ,使得 sqlite 能够在内存中加载和保存数据。SPHiveDB 支持一个进程同时使用多个 Cabinet 文件,使得单一 server 能够支持尽可能大的存储空间。
×× JSONRPC 请求和响应示例
[code]
{
"method" : "execute",
"params" : [
{
"dbfile" : 0,
"user" : "foobar",
"dbname" : "addrbook",
"sql" : [
"insert into addrbook values ( 1, \"foo@bar.com\" )",
"select * from addrbook"
]
}
],
"id" : "foobar"
}
[/code]
dbfile 指定操作哪一个 Cabinet 文件;user + dbname 指定操作哪一块数据;sql 需要执行的 sql 语句,支持批量执行多个 sql 语句,使用 all-or-nothing 的策略,要么全部成功,要么全部失败。dbname 还用于指明第一次操作一块数据时,用什么语句来创建 sqlite 数据库。用于创建 sqlite 数据库的语句保存在 sphivedbsvr.ini 配置文件中。以 ddl. 开头的配置节用于指定对应数据库的创建语句。
[code]
[ddl.addrbook]
create table if not exists addrbook ( id int, addr varchar(64) );
[/code]
[code]
{
"result" : [
{
"name" : [ "affected", "last_insert_rowid" ],
"type" : [ "int", "int" ],
"row" : [ [ 1, 1 ] ]
},
{
"name" : [ "id", "addr" ]
"type" : [ "int", "varchar(64)" ],
"row" : [ [ "1", "foo@bar.com" ] ],
}
],
"id" : "foobar"
}
[/code]
result 返回 sql 语句执行的结果,name 对应的 array 为 column 的名字,type 对应的 array 为 column 的类型,row 对应的 array 是返回 recordset 。特别地,对于 INSERT/UPDATE/DELETE 也使用类似 select 的方式来返回,affected 是 sql 语句执行之后 sqlite3_changes 返回的值,last_insert_rowid 是 sql 语句执行之后 sqlite3_last_insert_rowid 返回的值。