Drupal静态缓存

Drupal的伸缩性是存在的,而且非常强大。当我们问别人对Drupal的看法时候,多数时间得到的答案是:据说那东西很慢。在我的工作中见到过很多性能低下的Drupal站点,缓存是其中的重要原因。即使是基础的Drupal安装,其中也包含了一套针对数据表的多层缓存,不幸的是,这一缓存体系很容易被开发者破坏。

阻碍缓存的最大原因可能就是在自定义模块中错过了利用缓存提升性能的机会。把计算后的结果保存在PHP变量中,接下来的调用过程可能会得到成百上千倍的性能提升。要使用这一技巧只需要很小成本:如果一个结果已经得出,就返回这一结果;否则,运算得到结果之后,首先保存结果,然后才返回。

    function apachesolr_static_response_cache($searcher, $response = NULL) {
      $_response = &drupal_static(__FUNCTION__, array());

      if (is_object($response)) {
        $_response[$searcher] = clone $response;
      }
      if (!isset($_response[$searcher])) {
        $_response[$searcher] = NULL;
      }
      return $_response[$searcher];
    }

Apache Solr模块在很多地方使用了静态缓存,例如即使一个页面上存在多个搜索相关的Block,也保证每次请求只执行一个Solr搜索。

和其他缓存方案一样,缓存命中时候的访问速度和缓存未命中时的差异决定了缓存的效益。耗时长、执行频繁并且经常返回重复值的函数,通过缓存能够获得最好的收益,这一标准非常清晰,Drupal很多代码符合这一要求。

很多重负载的核心函数进行了静态缓存:menu.module使用了一个树状的数据结构,这意味着需要做很多重复的递归工作。当页面上有多处使用菜单的情况下,有了静态缓存的帮助,处理时间得到了极大的缩减。类似的还有Drupal的分类系统——在列表或画廊页面中,分类词的处理可能要进行非常多的次数。在taxonomy.module中的五个函数包含了对drupal_static()的调用,用于加速重复工作。

Drupal中还有一类函数,他们的执行非常快速,但是在很多位置调用,并且返回结果几乎不会变化。drupal_is_front_page()以及drupal_page_is_cacheable()只是简单的检查,一个更好的例子是ip_address()。这个函数需要处理HTTP头中的X-Forwarded-For,用于确定用户的真实IP地址,这需要字符串运算。相对其他操作来说,字符串解析需要更多的函数调用和内存访问。

上面的文字听起来很不错,不过如果缓存值不再准确了会怎样?虽说静态缓存只在一次请求中有效,这其中仍然存在缓存过期的可能性。在缓存函数内部对缓存数据进行失效处理是很容易的,但是由于缓存变量的作用域限制,会阻止其他函数访问。这意味着,静态缓存的实现还是可能有引入其他问题。

在Drupal 7之前,函数需要自行决定是否暴露失效缓存的途径。有些通过跟踪一个不太优雅的’失效缓存’的参数,不过多数连这个都没有。Druapl 7中加入drupal_static,让函数可以暴露一个可以为其他函数所用的静态变量,这样就可以在函数作用域之外改变这一变量了。

ip_address()函数是个静态缓存的好例子。很多站点具有地理相关的功能(例如把用户重定向到缺省语言或者展示本地内容),这种功能的测试也明显的比较麻烦。Smart IP模块实现了一个测试,用一个IP伪造的Form来测试用户权限和debug变量:

    if (user_access('administer smart_ip') && variable_get('smart_ip_debug', FALSE)) {

        $ip = variable_get('smart_ip_test_ip_address', ip_address());

        $location = smart_ip_get_location($ip);

如何对这个内容进行自动化测试呢?测试账号需要访问权限(阻止匿名用户访问测试函数),IP 地址的变化也会影响到管理员用户。更糟糕的是,每次对测试IP地址的修改都会导致一次variable表的写入,这会拖慢整个站点。

因为ip_address()使用drupal_static()暴露了他的静态缓存,所以就可以修改他的返回值了。这样测试过程就可以测试所有IP相关的函数,而不需要用户账号、权限或者对variable表的访问。要切换回普通的IP Address功能只要调用一次drupal_static_reset(),这将导致ip_address()的下次调用会像初次调用一样。

Drupal.org列出了Drupal 7核心中的180次对drupal_statc()的调用,drupalcontrib.org中报告了563此。并不是每次drupal_static()调用都是静态缓存,也不是每个静态缓存都用drupal_static实现,不过这仍然给我们以灵感,如何通过静态缓存来提高Drupal的性能。

Avatar
崔秀龙

简单,是大师的责任;我们凡夫俗子,能做到清楚就很不容易了。

comments powered by Disqus
下一页
上一页

相关