Chinaunix首页 | 论坛 | 博客
  • 博客访问: 214020
  • 博文数量: 39
  • 博客积分: 1949
  • 博客等级: 上尉
  • 技术积分: 347
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-24 16:24
文章分类

全部博文(39)

文章存档

2013年(1)

2012年(12)

2011年(24)

2010年(2)

分类:

2011-09-01 21:44:30

1、refresh_pattern机制分析概述

    refresh_pattern指令间接的控制磁盘缓存。它帮助squid决定,是否某个给定请求是cache命中,或作为cache丢失对待。宽松的设置增加了你的cache命中率,但也增加了用户接收过时响应的机会。另一方面,保守的设置,降低了cache命中率和过时响应。refresh_pattern规则仅仅应用到没有明确过时期限的响应。原始服务器能使用Expires头部,或者Cache-Control:max-age指令来指定过时期限。
你可以在配置文件里放置任意数量的refresh_pattern行。squid按顺序查找它们以匹配正则表达式。当squid找到一个匹配时,它使用相应的值来决定,某个缓存响应是存活还是过期。refresh_pattern语法如下:
refresh_pattern [-i] regexp min percent max [options]
例如:
refresh_pattern -i \.jpg$ 30 50% 4320 reload-into-ims
refresh_pattern -i \.png$ 30 50% 4320 reload-into-ims
refresh_pattern -i \.htm$ 0 20% 1440
refresh_pattern -i \.html$ 0 20% 1440
refresh_pattern -i . 5 25% 2880

    regexp参数是大小写敏感的正则表达式。你可以使用-i选项来使它们大小写不敏感。squid按顺序来检查refresh_pattern行;当正则表达式之一匹配URI时,它停止搜索。
min参数是分钟数量。它是过时响应的最低时间限制。如果某个响应驻留在cache里的时间没有超过这个最低限制,那么它不会过期。类似的,max参数是存活响应的最高时间限制。如果某个响应驻留在cache里的时间高于这个最高限制,那么它必须被刷新。
在最低和最高时间限制之间的响应,会面对squid的最后修改系数(LM-factor)算法。对这样的响应,squid计算响应的年龄和最后修改系数,然后将它作为百分比值进行比较。响应年龄简单的就是从原始服务器产生,或最后一次验证响应后,经历的时间数量。源年龄在Last-Modified和Date头部之间是不同的。LM-factor是响应年龄与源年龄的比率。
    图7-2论证了LM-factor算法。squid缓存了某个目标3个小时(基于Date和Last-Modified头部)。LM-factor的值是50%,响应在接下来的1.5个小时里是存活的,在这之后,目标会过期并被当作过时处理。假如用户在存活期间请求cache目标,squid返回没有确认的cache命中。若在过时期间发生请求,squid转发确认请求到原始服务器。

    图: 基于LM-factor计算过期时间
    理解squid检查不同值的顺序非常重要。如下是squid的refresh_pattern算法的简单描述:
假如响应年龄超过refresh_pattern的max值,该响应过期;
假如LM-factor少于refresh_pattern百分比值,该响应存活;
假如响应年龄少于refresh_pattern的min值,该响应存活;
其他情况下,响应过期。

refresh_pattern指令也有少数选项导致squid违背HTTP协议规范。它们如下:
override-expire
该选项导致squid在检查Expires头部之前,先检查min值。这样,一个非零的min时间让squid返回一个未确认的cache命中,即使该响应准备过期。
override-lastmod
改选项导致squid在检查LM-factor百分比之前先检查min值。
reload-into-ims
该选项让squid在确认请求里,以no-cache指令传送一个请求。换句话说,squid在转发请求之前,对该请求增加一个If-Modified-Since头部。注意这点仅仅在目标有Last-Modified时间戳时才能工作。外面进来的请求保留no-cache指令,以便它到达原始服务器。
ignore-reload

该选项导致squid忽略请求里的任何no-cache指令。

2、源码分析
2.1关键数据结构
refresh_t
  2009 struct _refresh_t {
  2010 const char *pattern;
  2011 regex_t compiled_pattern;
  2012 time_t min;
  2013 double pct;
  2014 time_t max;
  2015 refresh_t *next;
  2016 struct {
  2017 unsigned int icase:1;
  2018 #if HTTP_VIOLATIONS
  2019 unsigned int override_expire:1;
  2020 unsigned int override_lastmod:1;
  2021 unsigned int reload_into_ims:1;
  2022 unsigned int ignore_reload:1;
  2023 unsigned int ignore_no_cache:1;
  2024 unsigned int ignore_private:1;
  2025 unsigned int ignore_auth:1;
  2026 #endif
  2027 unsigned int ignore_stale_while_revalidate:1;
  2028 } flags;
  2029 int max_stale;
  2030 int stale_while_revalidate;
  2031 int negative_ttl;
  2032 }; 
stale_flags
  56 typedef struct
  57 {
  58 unsigned int expires: // 是否有过期时间的标记
  59 1;
  60 unsigned int min: // 匹配到MIN标记
  61 1;
  62 unsigned int lmfactor: // 匹配到百分比标记
  63 1;

  64 unsigned int max; // 匹配到MAX标记

  65 } stale_flags;

2.2refresh_pattern检查时机

   Refresh_pattern的检查时机位于clientCacheHit()函数中的refreshCheckHTTPStale()函数中。该函数的流程为在disk中找到obj,Hit后即开始检查时间,看是否可以用这个Obj进行回复。

2.3refresh_pattern检查流程
// 过期检查refresh_pattern stale==0时为Hit stale = refreshCheckHTTPStale(e, r) {
 int reason = refreshCheck(entry, request, -Config.refresh_stale_window)
 {
  if (check_time > entry->timestamp)
  age = check_time - entry->timestamp;//检查时间-时间戳
  // 搜索匹配的R规则
  R = uri ? refreshLimits(uri) : refreshUncompiledPattern("."); if (NULL == R) R = &DefaultRefresh; // 检查是否过期,这里描述了max\ percentage\min三个值的比较先后顺序 staleness = refreshStaleness(entry, check_time, age, R, &sf) {
  if (entry->expires > -1)
  { // 数据有过期时间标识则用时间来做是否过期的判断依据 if (entry->expires > check_time)//没过期
  return -1
  else
  return (check_time - entry->expires);//过期了
  }
  // 比较max的值,如果大于直接过期
  if (age > R->max)
  return (age - R->max);
  // 比较时间戳,如果小于时间戳直接过期
  if (check_time < entry->timestamp)
  return (entry->timestamp - check_time);
  // 比较百分比,有最后修改时间
  if (entry->lastmod > -1 && entry->timestamp > entry->lastmod)
  {
  ime_t stale_age = (entry->timestamp - entry->lastmod) * R->pct;
  //依据此时间做比较
  if (age >= stale_age)
  return (age - stale_age); // 直接过期
  else
  return -1; // 不过期
  }
   
  // 比较Min
  if (age < R->min)
  return -1;//不过期
  else
  return (age - R->min); //过期
  }
   
  if (staleness < 0)
  return 不过期标志
   
  // 得到过期的细分标志
  .....
  // 不过期 }
  
  if (reason == STALE_WITHIN_DELTA)
  return -1;
   
  if (reason == STALE_ASYNC_REFRESH)
  return -2;
  
  if (reason == STALE_MAX_STALE)
  return 3;
  return (reason < 200) ? 0 : 1; }
 
 // 过期处理
 if (stale)
 {
  ........
  // refresh pattern 检查
  clientRefreshCheck(http);
  return;
 }
 
 // Hit流程
 clientProcessHit(http)
refresh_pattern检查耗时的操作
refresh_pattern检查耗时的操作在函数refreshLimits(const char *url)中执行,该函数将遍历Config.Refresh进行正则匹配操作。具体代码如下:
  118 const refresh_t *
  119 refreshLimits(const char *url)
  120 {
  121 const refresh_t *R;
  122 for (R = Config.Refresh; R; R = R->next)
  123 {
  124 if (!regexec(&(R->compiled_pattern), url, 0, 0, 0))
  125 return R;
  126 }
  127 return NULL;
  128 }
可见如果每个正则的pattern很宽松,并且正好匹配到的正则在链表的最末尾,则耗时最长。

阅读(1376) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~