Category Archives: 云计算

去哪儿网基于Mesos和Docker构建私有云服务的实践

作者:徐磊

【导读】本文深入介绍了去哪儿网利用Mesos和Docker构建私有云服务的全过程,分享了从无状态应用向有状态应用逐步过度的经验与心得。

平台概览

2014年下半年左右,去哪儿完成了有关构建私有云服务的技术调研,并最终拍定了Docker/Mesos这一方案。下图1展示了去哪儿数据平台的整体架构:

大数据

图1:去哪儿数据平台的整体架构

该平台目前已实现了如下多项功能:

  • 每天处理约340亿/25TB的数据;
  • 90%的数据在100ms内完成处理;
  • 最长3h/24h的数据回放;
  • 私有的Elasticsearch Cloud;
  • 自动化监控与报警。

为什么选择Docker/Mesos

目前为止,这个数据平台可以说是公司整个流数据的主要出入口,包括私有的Elasticsearch Cloud和监控报警之类的数据。那么为什么选择Docker/Mesos?

选择Docker有两大原因。第一个是打包:对于运维来讲,业务打完包之后,每天面对的是用脚本分发到机器上时所出现的各种问题。业务包是一个比较上层的话题,这里不做深入的讨论,这里讲的“打包”指软件的Runtime层。如果用Docker的打包机制,把最容易出现问题的Runtime包装成镜像并放在registry里,需要的时候拿出来,那么整个平台最多只执行一个远程脚本就可以了,这是团队最看好的一个特性。第二个是运维:Docker取消了依赖限制,只要构建一个虚拟环境或一个Runtime的镜像,就可以直接拉取到服务器上并启动相应的程序。此外Docker在清理上也较为简单,不需要考虑环境卸载不干净等问题。

以常见的计算框架来说,它们本质上仍然属于运行在其上的Job的Runtime。综合上述情况,团队选择针对Runtime去打包。

选择Mesos是因为它足够简单和稳定,而且拥有较成熟的调度框架。Mesos的简单体现在,与Kubernetes相比其所有功能都处于劣势,甚至会发现它本身都是不支持服务的,用户需要进行二次开发来满足实际要求,包括网络层。不过,这也恰好是它的强项。Mesos本身提供了很多SDN接口,或者是有模块加载机制,可以做自定义修改,平台定制功能比较强。所以用Mesos的方案,需要考虑团队是否可以Hold住整个开发过程。

从框架层面来看,Marathon可以支撑一部分长期运行的服务,Chronos则侧重于定时任务/批处理。

以下图2是Mesos的一个简单结构图:

大数据

图2:Mesos结构

数据平台的最终目标架构如下图3所示:

大数据

图3:平台目标

组件容器化与部署

组件的容器化分为JVM容器化和Mesos容器化。JVM容器化需要注意以下几方面:

潜在创建文件的配置都要注意

  • java.io.tmpdir
  • -XX:HeapDumpPath
  • -Xloggc

-Xloggc会记录GC的信息到制定的文件中。现在很少有直接用XLoggc配置的了(已经用MXBean方式替代了)。如果有比较老的程序是通过-Xloggc打印GC日志的话,那么要额外挂载volume到容器内。

时区与编码

  • –env TZ=Asia/Shanghai
  • –volume /etc/localtime:/etc/localtime:ro
  • –env JAVA_TOOL_OPTIONS=”-Dfile.encoding=UTF-8 -Duser.timezone=PRC

时区是另一个注意点。上面所列的三种不同的方法都可以达到目的,其中第一/三个可以写在Dockerfile里,也可以在docker run时通过–env传入。第二种只在docker run时通过volume方式挂载。另外,第三种额外设置了字符集编码,推荐使用此方式。

主动设置heap

  • 防止ergonomics乱算内存

这是Docker内部实现的问题。即使给Docker设置内存,容器内通过free命令看到的内存和宿主机的内存是一样的。而JVM为了使用方便,会默认设置一个人机功能会根据当前机器的内存计算一个堆大小,如果我们不主动设置JVM堆内存的话,很有可能计算出一个超过 Memory Cgroup限制的内存,启动就宕掉,所以需要注意在启动时就把内存设置好。

CMS收集器要调整并行度

  • -XX:ParallelGCThreads=cpus
  • -XX:ConcGCThreads=cpus/2

CMS是常见的收集器,它设置并行度的时候是取机器的核数来计算的。如果给容器分配2个CPU,JVM仍然按照宿主机的核数初始化这些线程数量,GC的回收效率会降低。想规避这个问题有两点,第一点是挂载假的Proc文件系统,比如Lxcfs。第二种是使用类似Hyper的基于Hypervisor的容器。

Mesos容器化要求关注两类参数:配置参数和run参数。

  • 需要关注的配置参数
    • MESOS_systemd_enable_support
    • MESOS_docker_mesos_image
    • MESOS_docker_socket
    • GLOG_max_log_size
    • GLOG_stop_logging_if_full_disk

Mesos是配置参数最多的。在物理机上,Mesos默认使用系统的Systemd管理任务,如果把Mesos通过Docker run的方式启动起来,用户就要关systemd_Enable_support,防止Mesos Slave拉取容器运行时数据造成混乱。

第二个是Docker_Mesos_Image,这个配置告诉Mesos Slave,当前是运行在容器内的。在物理机环境下,Mesos Slave进程宕掉重启,、就会根据executor进程/容器的名字做recovery动作。但是在容器内,宕机后executor全部回收了,重启容器,Slave认为是一个新环境,跳过覆盖动作并自动下发任务,所以任务有可能会发重。

Docker_Socket会告诉Mesos,Docker指定的远端地址或本地文件,是默认挂到Mesos容器里的。用户如果直接执行文件,会导致文件错误,消息调取失败。这个时候推荐一个简单的办法:把当前物理机的目录挂到容器中并单独命名,相当于在容器内直接访问整个物理机的路径,再重新指定它的地址,这样每次一有变动Mesos就能够发现,做自己的指令。

后面两个是Mesos Logging配置,调整生成logging文件的一些行为。

  • 需要关注的run参数
    • –pid=host
    • –privileged
    • –net=host (optional)
    • root user

启动Slave容器的时候最好不加Pid Namespace,因为容器内Pid=1的进程一般都是你的应用程序,易导致子进程都无法回收,或者采用tini一类的进程启动应用达到相同的目的。–privileged和root user主要是针对Mesos的持久化卷功能,否则无法mount到容器内,–net=host是出于网络效率的考虑,毕竟源生的bridge模式效率比较低。

大数据

图4:去哪儿数据平台部署流程图

上图4就是去哪儿数据平台部署的流程图。

基于Marathon的Streaming调度

拿Spark on Mesos记录子,即使是基于Spark的Marathon调度,也需要用户开发一个Frameworks。上生产需要很多代码,团队之前代码加到将近一千,用来专门解决Spark运行在Master中的问题,但是其中一个软件经常跑到Master,对每一个框架写重复性代码,而且内部逻辑很难复用,所以团队考虑把上层的东西全都跑在一个统一框架里,例如后面的运维和扩容,都针对这一个框架做就可以了。团队最终选择了Marathon,把Spark作为Marathon的一个任务发下去,让Spark在Marathon里做分发。

除去提供维标准化和自动化外,基于Spark的Marathon还可以解决Mesos-Dispatcher的一些问题:

  • 配置不能正确同步;这一块更新频率特别慢,默认速度也很慢,所以需要自己来维护一个版本。第一个配置不能正确同步,需要设置一些参数信息、Spark内核核数及内损之类,这里它只会选择性地抽取部分配置发下去。
  • 基于attributes的过滤功能缺失;对于现在的环境,所设置的Attributes过滤功能明显缺失,不管机器是否专用或有没有特殊配置,上来就发,很容易占满ES的机器。
  • 按role/principal接入Mesos;针对不同的业务线做资源配比时,无法对应不同的角色去接入Mesos。
  • 不能re-registery;框架本身不能重注册,如果框架跑到一半挂掉了,重启之后之前的任务就直接忽略不管,需要手工Kill掉这个框架。
  • 不能动态扩容executor。最后是不能扩容、动态调整,临时改动的话只能重发任务。

整个过程比较简单,如下图5所示:

大数据

图5:替代Spark Mesos Dispatcher

不过还是有一些问题存在:

Checkpoint & Block

  • 动态预留 & 持久化卷
  • setJars
  • 清理无效的卷

关于Checkpoint&Block,通过动态预留的功能可以把这个任务直接“钉死”在这台机器上,如果它挂的话可以直接在原机器上重启,并挂载volume继续工作。如果不用它预留的话,可能调度到其他机器上,找不到数据Block,造成数据的丢失或者重复处理。

持久化卷是Mesos提供的功能,需要考虑它的数据永存,Mesos提供了一种方案:把本地磁盘升级成一个目录,把这个转移到Docker里。每次写数据到本地时,能直接通过持久化卷来维护,免去手工维护的成本。但它目前有一个问题,如果任务已被回收,它持久化卷的数据是不会自己删掉的,需要写一个脚本定时轮巡并对应删掉。

临时文件

  • java.io.tmpdir=/mnt/mesos/sandbox
  • spark.local.dir=/mnt/mesos/sandbox

如果使用持久化卷,需要修改这两个配置,把这一些临时文件写进去,比如shuffle文件等。如果配置持久化卷的话,用户也可以写持久化卷的路径。

Coarse-Grained

Spark有两种资源调度模式:细粒度和粗粒度。目前已经不太推荐细粒度了,考虑到细粒度会尽可能的把所有资源占满,容易导致Mesos资源被耗尽,所以这个时候更倾向选择粗粒度模式。

大数据

图6:Storm on Marathon

上图6展示了基于Storm的Marathon调度,Flink也是如此。结合线上的运维和debug,需要注意以下几方面:

源生Web Console

  • 随机端口
  • OpenResty配合泛域名
  • 默认源生Web Console,前端配置转发,直接访问固定域名。

Filebeat + Kafka + ELK

  • 多版本追溯
  • 日常排错
  • 异常监控

大部分WebUI上看到的都是目前内部的数据处理情况,可以通过ELK查询信息。如果任务曾经运行在不同版本的Spark上,可以把多版本的日志都追踪起来,包括日常、问题监控等,直接拿来使用。

Metrics

第三个需要注意的就是指标。比如Spark ,需要配合Metrics把数据源打出来就行。

ELK on Mesos

目前平台已有近50个集群,约100TB+业务数据量,高峰期1.2k QPS以及约110个节点,Elasticsearch需求逐步增多。

大数据

图7:ELK on Mesos

上图7是ELK on Mesos结构图,也是团队的无奈之选。因为Mesos还暂时不支持multi-role framework功能,所以选择了这种折中的方式来做。在一个Marathon里,根据业务线设置好Quota后,用业务线重新发一个新的Marathon接入进去。对于多租户来讲,可以利用Kubernetes做后续的资源管控和资源申请。

部署ES以后,有一个关于服务发现的问题,可以去注册一个callback,Marathon会返回信息,解析出master/slave进程所在的机器和端口,配合修改Haproxy做一层转发,相当于把后端整个TCP的连接都做一个通路。ES跟Spark不完全相同,Spark传输本身流量就比较大,而ES启动时需要主动联系Master地址,再通过Master获取相应集群,后面再做P2P,流量比较低,也不是一个长链接。

监控与运维

这部分包括了Streaming监控指标与报警、容器监控指标与报警两方面。

Streaming监控指标与报警

Streaming监控含拓扑监控和业务监控两部分。

  • Streaming拓扑监控
  • 业务监控
    • Kafka Topic Lag
    • 处理延迟mean90/upper90
    • Spark scheduler delay/process delay
    • Search Count/Message Count
    • Reject/Exception
    • JVM

拓扑监控包括数据源和整个拓扑流程,需要用户自己去整理和构建,更新的时候就能够知道这个东西依赖谁、是否依赖线上服务,如果中途停的话会造成机器故障。业务监控的话,第一个就是Topic Lag,Topic Lag每一个波动都是不一样的,用这种方式监控会频繁报警,90%的中位数都是落在80—100毫秒范围内,就可以监控到整个范围。

容器监控指标与报警

容器监控上关注以下三方面:

  • Google cAdvisor足够有效
    • mount rootfs可能导致容器删除失败 #771
    • –docker_only
    • –docker_env_metadata_whitelist
  • Statsd + Watcher
    • 基于Graphite的千万级指标监控平台
  • Nagios

容器这一块比较简单,利用Docker并配合Mesos,再把Marathon的ID抓取出来就可以了。我们这边在实践的过程发现一个问题,因为Statsd Watcher容易出现问题,你直接用Docker的时候它会报一些错误出来,这个问题就是Statsd Watcher把路径给挂了的原因。目前我们平台就曾遇到过一次,社区里面也有人曝,不过复现率比较低。用的时候如果发现这个问题把Statsd Watcher直接停掉就好。指标的话,每台机器上放一个statsd再发一个后台的Worker,报警平台也是这个。

其实针对Docker监控的话,还是存在着一些问题:

  • 基础监控压力
    • 数据膨胀
    • 垃圾指标增多
    • 大量的通配符导致数据库压力较高
  • 单个任务的容器生命周期
    • 发布
    • 扩容
    • 异常退出

首先主要是监控系统压力比较大。原来监控虚拟机时都是针对每一个虚拟机的,只要虚拟机不删的话是长期汇报,指标名固定,但在容器中这个东西一直在变,它在这套体系下用指标并在本地之外建一个目录存文件,所以在这种存储机制下去存容器的指标不合适。主要问题是数据膨胀比较厉害,可能一个容器会起名,起名多次之后,在Graphite那边对应了有十多个指标,像这种都是预生成的监控文件。比如说定义每一秒钟一个数据点,要保存一年,这个时候它就会根据每年有多少秒生成一个RRD文件放那儿。这部分指标如果按照现有标准的话,可能容器的生命周期仅有几天时间,不适用这种机制。测试相同的指标量,公司存储的方式相对来说比Graphite好一点。因为Graphite是基于文件系统来做的,第一个优化指标名,目录要转存到数据库里做一些索引加速和查询,但是因为容器这边相对通配符比较多,不能直接得知具体对应的ID,只能通配符查询做聚合。因为长期的通配符在字符串的索引上还是易于使用的,所以现在算是折中的做法,把一些常用的查询结果、目录放到里边。

另一个是容器的生命周期。可以做一些审计或者变更的版本,在Mesos层面基于Marathon去监控,发现这些状态后打上标记:当前是哪一个容器或者哪一个TASK出了问题,对应扩容和记录下来。还有Docker自己的问题,这样后面做整个记录时会有一份相对比较完整的TASK-ID。

End.

转载请注明来自36大数据(36dsj.com):36大数据 » 去哪儿网基于Mesos和Docker构建私有云服务的实践

Amazon’s AWS

原文链接:A Beginner’s Guide To Scaling To 11 Million+ Users On Amazon’s AWS

译者:杰微刊–汪建

 

一个系统从一个用户到多于1100万用户访问,你将如何对你的系统进行扩展?Amazon的web服务解决方案架构师乔尔?威廉姆斯就此话题给出了一个精彩的演讲:2015扩展你的第一个一千万用户。
如果你是一个拥有较丰富的AWS使用经验的用户,这个演讲将不太适合你,但如果你作为一个刚接触云、刚接触AWS的新用户,或者你还没有跟上Amazon源源不断对外发布的AWS新特性,它将是一个很好的入门资料。
正如大家所期望的,这个演讲讨论Amazon服务如何针对问题提出先进且主流的解决方案,Amazon平台总是令人印象深刻且拥有指导性。对于如何把所有产品组合在一起Amazon做了大量工作去提取出用户需要的是什么,并且确保Amazon对于每个用户的需求都拥有一个产品能满足这部分的需求。
演讲的一些有趣的要点:

1、一般刚开始时使用SQL而在必要时刻转向NoSQL。
2、一致的观点是通过引入组件去解耦系统,使用组件便于扩展并且组件故障不会影响到其他模块。组件便于使系统分层和构建微服务。
3、只把区别于已有任务的部分作为你的业务逻辑,不要重复发明轮子。
4、可伸缩性和冗余性不是两个互相独立的概念,你经常要将两个概念同时放在一起考虑。
5、没有提及成本,成为AWS解决方案被批评的一个主要方面。

 

基本情况
AWS覆盖全世界12个国家区域

1. 每个区域都对应着世界上的一个物理位置,每个位置都有弹性计算云提供多个可用区域(Availability Zones),这些区域包含北美、南美、欧洲、中东、非洲、亚太等地区。
2. 每个可用区域(AZ)实质上是单个数据中心,尽管它可由多个数据中心构造。
3. 每个可用区域都拥有很强的隔离性,他们各自拥有独立的电源和网络。
4. 可用区域之间只能通过低延迟网络互相连接,它们可以相距5或15英里,但网络的速度相当快以至于你的应用程序像在同一个数据中心。
5. 每个区域至少有2个可用区域,可用区域总共有32个。
6. 借助若干可用区域即可构建一个高可用的架构供你的应用使用。
7. 在即将到来的2016年将会增加至少9个可用区域和4个区域。

 

AWS在世界上拥有53个边缘位置
1. 这些边缘位置被用于Amazon的内容分发网络CDN、Route53、CloudFront以及Amazon的DNS管理服务器。
2. 边缘位置使用户可以在世界的任何角落低延迟地访问网页。
构建块服务
1. AWS已经使用多个可用区域构架了大量服务供使用,这些服务内部拥有高可用性和容错性。以下是可供使用的服务列表。
2. 你可以在你的应用中直接使用这些服务,它们是收费的,但使用它们你可以不必自己考虑高可用性。
3. 每个可用区域都提供很多服务,包括CloudFront, Route 53, S3, DynamoDB, 弹性负载均衡, EFS, Lambda, SQS, SNS, SES, SWF。
4. 即使这些服务只存在于一个单一的可用区域,通过使用这些服务任然可以构建一个高可用架构。
一个用户
在这种情况下,你是作为仅有的用户,你仅仅只想让web应用跑起来。
你的架构看起来像下面几点:

1. 运行在单独的实例上,可能是t2.micro型。实例类型包括了CPU、内存、存储和网络的不同组合,通过选择这些不同实例类型组成一个适合你的web应用的资源。
2. 在单独的实例上运行整个web栈,例如web应用程序、数据库以及各种管理系统等。
3. 使用Amazon的Route53作为DNS服务。
4. 在此实例上添加一个的弹性IP。
5. 在一段时间内运行的良好。
纵向扩展
1、你需要一个更大的容器放置你的应用,最简单的扩展方法是选择一个更大的实例类型,例如c4.8xlarge或者m3.2xlarge。
2、这种方法称为纵向扩展。
3、需要做的仅仅是选择一个新型实例取代原来的实例,应用跑起来即可以更加强大。
4、提供多种不同的硬件配置混搭选择,可以选择一个244G内存的系统(2TB的RAM即将到来),也可以选择40个CPU内核的系统,可以组成I/0密集型实例、CPU密集型实例以及高存储型实例。
5、Amazon的一些服务使用可配置的IOPS选项来保证性能,你可以使用小一点的实例去跑你的应用,对于需要扩展的服务独立使用Amazon的可扩展服务,例如DynamoDB。
6、纵向扩展有一个很大的问题:它不具备failover功能,同时也不具备冗余性。就像把所有鸡蛋都放在同一个篮子里,一旦实例发生故障你的web也会宕掉。
7、一个单独的实例最终能做到的也就这些,想要更加强大需要其他的措施。
10+用户
将单个主机分为多个主机
1. Web应用使用一台主机。
2. 数据库使用一台主机,你可以在上面跑任意数据库,只要负责数据库的管理。
3. 将主机分离成多个主机可以让web应用和数据库各自独立对自己进行扩展,例如在某种情况下可能你需要的数据库比web应用更大的规模。
或者你可以不自己搭建数据库转而使用Amazon的数据库服务
1. 你是一个DBA吗?你真的想要担心数据备份的问题吗?担心高可用?担心数据库补丁?担心操作系统?
2. 使用Amazon数据库服务有一大优势,你只要简单一点击即可完成多可用区域的数据库的安装,而且你不必担心这些可用区域之间的数据备份或其他类似的事情,这些数据库具备高可用性高可靠性。
正如你所想,Amazon有几种类型的完全托管数据库服务供出售:
1. Amazon RDS(Relational Database Service),可供选择的数据库类型相当多,包括Microsoft SQL Server, Oracle, MySQL, PostgreSQL, MariaDB, Amazon Aurora.
2. Amazon DynamoDB,一个NoSQL数据库。
3. Amazon Redshift,一个PB级的数据仓库系统。
更多Amazon 特性
1. 拥有自动扩展存储到64TB的能力,你不再需要限定你的数据存储。
2. 多大15个读副本。
3. 持续增量备份到S3。
4. 多达6路备份到3个可用区域,有助于处理故障。
5. MySQL兼容。
用SQL数据库取代NoSQL数据库
1. 建议使用SQL数据库。
2. SQL数据库相关技术完善。
3. 存在大量开源源码、社区、支持团队、书籍和工具。
4. 千万用户级别系统的还不足以拖垮SQL数据库,除非你的数据非常巨大。
5. 具有清晰的扩展模式。
什么时候你才需要使用NoSQL数据库
1. 如果你一年需要存储超过5TB的数据,或者你有一个令人难以置信的数据密集任务。
2. 你的应用具有超低延迟需求。
3. 你的应用需要一个非常高的吞吐量,需要在数据的读写I/O上进行优化。
4. 你的应用没有任何关系型数据。
100+用户
在web层进行主机分离。
使用Amazon RDS存储数据,它把数据库的所有工作都揽下了。
上面两点做好即可。

 

1000+用户
现在你构建的应用存在可用性问题,你的web应用将会宕掉如果你web服务的主机宕掉了。
你需要在另外一个可用区域上搭建另外一个web实例,由于可用区域之间拥有毫秒级别的低延迟,他们看起来就像互相挨着。
同样,你需要在另外一个可用区域上搭建一个RDS数据库slave,组成主备数据库,一旦主数据库发生故障你的web应用将会自动切换到slave备数据库。由于你的应用总是使用相同的端,failover不会带给应用任何改变。
在两个可用区域中分布着两个web主机实例,使用弹性负载均衡器(ELB)将用户访问分流到两个web主机实例。
弹性负载均衡器(ELB)
1. ELB是一个高可用的负载均衡器,它存在于所有的可用区域中,对于你的应用来说它是一个DNS服务,只需要把他放到Route53即可,它就会在你的web主机实例中进行负载分发。
2. ELB有健康检查机制,这个机制保证流量不会分发到宕掉的主机上。
3. 不用采取任何措施即可完成扩展,当它发现额外流量时它将在后台通过横向和纵向扩展,随着你的应用不断扩展,它也会自动不断扩展,而且这些都是系统自动完成的,你不必对ELB做任何管理。
10000到100000用户
前面例子中说到ELB后面挂载两个web主机实例,而实际上你可以在ELB后面挂载上千个主机实例,这就叫横向扩展。
添加更多的读副本到数据库中,或者添加到RDS中,但需要保持副本的同步。
通过转移一些流量到web层服务器减轻web应用的压力,例如从你的web应用中将静态内容抽离出来放到Amazon S3和Amazon CloudFront上,CloudFront是Amazon的CDN,它会将你的静态内容保存在全世界的53个边缘地区,通过这些措施提高性能和效率。
Amazon S3是一个对象仓库。
1. 它不像EBS,它不是搭载在EC2实例上的存储设备,它是一个对象存储而不是块存储。
2. 对于静态内容如JavaScript、css、图片、视频等存放在Amazon S3上再合适不过,这些内容没必要放到EC2实例上。
3. 高耐用性,11个9的可靠性。
4. 无限制的可扩展,只要你想可以往里面扔尽可能多的数据,用户在S3上存储了PB级别的数据。
5. 支持最大5TB的对象存储。
6. 支持加密,你可以使用Amazon的加密,或者你自己的加密,又或者第三方的加密服务。
Amazon CloudFront对你的内容提供缓存
1. 它将内容缓存在边缘地区以便供你的用户低延迟访问。
2. 如果没有CDN,将导致你的用户更高延迟地访问你的内容,你的服务器也会因为处理web层的请求而处于更高的负载。
3. 例如有个客户需要应对60Gbps的访问流量,CloudFront将一切都处理了,web层甚至都不知道有这么大的访问流量存在。
你还可以通过转移session状态减轻你的web层的负载
1. 将session状态保存到ElastiCache或DynamoDB。
2. 这个方法也让你的系统在未来可以自动扩展。
你也可以将数据库的一些数据缓存在ElastiCache减轻应用负载
数据库没有必要处理所有获取数据的请求,缓存服务可以处理这些请求从而让宝贵的数据库资源处理更加重要的操作。
Amazon DynamoDB——全托管的NoSQL数据库
1. 根据你自己想要的吞吐量,定制你想要的读写性能。
2. 支持高性能。
3. 具备分布式和容错性,它部署在多个可用区域中。
4. 它以kv结构存储,且支持JSON格式。
5. 支持最大400k大的文件。
Amazon Elasticache ——全托管的Memcached或Redis
1. 维护管理一个memcached集群并不会让你赚更多的钱,所以让Amazon来做。
2. Elasticache集群会自动帮你扩展,它是一个具备自我修复特性的基础设施,如果某些节点宕掉了其它的新节点即会自动启动。
你也可以转移动态内容到CloudFront减轻负载
众所周知CloudFront能处理静态内容,例如文件,但除此之外它还还能处理某些动态内容,这个话题不再进行深入的探讨,可以看看这个链接。
自动扩展
对于黑色星期五,假如你不用做任何扩展就足够处理这些峰值流量,那么你是在浪费钱。如果需求和计算能力相匹配自然是最好的,而这由自动扩展帮你实现,它会自动调整计算集群的大小。
作为用户,你可以决定集群的最小实例数和最大实例数,通过实例池中设置最小和最大实例数即可。
云监控是一种嵌入应用的管理服务
1. 云监控的事件触发扩展。
2. 你准备扩展CPU的数量吗?你准备优化延迟吗?准备扩展带宽吗?
3. 你也可以自定义一些指标到云监控上,如果你想要指定应用针对某些指标自动扩展,只需将这些指标放到云监控上,告诉根据云监控根据这些指标分别扩展哪些资源。
500000+用户
前面的配置可以自动扩展群组添加到web层,在两个可用区域里自动扩展群组,也可以在三个可用区域里扩展,在不同可用区域中的多实例模式不经可以确保可扩展性,同时也保证了可用性。
论题中的案例每个可用区域只有3个web层实例,其实它可以扩展成上千个实例,而你可以设置实例池中最小实例数为10最大实例数为1000。
ElastiCache用于承担数据库中热点数据的读负载。
DynamoDB用于Session数据的负载。
你需要增加监控、指标以及日志。
1. 主机级别指标,查看自动扩展的集群中的某一CPU参数,快速定位到问题的位置。
2. 整体级别指标,查看弹性负载均衡的指标判断整个实例集群的整体性能。
3. 日志分析,使用CloudWatch日志查看应用有什么问题,可以使用CloudTrail对这些日志进行分析管理。
4. 外部站点监控,使用第三方服务例如New Relic或Pingdom监控作为终端用户看到了什么情况。
你需要知道你的用户的反馈,他们是不是访问延迟很慢,他们在访问你的web应用时是不是出现了错误。
从你的系统结构中尽可能多地排出性能指标,这有助于自动扩展的决策,你可不希望你的系统CPU使用率才20%。
自动化运维
随着基础设施越来越大,它扩展到了上千个实例,我们有读副本,我们有水平横线扩展,对于这些我们需要一些自动化运维措施去对他们进行管理,我们可不希望对着每个实例一个一个单独地管理。
动化运维工具分为两个层级
1. DIY层,包括Amazon EC2和AWS CloudFormation。
2. 更高层次的服务,包括AWS Elastic Beanstalk和AWS OpsWorks。
AWS Elastic Beanstalk,为你的应用自动管理基础设施,很方便。
AWS OpsWorks,应用程序管理服务,用于部署和操作不同形态规模的应用程序,它还能做到持续集成。
AWS CloudFormation
1. 提供了最大的灵活性,它提供了你的应用栈的模板,它可以构建你的整个应用栈,或者仅仅是应用栈中的某个组件。
2. 如果你要更新你的应用栈你只要更新CloudFormation模板,它将更新你的整个应用。
3. 它拥有大量的控制,但缺乏便利性。
AWS CodeDeploy,部署你的程序到整个EC2实例集群
1. 可以部署一到上千个实例。
2. Code Deploy可以指向一个自动扩展配置。
3. 可连同Chef和Puppet一起使用。
解耦基础设施
使用SOA/微服务,从你的应用抽离出不同服务,就像前面你将web层与数据库层分离出来那样,再分别创建这些服务。
这些独立出来的服务就可以根据自己需要扩展,它给你系统的扩展带来了灵活性,同时也保证了高可用性。
SOA是Amazon搭建架构关键的组成部分。
松耦合解放了你
1. 你可以对某些服务单独地扩展和让它失效。
2. 如果一个工作节点从SQS拉取数据失败,没有没关系?没有,只要重启另外一个工作节点即可,所有操作都有可能发生故障,所以一定要搭建一个可以处理故障的架构,提供failover功能。
3. 将所有模块设置成黑盒。
4. 把交互设计成松耦合方式。
5. 优先考虑内置了冗余性和可扩展性的服务,而不是靠自己构建实现。
不要重复发明轮子
只需把你区别于已有任务的部分作为你的业务逻辑。
Amazon的很多服务本身具备容错能力,因为他们跨多个可用区域,例如:队列、邮件、转码、搜索、数据库、监控、性能指标采集、日志处理、计算等服务,没有必要自己搭建。
SQS:队列服务
1. Amazon提供的第一个服务。
2. 它是跨可用区域的所以拥有容错性。
3. 它具备可扩展性、安全性、简单性。
4. 队列可以帮助你的基础设施上的不同组件之间传递消息。
5. 以图片管理系统为例,图片收集系统和图片处理系统是两个不同的系统,他们各自都可以独立地扩展,他们之间具备松耦合特性,摄取照片然后扔进队列里面,图片处理系统可以拉取队列里面的图片再对其进行其他处理。
AWS Lambda,用于代码部署和服务管理。
1. 提供解耦你的应用程序的工具。
2. 在前面图片系统的例子中,Lambda可以响应S3的事件,就像S3中某文件被增加时Lambda相关函数会被自动触发去处理一些逻辑。
3. 已经在EC2上集成,供应用扩展。
百万级别用户
当用户数量达到百万级别时,这就要求前面提到的所有方案都要综合考虑。
1. 扩展多为可用区域。
2. 在所有层之间使用弹性负载均衡,不仅在web层使用,而且还要在应用层、数据层以及应用包含的其他所有层都必须使用弹性负载均衡。
3. 自动伸缩能力。
4. 面向服务的架构体系。
5. 巧妙使用S3和CloudFront部署一部分内容。
6. 在数据库前面引入缓存。
7. 将涉及状态的对象移除出Web层。
使用Amazon SES发送邮件。
使用CloudWatch监控。

 

千万级别用户
当我们的系统变得越来越大,我们会在数据层遇到一些问题,你可能会遇到竞争写主库的数据库问题,这也就意味着你最多只能发送这么多写流量到一台服务器上。
你如何解决此问题?
1. Federation,根据你的应用功能把数据库分成多个库。
2. Sharding,分表分片,使用多个服务器分片。
3. 把部分数据迁移到其他类型的数据库上,例如NoSQL、graph等。
Federation——根据应用功能切分成多个库
1. 例如,创建一个论坛数据库、一个用户数据库、一个产品数据库,你可能之前就是一个数据库包含这所有类型的数据,所以现在要将他们拆分开。
2. 按照功能分离出来的数据库可以各自独立进行扩展。
3. 缺点:不能做跨数据库查询。
Sharding——将数据分割到多主机上
1. 应用层变得更加复杂,扩展能力更强。
2. 例如,对于用户数据库,三分之一的用户被发送到一个分片上,三分之一发到另一个分片上,最后三分之一发到第三个分片。
将数据迁移到其他类型的数据库上
1. 考虑NoSQL数据库。
2. 如果你的数据不要求复杂的join操作,比如说排行榜,日志数据,临时数据,热表,元数据/查找表等等,满足这些情况可以考虑迁移到NoSQL数据库上。
3. 这意味着他们可以各自单独扩展。
11000000用户
扩展是一个迭代的过程,当你的系统变得越来越大,你总有更多的事情需要你解决。
调整你的应用架构。
更多的SOA特性和功能。
从多可用区域到多区域。
自定义解决方案去解决你的特定问题,当用户量到达十亿级别时自定义解决方案是必要的。
深入分析你的整个应用栈。
回顾
使用多可用区域的基础设施提升可靠性。
使用自带扩展能力的服务,比如ELB,S3,SQS,SNS,DynamoDB等等。
每一层级都建立冗余,可扩展性和冗余性不是两个分开单独的概念,经常需要同时考虑两者。
刚开始使用传统关系型数据库。
在你的基础设施的里面和外面都考虑缓冲数据。
在你的基础设施中使用自动化工具。
确保你的应用有良好的指标采样、系统监控、日志记录,确保收集你的用户访问你的应用过程中产生的问题。
将各个层分拆成独立的SOA服务,让这些服务能保持最大的独立性,可以各自进行扩展,及时发生故障也不波及其他。
一旦做了足够的准备及可使用自动扩展功能。
不重复发明轮子,尽量使用托管服务而不是自己构建,除非非要不可。
必要的情况下转向NoSQL数据库。

参考资料
On HackerNews / On Reddit

http://aws.amazon.com/documentation

http://aws.amazon.com/architecture

http://aws.amazon.com/start-ups

http://aws.amazon.com/free

From:http://www.jfh.com/jfperiodical/article/1242

 

Microsoft Azure存储架构设计

SQL Azure简介

SQL Azure是Azure存储平台的逻辑数据库,物理数据库仍然是SQL Server。一个物理的SQL Server被分成多个逻辑分片(partition),每一个分片成为一个SQL Azure实例,在分布式系统中也经常被称作子表(tablet)。和大多数分布式存储系统一样,SQL Azure的数据存储三个副本,同一个时刻一个副本为Primary,提供读写服务,其它副本为Secondary,可以提供最终一致性的读服务。每一个SQL Azure实例的允许的最大数据量可以为1GB或者5GB(Web Edition),10GB, 20GB, 30GB, 40GB或者50GB(Business Edition)。由于限制了子表最大数据量,Azure存储平台内部不支持子表分裂。

Azure整体架构.png

如上图,与大多数Web系统架构类似,Azure存储平台大致可以分为四层,从上到下分别为:

  • Client Layer:将用户的请求转化为Azure内部的TDS格式流;
  • Services Layer:相当于网关,相当于普通Web系统的逻辑层;
  • Platform Layer:存储节点集群,相当于普通Web系统的数据库层;
  • Infrastructure Layer:硬件和操作系统。Azure使用的硬件为普通PC机,论文中给出的典型配置为:8核,32GB内存,12块磁盘,大致的价格为3500美金;

Services Layer

服务层相当于普通Web系统的逻辑层,包含的功能包括:路由,计费,权限验证,另外,SQL Azure的服务层还监控Platform Layer中的存储节点,完成宕机检测和恢复,负载均衡等总控工作。Services Layer的架构如下:

Azure Service.png

sorry,图片直接copy的,字体比较小,重点理解功能划分及流程,Utility Layer理解大意即可

如上图,服务层包含四种类型的组件:

1, Front-end cluster:完成路由功能并包含防攻击模块,相当于Web架构中的Web服务器,如Apache或者Nginx;

2, Utility Layer:请求服务器合法性验证,计费等功能;

3, Service Platform:监控存储节点集群的机器健康状况,完成宕机检测和恢复,负载均衡等功能;

4, Master Cluster:配置服务器,保存每个SQL Azure实例的副本所在的物理存储节点信息;

其中,Master Cluster一般配置为七台机器,采用”Quorum Commit”技术,也就是任何一个Master操作必须同步到四个以上副本才算成功,四个以下Master机器故障不影响服务;其它类型的机器都是无状态的,且机器之间同构。上图中,请求的流程说明如下:

1, 客户端与Front-end机器建立连接,Front-end验证是否支持客户端的操作,如CREATE DATABASE这样的操作只能通过Azure实用工具执行;

2, Front-end网关机器与客户端进行SSL协议握手认证,如果客户端拒绝使用SSL协议则断开连接。这个过程中还将执行防攻击保护,比如拒绝某个或某一段范围IP地址频繁访问;

3, Front-end网关机器请求Utility Layer进行必要的验证,如请求服务器地址白名单认证;

4, Front-end网关机器请求Master获取用户请求的数据分片所在的物理存储节点副本信息;

5, Front-end网关机器请求请求Platform Layer中的物理存储节点验证用户的数据库权限;

6, 如果以上认证均通过,客户端和Platform Layer中的存储节点建立新的连接;

7~8, 后续所有的客户端请求都直接发送到Platform Layer中的物理存储节点,Front-end网关只是转发请求和回复数据,起一个中间代理作用。

Platform Layer

平台层就是存储节点集群,运行物理的SQL Server服务器。客户端的请求通过Front-end网关节点转发到平台层的数据节点,每个SQL Azure实例是SQL Server的一个数据分片,每个数据分片在不同的SQL Server数据节点上存储三个副本,同一时刻只有一个副本为Primary,其它副本为Secondary。数据写入采用”Quorum Commit”策略,至少两个副本写成功时才返回客户端,这样即使一个数据节点发生故障也不影响正常服务。Platform Layer的架构如下:

platform.jpg

sorry,图片直接copy,字体太小,请关注后续对存储节点Agent程序的描述

如上图,每个SQL Server数据节点最多服务650个数据分片,每一个数据节点上的所有数据分片的写操作记录到一个操作日志文件中,从而提高写入操作的聚合性能。每个分片的多个副本之间的数据同步是通过同步并回放操作日志实现的,由于每个分片的副本所在的机器可能不同,因此,每个SQL Server存储节点最多需要和650个其它存储节点进行数据同步,网络聚合不够,这也是限制单个存储节点最多服务650个分片的原因。

如上图,每个物理存储节点上都运行了一些实用的deamon程序(称为fabric),大致介绍如下:

1, Failure detection:检测数据节点故障从而触发Reconfiguration过程;

2, Reconfiguration Agent:节点故障后负责在数据节点重新生成Primary或者Secondary数据分片;

3, PM (Partition Manager) Location Resolution:解析Master的地址从而发送数据节点的消息给Master的Partition Manager处理;

4, Engine Throttling:限制每个逻辑的SQL Azure实例占用的资源比例,防止超出容量限制;

5, Ring Topology:所有的数据节点构成一个环,从而每个节点有两个邻居节点可以检测节点是否宕机;

分布式相关问题

1, 数据复制(Replication)

SQL Azure中采用”Quorum Commit”的策略,普通的数据存储三个副本,至少写成功两个副本才可以返回成功;Master存储七个副本,至少需要写成功四个副本。每个SQL Server节点的更新操作写到一个操作日志文件中并通过网络发送到另外两个副本,由于不同数据分片的副本所在的SQL Server机器可能不同,一个存储节点的操作日志最多需要和650个分片数量的机器通信,日志同步的网络聚合效果不够好。Yahoo的PNUTS为了解决这个问题采用了消息中间件进行操作日志分发,达到聚合操作日志的效果。

2, 宕机检测和恢复

SQL Azure的宕机检测论文中讲的不够细,大致的意思是:每个数据节点都被一些对等的数据节点监控,发现宕机则报告总控节点进行宕机恢复过程;同时,如果无法确定数据节点是否宕机,比如待监控数据节点假死而停止回复命令,此时需要由仲裁者节点进行仲裁。判断机器是否宕机需要一些协议控制,后面的文章会专门介绍。

如果数据节点发生了故障,需要启动宕机恢复过程。由于宕机的数据节点服务了最多650个逻辑的SQL Azure实例(子表),这些子表可能是Primary,也可能是Secondary。总控节点统一调度,每次选择一个数据分片进行Reconfiguration,即子表复制过程。对于Secondary数据分片,只需要通过从Primary拷贝数据来增加副本;对于Primary,首先需要从另外两个副本中选择一个Secondary作为新的Primary,接着执行和Secondary数据分片Reconfiguration一样的过程。另外,这里需要进行优先级的控制,比如某个数据分片只有一个副本,需要优先复制;某个数据分片的Primary不可服务,需要优先执行从剩余的副本中选择Secondary切换为Primary的过程。当然,这里还需要配置一些策略,比如只有两个副本的状态持续多长时间开始复制第三个副本,SQL Azure目前配置为两小时。

3, 负载均衡

新的数据节点加入或者发现某个节点负载过高时,总控节点启动负载均衡过程。数据节点负载影响因素包括:读写个数,磁盘/内存/CPU/IO使用量等。这里需要注意的是,新机器加入时需要控制子表迁移的节奏,否则大量的子表同时迁移到新加入的机器导致系统整体性能反而变慢。

SQL Azure由于可以控制每个逻辑SQL Azure实例,即每个子表的大小,因此,为了简便起见,可以不实现子表分裂,很大程度上简化了系统。

4, 事务

SQL Azure支持数据库事务,数据库事务相关的SQL语句都会记录BEGIN TRANSACTION,ROLLBACK TRANSACTION和COMMIT TRANSACTION相关的操作日志。在SQL Azure中,只需要将这些操作日志同步到其它副本即可,由于同一时刻同一个数据分片最多有一个Primary提供写服务,不涉及分布式事务。SQL Azure系统支持的事务级别为READ_COMMITTED。

5, 多租户干扰

云计算系统中多租用的操作相互干扰,因此需要限制每个SQL Azure逻辑实例使用的系统资源:

1, 系统操作系统资源限制,比如CPU和内存。超过限制时回复客户端要求10s后重试;

2, SQL Azure逻辑数据库容量限制。每个逻辑数据库都预先设置了最大的容量,超过限制时拒绝更新请求,但允许删除操作;

3, SQL Server物理数据库数据大小限制。超过该限制时返回客户端系统错误,此时需要人工介入。

与SQL Server的差别

1, 不支持的操作:Microsoft Azure作为一个针对企业级应用的平台,尽管尝试支持尽量多的SQL特性,仍然有一些特性无法支持。比如USE操作:SQL Server可以通过USE切换数据库,不过在SQL Azure不支持,这时因为不同的逻辑数据库可能位于不同的物理机器。具体可以参考SQL Azure vs. SQL Server

2, 观念转变:对于开发人员,需要用分布式系统的思维开发程序,比如一个连接除了成功,失败还有第三种不确定状态:云端没有返回操作结果,操作是否成功我们无从得知,又如,天下没有像SQL这么好的免费午餐;对于DBA同学,数据库的日常维护,比如升级,数据备份等工作都移交给了微软,可能会有更多的精力关注业务系统架构。

完整的信息可以参考微软前不久公布的Azure存储系统架构Inside SQL Azure论文

from:http://www.nosqlnotes.net/archives/83

Windows Azure Storage Architecture Overview

Update 1-2-2012:  See the new post on Windows Azure Storage: A Highly Available Cloud Storage Service with Strong Consistency , which gives a much more detailed and up to date description of the Windows Azure Storage Architecture.

 

In this posting we provide an overview of the Windows Azure Storage architecture to give some understanding of how it works. Windows Azure Storage is a distributed storage software stack built completely by Microsoft for the cloud.

Before diving into the details of this post, please read the prior posting on Windows Azure Storage Abstractions and their Scalability Targets to get an understanding of the storage abstractions (Blobs, Tables and Queues) provided and the concept of partitions.

3 Layer Architecture

The storage access architecture has the following 3 fundamental layers:

  1. Front-End (FE) layer – This layer takes the incoming requests, authenticates and authorizes the requests, and then routes them to a partition server in the Partition Layer. The front-ends know what partition server to forward each request to, since each front-end server caches a Partition Map. The Partition Map keeps track of the partitions for the service being accessed (Blobs, Tables or Queues) and what partition server is controlling (serving) access to each partition in the system.
  2. Partition Layer – This layer manages the partitioning of all of the data objects in the system. As described in the prior posting, all objects have a partition key. An object belongs to a single partition, and each partition is served by only one partition server. This is the layer that manages what partition is served on what partition server. In addition, it provides automatic load balancing of partitions across the servers to meet the traffic needs of Blobs, Tables and Queues. A single partition server can serve many partitions.
  3. Distributed and replicated File System (DFS) Layer – This is the layer that actually stores the bits on disk and is in charge of distributing and replicating the data across many servers to keep it durable. A key concept to understand here is that the data is stored by the DFS layer, but all DFS servers are (and all data stored in the DFS layer is) accessible from any of the partition servers.

These layers and a high level overview are shown in the below figure:

image

Here we can see that the Front-End layer takes incoming requests, and a given front-end server can talk to all of the partition servers it needs to in order to process the incoming requests. The partition layer consists of all of the partition servers, with a master system to perform the automatic load balancing (described below) and assignments of partitions. As shown in the figure, each partition server is assigned a set of object partitions (Blobs, Entities, Queues). The Partition Master constantly monitors the overall load on each partition sever as well the individual partitions, and uses this for load balancing. Then the lowest layer of the storage architecture is the Distributed File System layer, which stores and replicates the data, and all partition servers can access any of the DFS severs.

Lifecycle of a Request

To understand how the architecture works, let’s first go through the lifecycle of a request as it flows through the system. The process is the same for Blob, Entity and Message requests:

  1. DNS lookup – the request to be performed against Windows Azure Storage does a DNS resolution on the domain name for the object’s Uri being accessed. For example, the domain name for a blob request is “<your_account>.blob.core.windows.net”. This is used to direct the request to the geo-location (sub-region) the storage account is assigned to, as well as to the blob service in that geo-location.
  2. Front-End Server Processes Request– The request reaches a front-end, which does the following:
    1. Perform authentication and authorization for the request
    2. Use the request’s partition key to look up in the Partition Map to find which partition server is serving the partition. See this post for a description of a request’s partition key.
    3. Send the request to the corresponding partition server
    4. Get the response from the partition server, and send it back to the client.
  3. Partition Server Processes Request– The request arrives at the partition server, and the following occurs depending on whether the request is a GET (read operation) or a PUT/POST/DELETE (write operation):
    • GET – See if the data is cached in memory at the partition server
      1. If so, return the data directly from memory.
      2. Else, send a read request to one of the DFS Servers holding one of the replicas for the data being read.
    • PUT/POST/DELETE
      1. Send the request to the primary DFS Server (see below for details) holding the data to perform the insert/update/delete.
  4. DFS Server Processes Request – the data is read/inserted/updated/deleted from persistent storage and the status (and data if read) is returned. Note, for insert/update/delete, the data is replicated across multiple DFS Servers before success is returned back to the client (see below for details).

Most requests are to a single partition, but listing Blob Containers, Blobs, Tables, and Queues, and Table Queries can span multiple partitions. When a listing/query request that spans partitions arrives at a FE server, we know via the Partition Map the set of partition servers that need to be contacted to perform the query. Depending upon the query and the number of partitions being queried over, the query may only need to go to a single partition server to process its request. If the Partition Map shows that the query needs to go to more than one partition server, we serialize the query by performing it across those partition servers one at a time sorted in partition key order. Then at partition server boundaries, or when we reach 1,000 results for the query, or when we reach 5 seconds of processing time, we return the results accumulated thus far and a continuation token if we are not yet done with the query. Then when the client passes the continuation token back in to continue the listing/query, we know the Primary Key from which to continue the listing/query.

Fault Domains and Server Failures

Now we want to touch on how we maintain availability in the face of hardware failures. The first concept is to spread out the servers across different fault domains, so if a hardware fault occurs only a small percentage of servers are affected. The servers for these 3 layers are broken up over different fault domains, so if a given fault domain (rack, network switch, power) goes down, the service can still stay available for serving data.

The following is how we deal with node failures for each of the three different layers:

  • Front-End Server Failure – If a front-end server becomes unresponsive, then the load balancer will realize this and take it out of the available servers that serve requests from the incoming VIP. This ensures that requests hitting the VIP get sent to live front-end servers that are waiting to process requests.
  • Partition Server Failure – If the storage system determines that a partition server is unavailable, it immediately reassigns any partitions it was serving to other available partition servers, and the Partition Map for the front-end servers is updated to reflect this change (so front-ends can correctly locate the re-assigned partitions). Note, when assigning partitions to different partition servers no data is moved around on disk, since all of the partition data is stored in the DFS server layer and accessible from any partition server. The storage system ensures that all partitions are always served.
  • DFS Server Failure – If the storage system determines a DFS server is unavailable, the partition layer stops using the DFS server for reading and writing while it is unavailable. Instead, the partition layer uses the other available DFS servers which contain the other replicas of the data. If a DFS Server is unavailable for too long, we generate additional replicas of the data in order to keep the data at a healthy number of replicats for durability.

Upgrade Domains and Rolling Upgrade

A concept orthogonal to fault domains is what we call upgrade domains. Servers for each of the 3 layers are spread evenly across the different fault domains, and upgrade domains for the storage service. This way if a fault domain goes down we lose at most 1/X of the servers for a given layer, where X is the number of fault domains. Similarly, during a service upgrade at most 1/Y of the servers for a given layer are upgraded at a given time, where Y is the number of upgrade domains. To achieve this, we use rolling upgrades, which allows us to maintain high availability when upgrading the storage service.

The servers in each layer are broken up over a set of upgrade domains, and we upgrade a single upgrade domain at a time. For example, if we have 10 upgrade domains, then upgrading a single domain would potentially upgrade up to 10% of the servers from each layer at a time. A description of upgrade domains and an example of using rolling upgrades is in the PDC 2009 talk on Patterns for Building Scalable and Reliable Applications for Windows Azure (at 25:00).

We upgrade a single domain at a time for our storage service using rolling upgrades. A key part for maintaining availability during upgrade is that before upgrading a given domain, we proactively offload all the partitions being served on partition servers in that upgrade domain. In addition, we mark the DFS servers in that upgrade domain as being upgraded so they are not used while the upgrade is going on. This preparation is done before upgrading the domain, so that when we upgrade we reduce the impact on the service to maintain high availability.

After an upgrade domain has finished upgrading we allow the servers in that domain to serve data again. In addition, after we upgrade a given domain, we validate that everything is running fine with the service before going to the next upgrade domain. This process allows us to verify production configuration, above and beyond the pre-release testing we do, on just a small percentage of servers in the first few upgrade domains before upgrading the whole service. Typically if something is going to go wrong during an upgrade, it will occur when upgrading the first one or two upgrade domains, and if something doesn’t look quite right we pause upgrade to investigate, and we can even rollback to the prior version of the production software if need be.

Now we will go through the lower to layers of our system in more detail, starting with the DFS Layer.

DFS Layer and Replication

Durability for Windows Azure Storage is provided through replication of your data, where all data is replicated multiple times. The underlying replication layer is a Distributed File System (DFS) with the data being spread out over hundreds of storage nodes. Since the underlying replication layer is a distributed file system, the replicas are accessible from all of the partition servers as well as from other DFS servers.

The DFS layer stores the data in what are called “extents”. This is the unit of storage on disk and unit of replication, where each extent is replicated multiple times. The typical extent sizes range from approximately 100MB to 1GB in size.

When storing a blob in a Blob Container, entities in a Table, or messages in a Queue, the persistent data is stored in one or more extents. Each of these extents has multiple replicas, which are spread out randomly over the different DFS servers providing “Data Spreading”. For example, a 10GB blob may be stored across 10 one-GB extents, and if there are 3 replicas for each extent, then the corresponding 30 extent replicas for this blob could be spread over 30 different DFS servers for storage. This design allows Blobs, Tables and Queues to span multiple disk drives and DFS servers, since the data is broken up into chunks (extents) and the DFS layer spreads the extents across many different DFS servers. This design also allows a higher number of IOps and network BW for accessing Blobs, Tables, and Queues as compared to the IOps/BW available on a single storage DFS server. This is a direct result of the data being spread over multiple extents, which are in turn spread over different disks and different DFS servers, since any of the replicas of an extent can be used for reading the data.

For a given extent, the DFS has a primary server and multiple secondary servers. All writes go through the primary server, which then sends the writes to the secondary servers. Success is returned back from the primary to the client once the data is written to at least 3 DFS servers. If one of the DFS servers is unreachable when doing the write, the DFS layer will choose more servers to write the data to so that (a) all data updates are written at least 3 times (3 separate disks/servers in 3 separate fault+upgrade domains) before returning success to the client and (b) writes can make forward progress in the face of a DFS server being unreachable. Reads can be processed from any up-to-date extent replica (primary or secondary), so reads can be successfully processed from the extent replicas on its secondary DFS servers.

The multiple replicas for an extent are spread over different fault domains and upgrade domains, therefore no two replicas for an extent will be placed in the same fault domain or upgrade domain. Multiple replicas are kept for each data item, so if one fault domain goes down, there will still be healthy replicas to access the data from, and the system will dynamically re-replicate the data to bring it back to a healthy number of replicas. During upgrades, each upgrade domain is upgraded separately, as described above. If an extent replica for your data is in one of the domains currently being upgraded, the extent data will be served from one of the currently available replicas in the other upgrade domains not being upgraded.

A key principle of the replication layer is dynamic re-replication and having a low MTTR (mean-time-to-recovery). If a given DFS server is lost or a drive fails, then all of the extents that had a replica on the lost node/drive are quickly re-replicated to get those extents back to a healthy number of replicas. Re-replication is accomplished quickly, since the other healthy replicas for the affected extents are randomly spread across the many DFS servers in different fault/upgrade domains, providing sufficient disk/network bandwidth to rebuild replicas very quickly. For example, to re-replicate a failed DFS server with many TBs of data, with potentially 10s of thousands of lost extent replicas, the healthy replicas for those extents are potentially spread across hundreds to thousands of storage nodes and drives. To get those extents back up to a healthy number of replicas, all of those storage nodes and drives can be used to (a) read from the healthy remaining replicas, and (b) write another copy of the lost replica to a random node in a different fault/upgrade domain for the extent. This recovery process allows us to leverage the available network/disk resources across all of the nodes in the storage service to potentially re-replicate a lost storage node within minutes, which is a key property to having a low MTTR in order to prevent data loss.

Another important property of the DFS replication layer is checking and scanning data for bit rot. All data written has a checksum (internal to the storage system) stored with it. The data is continually scanned for bit rot by reading the data and verifying the checksum. In addition, we always validate this internal checksum when reading the data for a client request. If an extent replica is found to be corrupt by one of these checks, then the corrupted replica is discarded and the extent is re-replicated using one of the valid replicas in order to bring the extent back to healthy level of replication.

Geo-Replication

Windows Azure Storage provides durability by constantly maintaining multiple healthy replicas for your data. To achieve this, replication is provided within a single location (e.g., US South), across different fault and upgrade domains as described above. This provides durability within a given location. But what if a location has a regional disaster (e.g., wild fire, earthquake, etc.) that can potentially affect an area for many miles?

We are working on providing a feature called geo-replication, which replicates customer data hundreds of miles between two locations (i.e., between North and South US, between North and West Europe, and between East and Southeast Asia) to provide disaster recovery in case of regional disasters. The geo-replication is in addition to the multiple copies maintained by the DFS layer within a single location described above. We will have more details in a future blog post on how geo-replication works and how it provides geo-diversity in order to provide disaster recovery if a regional disaster were to occur.

Load Balancing Hot DFS Servers

Windows Azure Storage has load balancing at the partition layer and also at the DFS layer. The partition load balancing addresses the issue of a partition server getting too many requests per second for it to handle for the partitions it is serving, and load balancing those partitions across other partition servers to even out the load. The DFS layer is instead focused on load balancing the I/O load to its disks and the network BW to its servers.

The DFS servers can get too hot in terms of the I/O and BW load, and we provide automatic load balancing for DFS servers to address this. We provide two forms of load balancing at the DFS layer:

  • Read Load Balancing – The DFS layer maintains multiple copies of data through the multiple replicas it keeps, and the system is built to allow reading from any of the up to date replica copies. The system keeps track of the load on the DFS servers. If a DFS server is getting too many requests for it to handle, partition servers trying to access that DFS server will be routed to read from other DFS servers that are holding replicas of the data the partition server is trying to access. This effectively load balances the reads across DFS servers when a given DFS server gets too hot. If all of the DFS servers are too hot for a given set of data accessed from partition servers, we have the option to increase the number of copies of the data in the DFS layer to provide more throughput. However, hot data is mostly handled by the partition layer, since the partition layer caches hot data, and hot data is served directly from the partition server cache without going to the DFS layer.
  • Write Load Balancing – All writes to a given piece of data go to a primary DFS server, which coordinates the writes to the secondary DFS servers for the extent. If any of the DFS servers becomes too hot to service the requests, the storage system will then choose different DFS servers to write the data to.

Why Both a Partition Layer and DFS Layer?

When describing the architecture, one question we get is why do we have both a Partition layer and a DFS layer, instead of just one layer both storing the data and providing load balancing?

The DFS layer can be thought of as our file system layer, it understand files (these large chunks of storage called extents), how to store them, how to replicate them, etc, but it doesn’t understand higher level object constructs nor their semantics. The partition layer is built specifically for managing and understanding higher level data abstractions, and storing them on top of the DFS.

The partition layer understands what a transaction means for a given object type (Blobs, Entities, Messages). In addition, it provides the ordering of parallel transactions and strong consistency for the different types of objects. Finally, the partition layer spreads large objects across multiple DFS server chunks (called extents) so that large objects (e.g., 1 TB Blobs) can be stored without having to worry about running out of space on a single disk or DFS server, since a large blob is spread out over many DFS servers and disks.

Partitions and Partition Servers

When we say that a partition server is serving a partition, we mean that the partition server has been designated as the server (for the time being) that controls all access to the objects in that partition. We do this so that for a given set of objects there is a single server ordering transactions to those objects and providing strong consistency and optimistic concurrency, since a single server is in control of the access of a given partition of objects.

In the prior scalability targets post we described that a single partition can process up to 500 entities/messages per second. This is because all of the requests to a single partition have to be served by the assigned partition server. Therefore, it is important to understand the scalability targets and the partition keys for Blobs, Tables and Queues when designing your solutions (see the upcoming posts focused on getting the most out of Blobs, Tables and Queues for more information).

Load Balancing Hot Partition Servers

It is important to understand that partitions are not tied to specific partition servers, since the data is stored in the DFS layer. The partition layer can therefore easily load balance and assign partitions to different partition servers, since any partition server can potentially provide access to any partition.

The partition layer assigns partitions to partition severs based on each partition’s load. A given partition server may serve many partitions, and the Partition Master continuously monitors the load on all partition servers. If it sees that a partition server has too much load, the partition layer will automatically load balance some of the partitions from that partition server to a partition server with low load.

When reassigning a partition from one partition server to another, the partition is offline only for a handful seconds, in order to maintain high availability for the partition. Then in order to make sure we do not move partitions around too much and make too quick of decisions, the time it takes to decide to load balance a hot partition server is on the order of minutes.

Summary

The Windows Azure Storage architecture had three main layers – Front-End layer, Partition layer, and DFS layer. For availability, each layer has its own form of automatic load balancing and dealing with failures and recovery in order to provide high availability when accessing your data. For durability, this is provided by the DFS layer keeping multiple replicas of your data and using data spreading to keep a low MTTR when failures occur. For consistency, the partition layer provides strong consistency and optimistic concurrency by making sure a single partition server is always ordering and serving up access to each of your data partitions.

Brad Calder

from:http://blogs.msdn.com/b/windowsazurestorage/archive/2010/12/30/windows-azure-storage-architecture-overview.aspx

Microsoft Azure Storage架构分析

Microsoft云存储服务分为两个部分,SQL Azure和Azure  Storage。云存储系统的可扩展性和功能不可兼得,必须牺牲一定的关系数据库功能换取可扩展性。Microsoft实现云存储的思路有两种:

1, 做减法。SQL Azure直接在原有的SQL Server上引入分布式的因素,在满足一定可扩展性的前提下尽可能不牺牲原有的关系型数据库功能。SQL  Azure的可扩展性是有限的,单个SQL Azure实例不允许超过50GB,这是因为SQL Azure不支持子表动态分裂,单个SQL  Azure实例必须足够小从而可以被一个节点服务。具体信息可以参考我以前的一篇文章:Microsoft SQL Azure架构设计

2, 做加法。Azure Storage先做好底层可扩展性,然后再逐步加入功能,这与Google GFS &  Bigtable的思路比较一致。Azure Storage分为Blob, Queue和Table三个部分,其中Azure Table  Storage最具有代表性,由于底层系统支持子表分裂,单个用户的最大数据量可以达到100TB。然而Table  Storage支持的功能有限,甚至不支持索引功能。具体信息可以参考msdn的一篇文章:Azure  Storage架构介绍

Microsoft Azure Storage 逻辑上分为三层:

1, 前端(Front-End Layer):类似互联网公司的Web服务器层,可采用LVS +  Nginx的设计,主要做一些杂事,比如权限验证。由于前端服务器没有状态,因此很容易实现可扩展。

2, 存储层 (Partition Layer):类似Bigtable,分为Partition Master和Partition  Server两种角色,分别对应Bigtable Master和Tablet  Server。每一个Partition(相当于Bigtable中的Tablet)同时只能被一个Partition Server服务,Partition  Master会执行负载均衡等工作。Bigtable中分为Root Table, Meta Table和User Table,Azure Table  Storage可能会为了简单起见消除Meta Table,所有的元数据操作全部放到Partition Master上。

3, 文件系统层(DFS Layer):类似GFS,数据按照extent(相当于GFS中的chunk)划分,每个extent大小在100MB ~  1GB之间。数据存储三份,写操作经过Primary同步到多个Secondary,读操作可以选择负载较轻的某个Primary或者Secondary副本。当发生机器故障时,需要选择其它机器上的Secondary切换为Primary继续提供写服务,另外需要通过增加副本操作使得每个extent的副本数维持在安全值,比如三份。为了简单起见,DFS  Layer对上层Partition Layer可以不提供文件系统接口,只提供类似块设备的访问方式。

Azure Storage的主键包括Partition Key + Row Key两部分,其中,Partition  Key用于数据划分,规定相同的Partition Key只属于同一个Partition,从而被一台Partition  Server服务,这就使得Partition Key相同的多个行之间能够支持事务。与SQL Azure不同,Azure  Storage的并发操作通过乐观锁的方式实现。Azure Storage包含三个不同的产品,其中Azure Table  Storage支持用户设置Schema,支持byte[], bool, DataTime, double, Guid, Int32, Int64,  String这几种列类型;Azure Blob Storage将Blob数据存放到底层的DFS  Layer中,Blob过大时可能存放到多个extent中,Partition  Layer存储每个Blob的编号到Blob所在的多个extent位置之间的映射关系;Azure Queue Storage将Partition  Key设置为Queue的编号,Row Key设置为消息的编号,从而保证属于同一个Queue的消息连续存放。

总之,Microsoft Azure  Storage和早期的Bigtable总体架构是很类似的,可能做了一些简化,这也间接说明了一点:如果不发生重大硬件变革,工程上要实现高可扩展的分布式B+树,将云存储系统分成文件+表格两层还是比较靠谱的。开发人员更多地需要在实现细节上下功夫,落实到线上的每行代码上。

from:http://www.nosqlnotes.net/archives/175