您的当前位置:首页正文

【翻译】Stack Overflow 的 HTTPS 化:漫漫长

来源:华拓网

Cloudflare

注意,测试过程最少需要 24 小时。在各个时区,互联网的表现会随着用户作息或者 Netflix 的使用情况等发生变化。所以要测试一个国家,需要完整的一天数据。最好是在工作日(而不要半天落在周六)。我们知道会有各种意外情况。互联网的性能并不是稳定的,我们要通过数据来证明这一点。

我们最初的假设是,多增加了的一个节点会带来额外的延时,我们会因此损失一部分页面加载性能。但是 DNS 性能上的增加其实弥补了这一块。比起我们只有一个数据中心来说,Cloudflare 的 DNS 服务器部署在离用户更近的地方,这一块性能要好得多得多。我希望我们能有空来放出这一块的数据,只不过这一块需要很多处理(以及托管),而我现在也没有足够多的时间。

Cloudflare: Railgun

举个例子,想象一下,两个用户打开同一个问题的页面。从浏览效果来看,他们的页面技术上长得几乎一样,仅仅有细微的差别。如果我们大部分的传输内容只是一个 diff 的话,这将是一个巨大的性能提升。

Fastly

事实胜于雄辩:如果我不认可 Cloudflare,我的私人博客不可能选择它,嘿,就是这个博客,你现在正在阅读的。

sub vcl_fetch {
  if (beresp.http.Cache-Control) {
      if (req.url.path ~ "^/users/flair/") {
          set beresp.http.Cache-Control = "public, max-age=180";
      } else {
          set beresp.http.Cache-Control = "private";
      }
  }

另一个 Fastly 的特点是可以使用我们自己的证书,Cloudflare 虽然也有这个服务,但是费用太高。如我上文提到的,我们现在已经具备使用 HTTP/2 推送的能力。但是,Fastly 就不支持 DNS,这个在 Cloudflare 那里是支持的。现在我们需要自己解决 DNS 的问题了。可能最有意思的就是这些来回的折腾吧?

全局 DNS

  • 我们自己的 DNS 服务器(备用)
  • 的服务器(为了那些不需要 HTTPS 的跳转服务)
  • Cloudflare DNS
  • Route 53 DNS
  • Google DNS
  • Azure DNS
  • 其他一些(测试时候使用)
 REG_NAMECOM,
    DnsProvider(R53,2),
    DnsProvider(GOOGLECLOUD,2),
    SPF,
    TXT('@', 'google-site-verification=PgJFv7ljJQmUa7wupnJgoim3Lx22fbQzyhES7-Q9cv8'), // webmasters
    A('@', ADDRESS24, FASTLY_ON),
     '@'),
    CNAME('chat', 
    A('meta', ADDRESS24, FASTLY_ON),
END)

测试

[[plan]]
    label = "teststackoverflow_com"
    url = 
    ips = ["28i"]
    text = "<title>Test Stack Overflow Domain</title>"
    tags = ["so"]
[[plan]]
    label = "tls_teststackoverflow_com"
    url = 
    ips = ["28"]
    text = "<title>Test Stack Overflow Domain</title>"
    tags = ["so"]

应用层准备

换一句话说:我们的 Q&A 全站都是跑在同一个服务器上的同一个进程,而用户对此没有感知。我们在九台服务器上每一台跑一个进程,只是为了发布版本和冗余的问题。

全局登录

整个项目中有一些看起来可以独立出来(事实上也是),不过也同属于整个大 HTTPS 迁移中的一部分。登录就是其中一个项目。我首先来说说这个,因为这比别它变化都要早上线。

客户端的代码不复杂,基本上长这样:

$.post('/users/login/universal/request', function (data, text, req) {
    $.each(data, function (arrayId, group) {
        var url = '//' + group.Host + '/users/login/universal.gif?authToken=' + 
            encodeURIComponent(group.Token) + '&nonce=' + encodeURIComponent(group.Nonce);
        $(function () { $('#footer').append('![](' + url + ')</img>'); });
    });
}, 'json');

但是要做到这点,我们必须上升到账号级别的认证(之前是用户级别)、改变读取 cookie 的方式、改变这些 meta 站的登录工作方式,同时还要将这一新的变动整合到其它应用中。比如说,Careers(现在拆成了 Talent 和 Jobs)用的是另一份代码库。我们需要让这些应用读取相应的 cookies,然后通过 API 调用 Q&A 应用来获取账户。我们部署了一个 NuGet 库来减少重复代码。底线是:你在一个地方登录,就在所有域名都登录。不弹框,不重载页面。

本地 HTTPS 开发

要想做得更好的话,本地环境应该尽量与开发和生产环境保持一致。幸好我们用的是 IIS,这件事情还简单的。我们使用一个工具来设置开发者环境,这个工具的名字叫「本地开发设置」——单纯吧?它可以安装工具(Visual Studio、git、SSMS 等)、服务(SQL Server、Redis、Elasticsearch)、仓库、数据库、网站以及一些其它东西。做好了基本的工具设置之后,我们要做的只是添加 SSL/TLS 证书。主要的思路如下:

Websites = @(
    @{
        Directory = "StackOverflow";
        Site = 
        Aliases =  
        Databases = "Sites.Database", "Local.StackExchange.Meta", "Local.Area51", "Local.Area51.Meta";
        Certificate = $true;
    },
    @{
        Directory = "StackExchange.Website";
        Site = 
        Databases = "Sites.Database", "Local.StackExchange", "Local.StackExchange.Meta", "Local.Area51.Meta";
        Certificate = $true;
    }
)

「Nick 你就扯吧,我们能拿到从 Google 拿到 referer 啊!」确实。但是这是因为他们主动选择这一行为。如果你看一下 Google 的搜索页面,你可以看到这样的 <meta> 指令:

<meta content="origin" id="mref" name="referrer">

这也就是为什么你可以取到 referer。

好的,我们已经设置好了,现在该做些什么呢?