Tag Archives: 架构

分布式服务框架(RPC)

基础概念:

RPC Wiki

RPC 的概念模型与实现解析

分布式服务框架的4项特性

框架:

Thrift   protocol and framework.(facebook)推荐使用

gRPC  协议:Google Protocol Buffers (protobufs)

Finagle是Twitter基于Netty开发的支持容错的、协议无关的RPC框架

ZeroC ICE (Ice) distributed computing platform.

Apache Avro provides RPC where client and server exchange schemas in the connection handshake and code generation is not required.

DUBBO

一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

淘宝HSF

Zookeeper:

分布式服务框架 Zookeeper — 管理分布式环境中的数据

应用

Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)

Zookeeper+Spring跨机房容灾系统以及灰度发布

Apache Thrift – 可伸缩的跨语言服务开发框架

性能比较

RPC框架性能基本比较测试

ice-dubbo-thrift-grpc性能测试对比

分布式RPC框架性能大比拼

Book:

分布式服务框架:原理与实践

网站架构

1、amazon
Amazon的分布式key-value存储系统(dynamo)的论文

2、ebay(我对于eBay这几个PPT的一些看法和评价:http://www.blogjava.net/BlueDavy/archive/2009/07/24/288055.html
ebay架构演变历程(The eBay Architecture)
ebay架构原则(eBay architecture principles)
ebay的自动化(Teaching machines to fish)

3、facebook
facebook的缓存系统
facebook的架构
facebook百亿相片的高效存储

4、fotolog
扩展世界上最大的图片blog社区

5、google
GFS介绍
GFS论文
Mapreduce介绍
Mapreduce论文
Google在web前端方面的经验(even faster websites)
建设大型可扩展的IRS系统的挑战(challenges in building large-scale IRS)
松耦合分布式系统中的锁服务(lock service for loosly-coupled distributed system)
“滚木移石”不停机升级策略论文(modular software upgrades for distributed program)
Google wave的架构

6、linkedin
linkedin远程通讯架构

7、livejournal
livejournal架构演变历程

8、myspace
myspace架构

9、wikipedia
wikipedia架构

10、yahoo
yahoo定制的apache–yapache

11、youtube
scaling youtube

12、Twitter
Designing a Scalable Twitter

13、豆瓣
技术演变历程(QCon 2009北京)

14、freewheel
架构(QCon 2009北京)

15、优酷
架构(QCon 2009北京)

16、淘宝
技术演变历程(QCon 2009北京)

17、twitter
Improving the Performance and Scalability of Twitter

from:http://www.blogjava.net/BlueDavy/archive/2009/04/28/267970.html

知名网站架构整理

Here are some of the favorite posts on HighScalability…

from:http://highscalability.com/all-time-favorites/

Tumblr:150亿月浏览量背后的架构挑战

导读:和许多新兴的网站一样,著名的轻博客服务 Tumblr 在急速发展中面临了系统架构的瓶颈。每天 5 亿次浏览量,峰值每秒 4 万次请求,每天 3TB 新的数据存储,超过 1000 台服务器,这样的情况下如何保证老系统平稳运行,平稳过渡到新的系统,Tumblr 正面临巨大的挑战。近日,HighScalability 网站的 Todd Hoff 采访了该公司的分布式系统工程师 Blake Matheny,撰文系统介绍了网站的架构,内容很有价值。我们也非常希望国内的公司和团队多做类似分享,贡献于社区的同时,更能提升自身的江湖地位,对招聘、业务发展都好处多多。

Tumblr 每月页面浏览量超过 150 亿次,已经成为火爆的博客社区。用户也许喜欢它的简约、美丽,对用户体验的强烈关注,或是友好而忙碌的沟通方式,总之,它深得人们的喜爱。

每月超过 30% 的增长当然不可能没有挑战,其中可靠性问题尤为艰巨。每天 5 亿次浏览量,峰值每秒 4 万次请求,每天 3TB 新的数据存储,并运行于超过 1000 台服务器上,所有这些帮助 Tumblr 实现巨大的经营规模。

创业公司迈向成功,都要迈过危险的迅速发展期这道门槛。寻找人才,不断改造基础架构,维护旧的架构,同时要面对逐月大增的流量,而且曾经只有 4 位工程师。这意味着必须艰难地选择应该做什么,不该做什么。这就是 Tumblr 的状况。好在现在已经有 20 位工程师了,可以有精力解决问题,并开发一些有意思的解决方案。

Tumblr 最开始是非常典型的 LAMP 应用。目前正在向分布式服务模型演进,该模型基于 ScalaHBaseRedis(著名开源K-V存储方案)、Kafka(Apache 项目,出自 LinkedIn 的分布式发布-订阅消息系统)、Finagle(由 Twitter 开源的容错、协议中立的 RPC 系统),此外还有一个有趣的基于 Cell 的架构,用来支持 Dashboard(CSDN 注:Tumblr 富有特色的用户界面,类似于微博的时间轴)。

Tumblr 目前的最大问题是如何改造为一个大规模网站。系统架构正在从 LAMP 演进为最先进的技术组合,同时团队也要从小的创业型发展为全副武装、随时待命的正规开发团队,不断创造出新的功能和基础设施。下面就是 Blake Matheny 对 Tumblr 系统架构情况的介绍。

网站地址

http://www.tumblr.com/

主要数据

  • 每天 5 亿次 PV(页面访问量)
  • 每月超过 150 亿 PV
  • 约 20 名工程师
  • 峰值请求每秒近 4 万次
  • 每天超过 1TB 数据进入 Hadoop 集群
  • MySQL/HBase/Redis/memcache 每天生成若干 TB 数据
  • 每月增长 30%
  • 近 1000 硬件节点用于生产环境
  • 平均每位工程师每月负责数以亿计的页面访问
  • 每天上传大约 50GB 的文章,每天跟帖更新数据大约2.7TB(CSDN 注:这两个数据的比例看上去不太合理,据 Tumblr 数据科学家 Adam Laiacano 在 Twitter 上解释,前一个数据应该指的是文章的文本内容和元数据,不包括存储在 S3 上的多媒体内容)

软件环境

  • 开发使用 OS X,生产环境使用 Linux(CentOS/Scientific)
  • Apache
  • PHP, Scala, Ruby
  • Redis, HBase, MySQL
  • Varnish, HAProxy, nginx
  • memcache, Gearman(支持多语言的任务分发应用框架), Kafka, Kestrel(Twitter 开源的分布式消息队列系统), Finagle
  • Thrift, HTTP
  • Func——一个安全、支持脚本的远程控制框架和 API
  • Git, Capistrano(多服务器脚本部署工具), Puppet, Jenkins

硬件环境

  • 500 台 Web 服务器
  • 200 台数据库服务器(47 pool,20 shard)
  • 30 台 memcache 服务器
  • 22 台 Redis 服务器
  • 15 台 Varnish 服务器
  • 25 台 HAproxy 节点
  • 8 台 nginx 服务器
  • 14 台工作队列服务器(Kestrel + Gearman)

架构

1. 相对其他社交网站而言,Tumblr 有其独特的使用模式:

  • 每天有超过 5 千万篇文章更新,平均每篇文章的跟帖又数以百计。用户一般只有数百个粉丝。这与其他社会化网站里少数用户有几百万粉丝非常不同,使得 Tumblr 的扩展性极具挑战性。
  • 按用户使用时间衡量,Tumblr 已经是排名第二的社会化网站。内容的吸引力很强,有很多图片和视频,文章往往不短,一般也不会太长,但允许写得很长。文章内容往往比较深入,用户会花费更长的时间来阅读。
  • 用户与其他用户建立联系后,可能会在 Dashboard 上往回翻几百页逐篇阅读,这与其他网站基本上只是部分信息流不同。
  • 用户的数量庞大,用户的平均到达范围更广,用户较频繁的发帖,这些都意味着有巨量的更新需要处理。

2. Tumblr 目前运行在一个托管数据中心中,已在考虑地域上的分布性。

3. Tumblr 作为一个平台,由两个组件构成:公共 Tumblelogs 和 Dashboard

  • 公共 Tumblelogs 与博客类似(此句请 Tumblr 用户校正),并非动态,易于缓存
  • Dashboard 是类似于 Twitter 的时间轴,用户由此可以看到自己关注的所有用户的实时更新。与博客的扩展性不同,缓存作用不大,因为每次请求都不同,尤其是活跃的关注者。而且需要实时而 且一致,文章每天仅更新 50GB,跟帖每天更新2.7TB,所有的多媒体数据都存储在 S3 上面。
  • 大多数用户以 Tumblr 作为内容浏览工具,每天浏览超过 5 亿个页面,70% 的浏览来自 Dashboard。
  • Dashboard 的可用性已经不错,但 Tumblelog 一直不够好,因为基础设施是老的,而且很难迁移。由于人手不足,一时半会儿还顾不上。

老的架构

Tumblr 最开始是托管在 Rackspace 上的,每个自定义域名的博客都有一个A记录。当 2007 年 Rackspace 无法满足其发展速度不得不迁移时,大量的用户都需要同时迁移。所以他们不得不将自定义域名保留在 Rackspace,然后再使用 HAProxy 和 Varnish 路由到新的数据中心。类似这样的遗留问题很多。

开始的架构演进是典型的 LAMP 路线:

  • 最初用 PHP 开发,几乎所有程序员都用 PHP
  • 最初是三台服务器:一台 Web,一台数据库,一台 PHP
  • 为了扩展,开始使用 memcache,然后引入前端 cache,然后在 cache 前再加 HAProxy,然后是 MySQL sharding(非常奏效)
  • 采用“在单台服务器上榨出一切”的方式。过去一年已经用C开发了两个后端服务:ID 生成程序Staircar(用 Redis 支持 Dashboard 通知)

Dashboard 采用了“扩散-收集”方式。当用户访问 Dashboard 时将显示事件,来自所关注的用户的事件是通过拉然后显示的。这样支撑了 6 个月。由于数据是按时间排序的,因此 sharding 模式不太管用。

新的架构

由于招人和开发速度等原因,改为以 JVM 为中心。目标是将一切从 PHP 应用改为服务,使应用变成请求鉴别、呈现等诸多服务之上的薄层。

这其中,非常重要的是选用了 Scala 和 Finagle

  • 在团队内部有很多人具备 Ruby 和 PHP 经验,所以 Scala 很有吸引力。
  • Finagle 是选择 Scala 的重要因素之一。这个来自 Twitter 的库可以解决大多数分布式问题,比如分布式跟踪、服务发现、服务注册等。
  • 转到 JVM 上之后,Finagle 提供了团队所需的所有基本功能(Thrift, ZooKeeper 等),无需再开发许多网络代码,另外,团队成员认识该项目的一些开发者。
  • Foursquare 和 Twitter 都在用 Finagle,Meetup 也在用 Scala。
  • 应用接口与 Thrift 类似,性能极佳。
  • 团队本来很喜欢 Netty(Java 异步网络应用框架,2月 4 日刚刚发布3.3.1最终版),但不想用 Java,Scala 是不错的选择。
  • 选择 Finagle 是因为它很酷,还认识几个开发者。

之所以没有选择 Node.js,是因为以 JVM 为基础更容易扩展。Node 的发展为时尚短,缺乏标准、最佳实践以及大量久经测试的代码。而用 Scala 的话,可以使用所有 Java 代码。虽然其中并没有多少可扩展的东西,也无法解决 5 毫秒响应时间、49秒 HA、4万每秒请求甚至有时每秒 40 万次请求的问题。但是,Java 的生态链要大得多,有很多资源可以利用。

内部服务从C/libevent 为基础正在转向 Scala/Finagle 为基础。

开始采用新的NoSQL 存储方案如 HBase 和 Redis。但大量数据仍然存储在大量分区的 MySQL 架构中,并没有用 HBase 代替 MySQL。HBase 主要支持短地址生产程序(数以十亿计)还有历史数据和分析,非常结实。此外,HBase 也用于高写入需求场景,比如 Dashboard 刷新时一秒上百万的写入。之所以还没有替换 HBase,是因为不能冒业务上风险,目前还是依靠人来负责更保险,先在一些小的、不那么关键的项目中应用,以获得经验。MySQL 和时间序列数据 sharding(分片)的问题在于,总有一个分片太热。另外,由于要在 slave 上插入并发,也会遇到读复制延迟问题。

此外,还开发了一个公用服务框架

  • 花了很多时间解决分布式系统管理这个运维问题。
  • 为服务开发了一种 Rails scaffolding,内部用模板来启动服务。
  • 所有服务从运维的角度来看都是一样的,所有服务检查统计数据、监控、启动和停止的方式都一样。
  • 工具方面,构建过程围绕 SBT(一个 Scala 构建工具),使用插件和辅助程序管理常见操作,包括在 Git 里打标签,发布到代码库等等。大多数程序员都不用再操心构建系统的细节了。

200台数据库服务器中,很多是为了提高可用性而设,使用的是常规硬件,但 MTBF(平均故障间隔时间)极低。故障时,备用充足。

为了支持 PHP 应用有 6 个后端服务,并有一个小组专门开发后端服务。新服务的发布需要两到三周,包 括 Dashboard 通知、Dashboard 二级索引、短地址生成、处理透明分片的 memcache 代理。其中在 MySQL 分片上耗时很多。虽然在纽约本地非常热,但并没有使用 MongoDB,他们认为 MySQL 的可扩展性足够了。

Gearman用于会长期运行无需人工干预的工作。

可用性是以达到范围(reach)衡量的。用户能够访问自定义域或者 Dashboard 吗?也会用错误率。

历史上总是解决那些最高优先级的问题,而现在会对故障模式系统地分析和解决,目的是从用户和应用的角度来定成功指标。(后一句原文似乎不全)

最开始 Finagle 是用于 Actor 模型的,但是后来放弃了。对于运行后无需人工干预的工作,使用任务队列。而且 Twitter 的 util 工具库中有 Future 实现,服务都是用 Future(Scala 中的无参数函数,在与函数关联的并行操作没有完成时,会阻塞调用方)实现的。当需要线程池的时候,就将 Future 传入 Future 池。一切都提交到 Future 池进行异步执行。

Scala 提倡无共享状态。由于已经在 Twitter 生产环境中经过测试,Finagle 这方面应该是没有问题的。使用 Scala 和 Finagle 中的结构需要避免可变状态,不使用长期运行的状态机。状态从数据库中拉出、使用再写回数据库。这样做的好处是,开发人员不需要操心线程和锁。

22台Redis服务器,每台的都有8-32个实例,因此线上同时使用了 100 多个 Redis 实例。

  • Redis 主要用于 Dashboard 通知的后端存储。
  • 所谓通知就是指某个用户 like 了某篇文章这样的事件。通知会在用户的 Dashboard 中显示,告诉他其他用户对其内容做了哪些操作。
  • 高写入率使 MySQL 无法应对。
  • 通知转瞬即逝,所以即使遗漏也不会有严重问题,因此 Redis 是这一场景的合适选择。
  • 这也给了开发团队了解 Redis 的机会。
  • 使用中完全没有发现 Redis 有任何问题,社区也非常棒。
  • 开发了一个基于 Scala Futures 的 Redis 接口,该功能现在已经并入了 Cell 架构。
  • 短地址生成程序使用 Redis 作为一级 Cache,HBase 作为永久存储。
  • Dashboard 的二级索引是以 Redis 为基础开发的。
  • Redis 还用作 Gearman 的持久存储层,使用 Finagle 开发的 memcache 代理。
  • 正在缓慢地从 memcache 转向 Redis。希望最终只用一个 cache 服务。性能上 Redis 与 memcache 相当。

内部的 firehose(通信管道)

  • 内部的应用需要活跃的信息流通道。这些信息包括用户创建/删除的信息,liking/unliking 的提示,等等。挑战在于这些数据要实时的分布式处理。我们希望能够检测内部运行状况,应用的生态系统能够可靠的生长,同时还需要建设分布式系统的控制中心。
  • 以前,这些信息是基于 Scribe (Facebook 开源的分布式日志系统。)/Hadoop 的分布式系统。服务会先记录在 Scribe 中,并持续的长尾形式写入,然后将数据输送给应用。这种模式可以立即停止伸缩,尤其在峰值时每秒要创建数以千计的信息。不要指望人们会细水长流式的发布文 件和 grep。
  • 内部的 firehose 就像装载着信息的大巴,各种服务和应用通过 Thrift 与消防管线沟通。(一个可伸缩的跨语言的服务开发框架。)
  • LinkedIn 的 Kafka 用于存储信息。内部人员通过 HTTP 链接 firehose。经常面对巨大的数据冲击,采用 MySQL 显然不是一个好主意,分区实施越来越普遍。
  • firehose 的模型是非常灵活的,而不像 Twitter 的 firehose 那样数据被假定是丢失的。
  • firehose 的信息流可以及时的回放。他保留一周内的数据,可以调出这期间任何时间点的数据。
  • 支持多个客户端连接,而且不会看到重复的数据。每个客户端有一个 ID。Kafka 支持客户群,每个群中的客户都用同一个 ID,他们不会读取重复的数据。可以创建多个客户端使用同一个 ID,而且不会看到重复的数据。这将保证数据的独立性和并行处理。Kafka 使用 ZooKeeper (Apache 推出的开源分布式应用程序协调服务。)定期检查用户阅读了多少。

为 Dashboard 收件箱设计的 Cell 架构

  • 现在支持 Dashboard 的功能的分散-集中架构非常受限,这种状况不会持续很久。
  • 解决方法是采用基于 Cell 架构的收件箱模型,与 Facebook Messages 非常相似。
  • 收件箱与分散-集中架构是对立的。每一位用户的 dashboard 都是由其追随者的发言和行动组成的,并按照时间顺序存储。
  • 就因为是收件箱就解决了分散-集中的问题。你可以会问到底在收件箱中放了些什么,让其如此廉价。这种方式将运行很长时间。
  • 重写 Dashboard 非常困难。数据已经分布,但是用户局部升级产生的数据交换的质量还没有完全搞定。
  • 数据量是非常惊人的。平均每条消息转发给上百个不同的用户,这比 Facebook 面对的困难还要大。大数据+高分布率+多个数据中心。
  • 每秒钟上百万次写入,5万次读取。没有重复和压缩的数据增长为2.7TB,每秒百万次写入操作来自 24 字节行键。
  • 已经流行的应用按此方法运行。
  • cell
  • 每个 cell 是独立的,并保存着一定数量用户的全部数据。在用户的 Dashboard 中显示的所有数据也在这个 cell 中。
  • 用户映射到 cell。一个数据中心有很多 cell。
  • 每个 cell 都有一个 HBase 的集群,服务集群,Redis 的缓存集群。
  • 用户归属到 cell,所有 cell 的共同为用户发言提供支持。
  • 每个 cell 都基于 Finagle(Twitter 推出的异步的远程过程调用库),建设在 HBase 上,Thrift 用于开发与 firehose 和各种请求与数据库的链接。(请纠错)
  • 一个用户进入 Dashboard,其追随者归属到特定的 cell,这个服务节点通过 HBase 读取他们的 dashboard 并返回数据。
  • 后台将追随者的 dashboard 归入当前用户的 table,并处理请求。
  • Redis 的缓存层用于 cell 内部处理用户发言。
  • 请求流:用户发布消息,消息将被写入 firehose,所有的 cell 处理这条消息并把发言文本写入数据库,cell 查找是否所有发布消息追随者都在本 cell 内,如果是的话,所有追随者的收件箱将更新用户的 ID。(请纠错
  • cell 设计的优点:
  • 大规模的请求被并行处理,组件相互隔离不会产生干扰。 cell 是一个并行的单位,因此可以任意调整规格以适应用户群的增长。
  • cell 的故障是独立的。一个 Cell 的故障不会影响其他 cell。
  • cell 的表现非常好,能够进行各种升级测试,实施滚动升级,并测试不同版本的软件。
  • 关键的思想是容易遗漏的:所有的发言都是可以复制到所有的 cell。
  • 每个 cell 中存储的所有发言的单一副本。 每个 cell 可以完全满足 Dashboard 呈现请求。应用不用请求所有发言者的 ID,只需要请求那些用户的 ID。(“那些用户”所指不清,请指正。)他可以在 dashboard 返回内容。每一个 cell 都可以满足 Dashboard 的所有需求,而不需要与其他 cell 进行通信。
  • 用到两个 HBase table :一个 table 用于存储每个发言的副本,这个 table 相对较小。在 cell 内,这些数据将与存储每一个发言者 ID。第二个 table 告诉我们用户的 dashboard 不需要显示所有的追随者。当用户通过不同的终端访问一个发言,并不代表阅读了两次。收件箱模型可以保证你阅读到。
  • 发言并不会直接进入到收件箱,因为那实在太大了。所以,发言者的 ID 将被发送到收件箱,同时发言内容将进入 cell。这个模式有效的减少了存储需求,只需要返回用户在收件箱中浏览发言的时间。而缺点是每一个 cell 保存所有的发言副本。令人惊奇的是,所有发言比收件箱中的镜像要小。(请纠错)每天每个 cell 的发言增长 50GB,收件箱每天增长2.7TB。用户消耗的资源远远超过他们制造的。
  • 用户的 dashboard 不包含发言的内容,只显示发言者的 ID,主要的增长来自 ID。(请 Tumblr 用户纠错)
  • 当追随者改变时,这种设计方案也是安全的。因为所有的发言都保存在 cell 中了。如果只有追随者的发言保存在 cell 中,那么当追随者改变了,将需要一些回填工作。
  • 另外一种设计方案是采用独立的发言存储集群。这种设计的缺点是,如果群集出现故障,它会影响整个网站。因此,使用 cell 的设计以及后复制到所有 cell 的方式,创建了一个非常强大的架构。
  • 一个用户拥有上百万的追随者,这带来非常大的困难,有选择的处理用户的追随者以及他们的存取模式(见 Feeding Frenzy
  • 不同的用户采用不同并且恰当的存取模式和分布模型,两个不同的分布模式包括:一个适合受欢迎的用户,一个使用大众。
  • 依据用户的类型采用不同的数据处理方式,活跃用户的发言并不会被真正发布,发言将被有选择的体现。(果真如此?请 Tumblr 用户纠错)
  • 追随了上百万用户的用户,将像拥有上百万追随者的用户那样对待。
  • cell 的大小非常难于决定。cell 的大小直接影响网站的成败。每个 cell 归于的用户数量是影响力之一。需要权衡接受怎样的用户体验,以及为之付出多少投资。
  • 从 firehose 中读取数据将是对网络最大的考验。在 cell 内部网络流量是可管理的。
  • 当更多 cell 被增添到网络中来,他们可以进入到 cell 组中,并从 firehose 中读取数据。一个分层的数据复制计划。这可以帮助迁移到多个数据中心。

在纽约启动运作

  • 纽约具有独特的环境,资金和广告充足。招聘极具挑战性,因为缺乏创业经验。
  • 在过去的几年里,纽约一直致力于推动创业。纽约大学和哥伦比亚大学有一些项目,鼓励学生到初创企业实习,而不仅仅去华尔街。市长建立了一所学院,侧重于技术。

团队架构

  • 团队:基础架构,平台,SRE,产品,web ops,服务;
  • 基础架构:5层以下,IP 地址和 DNS,硬件配置;
  • 平台:核心应用开发,SQL 分片,服务,Web 运营;
  • SRE:在平台和产品之间,侧重于解决可靠性和扩展性的燃眉之急;
  • 服务团队:相对而言更具战略性,
  • Web ops:负责问题检测、响应和优化。

软件部署

  • 开发了一套 rsync 脚本,可以随处部署 PHP 应用程序。一旦机器的数量超过 200 台,系统便开始出现问题,部署花费了很长时间才完成,机器处于部署进程中的各种状态。
  • 接下来,使用 Capistrano(一个开源工具,可以在多台服务器上运行脚本)在服务堆栈中构建部署进程(开发、分期、生产)。在几十台机器上部署可以正常工作,但当通过 SSH 部署到数百台服务器时,再次失败。
  • 现在,所有的机器上运行一个协调软件。基于 Redhat Func(一个安全的、脚本化的远程控制框架和接口)功能,一个轻量级的 API 用于向主机发送命令,以构建扩展性。
  • 建立部署是在 Func 的基础上向主机发送命令,避免了使用 SSH。比如,想在组A上部署软件,控制主机就可以找出隶属于组A的节点,并运行部署命令。
  • 部署命令通过 Capistrano 实施。Func API 可用于返回状态报告,报告哪些机器上有这些软件版本。
  • 安全重启任何服务,因为它们会关闭连接,然后重启。
  • 在激活前的黑暗模式下运行所有功能。

展望

  • 从哲学上将,任何人都可以使用自己想要的任意工具。但随着团队的发展壮大,这些工具出现了问题。新员工想要更好地融入团队,快速地解决问题,必须以他们为中心,建立操作的标准化。
  • 过程类似于 Scrum(一种敏捷管理框架),非常敏捷。
  • 每个开发人员都有一台预配置的开发机器,并按照控制更新。
  • 开发机会出现变化,测试,分期,乃至用于生产。
  • 开发者使用 VIM 和 TextMate。
  • 测试是对 PHP 程序进行代码审核。
  • 在服务方面,他们已经实现了一个与提交相挂钩的测试基础架构,接下来将继承并内建通知机制。

招聘流程

  • 面试通常避免数学、猜谜、脑筋急转弯等问题,而着重关注应聘者在工作中实际要做什么。
  • 着重编程技能。
  • 面试不是比较,只是要找对的人。
  • 挑战在于找到具有可用性、扩展性经验的人才,以应对 Tumblr 面临的网络拥塞。
  • 在 Tumblr 工程博客(Tumblr Engineering Blog),他们对已过世的 Dennis Ritchie 和 John McCarthy 予以纪念。

经验及教训

  • 自动化无处不在
  • MySQL(增加分片)规模,应用程序暂时还不行
  • Redis 总能带给人惊喜
  • 基于 Scala 语言的应用执行效率是出色的
  • 废弃项目——当你不确定将如何工作时
  • 不顾用在他们发展经历中没经历过技术挑战的人,聘用有技术实力的人是因为他们能适合你的团队以及工作。
  • 选择正确的软件集合将会帮助你找到你需要的人
  • 建立团队的技能
  • 阅读文档和博客文章。
  • 多与同行交流,可以接触一些领域中经验丰富的人,例如与在 Facebook、Twitter、LinkedIn 的工程师多交流,从他们身上可以学到很多
  • 对技术要循序渐进,在正式投入使用之前他们煞费苦心的学习 HBase 和 Redis。同时在试点项目中使用或将其控制在有限损害范围之内。

from:

Tumblr:150亿月浏览量背后的架构挑战(上)

Tumblr:150亿月浏览量背后的架构挑战(下)

英文原文:High Scalability

百万级访问网站前期的技术准备

开了自己域名的博客,第一篇就得来个重磅一点的才对得起这4美金的域名。作为一个技术从业者十年,逛了十年发现有些知识东一榔头西一棒槌的得满世界看个遍才整理出个头绪,那咱就系统点的从头一步一步的说,一个从日几千访问的小小网站,到日访问一两百万的小网站,怎么才能让它平滑的度过这个阶段,别在技术上出现先天不足,写给一些技术人员,也写给不懂技术的创业者。

转载请注明出自 http://zhiyi.us ,假如您还想从这转到好文章的话。

对互联网有了解的人都有自己的想法,有人就把想法付诸实现,做个网站然后开始运营。其实从纯网站技术上来说,因为开源模式的发展,现在建一个小网站已经很简单也很便宜。当访问量到达一定数量级的时候成本就开始飙升了,问题也开始显现了。因为带宽的增加、硬件的扩展、人员的扩张所带来的成本提高是显而易见的,而还有相当大的一部分成本是因为代码重构、架构重构,甚至底层开发语言更换引起的,最惨的就是数据丢失,辛辛苦苦好几年,一夜回到创业前。

减少成本就是增加利润。很多事情,我们在一开始就可以避免,先打好基础,往后可以省很多精力,少操很多心。

假设你是一个参与创业的技术人员,当前一穷二白,什么都要自己做,自己出钱,初期几十万的资金,做一个应用不是特别复杂的网站,那么就要注意以下几点:

一、开发语言

一般来说,技术人员(程序员)创业都是根据自己技术背景选择自己最熟悉的语言,不过考虑到不可能永远是您一个人写程序,这点还得仔细想想。无论用什么语言,最终代码质量是看管理,所以我们还是从纯语言层面来说实际一点。现在流行的javaphp.netpythonruby都有自己的优劣,python和ruby,现在人员还是相对难招一些,性能优化也会费些力气,.net平台买不起windows server。java、php用的还是最多。对于初期,应用几乎都是靠前端支撑的网站来说,php的优势稍大一些,入门简单、设计模式简单、写起来快、性能足够等,不过不注重设计模式也是它的劣势,容易变得松散,隐藏bug稍多、难以维护。java的优势在于整套管理流程已经有很多成熟工具来辅助,强类型也能避免一些弱智BUG,大多数JAVA程序员比较注重设计模式,别管实不实际,代码格式看起来还是不错的。这也是个劣势,初学者可能太注重模式而很难解决实际需求。

前端不只是html、css这类。整个负责跟用户交互的部分都是前端,包括处理程序。这类程序还是建议用php,主要原因就是开发迅速、从业人员广泛。至于后端例如行为分析、银行接口、异步消息处理等,随便用什么程序,那个只能是根据不同业务需求来选择不同语言了。

二、代码版本管理

如果开发人员之间的网络速度差不多,就SVN;比较分散例如跨国,就hg。大多数人还是svn的.

假设选了svn,那么有几点考虑。一是采用什么树结构。初期可能只有一条主干,往后就需要建立分支,例如一条开发分支,一条上线分支,再往后,可能要每个小组一个分支。建议一开始人少时选择两条分支,开发和线上,每个功能本地测试无误后提交到开发分支,最后统一测试,可以上线时合并到上线分支。如果喜欢把svn当做移动硬盘用,写一点就commit一次也无所谓,就是合并的时候头大一些,这些人可以自己建个分支甚至建立个本地代码仓库,随便往自己的分支提交,测试完毕后再提交到开发分支上。

部署,可以手工部署也可以自动部署。手工部署相对简单,一般是直接在服务器上svn update,或者找个新目录svn checkout,再把web root给ln -s过去。应用越复杂,部署越复杂,没有什么统一标准,只要别再用ftp上传那种形式就好,一是上传时文件引用不一致错误率增加,二是很容易出现开发人员的版本跟线上版本不一致,导致本来想改个错字结果变成回滚的杯具。如果有多台服务器还是建议自动部署,更换代码的机器从当前服务池中临时撤出,更新完毕后再重新加入。

不管项目多小,养成使用版本管理的好习惯,最起码还可以当做你的备份,我的 http://zhiyi.us 虽然就是一个wordpress,可还是svn了,只改动一两句css那也是劳动成果。

三、服务器硬件

别羡慕大客户和有钱人,看看机房散户区,一台服务器孤独的支撑的网站数不清。如果资金稍微充足,建议至少三台的标准配置,分别用作web处理、数据库、备份。web服务器至少要8G内存,双sata raid1,如果经济稍微宽松,或静态文件或图片多,则15k sas raid1+0。数据库至少16G内存,15k sas raid 1+0。备份服务器最好跟数据库服务器同等配置。硬件可以自己买品牌的底板,也就是机箱配主板和硬盘盒,CPU内存硬盘都自己配,也可以上整套品牌,也可以兼容机。三台机器,市场行情6、7万也就配齐了。

web服务器可以既跑程序又当内存缓存,数据库服务器则只跑主数据库(假如是MySQL的话),备份服务器干的活就相对多一些,web配置、缓存配置、数据库配置都要跟前两台一致,这样WEB和数据库任意一台出问题,把备份服务器换个ip就切换上去了。备份策略,可以drbd,可以rsync,或者其他的很多很多的开源备份方案可选择。rsync最简单,放cron里自己跑就行。备份和切换,建议多做测试,选最安全最适合业务的,并且尽可能异地备份。

四、机房

三种机房尽量不要选:联通访问特别慢的电信机房、电信访问特别慢的联通机房、电信联通访问特别慢的移动或铁通机房。那网通机房呢?亲,网通联通N久以前合并改叫联通了。多多寻找,实地参观,多多测试,多方打探,北京、上海、广州等各个主节点城市,还是有很多优质机房的,找个网络质量好,管理严格的机房,特别是管理要严格,千万别网站无法访问了,打个电话过去才知道别人维护时把你网线碰掉了,这比DOS都头疼。自己扯了几根光纤就称为机房的,看您抗风险程度和心理素质了。机房可以说是非常重要,直接关系到网站访问速度,网站访问速度直接关系到用户体验,我可以翻墙看风景,但买个网游vpn才能打开你这个还不怎么知名的网站就有难度了。或许您网站的ajax很出色,可是document怎么也不ready,一些代码永远绝缘于用户。

五、架构

初期架构一般比较简单,web负载均衡+数据库主从+缓存+分布式存储+队列。大方向上也确实就这几样东西,细节上也无数文章都重复过了,按照将来会有N多WEB,N多主从关系,N多缓存,N多xxx设计就行,基本方案都是现成的,只是您比其他人厉害之处就在于设计上考虑到缓存失效时的雪崩效应、主从同步的数据一致性和时间差、队列的稳定性和失败后的重试策略、文件存储的效率和备份方式等等意外情况。缓存总有一天会失效,数据库复制总有一天会断掉,队列总有一天会写不进去,电源总有一天会烧坏。根据墨菲定律,如果不考虑这些,网站早晚会成为茶几。

六、服务器软件

Linux、nginx、php、mysql,几乎是标配,我们除了看名字,还得选版本。Linux发行版众多,只要没特殊要求,就选个用的人最多的,社区最活跃的,配置最方便的,软件包最全最新的,例如debianubuntu。至于RHEL之类的嘛,你用只能在RHEL上才能运行的软件么?剩下的nginx、php、mysql、activemq、其他的等等,除非你改过这些软件或你的程序真的不兼容新版本,否则尽量版本越新越好,版本新,意味着新特性增多、BUG减少、性能增加。总有些道听途说的人跟你说老的版本稳定。所谓稳定,是相对于特殊业务来说的,而就一个php写的网站,大多数人都没改过任何服务器软件源代码,绝大多数情况是能平稳的升级到新版本的。类似于jdk5到jdk6,python2到python3这类变动比较大的升级还是比较少见的。看看ChangeLog,看看升级说明,结合自己情况评估一下,越早升级越好,别人家都用php6写程序了这边还php4的逛游呢。优秀的开源程序升级还是很负责任的,看好文档,别怕。

以上这六点准备完毕,现在我们有了运行环境,有了基本架构骨架,有了备份和切换方案,应该开始着手设计开发方面的事情了。开发方面的事情无数,下一篇会先说一些重点。

七、数据库

几乎所有操作最后都要落到数据库身上,它又最难扩展(存储也挺难)。对于mysql,什么样的表用myisam,什么样的表用innodb,在开发之前要确定。复制策略、分片策略,也要确定。表引擎方面,一般,更新不多、不需要事务的表可以用myisam,需要行锁定、事务支持的,用innodb。myisam的锁表不一定是性能低下的根源,innodb也不一定全是行锁,具体细节要多看相关的文档,熟悉了引擎特性才能用的更好。现代WEB应用越来越复杂了,我们设计表结构时常常设计很多冗余,虽然不符合传统范式,但为了速度考虑还是值得的,要求高的情况下甚至要杜绝联合查询。编程时得多注意数据一致性。 复制策略方面,多主多从结构也最好一开始就设计好,代码直接按照多主多从来编写,用一些小技巧来避免复制延时问题,并且还要解决多数据库数据是否一致,可以自己写或者找现成的运维工具。

分片策略。总会有那么几个表数据量超大,这时分片必不可免。分片有很多策略,从简单的分区到根据热度自动调整,依照具体业务选择一个适合自己的。避免自增ID作为主键,不利于分片。

用存储过程是比较难扩展的,这种情形多发生于传统C/S,特别是OA系统转换过来的开发人员。低成本网站不是一两台小型机跑一个数据库处理所有业务的模式,是机海作战。方便水平扩展比那点预分析时间和网络传输流量要重要的多的多。

NoSQL。这只是一个概念。实际应用中,网站有着越来越多的密集写操作、上亿的简单关系数据读取、热备等,这都不是传统关系数据库所擅长的,于是就产生了很多非关系型数据库,比如Redis/TC&TT/MongoDB/Memcachedb等,在测试中,这些几乎都达到了每秒至少一万次的写操作,内存型的甚至5万以上。例如MongoDB,几句配置就可以组建一个复制+自动分片+failover的环境,文档化的存储也简化了传统设计库结构再开发的模式。很多业务是可以用这类数据库来替代mysql的。

八、缓存。

数据库很脆弱,一定要有缓存在前面挡着,其实我们优化速度,几乎就是优化缓存,能用缓存的地方,就不要再跑到后端数据库那折腾。缓存有持久化缓存、内存缓存,生成静态页面是最容易理解的持久化缓存了,还有很多比如varnish的分块缓存、前面提到的memcachedb等,内存缓存,memcached首当其冲。缓存更新可用被动更新和主动更新。被动更新的好处是设计简单,缓存空了就自动去数据库取数据再把缓存填上,但容易引发雪崩效应,一旦缓存大面积失效,数据库的压力直线上升很可能挂掉。主动缓存可避免这点但是可能引发程序取不到数据的问题。这两者之间如何配合,程序设计要多动脑筋。

九、队列。

用户一个操作很可能引发一系列资源和功能的调动,这些调动如果同时发生,压力无法控制,用户体验也不好,可以把这样一些操作放入队列,由另几个模块去异步执行,例如发送邮件,发送手机短信。开源队列服务器很多,性能要求不高用数据库当做队列也可以,只要保证程序读写队列的接口不变,底层队列服务可随时更换就可以,类似Zend Framework里的Zend_Queue类,java.util.Queue接口等。

十、文件存储。

除了结构化数据,我们经常要存放其他的数据,像图片之类的。这类数据数量繁多、访问量大。典型的就是图片,从用户头像到用户上传的照片,还要生成不同的缩略图尺寸。存储的分布几乎跟数据库扩展一样艰难。不使用专业存储的情况下,基本都是靠自己的NAS。这就涉及到结构。拿图片存储举例,图片是非常容易产生热点的,有些图片上传后就不再有人看,有些可能每天被访问数十万次,而且大量小文件的异步备份也很耗费时间。

为了将来图片走cdn做准备,一开始最好就将图片的域名分开,且不用主域名。很多网站都将cookie设置到了.domain.ltd,如果图片也在这个域名下,很可能因为cookie而造成缓存失效,并且占多余流量,还可能因为浏览器并发线程限制造成访问缓慢。

如果用普通的文件系统存储图片,有一个简单的方法。计算文件的hash值,比如md5,以结果第一位作为第一级目录,这样第一级有16个目录。从0到F,可以把这个字母作为域名,0.yourimg.com到f.yourimg.com(客户端dns压力会增大),还可以扩展到最多16个NAS集群上。第二级可用年月例如,201011,第三级用日,第四级可选,根据上传量,比如am/pm,甚至小时。最终的目录结构可能会是 e/201008/25/am/e43ae391c839d82801920cf.jpg。rsync备份时可以用脚本只同步某年某日某时的文件,避免计算大量文件带来的开销。当然最好是能用专门的分布式文件系统或更专业点的存储解决方案。

下面,我们要谈谈代码了。

这一系列的最后一篇写给普通编程人员,如果不感兴趣可直接看本文最后几段。

开始设计代码结构之前,先回顾一下之前准备过的事情:我们有负载均衡的WEB服务器,有主从DB服务器并可能分片,有缓存,有可扩展的存储。在组织代码的各个方面,跟这些准备息息相关,我一二三的列出来分别说,并且每一条都以“前面讲到”这个经典句式开头,为了方便对照。 别着急看经典句式,我思维跳跃了,插一段。实际开发中,我们总会在性能和代码优雅性上作折中。对于当今的计算机和语言解释器,多几层少几层对象调用、声明变量为Map还是HashMap这种问题是最后才需要考虑的问题,永远要考虑系统最慢的部分,从最慢的部分解决。例如看看你用的ORM是不是做了很多你用不到的事情,是不是有重复的数据调用。我们做的是web应用开发,不是底层框架API,代码易读易懂是保证质量很重要的一方面,你的程序是为了什么而设计,有不同的方法……算了,这个话题另起一篇文章来说,扯远了,想交流可关注我的微博 http://t.sina.com.cn/liuzhiyi,咱继续……

前面讲到,WEB服务器是要做负载均衡的,图片服务器是要分开的。对于这点,代码在处理客户端状态时,不要把状态放到单机上,举例,不要用文件session,嗯,常识。如果有可能,最好在一开始就做好用户单点认证的统一接口,包括跨域如何判断状态、静态页面如何判断状态,需要登录时的跳转和返回参数定义,底层给好接口,应用层直接就用(可参考GAE的user服务)。登录方面的设计要考虑移动设备的特性,比如电脑可以用浮动层窗口,但NOKIA自带的浏览器或UCWEB就无法处理这种表现形式,程序一定既能处理AJAX请求又能直接通过URL来处理请求。图片服务器分开,资源文件最好也布局到图片服务器,也就是WEB服务器只服务动态程序。虽然开发测试时稍微复杂(因为需要绝对URI才能访问),但将来页面前端优化上会轻松许多,并且你的WEB服务器IO优化也轻松许多。程序引用资源文件时,要有一个统一的处理方法,在方法内部可以自动完成很多事情,例如将css/js根据组合,拼成一个文件,或者自动在生成的URI后面加上QUERYSTRING,如果将来前端用了缓存服务,那生成QUERYSTRING是最简单的刷新服务端缓存和客户端缓存的办法。

前面讲到,数据库会有复制,可能会多主多从,可能会分片。我们程序在处理数据的过程中,最好能抽象出来单独放做一层。拿现在流行的MVC模式来说,就是在M层下方再放一个数据层,这个数据层不是通常所说的JDBC/PDO/ActiveRecord等,而是你自己的存取数据层,仅对外暴露方法,隐藏数据存取细节。这个数据层内部不要怕写的难看,但一定要提供所有的数据存储功能,其他任何层次不要看到跟数据库打交道的字眼。之所以这样做,是因为在单关系数据库的情况下,可能会SELECT…JOIN…或直接INSERT…INTO…,可你可能会将一些表放到key-value数据库里存储,或者分片,这么做之后原来的语句和方式要全部改变,如果过于分散,则移植时会耗费很大精力,或得到一个很大的Model。在数据层面的设计上,尽量避免JOIN查询,我们可以多做冗余,多做缓存,每种数据尽量只需要一次查询,然后在你的程序里面进行组合。对于比较复杂的数据组合,在实时性要求不高的情况下,可采用异步处理,用户访问时只取处理后的结果。在对于主键的处理上,避免使用自增ID,可以用一定规则生成的唯一值当做主键,这种主键是最简单的分片分布策略。即使用自增ID,也最好用一个自增ID发生器,否则从数据库不小心被写了一下,那主键很容易冲突。

前面讲到,咱数据库前面还有某些缓存挡着。别把mysql的query cache当缓存,应用稍复杂的时候QUERY CACHE反而会成为累赘。缓存跟数据库和业务结合的很紧密,正因为跟业务关系紧密,所以这点没有放之四海而皆准的方法。但我们还是有一些规则可参照。规则一:越接近前端,缓存的颗粒度越大。例如在WEB最前端缓存整个页面,再往后一层缓存部分页面区域,再往后缓存区域内的单条记录。因为越靠近后端,我们的可操作性越灵活,并且变化最多的前端代码也比较方便编写。在实践中,因为产品需求变化速度非常快,迭代周期越来越短,有时很难将Controller和Model分的那么清楚,Controller层面处理部分缓存必不可免,但要保证如果出现这种情况,Controller所操作的缓存一定不要影响其他数据需求方,也就是要保证这个缓存数据只有这一个Controller在用。规则二:没有缓存时程序不能出错。在不考虑缓存失效引发的雪崩效应时,你的程序要有缓存跟没缓存一个样,不能像新浪微博一样,缓存一失效,粉丝微博全空,整个应用都乱套了。在缓存必不可少的情况下,给用户出错信息都比给一个让人误解的信息强。规则三,缓存更新要保证原子性或称作线程安全,特别是采用被动缓存的方式时,很可能两个用户访问时导致同一个缓存被更新,通常情况这不是大问题,可缓存失效后重建时很可能是引发连锁反应的原因之一。规则四:缓存也是有成本的。不只是技术成本,还有人工时间成本。如果一个功能使用缓存和不使用,在可预见的访问量情况下区别微小,但使用缓存会使复杂度增加,那就不用,我们可以加个TODO标注,在下次迭代的时候加上缓存处理。

前面讲到,文件存储是独立的,那么所有的文件操作就都是远程调用。可以在文件服务器上提供一个很简单的RESTful接口,也可以提供xmlrpc或json serveice,WEB服务器端所生成和处理的文件,全部通过接口通知文件服务器去处理,WEB服务器本身不要提供任何文件存储。你会发现很多大网站的上传图片跟保存文章是分两步完成的,就是基于这个原因。

以上几条“前面讲到”,其实无数人都讲过,我也只是结合前几篇文章用自己的话重复了一遍,真正分析起来精髓很简单——除了良好的功能逻辑分层,我们还要为数据库存储、缓存、队列、文件服务等程序外层资源调用单独设计接口,你可以把你的程序想象成是运行在 Amazon EC2 上并用他的所有web service服务,你的数据库就是它的SimpleDB,你的队列就是他的SQS,你的存储就是他的S3,唯一不同是amazon的接口是远程调用,你的是内部调用。

将支撑服务接口化,意味着将MySQL更换到PostgreSQL不需要更改业务处理程序,移植团队甚至不需要跟业务开发团队过多沟通;意味着业务开发团队是对接口编程而不是对数据库编程;意味着不会因为某个业务开发人员的失误而拖垮性能。

对程序扫盲不感兴趣的直接看这里——

产品设计完了,程序框架搭完了,可能有矛盾在这个节骨眼儿产生了。不断有产品设计抱怨说他的创意没实现到预期效果,有程序员抱怨说产品设计不切实际。这种抱怨多缘于产品人员不懂技术,技术人员不理解产品。从广义上来讲,产品包含市场策略、营销手段、功能设计,产品和技术在争论时往往把焦点放在功能上,而实际重点是,实现这个功能所消耗的成本跟能这个功能带来的利益能否换算,能否取其轻重。若可以,争议解决。若不能,则抛硬币看运气。因为一个功能的加强而引发指标井喷,或因项目拖延而导致贻误战机的例子比比皆是。激进的决策者注重利益,保守的决策者注重损失,聪明的决策者会考虑这个问题是否真的那么严重。

关系到未来的事情谁都说不准,要不怎么说创业一半靠运气呢。不过总有能说的准的事情,那就得靠数据说话。

没有100%也有99.9%的网站安装了访问统计代码,连我的 http://zhiyi.us 也不例外,新闻联播也总说科学决策科学发展的。有了统计,能确定的事情就很多了。例如,可以根据来源-目标转化率来分析哪类渠道的人均获取成本低,根据来源-内容访问猜测用户跳出率原因,根据用户点击行为判断链接位置是否合理等。将数据以不同方式组合起来,找到内在联系,分析内因外因,制定对应策略,减少拍脑门决策。靠数据支撑运营是个非常专业的事情,虽然不懂深奥的数学模型不会复杂的公式计算,渐渐学会因为A所以B,因为A和B所以C还是相对简单的。

全系列完毕。老话,大半夜连抽烟带码字的挺伤身,转载请注明出处.

from:

http://zhiyi.us/internet/thinking-twice-before-building-your-site-one.html

http://zhiyi.us/internet/thinking-twice-before-building-your-site-two.html

http://zhiyi.us/internet/thinking-twice-before-building-your-site-final.html