fastdb用起来还是很方便简单的,但是在使用的过程当中发现了很多问题:
比如:
1、数据库对于内存的消耗实在是太大,尤其是数据量到达千万级时尤为明显。
2、数据量上千万级别以后,性能远地于预期,可能是服务器内存不够的缘故。事务过大后,提交时间很长。
3、在并发访问模式上,同一进程的线程只能用同一模式,只read能够并发。不能够write并发(多个write线程)。进程间也是如此,也就是说多个write并发的话会出现相互阻塞,连write进程读操作都阻塞。所以适用于那些并发读操作,或者只要一个并发写操作的模式。(毕竟只有3万来行的程序,没有提供记录锁甚至页级锁是很正常的)
4、程序出现异常,可以通过清理信号量来进行恢复数据文件,但是有时候数据文件没法恢复造成数据损失。幸亏有在线备份机制和多机器备份功能。
虽然如此,但是在适量的数据规模上,其性能是很彪悍的,加上在使用上特别方便。所以如果对于百万级数据规模的项目,需要简单并发和大量插入、查找、计算时,fastdb是个很不错的选择。毕竟代码很精炼,适当的时候自己可以根据需要进行修改源码。
磁盘模式与非磁盘模式的性能http://blog.csdn.net/hejianhua/article/details/6694356
在磁盘模式下,所有的数据将写到磁盘的文件中,对于这种模式,性能和一般的数据库差不多。对于非磁盘模式,效率非常高,网上有一篇文章,对fastdb和磁盘数据库的性能进行了对比。默认情况下是磁盘模式,要使用非磁盘模式,重新编译,加入
-DDISKLESS_CONFIGURATION
推荐文章:http://www.360doc.com/content/11/0227/02/6001117_96477992.shtml
在采用非磁盘模式的时候,要注意因为内存越界的问题导致进程crash。因为,对于非磁盘模式fastdb是实现划分了一大块共享内存,当超出这块内存的容量时,就会有可能导致程序crash。
最近项目中使用了fast db,为了提高访问效率,fast db采用diskless模式编译。
共享内存的最大尺寸受系统参数限制,
下面数据是在Linux im_monitor 2.6.9-42.ELsmp 下的缺省值:
cat /proc/sys/kernel/shmmax
33554432
默认大小都是32M;
同样fastdb里的代码也用32M作为容量上限,而且一旦越界,不再进行扩容;进程退出;
具体的代码行是:inc/database.h 文件里
#ifdef DISKLESS_CONFIGURATION
// In diskless confiuration database can not be reallocated
const size_t dbDefaultInitDatabaseSize = 32*1024*1024;
#else
const size_t dbDefaultInitDatabaseSize = 1024*1024;
#endif
为了支持fastdb在更大的共享内存下工作,需要做两点修改:
1、系统参数的修改
修改 /etc/sysctl.cfg,添加入下内容:
kernel.shmmni = 4096
kernel.shmall = 2097152
kernel.shmmax = 1073741824
sysctl -p 执行;
或者echo 1073741824 > /proc/sys/kernel/shmmax ,注意需要加到启动脚本里去;
2、修改fastdb源代码
const size_t dbDefaultInitDatabaseSize = 32*1024*1024;修改为合适的数值;比如32->1024
鉴于共享内存大小限制,以及不能动态扩容:当容量超过限制,进程不能进行再分配,直接退出,对于大容量的系统,对fastdb的数据使用超过2G, 或者总的虚拟内存使用量可能接近3G, 则不建议在32位操作系统中使用共享内存方式的fastdb,可以改用文件方式,实际上对于文件方式,也是通过mmap的方式来实现,对于io的写基本等同于内存效率,且可以在预分配的基础上扩容。
fastdb学习笔记
这几天一直在学习fastdb的使用,将一些学习心得和笔记写出来供大家参考!
1,register_in()宏不能在主函数中使用;
2,更新和删除操做的游标是updatecurrsor,其他的是一般的currsor;
3,游标的当前值就是当前查询的对象.
4,客户端服务器结构程序需要使用cli接口,程序包含cli.lib
5,如果在CBuilder中使用fastdb.lib,链接出现omf格式问题,直接将所有的src目录下的文件(有几个cpp从名字可以发现是其他平台或者用不上的可以不要)加到一个CBuilder的lib工程里边,然后build生成fastdb.lib就可以解决这个问题.同样使用cli的时候也可能出现这个问题,和上边一样,将cli.cpp,cgistub.cpp,repsock.cpp,stdtp.cpp,w32sock.cpp添加到一个lib工程里边,生成cli.lib即可解决问题.
6,不同的数据库之间共享classes,首先定义class,用register_unassigned()注册类,使用的时候游标有一个你要操做的数据库的指针作为参数.以此标识你要操作的数据库.如果你要插入数据的话,insert()函数这是是一个database类的成员使用.以此标识要插入的数据库.
7,fastdb的类(也就是表的数据成员都必须是public),否则外部不可访问.
8,fastdb表的字段可以是嵌套的结构或者动态增长的数组类型.并且表中可以有方法.
9,fastdb支持autoincrement字段,int4类型可以在descriptor中声明为autoincrement.
10,使用fastdb自己带的subsql程序的export命令可以将内存数据库导出成一个xml文件.
11,fastdb的inverse reference 保证了在你删除数据库中的记录的时候数据的引用完整性.当你删除数据库中的记录的时候,inverse reference自动更新.
12,fastdb1.20以后支持cascade deletes,只要相应的字段声明为owner.如果包含reference的字段为owner则这个字段同时要用relation宏声明.
对开源内存数据库FastDB作了一些测试。
采用两个long字段作为表的字段,首先使用带有文件映像的方式,结果是:
1. 字段申明时FIELD和KEY(,INDEXED)在存储量上没有区别,但是KEY(,HASHED)将额外占用大量空间,几乎增加一倍。
2. 从1,000,000条记录(64M)中查询1,000,000次,耗时5秒,平均每秒20万次,加上修改操作似乎影响不大,插入1,000,000条记录也是5秒。
将FastDB库编译成DISKLESS模式后,对每个表的大小似乎有限制,而且是一种以崩溃的方式出现的,同样的记录只能插入100,000个多一些。好像数据库申明时对初始大小的规定没有作用。
1. FastDB中的每个对象(记录)有12字节的头。
每个对象都是按32字节对齐的。
每个额外的索引占用16字节。
每个对象还有4字节的标识OID(Object Identifier),用于对对象的访问,并且OID有两个Current和Shadow,这样每个对象标识就占用8个字节,而且所有对象标识的数量是按2的倍数分配的。
如果分配的虚拟内存被耗尽,则总内存将会变为原来的两倍。
2. 在无盘模式下,数据库声明时的初始内存参数dbInitSize的单位是字节。当初始分配的内存不足时,会抛出OutOfMemory异常。
dbDatabase类控制与数据库的应用交互,比如对数据库的并发访问控制的同步,事务管理,内存分配,纠错处理等等。
dbDatabase类的构造函数允许程序员指定一些数据库的参数。
dbDatabase(dbAccessType type = dbAllAccess,
size_t dbInitSize = dbDefaultInitDatabaseSize,
size_t dbExtensionQuantum = dbDefaultExtensionQuantum,
size_t dbInitIndexSize = dbDefaultInitIndexSize,
int nThreads = 1);
访问模式有以下几种:
访问类型 | 描述 |
dbDatabase::dbReadOnly | 只读模式 |
dbDatabase::dbAllAccess | 普通模式 |
dbDatabase::dbConcurrentRead | Read only mode in which application can access the database concurrently with application updating the same database in dbConcurrentUpdate mode |
dbDatabase::dbConcurrentUpdate | Mode to be used in conjunction with dbConcurrentRead to perform updates in the database without blocking read applications for a long time |