Stack Overflow上部署HTTPS:长路尽头(四)

2017 年 9 月 23 日 Python程序员

Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发。

WebSockets

这个可以快速概括。 Websockets并不困难,这是我们在某些方面做的最简单的事情。我们使用websockets来实时更新用户,例如信誉改变,收件箱通知,新问题被询问,添加新的答案等。这意味着基本上每个打开Stack Overflow的页面都有一个相应的websocket连接到我们的负载均衡器。

那么有什么变化?很简单:安装一个证书,监听:443端口,并使用wss://qa.sockets.stackexchange.com而不是ws://(insecure)版本。后者在上面完成了所有的准备(我们在这里决定了一个特定的证书,但没有什么特别的)。 ws://到wss://更改只是一个配置。在转换期间,我们有ws://以wss://作为一个回退,但是从此变成只有wss://。一般使用安全的Websockets的原因有两个:

  1. 这是一个混合内容警告https://如果你没有。

  2. 它支持更多的用户,由于许多旧代理没有处理好Websockets。通过加密流量,大多数通过它而不用拒绝它。对于移动用户尤其如此。

这里的一个大问题是:“我们可以处理这些负载吗?”我们的网络处理了很多并发的Websockets;正如我写的那样,我们有超过60万个并发连接打开。以下是Opserver中HAProxy仪表板的视图:

非常多的连接产生于a)终端,b)抽象的socket,c)前端。 由于启用TLS会话恢复,HAProxy本身的负载也更大。 为了使用户能够在下次更快地重新连接,第一个协商产生令牌,用户可以在下一次发回。 如果我们有足够的内存,超时时间还没有过去,我们将恢复该会话,而不是每次都会协商一个新的会话。 这节省了CPU并提高了用户的性能,但是它加大了内存成本。 这个成本因密钥大小而异(2048,4096比特?更多?)。 我们目前使用4,096比特。 在任何给定的时间(我们的大部分内存使用量)中,大约有600,000个Websockets打开,我们仍然只使用了我们的64GB负载平衡器上的19GB的RAM。 其中,HAProxy正在使用大约12GB,其中大部分是TLS会话缓存。 所以...这不算太糟糕,如果我们不得不购买RAM,它仍然是这个举措中最便宜的一个。

未知数

我想现在是一个很好的时间来覆盖我们这次迁移的未知数(真的像赌博)。在我们测试了一个实际的行动之前,我们还不知道有几件事情:

  • Google Analytics(分析)流量出现的方式(我们是否丢失了引荐者?)

  • Google网站管理员转换的工作原理(301的工作原理?规范?站点地图?多快?)

  • Google搜索分析如何工作(我们在https://中看到搜索分析)?

  • 我们会搜索结果排名吗? (最可怕的)

有很多人已经转换为https://,但我们不是通常的用例。我们不是单纯的网站。我们是许多领域的网站网络。我们对Google如何对待我们的网络几乎没有洞察力。它知道stackoverflow.com和superuser.com是相关的?谁知道。而我们并没有乞求谷歌给我们任何洞察力。

所以,我们测试。在我们的网络范围的推出中,我们首先测试了几个领域:

  • meta.stackexchange.com

  • security.stackexchange.com

  • superuser.com

在Samo和我3分钟的会议上进行了详细的审查后,这些选择是非常仔细的。元因为它是我们的主要反馈网站(也是公告)。安全性因为他们有专家可能会注意到其他网站没有的问题,特别是在HTTPS空间。最后,超级用户。我们需要测试我们内容的搜索影响。虽然元和安全性较小,流量级别相对较小,但超级用户的流量明显增加。更重要的是,它有机地获得了Google的流量。

超级用户与网络其他部分之间长时间延迟的原因是我们正在查看并评估其对搜索的影响。据我们所知:几乎没有。搜索次数,结果,点击次数和排名的每周更改量都在正常的上/下限之内。我们公司依赖这个流量。这是非常重要的是要确定。幸运的是,我们很少担心,可能会继续推出。

错误

写这篇文章不是一个非常体面的练习,如果我也没有掩盖我们搞砸的部分。 失败永远是一个选择。 我们有经验来证明它。 我们来介绍一下我们所做的一些事情,从而不会留有遗憾。

错误:协议相关URL

当您有资源的网址时,您通常会看到类似http://example.com或https://example.com的内容,其中包含图片路径等。您可以使用的另一个选项是//example.com。 这些称为协议相关URL。 我们早期使用这些图像,JavaScript,CSS等(我们提供服务的,而不是用户提交的内容)。 几年后,我们发现这是一个坏主意,至少对我们来说。 协议相关链接的工作方式是相对于页面。 当您在http://stackoverflow.com上时,//example.com与http://example.com相同,并且在https://stackoverflow.com上与https://exam.COM。 那么有什么问题?

那么,图片的网址不仅在网页中使用,还可以用于电子邮件,我们的API和移动应用程序等场合。当我对路径结构进行归一化并使用相同的图像路径时,我们曾经遇到过一次。虽然这种变化大大减少了代码复制和简化了许多事情,但结果是电子邮件中的协议相关URL。大多数电子邮件客户端(适当)不会呈现此类图像。因为他们不知道哪个协议。电子邮件既不是http://也不是https://。您可能只是在网络浏览器中查看它,它才有效。

那么我们该怎么办?那么我们把所有的东西都转到https://。我将所有路径代码统一到2个变量:CDN的根目录和特定站点的文件夹。例如Stack Overflow的样式表位于:https://cdn.sstatic.net/Sites/stackoverflow/all.css(但使用缓存中断!)。在本地,它是https://local.sstatic.net/Sites/stackoverflow/all.css。你可以看到相似之处。通过计算所有路线,生活更简单。通过执行https://,即使在站点本身切换之前,人们也获得了HTTP/2的优势,因为静态内容已经准备好了。所有https://也意味着我们可以在网络,电子邮件,移动和API中使用一个属性作为URL。统一也意味着我们有一个一致的地方来处理所有的路径 - 这意味着缓存破坏者是建立在各处,而仍然更简单。

注意:当您像我们一样缓存资源时,例如:https://cdn.sstatic.net/Sites/stackoverflow/all.css?v=070eac3e8cf4,请不要使用版本编号。我们的缓存破解器是文件的校验和,这意味着只有在实际更改时才下载新的副本。做一个编号可能会稍微简单一点,但是它可能会同时花费你的钱和性能。

好的,所有这一切都很酷 - 为什么我们从来没有这样做?因为当时的HTTPS是一个性能损失。用户在http://页面上的加载时间会较慢。对于一个规模的想法:我们上个月在sstatic.net提供了40亿个请求,总计94TB。当HTTPS缓慢时,这将会是很多的集体延迟。现在这些表已经使用HTTP / 2和我们的CDN /Proxy设置启用了性能,这对大多数用户而言是一个完胜,而且更简单。好极了!

错误:API和.internal 

那么当我们启动代理并进行测试时,我们发现了什么呢?我们忘了一些关键的事情。我忘了一些关键的东西。我们使用HTTP作为众多内部API的连接协议。啊对。该死。虽然这些继续工作,但是它们同时变得更慢,更复杂,更脆弱。

假设内部API命中stackoverflow.com/some-internal-route。前面,原型有:

  • 原始应用

  • 网关/防火墙(退出公共IP空间)

  • 本地负载均衡器

  • 目标网络服务器

这是因为stackoverflow.com曾经帮我们解决了。它的IP是我们的负载均衡器。在代理情景中,为了让用户访问最近的一跳,他们正在访问不同的IP和目的地。他们的DNS解析的IP是现在的CDN /Proxy(Fastly)。好吧,废话。这意味着我们到同一个地方的道路是:

  • 原始应用

  • 网关/防火墙(退出公共IP空间)

  • 我们的外部路由器

  • ISP(多跳)

  • 代理(Cloudflare / Fastly)

  • ISP(代理路径给我们)

  • 我们的外部路由器

  • 本地负载均衡器

  • 目标网络服务器

好吧,那似乎更糟。要从A到B进行应用程序调用,我们大大增加了不必要的依赖关系,并且同时损失性能。我不是说我们的代理很慢,而是与数据中心内的一个1ms连接相比较好吗?是的,这很慢。

随之而来的很多内部讨论是解决这个问题的最简单的方法。我们可以提出像internal.stackoverflow.com这样的请求,但这将需要大量的应用程序更改网站的工作原理(稍后可能会产生冲突)。它还会为内部唯一地址(并创建通配符继承问题)创建了一个外部泄漏的DNS。我们可以使stackoverflow.com在内部解决不同(这被称为水平分割的DNS),但这更难调试,并创建其他问题,如多数据中心“谁赢”的场景。

最终,我们添加一个.internal后缀到我们有外部DNS的所有域并最终解决了问题。例如,在我们的网络中,stackoverflow.com.internal解析为负载平衡器的背面(DMZ)侧的内部子网。我们这样做有几个原因:

  • 我们可以覆盖并包含我们内部DNS服务器(Active Directory)上的顶级域名

  • 当我们通过HAProxy回到Web应用程序(应用程序方面甚至不知道)时,我们可以从Host头部剥离.internal。

  • 如果我们需要内部到DMZ的SSL,我们可以使用非常类似的通配符组合。

  • 客户端API代码很简单(如果在此域列表中添加.internal)

客户端API代码通过主要由Marc Gravell编写的名为StackExchange.Network的NuGet软件包/库完成。我们只需以静态的方式调用每个我们要访问的URL(所以只有几个地方,我们的实用程序提取方法)。它返回“内部化”URL,如果有的话,或者将其原样返回。这意味着任何对逻辑的更改都可以通过简单的NuGet更新快速部署到所有应用程序。调用很简单:

以下是stackoverflow.com DNS行为的具体说明:

  • Fastly:151.101.193.69,151.101.129.69,151.101.65.69,151.101.1.69

  • 直接(公共路由器):198.252.206.16

  • 内部:10.7.3.16

记得我们前面提到的dnscontrol吗? 这将使所有这一切都保持同步。 由于JavaScript配置/定义,我们可以轻松地共享所有并简化代码。 我们匹配所有IP的最后一个八位字节(在所有数据中心的所有子网中),所以在一些变量中,AD和外部的所有DNS条目都对齐。 这也意味着我们的HAProxy配置也更简单,它归结为:

总体来说,API路径现在比以前更快,更可靠:

  • 原始应用

  • 本地负载平衡器(DMZ侧)

  • 目标网络服务器

已经解决了十几个问题,还有几百个问题待解决。

错误:301缓存

我们没有意识到,应该测试的是,当我们开始将301流量从http://到https://的启用站点启动时,Fastly正在缓存响应。 在Fastly中,默认缓存密钥不考虑协议。 我个人不同意这种行为,因为默认情况下,启动301的重定向将导致无限重定向。 这个问题会导致一系列事件会发生:

  1. 用户访问http://上的页面

  2. 他们通过301重定向到https://

  3. Fastly缓存重定向

  4. 任何用户(包括上述#1中的一个)访问https://上的同一页面

  5. Fastly为301服务到https://,即使你已经在上面

这就是我们为什么遇到无限的重定向。 为了解决这个问题,我们关闭了301s,清除了Fastly缓存,并进行了调查。 在通过哈希更改修复它之后,我们与Fastly技术支持一起想办法,最终建议将Fastly-SSL添加到不同的变体,如下所示:

在我看来,这应该是默认行为。

错误:帮助中心SNAFU

还记得那些我们必须解决的帮助帖子吗?帮助帖子大多是以语言分类,所以他们被共享是有意义的。为了不复制一大堆的代码和存储结构,我们做一点点改变。我们将实际的Post对象(与问题或答案相同)存储在meta.stackexchange.com或任何特定的站点。我们将所产生的HelpPost存储在我们的中央站点数据库中,这只是烘焙的HTML。在混合内容方面,我们已经固定了各个站点的职位,因为他们是同样的职位是其他的事情。甜!那很简单!

原始帖子被修复后,我们只需要将重新生成的HTML重新填充到“站点”表中。这就是我排除了一个关键的代码的地方。回填查看当前网站(回收站被调用的站点),而不是原始站点。作为一个例子,这导致了一个HelpPost从postbox5在meta.stackechange.com上被替换为在stackoverflow.com上发布的12345。有时这是一个答案,有时候是一个问题,有时候是维基标签。这导致了在整个网络中有一些非常有趣的帮助文章。这里有一些创造的宝石。

至少承诺解决我的错误是简单的:

...并重新运行回填修复所有的错误。 不过,这是一些非常公开的“乐趣”。 很抱歉。

开源

以下是我们从HTTPS部署中获得或改进的所有项目的快速链接。 希望这些能为拯救世界节省一些时间:

  • Tom Limoncelli的BlackBox(安全地存储源代码管理中的秘密)

  • Marc Gravell的capnproto-net(UNSUPPORTED - Cap"n Proto for .NET)

  • Craig Peterson和Tom Limoncelli的DNSControl(控制多个DNS提供商)

  • Matt Jibson和Tom Limoncelli的httpUnit(网站的集成测试)

  • Nick Craver的Opserver(支持Cloudflare DNS)

  • fastlyctl(来自Go的快速API调用)由Jason Harvey

  • 由Jason Harvey提供的fastly-ratelimit(基于Fastly syslog流量的速率限制)

下一步

我们没有完成。还有很多事要做。

  • 我们需要在聊天域中修复混合内容,如chat.stackoverflow.com(来自用户嵌入的图像等)

  • 我们需要尽可能加入(如果我们可以)所有域上的Chrome HSTS预加载列表。

  • 我们需要评估HPKP,如果我们要部署它(这是非常危险的 - 目前倾向于“否”)

  • 我们需要将聊天移到https://

  • 我们需要将所有Cookie迁移到安全的

  • 我们正在等待HAProxy 1.8(ETA在9月左右),它将支持HTTP / 2

  • 我们需要利用HTTP / 2推送(我正在6月份快速讨论这个问题 - 他们不支持跨域推送)

  • 我们需要将https:// 301移动到CDN / Proxy来执行性能(有必要在我们推出时按每个站点进行)


英文原文:https://nickcraver.com/blog/2017/05/22/https-on-stack-overflow/
译者:jianli


登录查看更多
0

相关内容

超文本传输安全协议是超文本传输协议和 SSL/TLS 的组合,用以提供加密通讯及对网络服务器身份的鉴定。
【干货书】现代数据平台架构,636页pdf
专知会员服务
253+阅读 · 2020年6月15日
【实用书】Python技术手册,第三版767页pdf
专知会员服务
234+阅读 · 2020年5月21日
在K8S上运行Kafka合适吗?会遇到哪些陷阱?
DBAplus社群
9+阅读 · 2019年9月4日
Kali Linux 渗透测试:密码攻击
计算机与网络安全
16+阅读 · 2019年5月13日
浅谈 Kubernetes 在生产环境中的架构
DevOps时代
11+阅读 · 2019年5月8日
使用 C# 和 Blazor 进行全栈开发
DotNet
6+阅读 · 2019年4月15日
Kong 1.1 带来声明式配置与无数据库部署模式
开源中国
8+阅读 · 2019年3月28日
如何用GitLab本地私有化部署代码库?
Python程序员
9+阅读 · 2018年12月29日
WebAssembly在QQ邮箱中的一次实践
IMWeb前端社区
13+阅读 · 2018年12月19日
手把手 | 关于商业部署机器学习,这有一篇详尽指南
10个深度学习软件的安装指南(附代码)
数据派THU
17+阅读 · 2017年11月18日
十五条有用的Golang编程经验
CSDN大数据
5+阅读 · 2017年8月7日
A Modern Introduction to Online Learning
Arxiv
20+阅读 · 2019年12月31日
Arxiv
35+阅读 · 2019年11月7日
Deep Co-Training for Semi-Supervised Image Segmentation
Learning Blind Video Temporal Consistency
Arxiv
3+阅读 · 2018年8月1日
Arxiv
4+阅读 · 2018年5月4日
Arxiv
5+阅读 · 2018年5月1日
VIP会员
相关资讯
在K8S上运行Kafka合适吗?会遇到哪些陷阱?
DBAplus社群
9+阅读 · 2019年9月4日
Kali Linux 渗透测试:密码攻击
计算机与网络安全
16+阅读 · 2019年5月13日
浅谈 Kubernetes 在生产环境中的架构
DevOps时代
11+阅读 · 2019年5月8日
使用 C# 和 Blazor 进行全栈开发
DotNet
6+阅读 · 2019年4月15日
Kong 1.1 带来声明式配置与无数据库部署模式
开源中国
8+阅读 · 2019年3月28日
如何用GitLab本地私有化部署代码库?
Python程序员
9+阅读 · 2018年12月29日
WebAssembly在QQ邮箱中的一次实践
IMWeb前端社区
13+阅读 · 2018年12月19日
手把手 | 关于商业部署机器学习,这有一篇详尽指南
10个深度学习软件的安装指南(附代码)
数据派THU
17+阅读 · 2017年11月18日
十五条有用的Golang编程经验
CSDN大数据
5+阅读 · 2017年8月7日
Top
微信扫码咨询专知VIP会员