欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  资讯频道

偏爱MySQL,Nifty使用4个Web Server支撑5400万个用户网站

程序员文章站 2022-05-13 22:45:49
...

【编者按】Nifty运营网站已经有很长一段时间,而在基于HTML5的WYSIWYG网页制作平台推出后,用户在该公司建立的网站已超过5400万个,同时其中大部分网站的日PV都不到100。鉴于每个网页的PV都很低,因此传统的缓存策略并不适用。然而即使是这样,该公司也只使用了4个Web Server就完成了这些工作。近日,Wix首席后端工程师Aviran Mordo在“ Wix Architecture at Scale”的演讲中分享了他们的策略,下面我们一起看High Scalability创始人Todd Hoff的总结:

以下为译文

Wix围绕扩展性上的努力可以用“定制化”三个字来总结——在仔细地审视了系统之后,以高可用和高性能为目标对系统进行了改善。

Wix使用了多数据中心和云服务,这在通常情况下非常少见,他们将数据同时复制到Google Compute Engine和AWS。对于故障转移,他们有专门的应对策略。

从始至终,Wix都没有使用事务。取而代之,所有数据都是不可变的,他们为用例使用了一个非常简单的最终一致性策略。Wix并不是缓存策略爱好者,简而言之他们并没有打造一个非常高端的缓存层。取而代之,他们将大部分的精力放在了路径渲染优化上,让每个页面的显示时间不超过100毫秒。

Wix开始于一个非常小的系统,使用了单片架构;而在业务发展过程中,他们很自然地过渡到一个面向服务的架构。在整个架构中,他们使用了一个非常成熟的服务识别策略,从而可以很轻易的将所有精力都集中到一个事件上来。

系统统计

 

  • 5400个网站,每个月都会新增100万个
  • 800+TB的静态数据,每天1.5TB的新文件
  • 3个数据中心+两个云服务(谷歌和亚马逊)
  • 300个服务器
  • 每天7亿个HTTP请求
  • 总计600员工,200人的研发团队
  • 系统内服务数量达50个
  • 4个公共Web Server来支撑4500万个网站

 

系统组件

 

  • MySQL
  • Google和Amazon云服务
  • CDN(内容分发网络)
  • Chef

 

系统衍变

1. 系统始于简单的单片架构,开始时只有一个应用服务器,对于任何人来说,这都是最简单的初始策略,非常灵活且易于更新。

 

  • Tomcat、Hibernate、定制网络框架。
  • 使用有状态的登录。
  • 无视任何性能和扩展性相关。

 

2. 两年后。

 

  • 仍然使用单片服务器支撑所有事情。
  • 拥有了一定规模的开发团队,且需要支撑一定规模的用户。
  • 依赖性产生的问题。某点的改变通常会造成整个系统的变更,无关领域的故障通常会造成整个系统大范围崩溃。

 

3. 系统拆分的时候到了。

 

  • 到面向服务的架构转变,但是这并不是件容易的事情。比如,你如何将某个功能分离到两个服务中?
  • 聚焦用户在系统中的行为,并将之主要归结为3类:修改网站、查看Wix建立的网站以及媒体服务。
  • 网站更新包括服务器数据的数据有效性、安全和验证、数据一致性以及大量的数据修改操作。
  • 一旦某个网站建立完成,用户就会进行查看。因此,对于整个系统来说,访客的数量十倍于修改者。因此关注点会转换为:

 

 

  • 高可用性。因为用户业务行为,HA成为系统最大的特性。
  • 高性能。
  • 高流量值。
  • 长尾问题。平台上已经有了大量的网站,但是它们通常都非常小。单独看某个网站,每天可能只有10或100个PV。鉴于这种特性,缓存对于系统扩展来说并不会起到太大的作用。因此,缓存变得非常低效。

 

 

  • 媒体支撑是第二大服务,包括HTML、javascript、css及images。他们需要一个途径来支撑800TB数据上的大量请求,其中缓存静态内容成为制胜的关键。
  • 新系统看起来像一个网络层,网站被切分为3个部分服务:修改部分(任何对数据产生修改的操作),媒体部分(支撑静态内容,只读),公共部分(一个文件被访问的首部分,只读)。

 

服务打造的指导方针

 

  • 每个服务都有自己独立的数据库,每个数据库只能一个被一个服务写入。
  • 数据库只能被服务的API访问,这样可以将关注点分离,并将数据模型对其他服务透明。
  • 鉴于性能原因,其他服务只被赋予数据库的只读权限,一个数据库只能被一个服务写入。
  • 服务都是无状态的,这让水平扩展非常便捷,业务的增长只需要添加更多服务器就可以支撑。
  • 不使用事务。除下billing/financial 事务以外,所有其他服务都不使用事务,这里的理念是避免数据库事务所带来的开销,从而提升性能。鉴于不使用事务,开发者必须考虑设计合适的数据模型来完成事务逻辑特性,从而避免不一致状态。
  • 在新服务设计时,缓存并不是所需要考虑的因素。首先,尽可能的考虑服务性能,然后快速的部署到生产环境,查看服务的运行情况。只有在代码无法优化的情况下,才使用缓存来解决性能问题。

 

更新服务

 

  • 更新服务必须处理大量的文件。
  • 数据被使用不可变的JSON pages在MySQL中存储,每天大约250万个。
  • MySQL是个非常棒的键值存储。键的设定基于文件的哈希函数,因此键是不可变的,通过主键来访问MySQL可以获得非常理想的性能。
  • 可接受的扩展性。在扩展性方面,Wix又做了什么样的权衡?Wix之所以不使用NoSQL的原因是NoSQL往往会牺牲一致性,而通常开发者并不具备处理这种情况的能力,所以坚持MySQL也并非不可。
  • 动态数据库。为了给那些经常访问的网站让路,所有网站的冷数据(通常是建立时间超过3个月以上的数据)都会被转移到其他的数据库,这些数据库的性能往往会非常低,但是容量很高。
  • 给用户增长留有容量空间。大型档案数据库是非常缓慢的,但是鉴于数据使用的频率这不会出现任何问题。但是一旦这个数据被访问,在下次访问之前这个数据就会被转移到活跃数据库。

 

打造更新服务的高可用性

 

  • 大数据体积达到一定程度时,任何事情的高可用都是难以保证的。因此,着眼关键路径,在网站领域无疑就是网站的内容。如果网站的一个装饰部分问题,它对网站的可用性不会造成任何致命影响。因此对一个网站来说,关键路径才是唯一关注点。
  • 防止数据库崩溃。如果你想尽可能快的完成故障转移,务必做好数据库的备份,并在故障恢复时快速切换到从数据库。
  • 数据完整性保护。这里并不一定是恶意破坏,一个bug可能就会对数据存储产生影响。所有数据都是不可变的,为任何数据保存校订版本。最坏的情况下,即使数据被破坏到无法修复,我们也可以将之恢复到修订版本。
  • 阻止不可用情况发生。区别于桌面应用程序,网站必须可以被随时随地地访问。因此,在不同地理位置的数据中心,不同云环境中对数据进行备份非常重要,这将赋予系统足够的弹性。

 

 

  • 在一个网站上点击“保存”按钮,修改会话会给修改服务器发送一个JSON文件。
  • 服务器会给活跃MySQL服务器发送页面,同时它会在另一个数据中心进行备份。
  • 当数据在本地修改后,一个异步的进程会将修改上传到一个静态网格,也就是所谓的媒体部分。
  • 当数据被传输到静态网格后,一个通知会发送给保存在Google Compute Engine上的存档服务。存档服务会连接到这个静态网格,下载这个修改页面,并将之保存在谷歌云服务中。
  • 然后,一个通知会发送到修改器,告知页面已经存储到GCE。
  • 同时,系统会根据GCE的数据在Amazon中保存另一个副本。
  • 当最后一个通知收到后,这意味着这个数据已经保存了3个副本:一个数据库,一个静态网格以及一个GCE。
  • 对于新版本来说是3个副本,而对于旧版本来说则会存在两个副本。
  • 这个过程具备自我修复的特性。如果这里存在一个错误,当用户下一次更新其网站内容时,所有未完成的修改会被重新上传。
  • 停用文件会做垃圾收集处理。

使用无数据库事务方式给数据建模

 

  • 对于服务拥有者来说,他们从来都不期望发生这样的情况:用户同时对两个页面进行修改,结果只有一个页面被存储到了数据库中,这就造成了不一致状态。
  • 取得所有JSON文件,随后按照顺序将他们保存到数据库。当所有数据被保存后,一个命令会被发布,它包含了上传到这个静态服务器上所有被保存页面的ID清单(静态服务器中文件名称的哈希值)。

 

 

媒体部分

 

  • 存储了大量文件。800TB的用户媒体文件,平均每天300万个文件,5亿条元记录。
  • 对图像进行修改。它们会针对不同设备和屏幕对图像进行修改。在这里,可以根据需求插入水印,同时还可以对音频格式进行转换。
  • 建立一个一致性分布式文件系统,使用多数据中心备份模式,并且实现跨数据中心的故障恢复。
  • 运行的痛苦。32个服务器,每9个月翻一倍。
  • 计划迁移到云中以获得更好的扩展性。
  • 让供应商锁定见鬼。因为都使用了API,只需要改变实现方式就可以在数周内跨云服务供应商进行迁移。
  • 在Google Compute Engine中遭遇失败。当他们从数据中心迁移到GCE时,很快就受到了谷歌云服务的限制。而在谷歌做出了一些改变后,系统得以正常运行。
  • 数据是不可变的,因此非常有利于缓存。
  • 图像请求会首先发送到CDN。如果所请求的图像在CDN中并不存在,请求会被直接传递给他们奥斯丁的主数据中心。如果在主数据中心也没有发现这个图像,随后寻找的地点就是谷歌云服务。如果谷歌云服务中仍然未发现所请求的图像,那么下一个寻找地点则是坦帕市的数据中心。

 

公用部分

 

  • 解析URL(在4500万网站中),并将之分配给指定的渲染程序,然后转换成HTML、sitemap XML或者robots TXT等。
  • 公用的SLA,峰值时响应时间低于100毫秒。网站必须是高可用的,同时也需要非常高的性能,但是缓存却并不能发挥作用。
  • 当一个用户修改某个页面并进行发布后,包括这个页面元素的清单会被推送到公用环境,同时推送的还有路由表。
  • 最小化宕机情况。解析一次路由需要促发一个数据库调用。将请求分配个渲染器需要1次RPC调用。获得网站清单也需要一次数据库调用。
  • 查询表会在内存中进行缓存,每5分钟修改一次。
  • 因为需要传送给编辑器,数据不可能保存为同一种格式。数据使用非规范化格式进行存储,通过主键进行优化,所有需求的内容都会在单一请求中返回。
  • 最小化业务逻辑。数据是非规范化的,并且进行预计算。大规模场景下,每秒内发生的每个操作都会乘以4500万次,因此发生在公共服务器上的每个操作都需要被调整。
  • 页面渲染

 

 

  • 由公共服务器返回的html是 bootstrap html类型的,它使用了一个JavaScript Shell,并包含了所有网站清单和动态数据相关的JSON数据。
  • 渲染会被放在客户端进行。当下,笔记本电脑和移动设备已经拥有了很强大的性能,它们完全可以从事这个工作。
  • 之所以选择JSON,因为解析和压缩都非常方便。
  • 客户端上的bug非常容易修补。修补客户端bug只需要重新部署一个客户端代码,如果在服务器端进行渲染,html则会被缓存,因此修补一个bug需要重新渲染上千万个网站。

 

公用部分的高可用性

 

  • 虽然目标是一直可用,但是总会发生一些意外情况
  • 通常情况下:请求由浏览器发出,随之会被传输到一个数据中心,通过一个负载均衡器,它将会给发送到一个公共服务器,解析路由,传送给渲染器,随后返回到浏览器,并使用浏览器运行javascript。随后,浏览器会对档案服务发送请求,档案服务会做与浏览器相同的操作,然后将数据储存到缓存。
  • 数据中心丢失发生的情况:这时候,所有UPS都会挂掉,数据中心也会丢失。所有DNS都会被改变,请求会发送给次数据中心。
  • 公用部分丢失的情况:当负载均衡器配置只进行一半发生这个问题时,所有公共服务器都会丢失。或者当部署错误版本时,服务器则会抛出故障。Wix通过定制负载均衡器代码来解决这个问题,在公共服务器丢失时,他们会将档案服务器路由到高速缓存,即使系统在警报后已经进行故障恢复。
  • 在网络连通性很烂的情况:请求由浏览器发出,随之会被传输到一个数据中心,通过一个负载均衡器,并返回对应的html。现在JavaScript代码必须取回所有的JSON数据和页面。随后进入内容分发网络,发送到静态网格,并获得所有的文件进行网站渲染。在网络很卡的情况下,文件返回可能无法进行。JavaScript则会做出选择:如果主要位置无法获得文件,代码则会在档案服务中获取。

 

学到的知识

 

  • 识别业务的关键路劲和关注点,仔细了解产品运行的方式,开发使用场景,尽力让你工作物有所值。
  • 使用多云和多数据中心。为了更好的可用性,在关键路径上建立冗余。
  • 对数据进行转换,最小化进程外跳,一切只为了性能。预计算并做一切可以做的事情来减少网络抖动。
  • 利用好客户端的CPU,为可用性建立关键路径上的冗余。
  • 从小做起,先跑起来,然后寻找下一个决策。从始至终,Wix首要解决的都是如何才能让服务可以良好运行的工作,然后有条不紊的转移到面向服务的架构。
  • 长尾需要不同的途径进行解决。取代缓存一切,Wix通过优化渲染途径来提升服务,并将数据在活跃和档案数据库中同时进行备份。
  • 使用不可变的方式。不可变会对服务的架构产生深远影响,覆盖后端到客户端的所有处理,对于许多问题来说,这都是个优雅的解决方案。
  • 供应商锁定根本不存在。所有功能都通过API实现,只需要修改实现就可以在数周内完成不同云供应商的迁移。
  • 最大的瓶颈来自数据。在不同云环境中转移大量数据异常困难。