ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# Vinted 体系结构:每天部署数百次,以保持繁忙的门户稳定 > 原文: [http://highscalability.com/blog/2015/2/9/vinted-architecture-keeping-a-busy-portal-stable-by-deployin.html](http://highscalability.com/blog/2015/2/9/vinted-architecture-keeping-a-busy-portal-stable-by-deployin.html) ![](https://img.kancloud.cn/5c/3d/5c3df8465fc2f3d17abd25ea2143021a_122x122.png) *这是 [Vinted](https://www.vinted.com/) 的 [NerijusBendžiūnas](https://www.linkedin.com/profile/view?id=48589106)和 [Tomas Varaneckas](https://twitter.com/spajus) 的来宾帖子。* [Vinted](https://www.vinted.com/) 是一个对等市场,用于出售,购买和交换衣服。 它允许成员直接通信,并具有社交网络服务的功能。 它始于 2008 年,最初是一个立陶宛女孩的小社区,后来发展成为一个全球性项目,为 8 个不同国家/地区的 700 万用户提供服务,并且这一需求正在不断增长,每天处理超过 2 亿个请求。 ## 统计资料 * 700 万用户,并且还在不断增长 * 每月 250 万活跃用户 * 每天 2 亿个请求(浏览量+ API 调用) * 9.3 亿张照片 * 80 TB 原始空间用于图像存储 * 60 TB HDFS 原始空间用于分析数据 * 70%的流量来自移动应用(API 请求) * 每位成员每周花费 3 个小时以上的时间 * 2500 万个上市项目 * 超过 220 台服务器: * 47 用于内部工具(vpn,厨师,监视,开发,制图,构建,备份等) * Hadoop 生态系统 38 * 34 用于图像处理和存储 * 独角兽和微服务 30 * 28 个用于 MySQL 数据库,包括副本 * 19 用于狮身人面像搜索 * 10 个用于背景工作 * 10 用于使用 Nginx 进行负载平衡 * 卡夫卡 6 * Redis 4 * 4 用于电子邮件传递 ## 技术栈 ### 第三方服务 * [GitHub](https://github.com/) ,用于代码,问题和讨论 * [NewRelic](http://newrelic.com/) 用于监视应用程序响应时间 * [CloudFlare](https://www.cloudflare.com/) 用于 DDoS 保护和 DNS * [Amazon Web Services](http://aws.amazon.com/) (SES,Glacier),用于通知和长期备份 * [闲暇](https://slack.com/)用于工作对话和“聊天操作” * [Trello](https://trello.com/) 完成任务 * [Pingdom](http://pingdom.com/) 用于正常运行时间监控 ### 核心应用和服务 * [Ruby](https://www.ruby-lang.org/) 用于服务,脚本和主应用 * [主应用程序和内部应用程序的 Rails](http://rubyonrails.org/) * [独角兽](http://unicorn.bogomips.org/)服务于主应用 * [Percona MySQL 服务器](http://www.percona.com/software/percona-server/ps-5.6)作为主数据库 * [Sphinx 搜索](http://sphinxsearch.com/)用于全文搜索并减少 MySQL 的负载(测试 [ElasticSearch](http://www.elasticsearch.org/) ) * [Capistrano](http://capistranorb.com/) 用于部署 * [Jenkins](http://jenkins-ci.org/) 用于运行测试,部署和其他各种任务 * [Memcached](http://memcached.org/) 用于缓存 * [请求](http://resquework.org/)进行后台作业 * [Redis](http://redis.io/) 用于 Resque 和 Feed * [RabbitMQ](http://www.rabbitmq.com/) 用于将消息传递到服务 * [HAproxy](http://www.haproxy.org/) 提供高可用性和负载平衡 * [GlusterFS](http://www.gluster.org/) 用于分布式存储 * [Nginx](http://nginx.org/) 投放 Web 请求 * [Apache Zookeeper](http://zookeeper.apache.org/) 用于分布式锁定 * [Flashcache](https://github.com/facebook/flashcache/) 可提高 I / O 吞吐量 ### 数据仓库堆栈 * [Clojure](http://clojure.org/) 用于数据提取服务 * [Apache Kafka](http://kafka.apache.org/) ,用于存储飞行中的数据 * [Camus](https://github.com/linkedin/camus) 用于将数据从 Kafka 卸载到 HDFS * [Apache Hive](https://hive.apache.org/) 作为 SQL-on-Hadoop 解决方案 * [Cloudera CDH](http://www.cloudera.com/content/cloudera/en/products-and-services/cdh.html) Hadoop 发行版 * [Cloudera Impala](http://www.cloudera.com/content/cloudera/en/products-and-services/cdh/impala.html) 作为低延迟 SQL-on-Hadoop 解决方案 * [Apache Spark](https://spark.apache.org/) 处于实验阶段 * [Apache Oozie](http://oozie.apache.org/) 作为工作流调度程序(研究替代方案) * [扩展](https://github.com/twitter/scalding)用于数据转换 * [Avro](http://avro.apache.org/) 用于数据序列化 * [Apache Parquet](http://parquet.incubator.apache.org/) 用于数据序列化 ### 服务器和资源调配 * 多为裸金属 * 多个数据中心 * [CentOS](http://www.centos.org/) * [厨师](https://www.chef.io/)用于配置几乎所有内容 * [Berkshelf](http://berkshelf.com/) ,用于管理 Chef 依赖项 * [测试厨房](http://kitchen.ci/),用于在 VM 上运行基础结构测试 * [Ansible](http://www.ansible.com/) 用于滚动升级 ### 监控方式 * [Nagios](http://www.nagios.org/) 用于常规操作监控 * [仙人掌](http://www.cacti.net/)用于图形和容量规划 * [Graylog2](https://www.graylog2.org/) 适用于应用程序日志 * 用于服务器日志的 [Logstash](http://logstash.net/) * [Kibana](http://www.elasticsearch.org/overview/kibana/) 用于查询 logstash * [统计信息](https://github.com/etsy/statsd),用于从应用程序收集实时指标 * [石墨](http://graphite.wikidot.com/),用于存储应用程序中的实时指标 * [Grafana](http://grafana.org/) 用于创建带有应用指标的精美仪表板 * [集线器](https://hubot.github.com/)用于基于聊天的监视 ## 架构概述 * 裸机服务器被用作云提供商的更便宜,更强大的替代产品。 * 在欧洲和美国的 3 个不同数据中心托管服务器。 * Nginx 前端将 HTTP 请求路由到独角兽工作者并执行 SSL 终止。 * [Pacemaker](http://clusterlabs.org/) 用于确保 Nginx 服务器的高可用性。 * 在不同的国家/地区,每个 Vinted 门户网站都有自己单独的部署和资源集。 * 为了提高机器利用率,属于多个门户的大多数服务可以在单个裸机服务器上彼此并行运行。 主厨配方负责唯一的端口分配和其他分离问题。 * 通过为每个门户网站使用单独的数据库来避免 MySQL 分片。 * 在我们最大的门户中,功能性分片已经在发生,距离单个最大表无法容纳在服务器中的点还差几个月。 * Rails 应用程序中的缓存使用带有 L2 缓存的自定义机制,可以防止主缓存过期时出现峰值。 使用了几种缓存策略: * 远程(在 memcached 中) * 本地(在独角兽工作者的记忆中) * 半本地(在独角兽工作器内存中,当本地缓存到期时回退到 memcached)。 * 围绕核心 Rails 应用程序构建了几个微服务,它们都有明确的用途,例如发送 iOS 推送通知,存储和提供品牌名称,存储和提供标签。 * 微服务可以是按端口,按数据中心或全局的。 * 每个微服务的多个实例正在运行以实现高可用性。 * Nginx 平衡了基于 HTTP 的微服务。 * 使用 Redis 实现每个成员的自定义 feed。 * 使用过滤器(自定义大小,颜色等)时,从 Sphinx 索引而不是 MySQL 加载目录页面。 * 图像由单独的 Rails 应用处理。 * 处理后的图像存储在 GlusterFS 中。 * 第 3 次匹配后会缓存图片,因为前几次匹配通常来自上传者,并且图片可能会旋转。 * 使用 [twemproxy](https://github.com/twitter/twemproxy) 分割 Memcached 实例。 ## 球队 * 超过 150 名全职员工 * 30 位开发人员(后端,前端,移动) * 5 名现场可靠性工程师 * 立陶宛维尔纽斯的总部 * 在美国,德国,法国,捷克共和国和波兰设有办事处 ## 公司的运作方式 * 几乎所有信息对所有员工开放 * 使用 GitHub 进行几乎所有操作(包括讨论公司问题) * Slack 中的实时讨论 * 每个人都可以自由参加他们感兴趣的事情 * 自治队 * 没有资历等级 * 跨职能开发团队 * 没有强制执行的流程,团队可以决定如何管理自己 * 团队致力于解决高层问题,并决定如何解决它们 * 每个团队都决定如何,何时何地工作 * 团队在需要时自行雇用 ## 开发周期 * 开发人员从主人处分支。 * 更改成为 GitHub 中的请求请求。 * Jenkins 运行 [Pronto](https://github.com/mmozuras/pronto) 进行静态代码和样式检查,在 pull request 分支上运行所有测试,并使用状态更新 GitHub pull request。 * 其他开发人员查看更改,添加评论。 * 拉取请求可能会使用各种修复程序多次更新。 * 每次更新后,Jenkins 都会运行所有测试。 * 在与 master 合并之前清理 Git 历史,以保持 master 历史的简洁性。 * 接受的请求请求将合并到主服务器中。 * Jenkins 使用所有测试运行主版本,并触发部署作业以推出新版本。 * 几分钟后,代码到达 master 分支后,将其应用于生产中。 * 拉取请求通常很小。 * 每天部署约 300 次。 ## 避免失败 每天部署数百次并不意味着总是必须破坏所有东西,但是保持站点稳定需要一定的纪律。 * 如果测试失败,则不会进行部署。 没有方法可以覆盖它,母版必须为绿色才能进行部署。 * 每天晚上和周末自动部署锁定。 * 任何人都可以通过 Slack 聊天手动锁定部署。 * 部署锁定后,可以从 Slack 聊天中手动“强制”部署。 * 在审查代码时,团队非常挑剔。 质量标准设置得很高。 测试是强制性的。 * 在 Unicorn 重新加载代码之前,将在生产中进行预热。 它包括对门户网站各个关键部分的若干请求。 * 在预热期间,如果任何一个请求均未返回 200 OK,则旧代码将保留,并且部署将失败。 * 有时,测试/预热未发现问题,并且已损坏的代码发布到了生产环境中。 * 错误将流式传输到 Graylog 服务器。 * 如果错误率超过阈值,则会触发警报。 * 错误率警报和失败的构建通知会立即报告给 Slack 聊天。 * 所有错误都包含额外的元数据:Unicorn worker 主机和 pid,HTTP 请求详细信息,导致问题的代码的 git 修订版,错误回溯。 * 某些类型的“致命”错误也直接报告给 Slack 聊天。 * 每个部署日志都包含带有所有更改的 GitHub 差异 URL。 * 如果生产中出现问题,由于变更集和即时错误反馈的原因,很容易快速查明问题。 * 部署详细信息会报告给 NewRelic,从而可以轻松解决性能瓶颈的引入。 ## 减少生产时间 快速发布和稳定发布都非常受关注,团队一直在努力使构建和部署时间尽可能短。 * 完整的测试套件包含> 7000 个测试,运行时间约为 3 分钟。 * 不断添加新的测试。 * Jenkins 在具有 32 个 CPU,128G RAM 和 SSD 驱动器的裸机上运行。 * Jenkins 将所有测试分成多个块,并并行运行它们,以汇总最终结果。 * 在没有并行化的情况下,测试将在一台普通计算机上运行 1 个小时以上。 * 在 Jenkins 中,对于 master 分支中的每次提交,Rails 资产都是预先构建的。 * 在部署期间,从 jenkins 下载预建资产,并将其上载到所有目标服务器。 * 将版本上载到目标服务器时使用 BitTorrent。 ## 运行实时数据库迁移 在大多数情况下,即使在高峰时间,我们也可以在不停机的情况下更改生产 MySQL 数据库的结构。 * 在任何部署期间都可能发生数据库迁移 * Percona 工具箱的 pt-online-schema-change 用于在表的副本上运行更改,同时使其与原始副本保持同步,并在更改完成后将副本与原始副本切换 # 运作方式 ## 服务器配置 * Chef 用于提供我们基础架构的几乎所有方面。 * SRE 团队确实会提出对基础结构更改的请求,就像开发团队对代码更改所做的一样。 * 詹金斯(Jenkins)正在验证所有 Chef 拉取请求,运行交叉依赖关系检查,食品评论等。 * 团队在 GitHub 上审查了厨师代码的更改。 * 开发人员可以向 Chef 存储库发出基础结构更改请求请求。 * 合并拉取请求时,Jenkins 上载更改后的 Chef 食谱并将其应用于生产中。 * 计划产生 DigitalOcean 小滴以与 Jenkins 一起进行 Chef 厨房测试。 * Jenkins 本身是使用 Chef 配置的,而不是使用 Web UI。 ## 监控方式 * 仙人掌图服务器端指标 * Nagios 检查可能出现的所有故障 * Nagios 健康检查,用于我们的某些应用程序和服务 * Statsd / Graphite,用于跟踪应用程序指标,例如成员登录,注册,数据库对象创建 * Grafana 用于漂亮的仪表板 * 可以使用 Chef 动态描述和创建 Grafana 仪表板 ## 聊天操作 * Hubot 坐在 Slack 中。 * 松弛房间通过 [hubot-pubsub](https://github.com/spajus/hubot-pubsub) 订阅了各种事件通知。 * #deploy 会议室显示有关部署的信息,并提供指向 GitHub diff,Jenkins 控制台输出等的链接。在这里,可以使用简单的聊天命令来触发,锁定和解锁部署。 * #deploy-fail 会议室仅显示部署失败。 * #failboat 会议室显示有关错误率和生产中个别错误的公告。 * 有多个#failboat- *房间,其中提供有关 cron 故障,卡住的 resque 作业,nagios 警告,newrelic 警报的信息。 * 每天两次将 Graylog 错误与 GitHub 进行处理和交叉检查,生成报告并将其提交给开发团队。 * 如果有人在 GitHub 上提到您,Hubot 会在 Slack 上的私人消息中为您提供该问题的链接。 * 在 GitHub 中创建问题或请求请求时,提到的团队会在其适当的 Slack 会议室中收到 ping 命令。 * 可以通过 Hubot 在 Slack 聊天中查询并显示石墨图。 * 您可以向 Hubo​​t 询问有关基础设施的问题,即有关部署特定服务的机器的问题。 Hubot 查询 Chef 服务器以获取数据。 * 开发人员将 Hubot 通知用于我们应用中发生的某些事件。 例如,向客户支持聊天室自动通知可能的欺诈案件。 * Hubot 与 Office [netatmo](https://www.netatmo.com/) 模块集成在一起,可以告诉所有人什么是 CO2,噪声,温度和湿度水平。 # 数据仓库堆栈 * 我们从两个来源提取数据: * 网站事件跟踪数据:印象数,点击数等 * 数据库(MySQL)更改。 * 大多数事件跟踪数据都从 JavaScript / Android / iOS 前端应用程序发布到 HTTP 端点。 一些事件由我们的核心 Ruby on Rails 应用程序发布到本地 UDP 套接字。 我们选择 UDP 以避免阻塞请求。 * 有一种服务可以监听 UDP 套接字上的新事件,对它们进行缓冲,并定期在 Kafka 中发出原始事件的主题。 * 流处理服务使用原始事件主题,验证事件,将它们编码为 Avro 格式,然后发出特定于事件的主题。 * 我们将事件的 Avro 模式保存在单独的集中式模式注册表服务中。 * 无效事件被置于单独的 Kafka 主题中,以进行可能的更正。 * 我们使用 LinkedIn 的 Camus 作业将事件从特定于事件的主题逐步转移到 HDFS。 事件到 Hadoop 的时间通常最多为一个小时。 * 使用 Hive 和 Impala 进行临时查询和数据分析。 * 研究基于伸缩的数据处理解决方案。 * 报告使用我们内部开发的,用 Ruby 编写的类似 OLAP 的报告系统运行。 # 得到教训 ## 产品开发 * 投资代码质量。 * 通过测试涵盖所有内容。 * 发布小更改。 * 使用功能开关将未完成的功能部署到生产中。 * 开发某些东西时,不要保留长时间运行的代码分支。 * 投资一个快速的发布周期。 * 首先构建移动产品。 * 设计 API 从一开始就很好,以后很难更改。 * 在 RabbitMQ 消息中包含发件人主机名和应用程序名称可以节省生命。 * 不要猜测或做假设,请进行 [AB](https://github.com/vinted/ab) 测试并检查数据。 * 如果您打算将 Redis 用于更大的事情,请从一开始就考虑分片。 * 如果您计划使 Rails 保持最新状态,则切勿使用叉状和稍作修饰的红宝石宝石。 * 通过社交网络尽可能轻松地共享您的内容。 * 搜索引擎优化是一项全职工作。 ## 基础设施和运营 * 经常部署以提高系统稳定性。 起初听起来可能违反直觉。 * 自动化一切。 * 监视所有可能发生的故障。 * 网络交换缓冲区很重要。 * 容量规划很困难。 * 从一开始就考虑 HA。 * RabbitMQ 集群不值得付出努力。 * 测量并绘制所有图形:HTTP 响应时间,Resque 队列大小,模型持久率,Redis 响应时间。 您无法改善无法衡量的东西。 ## 数据仓库堆栈 * Hadoop 生态系统中有许多工具。 很难选择合适的。 * 如果您正在为 Hive 编写用户定义函数(UDF),那么该考虑使用非 SQL 解决方案进行数据转换了。 * “ Hadoop 应用程序”概念含糊不清。 通常,我们需要手动将应用程序组件粘合在一起。 * 每个人都编写自己的工作流管理器。 并且有充分的理由。 * 分布式系统监视非常困难。 异常检测和作图很有帮助。 * 核心 Hadoop 基础架构(HDFS,YARN)坚如磐石,但较新的工具通常会有细微差别。 * 卡夫卡很棒。 这个网站是关于高可扩展性还是如何浪费服务器? 您是否真的需要 220 台服务器来服务〜2300req / sec? 他了解了其中一些服务器使用情况。 这是 Ruby on Rails,所以这就是原因。 您能否详细说明“ RabbitMQ 集群不值得付出”? 您在运行时遇到问题吗? @Peter-与其他高可用性站点一样,它们可以使用少于十个服务器来为流量提供服务。 从文章看来-其余内容涉及(a)收集和分析数据; (b)监督和监督系统; (c)确保高可用性。 在三个区域中只有 10 台边缘(缓存/ nginx)服务器(由于 HA,30 台独角兽是自然扩展)。 鉴于流量不统一(因此 200M req / day 不能转换为 2300 req / s),这似乎是适中的,因为在任何区域中,请求都只能由几个端点服务器之一来处理。 再次-这就是您在 HA 设置中所期望的-2 个以上的服务器用于任何潜在的传入(请求)请求。 我必须同意彼得的观点。 在最近阅读了此处的 Stack Exchange 文章之后,很难不认为此设置会浪费一些资源。 感谢分享。 您似乎正在使用大量的开源项目。 我对你的决定感到好奇。 团队成员一开始是否已经熟悉大多数技术? 如果没有,那么在这么多方面加强工作是否有点势不可挡? 大家好, Vaidotas,这里的 Vinted 工程师之一。 想对服务器数量发表评论。 如果您查看详细信息,将会看到很多服务器专用于分析数据收集。 而且我认为分析数据可能是单独的主题。 如果您查看运行 Vinted 应用程序所需的服务器及其所有内容,则会看到以下内容: 34 个用于图像处理和存储(9.3 亿张照片) 30 个用于 Unicorn 和微服务(每天 2 亿个请求) 28 个用于 MySQL 数据库,包括副本 19 个用于 Sphinx 搜索(2500 万个列出的项 索引) 10,用于可处理的后台作业 10,用于与 Nginx 进行负载平衡(充当代理和一些缓存,可能会更少,但在我们运营所在的不同国家/地区需要它们)。 Redis 4 因此,这就是 135 台运行应用程序基础结构的服务器。 现在请记住,所有内容都必须具有高可用性。 这意味着至少所有内容的 2 倍,即使您目前不需要/不使用它也是如此。 希望能解释一下服务器数量。 另外,您的行动小组的规模如何,才能维持这种运营/基础架构? 仅列出了 SRE。5\. DevOps 工程师,系统管理员和/或 DBA 怎么样? 您的 Jenkins 并行化设置似乎很有趣。 你是如何做到的? 也许不久之后还会有另一篇专门针对此的博客文章? 乔恩,我们有 5 位站点可靠性工程师来维护所有基础架构。 我们执行从服务器引导到数据库管理的所有工作。 我们严重依赖自动化:) 我真正无法理解的是-每天 200 M 的请求如何转换为实际的 Internet 流量? StackExchange 的请求量为 1.5 亿,在 Alexa 评分中排名第 53,vinted.com 在 38763 上排名较高,但 RPS 较高。 与 http://highscalability.com/blog/2014/11/10/nifty-architecture-tricks-from-wix-building-a-publishing-pla.html(wix)相同-他们要求 700M 请求/ 一天,但肯定无法将 Alexa 评级与 StackExchange 相比。 谁能澄清? @tao,一开始只有一个开发人员(CEO,联合创始人),而且技术堆栈要小得多。 您的问题的答案是否定的。 当项目开始发展时,出现了一些东西。 我们雇用了更多的开发人员,工程师等。我们选择雇用最聪明的工程师。 之所以使用某些技术是因为他们具有经验,而其他技术则是“试验和错误”(尤其是大数据的东西)。 我们在解决问题的过程中一直在解决它们。 我们仍然有需要解决的问题。 这就是新技术出现的方式。 我相信,一年后,我们可以写一篇关于我们如何做事的文章。 @lan:RabbitMQ 非常棒,我们正在使用它,但是在分析事件方面,我们遇到了一些限制,因此选择 kafka 作为事件发射。 RabbitMQ 集群的东西很容易破解。 正如文档所述-“ RabbitMQ 群集不能很好地容忍网络分区”,这并不像我们希望的那样罕见。 @Tim:我们使用 https://github.com/grosser/parallel_tests 的稍加修改版本 @安东:不确定“转换”的含义,但我们为女孩提供了超过 10 Gigs 的流量。 在谈论 Alexa 时,目前我们有 8 个不同的国家,例如,我们的一个国家(http://kleiderkreisel.de)的排名为 7,468,因此没有一个汇总排名。 另一件事是,70%的流量来自移动应用程序,我不确定 Alexa 是否会对此进行计数。 希望大家,Vinted 回答了您所有的问题:)