Berkeley DB:网站数据缓存方案测试

January 28th, 2009 | by 超群.com | 知识共享署名-非商业性使用-相同方式共享,转载请保留链接。

本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享,转载请保留链接http://chaoqun.17348.com/2009/01/bdb-cache/

做网站,好像大家都比较喜欢文件缓存,把那些读操作多写操作少的内容缓存成一个文件放服务器硬盘上,下次直接读取或者更新。针对每一个key缓存成一个文件,当需要缓存的内容多的时候,文件数也就相应的多,这么多文件的同步和备份都是大问题,数据的可靠性也无从保证。

可是为了”效率”,我们也忍了,但文件缓存的效率真的好吗?有没有更好的方案?当然,memcached是很好的解决方案,今天这里测试另外一种方案:使用Berkeley DB作为网站数据缓存方案。

测试环境:CentOS 5.2,Core2 T5500@ 1.66GHz,1.5G内存,Ext3文件系统,apache 2.2.3,php 5.2.8 with php_dba

数据初始化:为了不至于在一个目录下文件数目过多,文件缓存分了两级hash目录,初始化数据数10万条。

/**
 * 初始化缓存
 *
 * @param int $limit
 */
function init_cache($limit = 100000)
{
    $str = 'good good study,and day day up.';
    $bdb = dba_open('./bdb.db', 'c', 'db4');
    for ($i = 0; $i < $limit; $i++)
    {
        $data = str_repeat($str, rand(1,100));
        dba_insert($i, $data, $bdb);
        $cache_file = get_cache_file($i);
        file_put_contents($cache_file, $data);
    }
    dba_close($bdb);
}
 
/**
 * 获得缓存文件
 *
 * @param string $cache_key
 * @param string $md5_key
 * @return string
 */
function get_cache_file($cache_key, $md5_key = '9527')
{
    $dir_md5 = md5($cache_key . $md5_key);
    $file_md5 = md5($cache_key);
    $dir = './cache/' . substr($dir_md5, 0, 2);
    is_dir($dir) || mkdir($dir);
    $dir .= '/' . substr($dir_md5, 2, 2);
    is_dir($dir) || mkdir($dir);
    return  $dir  . '/' . $file_md5 . '.txt';
}

同样的缓存内容,占用磁盘大小:

文件缓存:348.9MB
BDB缓存:296.5MB

BDB缓存占用磁盘空间要小一些。

测试程序尽可能的模拟真实环境,90%的读操作,10%的写操作,很多应用可能98%的读操作,2%的写操作,另外还模拟了一些新增缓存。

文件缓存测试程序代码:

/**
 * 文件缓存测试程序
 */
require_once './common.php';
// 随机一个key
$key = rand(0, 109999);
 
$cache_file = get_cache_file($key);
 
// 读写标记
$flag = rand(0,9);
 
if (file_exists($cache_file) && 9 > $flag)
{
    echo file_get_contents($cache_file);
}else
{
    file_put_contents($cache_file, str_repeat('learn from LeiFeng!', rand(1,100)));
    echo file_get_contents($cache_file);
}

BDB缓存测试程序代码:

/**
 * BDB缓存测试程序
 */
// 随机一个key
$key = rand(0, 109999);
 
// 读写标记
$flag = rand(0,9);
 
$bdb = dba_popen('./bdb.db', 'w', 'db4');
 
$data = dba_fetch($key, $bdb);
 
// dba_close($bdb);
 
if ($data && 9 > $flag)
{
    echo $data;
}else
{
    dba_replace($key, str_repeat('learn from Comrade LeiFeng!', rand(1,100)), $bdb);
    echo dba_fetch($key, $bdb);
}
dba_close($bdb);

文件缓存测试结果:

ab -n10000 -c200 http://127.0.0.1/labs/TestCache/file.php

Requests per second: 189.92 [#/sec] (mean)
Time per request: 1053.055 [ms] (mean)
Time per request: 5.265 [ms] (mean, across all concurrent requests)

BDB缓存测试结果:

ab -n10000 -c200 http://127.0.0.1/labs/TestCache/bdb.php

Requests per second: 220.69 [#/sec] (mean)
Time per request: 906.249 [ms] (mean)
Time per request: 4.531 [ms] (mean, across all concurrent requests)

反复测试了几次,文件缓存每秒大概能处理170~200个请求,BDB缓存每秒大概能处理190~230个请求,貌似BDB还比文件缓存要快一些,其实BDB还可以更快一些,我们在测试代码里面用了不管是读操作还是写操作都用了$bdb = dba_popen(‘./bdb.db’, ‘w’, ‘db4′);写的方式,其实我们很多的应用只是读操作,如果把BDB测试代码换成只有在写的时候才用写操作:

/**
 * BDB缓存测试程序
 */
// 随机一个key
$key = rand(0, 109999);
 
// 读写标记
$flag = rand(0,9);
 
$bdb = dba_popen('./bdb.db', 'r', 'db4');
 
$data = dba_fetch($key, $bdb);
 
if ($data && 9 > $flag)
{
    echo $data;
}else
{
    dba_close($bdb);
    $bdb = dba_popen('./bdb.db', 'w', 'db4');
    dba_replace($key, str_repeat('learn from Comrade LeiFeng!', rand(1,100)), $bdb);
    echo dba_fetch($key, $bdb);
    dba_close($bdb);
}

测试结果:

ab -n10000 -c200 http://127.0.0.1/labs/TestCache/bdb.php

Requests per second: 361.62 [#/sec] (mean)
Time per request: 553.068 [ms] (mean)
Time per request: 2.765 [ms] (mean, across all concurrent requests)

有点吓人,速度快要翻翻了。

后记:

php_dba扩展中建立数据库句柄,有dba_open和dba_popen两个函数,dba_popen建立的是持久连接,我在测试中发现使用dba_popen的性能要大大好于dba_open,测试中使用亦非常稳定。

其实memcachedb的核心还是BDB,引入了缓存和兼容memcached协议的socket接口,memcachedb当然会比单纯的BDB快,如果没办法用memcachedb,纯粹的BDB也是一种不错的方案,照测试看,各个方面比文件缓存都要好一些,当然,写频繁的操作可能要差些,因为存在文件锁的问题,换个思路想,写频繁缓存又有什么用呢。

Tags: ,

  1. 2 Responses to “Berkeley DB:网站数据缓存方案测试”

  2. By david on Feb 28, 2009 | Reply

    小文件cache居然比db慢,有点不解。

    在我理解中,db打开和cache打开应该是一样的io操作,db还要进行索引,而cache不用。不知理解的对不对?

    把ab测试换成在php脚本内的循环测试是否更可靠?

  3. By 超群.com on Mar 1, 2009 | Reply

    @david

    当目录下文件数过多时,文件的定位会是个大问题,尤其都是小文件,我猜测可能是这一个原因。

    php内的循环测试没有多大的意义,ab可以模拟并发访问的情况,更有实际意义。

    使用文件cache还有一个更大的问题是文件的可靠性和一致性没法保证。我们就发现会出现cache写错误的情况,尤其当你的磁盘是通过nfs mount过来的。

Post a Comment