看StackOverflow如何用25台服务器撑起5.6亿的月PV(6)

使用这种极简的方式主要基于几个原因。首先,不需要太多测试,因为 Meta.stackoverflow 本来就是一个问题和 bug 讨论社区。其次,Meta.stackoverflow 还是一个软件的测试网站,如果用户发现问题的话,往往会提出并给予解决方案。

纽约数据中心使用的是 Windows 2012,已经向 2012 R2 升级(Oregon 已经完成了升级),Linux 系统使用的是 Centos 6.4。

SSD

默认使用的是 Intel 330(Web 层等)

Intel 520 用于中间层写入,比如 Elastic Search

数据层使用 Intel 710 和 S3700

系统同时使用了 RAID 1 和 RAID 10(任何4+ 以上的磁盘都使用 RAID 10)。不畏惧故障发生,即使生产环境中使用了上千块 2.5 英寸 SSD,还没碰到过一块失败的情景。每个模型都使用了 1 个以上的备件,多个磁盘发生故障的情景不在考虑之中。

ElasticSearch 在 SSD 上表现的异常出色,因为 SO writes/re-indexes 的操作非常频繁。

SSD 改变了搜索的使用方式。因为锁的问题,Luncene.net 并不能支撑 SO 的并发负载,因此他们转向了 ElasticSearch。在全 SSD 环境下,并不需要围绕 Binary Reader 建立锁。

高可用性

异地备份——主数据中心位于纽约,备份数据中心在 Oregon。

Redis 有两个从节点,SQL 有 2 个备份,Tag Engine 有 3 个节点,elastic 有 3 个节点,冗余一切,并在两个数据中心同时存在。

Nginx 是用于 SSL,终止 SSL 时转换使用 HAProxy。

并不是主从所有,一些临时的数据只会放到缓存中

所有 HTTP 流量发送只占总流量的 77%,还存在 Oregon 数据中心的备份及一些其他的 VPN 流量。这些流量主要由 SQL 和 Redis 备份产生。

数据库

MS SQL Server

Stack Exchange 为每个网站都设置了数据库,因此 Stack Overflow 有一个、Server Fault 有一个,以此类推。

在纽约的主数据中心,每个集群通常都使用 1 主和 1 只读备份的配置,同时还会在 Oregon 数据中心也设置一个备份。如果是运行的是 Oregon 集群,那么两个在纽约数据中心的备份都会是只读和同步的。

为其他内容准备的数据库。这里还存在一个“网络范围”的数据库,用于储存登陆凭证和聚合数据(大部分是 stackexchange.com 用户文件或者 API)。

Careers Stack Overflow、stackexchange.com 和 Area 51 等都拥有自己独立的数据库模式。

模式的变化需要同时提供给所有站点的数据库,它们需要向下兼容,举个例子,如果需要重命名一个列,那么将非常麻烦,这里需要进行多个操作:增加一个新列,添加作用在两个列上的代码,给新列写数据,改变代码让新列有效,移除旧列。

并不需要分片,所有事情通过索引来解决,而且数据体积也没那么大。如果有 filtered indexes 需求,那么为什么不更高效的进行?常见模式只在 DeletionDate = Null 上做索引,其他则通过为枚举指定类型。每项 votes 都设置了 1 个表,比如一张表给 post votes,1 张表给 comment votes。大部分的页面都可以实时渲染,只为匿名用户缓存,因此,不存在缓存更新,只有重查询。

Scores 是非规范化的,因此需要经常查询。它只包含 IDs 和 dates,post votes 表格当下大约有 56454478 行,使用索引,大部分的查询都可以在数毫秒内完成。

Tag Engine 是完全独立的,这就意味着核心功能并不依赖任何外部应用程序。它是一个巨大的内存结构数组结构,专为 SO 用例优化,并为重负载组合进行预计算。Tag Engine 是个简单的 windows 服务,冗余的运行在多个主机上。CPU 使用率基本上保持在2-5%,3 个主机专门用于冗余,不负责任何负载。如果所有主机同时发生故障,网络服务器将把 Tag Engine 加载到内存中持续运行。

关于 Dapper 无编译器校验查询与传统 ORM 的对比。使用编译器有很多好处,但在运行时仍然会存在 fundamental disconnect 问题。同时更重要的是,由于生成 nasty SQL,通常情况还需要去寻找原始代码,而 Query Hint 和 parameterization 控制等能力的缺乏更让查询优化变得复杂。

编码

流程

大部分程序员都是远程工作,自己选择编码地点

编译非常快

然后运行少量的测试

一旦编译成功,代码即转移至开发交付准备服务器

通过功能开关隐藏新功能

在相同硬件上作为其他站点测试运行

然后转移至 Meta.stackoverflow 测试,每天有上千个程序员在使用,一个很好的测试环境

如果通过则上线,在更广大的社区进行测试

大量使用静态类和方法,为了更简单及更好的性能

编码过程非常简单,因为复杂的部分被打包到库里,这些库被开源和维护。.Net 项目数量很低,因为使用了社区共享的部分代码。

开发者同时使用 2 到 3 个显示器,多个屏幕可以显著提高生产效率。

缓存

缓存一切

5 个等级的缓存

1 级是网络级缓存,缓存在浏览器、CDN 以及代理服务器中。

2 级由 .Net 框架 HttpRuntime.Cache 完成,在每台服务器的内存中。

3 级 Redis,分布式内存键值存储,在多个支撑同一个站点的服务器上共享缓存项。

4 级 SQL Server Cache,整个数据库,所有数据都被放到内存中。

5 级 SSD。通常只在 SQL Server 预热后才生效。

举个例子,每个帮助页面都进行了缓存,访问一个页面的代码非常简单:

使用了静态的方法和类。从 OOP 角度来看确实很糟,但是非常快并有利于简洁编码。

缓存由 Redis 和 Dapper 支撑,一个微型 ORM

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/3d9df25ed8477d7f173ad0bb0ed2a62e.html