如何处理清漆堆栈中的Cookie

Ner*_*ses 6 linux cookies passenger nginx varnish

由于网站性能下降,我开始将Varnish信息作为缓存解决方案,并对Google Analytics有一些疑问.

当网站上有5K活跃用户时(根据GA的实时流量报告),后端服务器上的服务器加载到30-40 +,乘客的队列开始堆叠,站点几乎无法使用.我知道需要获得更好性能的慢查询和数据库工作,但目前我没有资源来优化查询和数据库模式,索引等,所以考虑添加清漆.

我创建了一个图表来更好地显示堆栈,这是当前堆栈的样子:(该站点当前在CDN中缓存images/css/js - Akamai)

在此输入图像描述

我想在后端服务器前面添加两个varnish实例来缓存文章,堆栈将如下所示:

在此输入图像描述

该网站是一个新闻网站,我正在寻找建议,如何正确处理cookie和缓存.对于第1阶段,我想简单地完全排除经过身份验证的用户并提供动态内容,因为同时经过身份验证的用户并不多.

混淆是谷歌分析的cookie.我的理解是,Google使用javascript在客户端设置了Cookie,客户端直接与Google通信,因此后端不需要客户端发送的GA Cookie,在vcl_recv子例程中可以安全地取消它们.

sub vcl_recv {

// Remove has_js and Google Analytics __* cookies.
set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[_a-z]+|has_js)=[^;]*", "");
// Remove a ";" prefix, if present.
set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");
}
Run Code Online (Sandbox Code Playgroud)

问题

  • 这是一种安全的方法吗?
  • Google仍会正确跟踪,包括重复访问者吗?
  • 在我的阶段1政策中还有其他需要注意的事项吗?

由于varnish默认不会缓存任何具有cookie集的内容,因此只需添加一个删除GA cookie的策略就可以安全地实现上述堆栈吗?据我所知,如果没有微调VCL策略,我不会获得高命中率,但是在我的测试中,看来即使在后端服务器前面有默认清漆,命中率为30%,在分析后,我看到了大多数是js/css和图像文件,所以很明显一些静态文件不是由Akamai甚至Apache提供的,而是传递给Passenger/Rails来提供静态文件.这肯定需要纠正.

  • Varnish会在默认情况下改善性能吗?

我是清漆的新手所以非常感谢任何关于清漆或我提出的堆栈的更多细节/建议.

对于阶段2 +

由于内容得到更新,我计划在两个varnish服务器上执行清除,在应用更改时由后端服务器触发,例如用户注释,页面查看等.

有大量存档文章没有更新,永久缓存它们是否安全?

由于我打算使用RAM进行清漆存储,我是否应该使用额外的(第三种)清漆,并使用磁盘进行存储,以明确这些存档的页面.也许在清漆服务器前添加nginx堆栈以将流量定向到存档内容的特定清漆实例?负载均衡器 - >一对Nginx反向代理>一对清漆 - >(清漆LB到8个后端服务器)

我也很欣赏有关架构的任何建议.如果您需要更多详细信息以提供更好的建议,请告诉我们,我们很乐意为您提供更多详细信息.

Ric*_*lse 11

这是很多问题!:-)

Q. Is this a safe approach?
Run Code Online (Sandbox Code Playgroud)

从表面上看,我会这么说.

通常,在流量高且内容快速变化的新闻网站上设置清漆可能是一个挑战.

一个非常好的检查方法是构建一个单独的清漆盒并让它直接访问您的集群(而不是通过负载均衡器),并为其提供一个临时的公共IP地址.这将使您有机会测试VCL更改.您将能够测试评论,登录(如果有的话)以及其他任何内容以确保没有任何意外.

Q. Will Google still track properly, including repeat visitors?
Run Code Online (Sandbox Code Playgroud)

是.Cookie仅在客户端使用.

您应该注意的一件事是,当后端发送cookie时,Varnish也不会缓存内容.您需要删除vcl_fetch上不需要的任何cookie.如果使用cookie来跟踪用户状态,这可能是一个问题.

Q. Is there anything else that I need to watch for in my policies for phase1?
Run Code Online (Sandbox Code Playgroud)

您需要在Rails中禁用rack-cache,并设置自己的标头.请注意,如果您删除清漆,Rails将运行而不会缓存,并且可能会崩溃!

这就是我在production.rb中的内容:

  # We do not use Rack::Cache but rely on Varnish instead
  config.middleware.delete Rack::Cache
  # varnish does not support etags or conditional gets
  # to the backend (which is this app) so remove them too
  config.middleware.delete Rack::ETag
  config.middleware.delete Rack::ConditionalGet
Run Code Online (Sandbox Code Playgroud)

在我的application_controller中,我有这个私有方法:

def set_public_cache_control(duration)
  if current_user
    response.headers["Cache-Control"] = "max-age=0, private, must-revalidate"
  else
    expires_in duration, :public => true
    response.headers["Expires"] = CGI.rfc1123_date(Time.now + duration)
  end
end
Run Code Online (Sandbox Code Playgroud)

这在我的其他控制器中调用,以便我可以非常细粒度地​​控制对网站的各个部分应用多少切割.我在每个作为before_filter运行的控制器中使用一个setup方法:

def setup
  set_public_cache_control 10.minutes
end
Run Code Online (Sandbox Code Playgroud)

(application_controller具有过滤器和空白设置方法,因此在其他控制器中可以是可选的)

如果您的网站的一部分不需要cookie,您可以根据VCL中的URL将其剥离,并应用标头.

您可以像这样在apache配置中设置静态资产的缓存时间(假设您使用的是默认资产路径):

<LocationMatch "^/assets/.*$">
    Header unset ETag
    FileETag None
    # RFC says only cache for 1 year
    ExpiresActive On
    ExpiresDefault "access plus 1 year"
    Header append Cache-Control "public"
</LocationMatch>

<LocationMatch "^/favicon\.(ico|png)$">
    Header unset ETag
    FileETag None
    ExpiresActive On
    ExpiresDefault "access plus 1 day"
    Header append Cache-Control "public"
</LocationMatch>

<LocationMatch "^/robots.txt$">
    Header unset ETag
    FileETag None
    ExpiresActive On
    ExpiresDefault "access plus 1 hour"
    Header append Cache-Control "public"
</LocationMatch>
Run Code Online (Sandbox Code Playgroud)

这些标题将被发送到您的CDN,这会将资产缓存更长时间.看着清漆,你仍然会看到请求以递减的速度进入.

我还会在页面不需要cookie的所有内容上设置非常短的缓存,但经常更改.在我的情况下,我为主页设置了10秒的缓存时间.这对Varnish来说意味着一个用户请求将每10秒转到后端.

您还应该考虑将varnish设置为使用宽限模式.这允许它从缓存中提供略微陈旧的内容,而不是让访问者对刚刚过期的项目的后端的响应缓慢.

Q. There are plenty of archived articles that don't get updated, is it safe to cache them forever?
Run Code Online (Sandbox Code Playgroud)

为此,您需要更改应用程序,以便为存档的文章发送不同的标题.这假设他们没有cookie.根据我在网站上的操作,我会这样做: -

在上面的设置中添加条件以更改缓存时间:

def setup
  # check if it is old. This code could be anything
  if news.last_updated_at < 1.months.ago
    set_public_cache_control 1.year
  else
    set_public_cache_control 10.minutes
  end
end 
Run Code Online (Sandbox Code Playgroud)

这将设置一个公共标题,因此Varnish将缓存它(如果没有cookie),任何远程缓存(在ISP或公司网关)也是如此.

问题在于,如果您想要删除故事或更新故事(例如,出于法律原因).

在这种情况下,您应该发送Varnish私有标头来更改该URL的TTL,但为其他人发送更短的公共标头.

这将允许你设置Varnish服务内容(比如说)1年,同时发送标题告诉客户每10分钟回来一次.

在这些情况下,您需要添加清除清漆的制度.

为了让你入门我在application_controller中有第二个方法:

def set_private_cache_control(duration=5.seconds)
  # logged in users never have cached content so no TTL allowed
  if ! current_user
    # This header MUST be a string or the app will crash
    if duration
      response.headers["X-Varnish-TTL"] = duration.to_s
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

在我的vcl_fetch中,我有这个:

call set_varnish_ttl_from_header;
Run Code Online (Sandbox Code Playgroud)

而vcl函数是这样的:

sub set_varnish_ttl_from_header {
  if (beresp.http.X-Varnish-TTL) {
    C{  
      char *x_end = 0;
      const char *x_hdr_val = VRT_GetHdr(sp, HDR_BERESP, "\016X-Varnish-TTL:"); /* "\016" is length of header plus colon in octal */
      if (x_hdr_val) {
        long x_cache_ttl = strtol(x_hdr_val, &x_end, 0);
        if (ERANGE != errno && x_end != x_hdr_val && x_cache_ttl >= 0 && x_cache_ttl < INT_MAX) {
          VRT_l_beresp_ttl(sp, (x_cache_ttl * 1));
        }
      }
    }C
    remove beresp.http.X-Varnish-TTL;
  }
}
Run Code Online (Sandbox Code Playgroud)

这样就不会将标头传递给任何上游缓存(s-max-age确实如此).

设置方法如下所示:

def setup
  # check if it is old. This code could be anything
  if news.last_updated_at < 1.months.ago
    set_public_cache_control 10.minutes
    set_private_cache_control 1.year
  else
    set_public_cache_control 10.minutes
  end
end 
Run Code Online (Sandbox Code Playgroud)

随意提出任何补充问题,我会更新这个答案!