这种基于文件的数据库方法的可扩展性如何?

时间:2016-08-08 13:50:33

标签: php filesystems ext3

我有一个简单的PHP脚本,可以计算给定字符串输入的一些内容。它将结果缓存到数据库,我们偶尔会删除超过特定天数的条目。

我们的程序员将此数据库实现为:

function cachedCalculateThing($input) {
  $cacheFile = 'cache/' . sha1($input) . '.dat';
  if (file_exists($cacheFile) {
    return json_decode(file_get_contents($cacheFile));
  }
  $retval = ...
  file_put_contents(json_encode($retval));
}
function cleanCache() {
  $stale = time() - 7*24*3600;
  foreach (new DirectoryIterator('cache/') as $fileInfo) {
    if ($fileInfo->isFile() && $fileInfo->getCTime() < $stale) {
      unlink($fileInfo->getRealPath());
    }
}

我们使用Ubuntu LAMP和ext3。缓存查找变为非常数或违反硬限制的条目数是多少?

1 个答案:

答案 0 :(得分:1)

虽然这个特定的代码根本不具备可扩展性,但是有很多东西可以改进它:

  1. sha1接受一个字符串。因此,在计算哈希值之前,必须先对非字符串$ input变量进行序列化或json_encoded。只需更改订单以防止意外输入。
  2. 使用crc32代替sha1,速度更快(Fastest hash for non-cryptographic uses?
  3. 目录&#39;缓存/&#39;是相对于当前目录,因此页面工作目录更改,缓存目录也将更改。这将是人为的大量缓存未命中。
  4. 每次在cachedCalculateThing()中存储文件时,请将文件名保存在/ dev / shm / indexedofcaches(或类似内容)中的索引中。在调用file_exists之前检查索引。 ext3很慢,缓存以及内核ext3索引将被分页。这意味着每次询问file_exists时都会命中目录扫描。对于小缓存来说,它足够快,但是大的缓存,你会看到减速。
  5. 写入将阻塞,因此当缓存为空时将触发服务器负载限制,并且当两个或多个php编写器同时出现尝试编写先前不存在的缓存文件时,将在缓存文件名上发生冲突。因此,您可能希望尝试捕获这些错误和/或进行锁定文件测试。
  6. 我们在一个有些处女的环境中考虑这个代码。事实是,写入还将根据当前磁盘利用率阻止不确定的时间量。如果您的磁盘是旋转磁盘或较旧的ssd,您可能会看到非常慢的写入。检查iostat -x 4并查找当前的磁盘利用率。如果它已经高于25%,那么启用磁盘缓存将使其随机时间达到100%并减慢所有Web服务的速度。 (因为对磁盘的请求必须按顺序排队和服务(通常)(不总是,但不要在其上存放)。)
  7. 根据缓存文件的大小,可以直接将它们存储在/ dev / shm / my_cache_files /中。如果它们都能很好地适应内存,那么您就可以将磁盘完全保留在服务链之外。然后你必须放一个cron作业来检查整体缓存大小,并确保它不会占用你所有的内存。缺点=非持久性。你也可以对它进行备份安排。
  8. 不要在运行时/服务代码中调用cleanCache()。该目录迭代扫描将非常缓慢并阻塞。
  9. &#39; *对于可伸缩性,它通常根据线性请求速度或并行服务器资源来定义。那段代码:

    1. ( - )取决于运行cleanCache()函数的时间/位置 - 它有效地阻止目录索引,直到扫描缓存目录中的所有项目。所以它应该进入一个cron工作。如果在cron / shell作业中,有更快的方法可以删除过期的缓存。例如:find ./cache -type f -mtime +7 -exec rm -f "{}" \;
    2. ( - )你提到ext3 - ext3的索引和小文件的结果速度是非常正确的,而且非常大的目录内容相对较差。 google noatime for index,如果您可以将缓存目录移动到单独的卷,则可以关闭日志,避免双重写入,或使用单独的文件系统类型。或者看看你是否有dir_index可用作挂载选项。以下是基准链接:http://fsi-viewer.blogspot.com/2011/10/filesystem-benchmarks-part-i.html
    3. (+)目录缓存条目使用rsync比使用数据库复制更容易分发到其他服务器。
    4. (+/-)实际上,这取决于您将存储多少个不同的缓存项以及访问频率。对于少量文件,例如10-100,低于100K,频繁命中,内核会将缓存文件保存在内存中,并且您根本看不到严重的减速(如果正确实施)。
    5. 主要的要点是,为了在缓存系统之外实现真正的可扩展性和良好性能,必须比短代码块显示更多的考虑因素。可能存在比我所枚举的限制更多的限制,但即使是那些也受诸如大小,条目数,请求数/秒,当前磁盘负载,文件系统类型等变量的影响 - 在代码外部。这是可以预料到的,因为缓存在代码之外仍然存在。列出的代码可以执行一系列小型精品缓存,请求数量较少,但可能不适用于需要缓存的较大尺寸。

      另外,您是在线程还是prefork模式下运行Apache?它将影响php如何阻止其读写。

      - 嗯,我可能应该补充一点,你想要跟踪你的对象和key / hash ..如果$ input已经是一个字符串,那么它的基本形式/已经被计算出来,如果$ input是键,则file_put_contents()需要输入其他内容(实际变量/内容)。如果$ input是要查找的对象(可能就像一个长字符串,甚至是一个短字符串),那么它需要一个查找键,否则不会绕过/保存任何计算。