《高可用架构第1卷【2】》——高可用架构原理与分布式实践

《高可用架构第1卷【1】》

https://www.cnblogs.com/cx2016/p/12074835.html

《高可用架构第1卷【2】》

麦俊生/1.6 亿级短视频社交美拍架构实战59
1.6.1 短视频市场的发展59
1.6.2 美拍的发展.60
1.6.3 短视频所面临的架构问题61
1.6.4 为支持亿级用户,美拍架构所做的一些改进62
1.6.5 后续发展68

[转载] 亿级短视频社交美拍架构实战 - 云栖社区 - 阿里云一、短视频市场的发展 近几年来,短视频应用在国内应用市场引爆,美图公司推出了美拍,相关的产品还有 GIF 快手、秒拍、微视、逗拍、玩拍等,一系列短视频产品的出现也丰富了短视频应用市场。

一、短视频市场的发展

近几年来,短视频应用在国内应用市场引爆,美图公司推出了美拍,相关的产品还有 GIF 快手、秒拍、微视、逗拍、玩拍等,一系列短视频产品的出现也丰富了短视频应用市场。

短视频的相继爆发,与几个因素有关:

1、带宽,随着中国基础网络环境的发展,越来越多的 2G 移动网民开始转向使用 3G/4G 网络,从而体验到更好的上传下载带宽和更稳定的网络, 目前 3G/4G 的移动用户比例大概占比 85% 以上;同时随着资费的进一步降低,月户平均流量也达到了 360M,甚至不少部分是 GB 甚至几十 GB 的级别的流量,所以就一个普通的 10s 视频而言大概不到 1~2M 甚至几百 K,带宽流量的提升无疑会逐步降低用户使用的门槛;此外,家用带宽也随之增加,目前 10M 甚至 100M ` 已经成为家用带宽的主流,从而为短视频的发展提供了必要条件。

2、手机硬件配置的极大改进,随着像素的增加、手机硬件配置 CPU、GPU、内存等的升级,能够让手机更快的来处理和优化视频效果,从而能够给手机视频的处理带来更多的创意空间。

3、传统的文字和图片的表达能力不够丰富,所以无法满足网民的需求,而短视频带来了足够大的表现空间。

4、产品本身,提供了各种方式来降低用户视频的制作门槛,比如美拍提供了 MV 特效等,来提升了制作视频的趣味性的同时,降低使用的门槛。同时产品的多样化,也满足了各种用户的差异化需求,激发用户自传播。

二、美拍的发展

美拍在 2014.05 月发布,上线仅 1 天,即登入 App Store 免费总榜第一,当月下载量排名第一。在发布 9 个月的时候,用户就突破 1 个亿。目前每天美拍视频日播放量在 2.7 亿以上,日视频播放时长达到 183 万小时。

面临这种用户量爆发的增长,美拍也遇到了很多应用起步之初那些年所遇到的甜蜜和苦涩的回忆,经过 1 年多的架构的演进,美拍也积累了一定的经验,形成了一套高可用高可扩展的架构实践。虽无法做到很华丽,却会随着架构的不断的演进而不断的完善。

相比于普通的文本社交类 APP,做这么一个短视频产品在技术架构层面,会面临哪些问题呢?


和通用的文本社交类产品一样,美拍有首页热门、好友动态(feed 流)、评论服务、私信服务等基础功能;所以在用户爆发增长后,同样会面临应用层、数据库、缓存、接入层等方面的挑战,那么如何做到低延迟、高可用呢。同时因为是短视频本身,也会面临一些特定的领域性相关的问题。

三、短视频所面临的架构问题

短视频相比于文本数据而言,有着一些差异:

1、数据大小的差异

比如一条美拍,经过视频压缩和清晰度的权衡,10s 的视频大小 1MB 多,而一条 5 分钟视频的美拍甚至要达到几十 M,相比与几十字节或者几百字节的文本要大得多。因为数据量要大得多,所以也会面临一些问题:如何上传、如何存放、以及如何播放的问题。

关于上传,要在手机上传这么一个视频,特别是弱网环境要上传这么一个文件,上传的成功率会比较低,晚高峰的时候,省际网络的拥塞情况下,要更为明显得多。所以针对上传,需要基于 CDN 走动态加速来优化网络链路(通过基调实测过对于提升稳定性和速度有一定帮助),同时对于比较大的视频需要做好分片上传,减少失败重传的成本和失败概率等来提升可用性。同时不同 CDN 厂商的链路状况在不同的运营商不同地区可能表现不一,所以也需要结合基调测试,选择一些比较适合自己的 CDN 厂商链路

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

所谓的 CDN 动态加速技术

原标题:所谓的 CDN 动态加速技术

以前说 CDN 的优势是其在网络边缘缓存了用户请求的内容,离用户近,从而保证用户的访问效果; 但是动态网页由于是源站动态生成的内容,CDN 的边缘节点无法存储用户请求的内容,请求到了边缘节点之后还得回源,传统 CDN 架构上的优势就没有了。那么 cdn 动态加速还没有价值? 首先让我们看看 cdn 动态加速技术是怎么样的:

让我们看以下公式:

用户请求耗费的时间 = 用户和边缘交互的时间 + 边缘等待的时间;

其中用户和边缘交互的时间,我们可以看做用户向边缘请求一个静态文件的时间,边缘等待时间,是用户请求到了以后,边缘需要向用户发送数据,确没有数据可以发送,等他数据到达的这段时间; CDN 动态加速技术的本质主要是要减少第二部分的时间;

首先我们说,通过网络优化和协议优化,我们可以容易的把上面那个公式变成下式:

用户请求耗费的时间 = 用户和边缘交互的时间 + 1*RTT(边缘到源站)+ 源站的反应时间;

让我们忽略掉源站的反应时间,因为他和我们今天讨论的动态加速没有关系,我们可以把它看做一个常量;

Ok,让我们看看,这是怎么做到的,首先让我们看看,不优化的时候是个什么情况,如图 1 所示,最坏情况下边缘等待的时间 = 建立连接的时间 (1*RTT)+ 发送请求的时间 (1*RTT)+ 数据传输中的等待时间。

其中通过优化我们可以把建立连接的时间消灭掉,有两种发送可以做到这一点:

1. 通过连接复用,保证每次动态请求到达时,边缘和源之间的通路,连接都已经建立了,它的弊端是在突发情况下很难保证;

2. 通过 TCP 协议栈的定制,把连接和请求的过程合并起来,这事我们在 09 年就一直在说,只不过由于种种原因没有做下去,据说 google 已经做出来了;

除此以外我们还可以把数据传输开始以后的等待时间给去除掉,这里面涉及到了两个技术,一个是动态路由,一个是 TCP 协议优化;

动态路由:所谓动态路由,指的是利用 CDN 节点多的优势,把每个节点都看做一个路由,在边缘 A 和源 B 之间找到一个最佳路径,也就是说以前是直接从 A 到 B,变成了 A-C-D-B; 另外还需要强调的是,D-B 之间一定是要通过连接建立,而且 D-B 一定要很近,时延很小,否则的话 TCP 协议优化就发挥不了作用; 通过动态路由技术我们可以在 A-B 间建立一个更低的 RTT 和更小的丢包率的通过; 网络调度规划问题

节点间的 TCP 协议优化:有了动态路由做保证,节点间的 TCP 协议优化就是很简单的事情了,我们要知道用户的带宽往往是有限的,而节点间的带宽往往是冗余的,我们要做到节点间的发送速率高于边缘到用户是非常容易的,改几行代码就够了;

通过以上一些技术我们就可以把图 1 精简成图 2:

这还不够,我们能不能把这一个时延也去掉呢,这是部分可能的,这里面涉及到了一下一些技术:

1. 缓存,部分的动态内容也是可以在很短的时间内缓存的;

2. 预取:通过用户请求的页面内容解析,预先感知用户接下来要获取的内容,提前预取;

3. 在边缘生成用户请求的内容,这个水太深,我说不清楚,点到为止;

4. 证书类:通过在边缘部署 SSL 证书,在边缘将 SSL 请求,变成普通请求,从而将动态加速变成静态加速,但是如此是有风险的,把 CDN 运营商看成安全是不安全的;

除了以上一些技术以外,我还漏了一个,那就是压缩,压缩分成两部分,一部分是 http 头支持的压缩,这些就不要让 CDN 帮你干了,源站应该自己做的; 另一部分是 CDN 节点间的,如此可以减少 CDN 节点间传递的数据量,从而变向加快传输速度; 但是这里会增加机器的 CPU 负载,同时,有了 TCP 协议优化技术,不需要通过压缩来提高传输速度,所以个人认为它不重要。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

同时因为数据相对比较大,当数据量达到一定规模,存储容量会面临一些挑战,目前美拍的视频容量级别也达到 PB 级别的规模,所以要求存储本身能够具备比较强的线性扩展能力,并且有足够的资源冗余,而传统的 MySQL 等数据库比较难来支持这个场景,所以往往需要借助于专用的分布式对象存储。可以通过自建的服务或者云存储服务来解决。得益于近几年云存储的发展,目前美拍主要还是使用云存储服务来解决。自身的分布式对象存储主要用于解决一些内部场景,比如对于数据隐私性和安全性要求比较高的场景。

播放方面,因为文件比较大,也容易受到网络的影响,所以为了规避卡顿,一些细节也需要处理。比如对于 60s,300s 的视频,需要考虑到文件比较大,同时有拖动的需求,所以一般使用 http range 的方式,或者基于 HLS 的点播播放方式,基于前者比较简单粗暴,不过基于播放器的机制,也能够满足需求,也能实现点播拖动。而直接基于 HLS 的方式会更友好,特别是更长的一些视频,比如 5 分钟甚至更大的视频,不过这种需要单独的转码支持。之前美拍主要是短视频为主,所以更多使用 http range 的方式。而后续随着 5 分钟或者更大视频的场景,也在逐步做一些尝试。同时对于播放而言,在弱网环境下,可能也会面临一些问题,比如播放时卡顿的问题,这种一般通过网络链路优化;或者通过多码率的自适应优化,比如多路转码,然后根据特定算法模型量化用户网络情况进行选码率,网络差的用低码率的方式

2、数据的格式标准差异

相比于文本数据,短视频本身是二进制数据,有比较固定的编码标准,比如 H.264、H.265 等,有着比较固定和通用的一些格式标准。

3、数据的处理需求

视频本身能够承载的信息比较多,所以会面临有大量的数据处理需求,比如水印、帧缩略图、转码等。而视频处理的操作是非常慢的,会带来巨大的资源开销。

美拍对于视频的处理,主要分为两块:

客户端处理,视频处理尽量往客户端靠,利用现有强大的手机处理性能来减少服务器压力, 同时这也会面临一些低端机型的处理效率问题,不过特别低端的机型用于上传美拍本身比较少数,所以问题不算明显。客户端主要是对于视频的效果叠加、人脸识别和各种美颜美化算法的处理,我们这边客户端有实验室团队,在专门做这种效果算法的优化工作。同时客户端处理还会增加一些必要的转码和水印的视频处理。目前客户端的视频编解码方式,会有软编码和硬编码的方式,软编码主要是兼容性比较好,编码效果好些,不过缺点就是能耗高且慢些。而硬编码借助于显卡等,能够得到比较低的能耗并且更快,不过兼容和效果要差一些,特别是对于一些低配的机型。所以目前往往采用结合的方式

服务端的处理,主要是进行视频的一些审核转码工作,也有一些抽帧生成截图的工作等,目前使用 ffmpeg 进行一些处理。服务端本身需要考虑的一些点,就是因为资源消耗比较高,所以需要机器数会更多,所以在服务端做的视频处理操作,会尽量控制在一个合理的范围。同时因为美拍这种场景,也会遇到这些热点事件的突变峰值,所以转码服务集群本身需要具备可弹性伸缩和异步化消峰机制,以便来适应这种突增请求的场景。

四、为支持亿级用户,美拍架构所做的一些改进

随着用户和访问量的快速增长,美拍遇到不少的挑战

  • 性能的挑战

  • 可用性的挑战

  • 突发热点的挑战

  • 业务频繁迭代的挑战

在频繁的业务迭代的情况下,如何能够在海量请求下保证足够高的可用性,同时以一个比较好的用户体验和比较低的成本的方式来提供服务成为我们努力的方向。

这个是目前美拍的整体架构全貌


这一个架构目前也正在不断的持续演进的过程中,除了一些基础服务组件的建设外,我们还着重在服务治理做一些相关工作,来保证整体服务的可用和稳定。

 


分而治之、化繁为简

规划整体架构,明确服务模块的单一职责,尽量保持足够内聚,而服务模块之间做到解耦,这样就能够针对单一模块进行更精细化的优化工作,同时能够用适合的技术来解决适合的场景问题。

服务之间的交互和通讯,我们主要走了两种方式:

  • 基于 HTTP 的方式

  • 基于 config service + RPC 的方式

前者使用的方式比较简单,目前我们主要在跨团队、跨语言(比如 PHP 和 golang 之类的)会使用,主要会在七层 nginx 层做一些工作,如负载均衡、节点探测、并发保护等。


而第二种方式,我们主要用于内部系统之间的一些交互。目前我们主要基于 etcd 来实现我们的动态服务发现和配置服务,在 client 层面扩展实现了包含负载均衡、心跳、节点健康状态探测、etcd 节点挂掉的灾备等基础功能,同时会通过一些 metrics 埋点,以便跟踪内部的状态,用统一的 trace_id 来跟踪服务的链路调用情况。


开放扩展

主要针对下面几个点:

  • 代码功能的可扩展性

  • 交互协议的扩展性

  • 数据存储格式的可扩展性

  • 应用的可扩展性

  • 资源的可扩展性

交互协议,既针对交互接口,也针对 app 客户端和服务端的交互协议。特点是 app 客户端和服务端的交互协议,因为 app 的升级较之服务端升级的时间久得多,比如你发布了一个客户端版本 V0.1,如果用户后面一直不升级,这个时间可能是几个月、半年甚至一年,那么就会引入一些兼容问题,所以在协议层面设计的关键点需要考虑这种情况的存在,需要保证协议能够向前兼容,预留好扩展点。

而关于数据存储格式的可扩展性,美拍第一个版本每个属性在数据库中为一个字段,并且为了保持一定的扩展性也多加了几个扩展字段。在发展过程中演化为所有属性字段序列化为 protocol buffer 数据的方式,这样能更好满足快速发展的业务需求。但是大家往往也更多关注在服务端,其实有时候比较坑的是在客户端。之前就踩过坑客户端上有个 id 字段的数据类型使用 int32,因为客户端基本很难做强升,一个这样小的事情最终需要很长时间来消化解决,并且为此还需要做一些兼容工作。所以针对这类事情,建议大家在一开始时候也多留意,尽量少为将来埋坑。

分级隔离

目前我们主要通过这几个维度进行一些隔离:

  • 核心和非核心的隔离

  • 单一集群的内部隔离

  • 不同集群的外部物理资源隔离

  • 不同集群的外部依赖资源的隔离


美拍在发展早期,跟多数发展早期的系统一样,也是多数接口部署在同一个集群中,包括也共用了一些资源(比如 memcached ),这样的好处是早期部署上足够的简单。在发展的过程中,业务在快速发展,业务复杂度也在逐步提升,接口调用量也急剧增加,逐步就暴露出一些问题。美拍的发展过程也是实际的去验证了前面提到的分级隔离机制。

在发展早期,曾经有个调用量不小的非核心的业务,在对存储数据结构做了调整后的上线过程中出现性能问题,导致整个集群服务都受到一定的影响。虽然通过降级策略和运维配套设施快速的解决了问题,但是也引发了我们的进一步思考。在架构上我们会尽量保证在开发效率、系统架构、部署和运维成本等方面达到一定的平衡,以避免过度设计或者架构支撑不了业务。这到了需要做一些事情的时候,我们把核心业务和非核心业务在七层和应用层做了部署上的隔离。

做完上面的核心业务和非核心业务拆分之后,接口互相之间的依赖影响降低很多。但是还没有解决核心业务或者非核心业务内部接口之间的依赖影响问题。所以接下来也更进一步,针对部分场景也做了内部隔离,通过限定每个接口最多只能使用的固定处理线程数方式,来避免因为单个集群内某个接口的问题导致整个集群出问题的情况发生。

以上主要是在接口层面做隔离,而在依赖的资源及其外部服务方面,如果没有相应的隔离机制,也会有互相依赖影响的问题,比较典型的有 memcached slab calcification (钙化~)问题等。所以我们也在 memcached、mysql 等核心资源层面做了拆分。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Memcached采用LRU(Least Recent Used)淘汰算法,在内存容量满时踢出过期失效和LRU数据,为新数据腾出内存空间。不过该淘汰算法在内存空间不足以分配新的Slab情况下,这时只会在同一类Slab内部踢出数据。即当某个Slab容量满,且不能在内存足够分配新的Slab,只会在相同Slab内部踢出数据,而不会挪用或者踢出其他Slab的数据。这种局部剔除数据的淘汰算法带来一个问题:Slab钙化

Slab钙化降低内存使用率,如果发生Slab钙化,有三种解决方案:

1) 重启Memcached实例,简单粗暴,启动后重新分配Slab class,但是如果是单点可能造成大量请求访问数据库,出现雪崩现象,冲跨数据库。

2) 随机过期:过期淘汰策略也支持淘汰其他slab class的数据,twitter工程师采用随机选择一个Slab,释放该Slab的所有缓存数据,然后重新建立一个合适的Slab。

3) 通过slab_reassign、slab_authmove参数控制。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

『九个月实现破亿用户的可扩展架构』学习笔记 - blankyao 的代码随想 - SegmentFault 思否昨晚把美拍架构负责人洪小军在 Qcon 上的『九个月实现破亿用户的可扩展架构』分享看了一遍(其实那场 QCon 我也在现场,但是当时小军这个会场实在太多人了,而且当时北京还没开空调又热又闷,所以我就挑了个凉快的......

昨晚把美拍架构负责人洪小军在 Qcon 上的『九个月实现破亿用户的可扩展架构』分享看了一遍(其实那场 QCon 我也在现场,但是当时小军这个会场实在太多人了,而且当时北京还没开空调又热又闷,所以我就挑了个凉快的会场去听了哈哈),感觉有不少值得学习的地方,在这里记录一下,强烈建议大家把视频从头到尾看一遍,不要只看 ppt。尤其是身在创业公司且公司业务发展速度比较快的同学。

总的一个中心思想是在不同阶段选择最适合自己的方案。这句话说起来简单,但是背后的各种辛酸泪以及血的教训只有亲历者才能理解了。下面我们从各个角度分别来看一下。

对了,忘了说一个前提了,美拍从上线到发展到一亿用户只经历了短短几个月的时间,在这业界应该是没有几个先例的,这也是前面为什么说一定要仔细看看。另外说个八卦,据说美图的第一个后端开发(也是唯一的一个)在刚上线时连续三天没回家...

首先先从架构上来说,看下美拍经历的几个阶段:

  1. 极简化设计(快速发布上线)
  2. 保持简单行设计(产品快速迭代)
  3. 可扩展和高可用保证(用户量到一定量级)
  4. 高可扩展和高可用保证

然后我们来看下美拍一路走来遇到的问题:

  1. MySQL 慢查询
  2. MySQL 写入瓶颈
  3. redis 超时
  4. memcached 命中率奇低
  5. 服务相互依赖
  6. 监控报警不稳定
  7. CDN 服务各种故障
  8. 添加字段成本高
  9. 量级上来后,MySQL 继续慢

然后,我们按服务维度把每一个服务拆开,看下每一个服务在美拍架构上的迭代过程。

一、MySQL

MySQL 是最重要的一个服务,在美拍架构里经历了多次迭代。在第一版直接就是一个实例,为了保持代码的简单,业务逻辑能在数据库里做的都放到数据库做了,比如 Feed 功能,直接用 MySQL 的 join 查询。

但是后来就出现了一些慢查询的情况,这时候做了主从,做读写分离,多个从库用来做查询。再到后来出现写入也慢的情况,这时候也没有做架构上的优化,而是升级硬件,因为现在正是业务高速发展阶段,需要极简化设计,这个阶段更多精力要放在业务开发上(估计当时也木有招到合适的人:))。

过了一段时间又开始出现写入慢的情况,这时候才开始做分表。但是等到了重心放在扩展性和可用性上时,又遇到了新的问题,一个很大的问题还是写入慢,另外一个就是随着数据量的增大,添加字段成本特别的高。针对这两个问题做了下面两个方案:

  1. 异步写入,做到前端永远可写,后面复杂的事情放到队列里面去异步的做
  2. 索引和数据分离,把需要索引的字段单独拆出来一个表,其他数据用 kv 存储,value 就是所有属性和值的 pb 二进制数据,解决家字段困难的问题

这个时候针对 MySQL 的架构优化才告了一段落 :)

二、缓存

缓存主要用到了 memcache 和 redis(redis 应该主要是用在队列和计数服务)。在量比较小的时候就是简单粗暴的用,但是很快就遇到了 redis 超时的问题,这时候对 redis 扩容,使用多 slave 架构。然后是 rdb dump 时影响用户请求的问题,解决方法一是在凌晨访问量低的时候才去 dump,二是用不对外服务的机器来做 dump。

然后 memcached 遇到了命中率很低的问题,一个大问题就是容量瓶颈,这没啥好说的,扩容(小军有提到,要随时做好扩容的准备)。另外一个就是 slab calcification 的问题(又叫 slab 钙化问题,这个是 memcached 的内存分配机制导致的,简单来说就是 memcached 会内存分成 N 个 slab,当新添加一个内存对象时会根据这个对象的大小来选择不同的 slab,如果没有合适的就会创建一个 slab,那如果这时候剩余内存不足以分配一个 slab 呢?这时候就出现了钙化问题了),美拍当时的解决办法是核心业务隔离部署,避开这个问题。

到可用性保证阶段,缓存的可用性就更加的非常的重要了,缓存挂了可能就整个系统都挂了,很难收场,所以就要保证缓存的可用性。这时候做了主从的优化,master 也承担读查询,以保证缓存热度,slave 穿透到 master,master 穿透到 slave,防止单点故障

三、运维

在初期只是简单的监控告警,有时候出问题了可能收不到告警或者看不到是啥地方出问题,后来逐渐完善监控告警,且监控告警是用配置比较高的服务器,保证监控告警的可用性。然后假如更多监控维度和更多日志,方便定位问题。对依赖的第三方服务和资源做开关,出问题时可以通过服务的开关保证核心路径可用。

四、第三方服务

主要提到的是 CDN 服务。其中一个很大的问题就是 DNS 被攻击、被劫持,除了和运营商保持沟通外,还做了多服务商配合的策略,比如同样的数据在多个云服务那里做冗余,客户端在访问时如果出现问题就切换到其他的访问地址,并且在客户端做了服务端可用性探测。这也是个非常有价值的经验。

五、技术栈

整个看下来会发现美拍的架构做的非常的稳,小军也有提到,在项目初期高速发展阶段做架构时要克服对完美架构的欲望、克服对新技术的欲望,先让系统跑起来

但是在整个迭代过程中,美拍也一直在引入新技术,比如在团队不太熟悉时先在部分业务上使用 MongoDB,在注重可扩展和可用性阶段,引入 java 做业务逻辑,引入 c 做底层基础服务。

通过这个分享可以学习到一个系统从 0 到亿的架构迭代过程,但是更多的还是在于实践,估计美拍走过的坑也远不止小军分享里提到的这些,每一个点都可能出现 N 多的问题,每个点都可以展开很多话题来讲。希望能看到更多类似的有价值的分享!

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

综合来看,分级隔离本质上也是在解决服务之间依赖影响问题。

资源冗余

因为短视频是一个比较耗带宽的服务,因此在通用的应用自身资源冗余的情况下,还需要考虑到服务所依赖的外部资源,比如 CDN 和云存储服务本身的情况。对于 CDN 层面,可能还要考虑不同厂商在不同区域不同运营商下的资源冗余情况。而依赖的云服务等,这些服务本身从对外角度看是一个可无限扩展的服务,理论上通过扩展就能够满足性能需求,但是在使用往往会受限于实现,因为内部不一定是一个完全隔离的场景,比如说和别的企业服务混跑,同时可能只会分配对应的资源池,但这个资源超过性能预期的时候,不是一个可自动动态伸缩调度的场景。

容灾

美拍的容灾主要分为自身服务容灾、CDN 容灾、云存储容灾等。

自身服务容灾主要包含一些典型的容灾场景,比如 cache 容灾,通过多级 cache、cache 的分片 hash 的方式、以及本地 cache 的方式来解决。目前我们这边的容灾也借鉴了微博的多级 cache 机制的机制,针对核心的 cache 资源会有主备节点,避免单一节点挂掉后,穿透会压垮后端 DB,同时对于请求量特别大的场景,比如对于某个热点资源访问量很大的情况下,也会在之前增加一层 L1 的 LRU cache 来规避和缓解这一问题。


CDN 容灾主要通过接入多家供应商进行互备,然后通过一些基调检测不同服务厂商的链路和服务状态,当发现服务有问题的时候,通过 DNS 进行区域的切换。不过不同 CDN 厂商的服务表现不对等,所以在选型 CDN 厂商的话,需要侧重关注可用性、节点布点和链路状况、回源量、资源冗余量、晚高峰的链路状况、以及对于多媒体是否有单独优化等等来评估靠谱性

云存储容灾,目前美拍也主要使用两家互备的方式,因为国内的网络链路状况容易发生问题容易导致个别上传服务失败,以及云服务厂商服务挂掉的情况我们需要保证我们的服务可用。目前的做法是上传优先走主的云服务,如果上传失败的话,那么就会启用备的云服务。然后服务端层面也可以控制整体降级的方式,可以直接从主云服务直接降级读写备云服务。 基于每天的统计来看,通过这个方式至少提升上传的 0.1% 以上的可用性,在某些极端情况下,可能达到 1% 的可用性,当然这一块通过网络链路优化可能使得可用性情况没有数据中那么差。不过他的主要作用是在当某个云服务厂商节点服务出现短暂不可用或者长时间不可用的时候,我们也不会受太大影响。


五、后续的一些发展

随着短视频的不断的发展,以及实时直播的崛起,带宽的压力会越来越大,所以能够结合着 P2P + CDN 的方式来缓解服务端的带宽压力,不过 P2P 主要会面临着防火墙的问题、以及节点网络质量的影响,同时也依赖与视频播放的热度,这种对于效果都会有一些影响,同时为了更好的播放流畅度,单一的 P2P 无法满足需求,需要基于 P2P 和 CDN 的辅助进行。

带宽的另外一个节省之道,就是通过更好的编码标准来进行优化,比如 H.265 的编码标准,通过这个能够节省一半的流量。不过目前 H.265 在硬编支持不是很好,只有个别手机机型支持,而软编码的方式相比与 H.264,编解码速度要慢个几倍,这种对于能耗消耗比较高,处理也比较慢。而在往 H.265 演化的过程中,解码的普及程度也将会比编码来得更早。因为在解码算法层面,现有开源的方案还有很大的优化空间,以现有的手机硬件配置,是存在可以通过算法优化达到可以支撑 H.265 的空间。所以随着解码算法的不断优化和硬件的不断升级,解码普及的时间点也应该会比大家预期的时间来得更早,晋时也将会有更大比例的端能支持 H.265 的解码,对于 H.265 的普及奠定了很好的基础。

H.265 的普及理想情况是需要很大比例的端上设备在编码和解码层面都有支持,在解码更早普及的情况下,那么其实是有一种中间过渡方式:上传端上传 H.264 数据,服务端转为 H.265,播放端根据自身机器状况选择使用 H.264 或者 H.265 数据。这样的方案需要服务端需要额外做一次转码,并且存储成本也会提升。在有更大比例的端上支持 H.265 后,这样虽然有额外的成本开销,但是相比使用 H.265 带来的带宽成本的节省可能就越来越可以忽略掉。并且也可以根据访问热度情况做控制,取得两者更好的平衡。

另外一个方向,目前美拍会越多越多的把一些客户端的图片视频美化算法云端化,以服务的形式暴露给内部其他服务使用,以便能够支撑更多围绕 “美” 体系建设的产品生态链。这主要会面临的架构难点,就是资源消耗高。而这个的解决会依赖与两种方式,一种通过硬件 GPU、协处理器、CPU SIMD 指令等来优化性能,同时还需要解决架构的视频处理集群的自动弹性调度的问题,同时对于一些场景,比如类似与 H5 的推广页面,会逐步通过结合公有云调度的方式来解决。

本文转载来自高可用架构 「ArchNotes」公众号

 
   


刘道儒/1.7 微博“异地多活”部署经验谈69
1.7.1 微博异地多活建设历程69
1.7.2 微博异地多活面临的挑战70
1.7.3 异地多活的最佳实践.73
1.7.4 异地多活的新方向74

微博 “异地多活” 部署经验谈 - InfoQ

【编者按】近日,InfoQ 专访了阿里巴巴的研究员林昊(花名毕玄),了解了他们的数据中心异地多活项目的来龙去脉。本文在微博上引起了很多讨论。新浪微博的高级技术经理刘道儒( @liudaoru )也总结了微博平台的一些经验。

正文

异地多活的好处阿里巴巴的同学已经充分阐述,微博的初始出发点包括异地灾备、提升南方电信用户访问速度、提升海外用户访问速度、降低部署成本(北京机房机架费太贵了)等。通过实践,我们发现优势还包括异地容灾、动态加速、流量均衡、在线压测等,而挑战包括增加研发复杂度、增加存储成本等。

微博外部历程

先说说微博外部的历程,整个过程可谓是一波多折。微博的主要机房都集中在北京,只有很小一部分业务在广州部署,2010 年 10 月,因微博高速发展,所以准备扩大广州机房服务器规模,并对微博做异地双活部署。

第一版跨机房消息同步方案采取的是基于自研的 MytriggerQ(借助 MySQL 从库的触发器将 INSERT、UPDATE、DELETE 等事件转为消息)的方案,这个方案的好处是,跨机房的消息同步是通过 MySQL 的主从完成的,方案成熟度高。而缺点则是,微博同一个业务会有好几张表,而每张表的信息又不全,这样每发一条微博会有多条消息先后到达,这样导致有较多时序问题,缓存容易花。(得join)

第一套方案未能成功,但也让我们认识到跨机房消息同步的核心问题,并促使我们全面下线 MytriggerQ 的消息同步方案,而改用基于业务写消息到 MCQ( MemcacheQ ,新浪自研的一套消息队列,类 MC 协议)的解决方案。

基于业务写消息到消息队列

2011 年底在微博平台化完成后,开始启用基于 MCQ 的跨机房消息同步方案,并开发出跨机房消息同步组件 WMB(Weibo Message Broker)。经过与微博 PC 端等部门同学的共同努力,终于在 2012 年 5 月完成 Weibo.com 在广州机房的上线,实现了 “异地双活”。

由于广州机房总体的机器规模较小,为了提升微博核心系统容灾能力,2013 年年中我们又将北京的机房进行拆分,至此微博平台实现了异地三节点的部署模式。依托于此模式,微博具备了在线容量评估、分级上线、快速流量均衡等能力,应对极端峰值能力和应对故障能力大大提升,之后历次元旦、春晚峰值均顺利应对,日常上线导致的故障也大大减少。上线后,根据微博运营情况及成本的需要,也曾数次调整各个机房的服务器规模,但是整套技术上已经基本成熟。

异地多活面临的挑战

根据微博的实践,一般做异地多活都会遇到如下的问题:

  • 机房之间的延时:微博北京的两个核心机房间延时在 1ms 左右,但北京机房到广州机房则有近 40ms 的延时。对比一下,微博核心 Feed 接口的总平均耗时也就在 120ms 左右。微博 Feed 会依赖几十个服务上百个资源,如果都跨机房请求,性能将会惨不忍睹;
  • 专线问题:为了做广州机房外部,微博租了两条北京到广州的专线,成本巨大。同时单条专线的稳定性也很难保障,基本上每个月都会有或大或小的问题;
  • 数据同步问题:MySQL 如何做数据同步?HBase 如何做数据同步?还有各种自研的组件,这些统统要做多机房数据同步。几十毫秒的延时,加上路途遥远导致的较弱网络质量(我们的专线每个月都会有或大或小的问题),数据同步是非常大的挑战;
  • 依赖服务部署问题:如同阿里巴巴目前只做了交易单元的 “异地双活”,微博部署时也面临核心服务过多依赖小服务的问题。将小服务全部部署,改造成本、维护成本过大,不部署则会遇到之前提到的机房之间延时导致整体性能无法接受的问题;
  • 配套体系问题:只是服务部署没有流量引入就不能称为 “双活”,而要引入流量就要求配套的服务和流程都能支持异地部署,包括预览、发布、测试、监控、降级等都要进行相应改造。

微博异地多活解决方案

由于几十毫秒的延时,跨机房服务调用性能很差,异地多活部署的主体服务必须要做数据的冗余存储,并辅以缓存等构成一套独立而相对完整的服务。数据同步有很多层面,包括消息层面、缓存层面、数据库层面,每一个层面都可以做数据同步。由于基于 MytriggerQ 的方案的失败,微博后来采取的是基于 MCQ 的 WMB 消息同步方案,并通过消息对缓存更新,加上微博缓存高可用架构,可以做到即便数据库同步有问题,从用户体验看服务还是正常的。

这套方案中,每个机房的缓存是完全独立的,由每个机房的 Processor(专门负责消息处理的程序,类 Storm)根据收到的消息进行缓存更新。由于消息不会重复分发,而且信息完备,所以 MytriggerQ 方案存在的缓存更新脏数据问题就解决了。而当缓存不存在时,会穿透到 MySQL 从库,然后进行回种。可能出现的问题是,缓存穿透,但是 MySQL 从库如果此时出现延迟,这样就会把脏数据种到缓存中。我们的解决方案是做一个延时 10 分钟的消息队列,然后由一个处理程序来根据这个消息做数据的重新载入。一般从库延时时间不超过 10 分钟,而 10 分钟内的脏数据在微博的业务场景下也是可以接受的。

微博的异地多活方案如下图(三个节点类似,消息同步都是通过 WMB):

跟阿里巴巴遇到的问题类似,我们也遇到了数据库同步的问题。由于微博对数据库不是强依赖,加上数据库双写的维护成本过大,我们选择的方案是数据库通过主从同步的方式进行。这套方案可能的缺点是如果主从同步慢,并且缓存穿透,这时可能会出现脏数据。这种同步方式已运行了三年,整体上非常稳定,没有发生因为数据同步而导致的服务故障。从 2013 年开始,微博启用 HBase 做在线业务的存储解决方案,由于 HBase 本身不支持多机房部署,加上早期 HBase 的业务比较小,且有单独接口可以回调北京机房,所以没有做异地部署。到今年由于 HBase 支撑的对象库服务已经成为微博非常核心的基础服务,我们也在规划 HBase 的异地部署方案,主要的思路跟 MySQL 的方案类似,同步也在考虑基于 MCQ 同步的双机房 HBase 独立部署方案。

阿里巴巴选择了单元化的解决方案,这套方案的优势是将用户分区,然后所有这个用户相关的数据都在一个单元里。通过这套方案,可以较好的控制成本。但缺点是除了主维度(阿里巴巴是买家维度),其他所有的数据还是要做跨机房同步,整体的复杂度基本没降低。另外就是数据分离后由于拆成了至少两份数据,数据查询、扩展、问题处理等成本均会增加较多。总的来讲,个人认为这套方案更适用于 WhatsApp、Instagram 等国外业务相对简单的应用,而不适用于国内功能繁杂、依赖众多的应用

数据同步问题解决之后,紧接着就要解决依赖服务部署的问题。由于微博平台对外提供的都是 Restful 风格的 API 接口,所以独立业务的接口可以直接通过专线引流回北京机房。但是对于微博 Feed 接口的依赖服务,直接引流回北京机房会将平均处理时间从百毫秒的量级直接升至几秒的量级,这对服务是无法接受的。所以,在 2012 年我们对微博 Feed 依赖的主要服务也做了异地多活部署,整体的处理时间终于降了下来。当然这不是最优的解决方案,但在当时微博业务体系还相对简单的情况下,很好地解决了问题,确保了 2012 年 5 月的广州机房部署任务的达成。

而配套体系的问题,技术上不是很复杂,但是操作时却很容易出问题。比如,微博刚开始做异地多活部署时,测试同学没有在上线时对广州机房做预览测试,曾经导致过一些线上问题。配套体系需要覆盖整个业务研发周期,包括方案设计阶段的是否要做多机房部署、部署阶段的数据同步、发布预览、发布工具支持、监控覆盖支持、降级工具支持、流量迁移工具支持等方方面面,并需开发、测试、运维都参与进来,将关键点纳入到流程当中。

关于为应对故障而进行数据冗余的问题,阿里巴巴的同学也做了充分的阐述,在此也补充一下我们的一些经验。微博核心池容量冗余分两个层面来做,前端 Web 层冗余同用户规模成正比,并预留日常峰值 50% 左右的冗余度,而后端缓存等资源由于相对成本较低,每个机房均按照整体两倍的规模进行冗余。这样如果某一个机房不可用,首先我们后端的资源是足够的。接着我们首先会只将核心接口进行迁移,这个操作分钟级即可完成,同时由于冗余是按照整体的 50%,所以即使所有的核心接口流量全部迁移过来也能支撑住。接下来,我们会把其他服务池的前端机也改为部署核心池前端机,这样在一小时内即可实现整体流量的承接。同时,如果故障机房是负责数据落地的机房,DBA 会将从库升为主库,运维调整队列机开关配置,承接数据落地功能。而在整个过程中,由于我们核心缓存可以脱离数据库支撑一个小时左右,所以服务整体会保持平稳。

异地多活最好的姿势

以上介绍了一下微博在异地多活方面的实践和心得,也对比了一下阿里巴巴的解决方案。就像没有完美的通用架构一样,异地多活的最佳方案也要因业务情形而定。如果业务请求量比较小,则根本没有必要做异地多活,数据库冷备足够了。不管哪种方案,异地多活的资源成本、开发成本相比与单机房部署模式,都会大大增加。

以下是方案选型时需要考虑的一些维度:

  • 能否整业务迁移:如果机器资源不足,建议优先将一些体系独立的服务整体迁移,这样可以为核心服务节省出大量的机架资源。如果这样之后,机架资源仍然不足,再做异地多活部署。
  • 服务关联是否复杂:如果服务关联比较简单,则单元化、基于跨机房消息同步的解决方案都可以采用。不管哪种方式,关联的服务也都要做异地多活部署,以确保各个机房对关联业务的请求都落在本机房内。
  • 是否方便对用户分区:比如很多游戏类、邮箱类服务,由于用户可以很方便地分区,就非常适合单元化,而 SNS 类的产品因为关系公用等问题不太适合单元化
  • 谨慎挑选第二机房:尽量挑选离主机房较近(网络延时在 10ms 以内)且专线质量好的机房做第二中心。这样大多数的小服务依赖问题都可以简化掉,可以集中精力处理核心业务的异地多活问题。同时,专线的成本占比也比较小。以北京为例,做异地多活建议选择天津、内蒙古、山西等地的机房
  • 控制部署规模:在数据层自身支持跨机房服务之前,不建议部署超过两个的机房。因为异地两个机房,异地容灾的目的已经达成,且服务器规模足够大,各种配套的设施也会比较健全,运维成本也相对可控。当扩展到三个点之后,新机房基础设施磨合、运维决策的成本等都会大幅增加。
  • 消息同步服务化:建议扩展各自的消息服务,从中间件或者服务层面直接支持跨机房消息同步,将消息体大小控制在 10k 以下,跨机房消息同步的性能和成本都比较可控。机房间的数据一致性只通过消息同步服务解决,机房内部解决缓存等与消息的一致性问题。跨机房消息同步的核心点在于消息不能丢,微博由于使用的是 MCQ,通过本地写远程读的方式,可以很方便的实现高效稳定的跨机房消息同步。

异地多活的新方向

时间到了 2015 年,新技术层出不穷,之前很多成本很高的事情目前都有了很好的解决方案。接下来我们将在近五年异地多活部署探索的基础上,继续将微博的异地多活部署体系化。

升级跨机房消息同步组件为跨机房消息同步服务。面向业务隔离跨机房消息同步的复杂性,业务只需要对消息进行处理即可,消息的跨机房分发、一致性等由跨机房同步服务保障。且可以作为所有业务跨机房消息同步的专用通道,各个业务均可以复用,类似于快递公司的角色。

推进 Web 层的异地部署。由于远距离专线成本巨大且稳定性很难保障,我们已暂时放弃远程异地部署,而改为业务逻辑近距离隔离部署,将 Web 层进行远程异地部署。同时,计划不再依赖昂贵且不稳定的专线,而借助于通过算法寻找较优路径的方法通过公网进行数据传输。这样我们就可以将 Web 层部署到离用户更近的机房,提升用户的访问性能。依据我们去年做微博 Feed 全链路的经验,中间链路占掉了 90% 以上的用户访问时间将 Web 层部署的离用户更近,将能大大提升用户访问性能和体验

借助微服务解决中小服务依赖问题。将对资源等的操作包装为微服务,并将中小业务迁移到微服务架构。这样只需要对几个微服务进行异地多活部署改造,众多的中小业务就不再需要关心异地部署问题,从而可以低成本完成众多中小服务的异地多活部署改造。

利用 Docker 提升前端快速扩容能力。借助 Docker 的动态扩容能力,当流量过大时分钟级从其他服务池摘下一批机器,并完成本服务池的扩容。之后可以将各种资源也纳入到 Docker 动态部署的范围,进一步扩大动态调度的机器源范围。

以上是对微博异地多活部署的一些总结和思考,希望能够对大家有所启发,也希望看到更多的同学分享一下各自公司的异地多活架构方案。

编后语

为了更好地向读者输出更优质的内容,InfoQ 将精选来自国内外的优秀文章,经过整理审校后,发布到网站。本文首发于 “微博平台架构” 微信公众号,已由原作者授权 InfoQ 中文站转载。

关于作者

刘道儒,毕业于北京信息工程学院,现任微博平台研发高级技术经理、Feed 项目技术负责人,负责 Feed 体系后端研发,先后在 TRS、搜狗、新浪微博从事社区 & 社交业务研发,专注于大规模分布式系统的研发、高可用等领域。他曾代表平台在 2012 年主导了微博广州机房部署项目以及北京双机房部署项目。

 


孙宇聪/1.8 来自Google 的高可用架构理念与实践75
1.8.1 决定可用性的两大因素76
1.8.2 高可用性方案77
1.8.3 可用性7 级图表80
1.8.4 疑问与解惑.81

讲的人话。。。  
来自 Google 的高可用架构理念与实践 - CODING 博客孙宇聪,CTO @ coding.net 。2007 - 2015 年初在 Google 的 Moutain View 担任 SRE 职位。 参与了 Google 的两个项目:第一个是 Youtube

孙宇聪,CTO @ coding.net 。2007 - 2015 年初在 Google 的 Moutain View 担任 SRE 职位。 参与了 Google 的两个项目:第一个是 Youtube,工作内容涵盖 Video transfer、Coding、Streaming、Global CDN 等;第二个是 Google Cloud Platform Team,主要工作是管理 Google 全球 100 万台左右的服务器,开发用于管理 Google 整个云平台的任务调度、协作的集群管理系统 Omega 。

在 Google 我参与了两个比较大的 Project。

第一个是 YouTube,其中包括 Video transcoding,streaming 等。Google 的量很大,每个月会有 1PB 级别的存储量。存储、转码后,我们还做 Global CDN。到 2012 年的时候,峰值流量达到 10 TBps,全球 10 万个节点,几乎每台机器都是 16/24 核跑满, 10G uplink 也是跑满的状态。

然后我加入了 Google Cloud Platform Team, 也就是 Borg 团队。这个团队的主要工作是就是管理 Google 全球所有的服务器,全球大概有 100 万台左右。另外就是维护 Borg 系统,同时我也是 Omega 系统运维的主要负责人,很可惜这个项目最后由于各种各样的原因在内部取消了。

下面我想跟大家分享的是关于可用性、可靠性上面的一些理念和思考。

一、决定可用性的两大因素

谈可用性不需要绕来绕去,大家只谈 SLA 即可。大家可以看下面这个图:

要谈可用性,首先必须承认所有东西都有不可用的时候,只是不可用程度而已。一般来说,我们的观念里一个服务至少要做到 99.9% 才称为基本上可用,是合格性产品。否则基本很难被别人使用。

从 3 个 9 迈向 4 个 9,从 8 小时一下缩短到 52.6 分钟的不可用时间,是一个很大的进步。Google 内部只有 4 个 9 以上的服务才会配备 SRE,SRE 是必须在接到报警 5 分钟之内上线处理问题的,否则报警系统自动升级到下一个 SRE。如果还没有,直接给老板发报警。

大家之前可能听说谷歌搜索服务可用度大概是全球 5 个 9,6 个 9 之间。其实这是一个多层,多级,全球化的概念,具体到每个节点其实没那么高。比如说当年北京王府井楼上的搜索集群节点就是按 3 个 9 设计的。

有关 SLA 还有一个秘密,就是一般大家都在谈年 SLA,但是年 SLA 除了客户赔款以外,一般没有任何实际工程指导意义。 Google 内部更看重的是季度 SLA,甚至月 SLA,甚至周 SLA。这所带来的挑战就更大了。

为什么说看这个图有用,因为 99%、99.9% 是基本可以靠运气搞定的哦。到 3 个 9 可以靠堆人,也就是 3 班倒之类的强制值班基本搞定。但是从 3 个 9 往上,就基本超出了人力的范畴,考验的是业务的自愈能力,架构的容灾、容错设计,灾备系统的完善等等。

说了这么多,作为一个架构者,我们如何来系统的分解 “提升 SLA” 这一个难题呢。

这里我引入两个工业级别的概念 MTBF 和 MTTR。

MTBF: Mean time between Failures。 用通俗的话讲,就是一个东西有多不可靠,多长时间坏一次。
MTTR: Mean time to recover。意思就是一旦坏了,恢复服务的时间需要多长。

有了这两个概念, 我们就可以提出:

一个服务的可用度,取决于 MTBF 和 MTTR 这两个因子。从这个公式出发,结合实际情况,就很好理清高可用架构的基本路数了。那就是: 要么提高 MTBF, 要么降低 MTTR。除此之外别无他法。

要注意的是,考虑 MTBF 和 MTTR 的时候都不能脱离现实。

理论上来说,作为一个正常人类,收到突发报警、能正确的分析出问题所在、找到正确的解决方案、并且 【正确实施】的时间极限大概是 【两分钟】。这个标准我个人觉得是高到天上去了。作为一个苦练多年的 Oncall 工程师,我 2 分钟能看清报警,上了 VPN,找到 dashboard,就不错了。就算是已知问题,有应对方案,能敲对命令,完全成功,也至少需要 15 - 20 分钟。所以如果按照这个标准的话,管理的服务如果想达到 4 个 9,那么一年只能坏 1 次,2 次就超标了。实现高可用基本靠运气~

回过来接着说说 MTBF 吧。请各位想一下,影响服务 MTBF 的三大因素!

  1. 发布
  2. 发布
  3. 还是发布!

这个术语上叫 Age Mortality Risk。

一般一个服务只要你不去碰他一年都不会坏一次。更新越频繁,坏的可能性就越大。凡是 Software 都有 BUG,修 BUG 的更新也会引入新的 BUG。发布新版本,新功能是 MTBF 最大的敌人。

二、高可用性方案

说了 MTBF 和 MTTR 这两个定义,那么具体究竟应该如何落地实践来提高可用性呢?

首先说几个大家可能都听腻了的方案

一、提高冗余度,多实例运行,用资源换可用性。

虽然道理很简单,实现起来可不简单,有很多很多细节上的东西需要考虑。

第一个细节:N + 2 应该是标配。

N + 2 就是说平时如果一个服务需要 1 个实例正常提供服务,那么我们就在生产环境上应该部署 1 + 2 = 3 个节点。大家可能觉得 N + 1 很合理,也就是有个热备份系统,比较能够接受。但是你要想到:服务 N + 1 部署只能提供热备容灾,发布的时候就失去保护了。

因为刚才说了, 发布不成功的几率很高!

从另一个角度来讲,服务 N + 2 说的是在丢失两个最大的实例的同时,依然可以维持业务的正常运转。

这其实就是最近常说的两地三中心的概念有点像。

第二个细节: 实例之间必须对等、独立。

千万不要搞一大一小,或者相互依赖。否则你的 N + 2 就不是真的 N + 2。如果两地三中心的一个中心是需要 24 小时才能迁移过去的,那他就不是一个高可用性部署,还是叫异地灾备系统吧。

第三个细节:流量控制能力非常重要。

想做到高可用,必须拥有一套非常可靠的流量控制系统。这套系统按常见的维度,比如说源 IP,目标 IP 来调度是不够的,最好能按业务维度来调度流量。比如说按 API, 甚至按用户类型,用户来源等等来调度。

为什么?因为一个高可用系统必须要支持一下几种场景:

  1. Isolation。A 用户发来的请求可能和 B 用户发来的请求同时处理的时候有冲突,需要隔离。
  2. Quarantine。用户 A 发来的请求可能资源消耗超标,必须能将这类请求钉死在有限的几个节点上,从而顾全大局。
  3. Query-of-death。大家都遇到过吧。上线之后一个用户发来个一个异常请求直接搞挂服务。连续多发几个,整个集群都挂没了,高可用还怎么做到?那么,对这种类型的防范就是要在死掉几台服务器之后可以自动屏蔽类似的请求。需要结合业务去具体分析。

但是想要达到高可用,这些都是必备的,也是一定会遇到的场景。还是那句话,靠人是没戏的。

二、变更管理(Change Management)

还记得影响 MTBF 最大的因子吗?发布质量不提高,一切都是空谈。

第一点: 线下测试(Offline Test)

线下测试永远比线上调试容易一百倍,也安全一百倍。

这个道理很简单,就看执行。如果各位的团队还没有完整的线下测试环境,那么我的意见是不要再接新业务了,花点时间先把这个搞定。这其中包括代码测试、数据兼容性测试、压力测试等等。

台上一分钟,台下十年功。

可用性的阶段性提高,不是靠运维团队,而是靠产品团队。能在线下完成的测试,绝不拍脑门到线上去实验。

第二点:灰度发布

这个道理说起来好像也很普通,但是具体实施起来是很有讲究的。

首先灰度发布是速度与安全性作为妥协。他是发布众多保险的最后一道,而不是唯一的一道。如果只是为了灰度而灰度,故意人为的拖慢进度,反而造成线上多版本长期间共存,有可能会引入新的问题。

做灰度发布,如果是匀速的,说明没有理解灰度发布的意义。一般来说阶段选择上从 1% -> 10% -> 100% 的指数型增长。这个阶段,是根据具体业务不同按维度去细分的。

这里面的重点在于 1% 并不全是随机选择的,而是根据业务特点、数据特点选择的一批有极强的代表性的实例,去做灰度发布的小白鼠。甚至于每次发布的 第一阶段用户(我们叫 Canary / 金丝雀) ,根据每次发布的特点不同,是人为挑选的。

如果要发布一个只给亚洲用户使用的功能,很明显用美国或欧洲的集群来做发布实验,是没有什么意义的。从这个角度来想,是不是灰度发布可做的事情很多很多?真的不只是按机器划分这么简单。

回到本质:灰度发布是上线的最后一道安全防护机制。即不能过慢,让产品团队过度依赖,也不能过于随机,失去了他的意义。

总之,灰度发布,全在细节里。

第三点:服务必须对回滚提供支持

这点不允许商量!

这么重要的话题,我还要用一个感叹号来强调一下!

但是估计现实情况里,大家都听过各种各样的理由吧。我这里有三条买也买不到的秘籍,今天跟大家分享一下,保证药到病除。

理由 1:我这个数据改动之后格式跟以前的不兼容了,回退也不能正常!
秘籍 1:设计、开发时候就考虑好兼容性问题!!!比如说数据库改字段的事就不要做,改成另加一个字段就好。数据存储格式就最好采用 protobuf 这种支持数据版本、支持前后兼容性的方案。最差的情况,也要在变更实施『之前』,想清楚数据兼容性的问题。没有回滚脚本,不给更新,起码做到有备而战。

理由 2:我这个变更删掉东西了!回退之后数据也没了!
秘籍 2:你一定是在逗我。把这个变更打回去,分成两半。第一半禁止访问这个数据。等到发布之后真没问题了,再来发布第二半,第二半真正删掉数据。这样第一半实施之后需要回滚还可以再回去

理由 3:我这个变更发布了之后, 其他依赖这个系统的人都拿到了错误的数据,再回退也没用了,他们不会再接受老数据了!
秘籍 3:这种比较常见出现在配置管理、缓存等系统中。对这类问题,最重要的就是, 应该开发一种跟版本无关的刷新机制。触发刷新的机制应该独立于发布过程要有一个强制刷新数据的手段

以上三个秘籍覆盖了 100% 的回滚兼容性问题,如果有不存在的,请务必告诉我!

回滚兼容性问题,是一个整体难题。只有开发和运维都意识到这个问题的严重性,才能从整体上解决这个问题。而解决不了回滚难题,就不可能达到高可用

三、可用性 7 级图表

说完了变更管理,给大家带来一个 7 级图表,可以看看自己的服务到底在哪个可用性的级别上。

当一个服务挂了的时候......

第一级:Crash with data corruption, destruction.

内存数据库就容易这样。出现个意外情况,所有数据全丢。写硬盘写到一半,挂了之后,不光进程内数据没了,老数据都丢光了。碰上这样的系统,我只能对你表示同情了。

第二级:Crash with new data loss.

一般来说 正常的服务都应该做到这一点...... 。挂了之后最多只丢个几秒之内的数据。

第三级:Crash without data loss.

要达到这一级,需要付出一定程度的技术投入。起码搞清楚如何绕过 OS 各种 Cache,如何绕过硬件的各种坑

第四级:No crash, but with no or very limited service, low service quality.

做的好一点的系统,不要动不动就崩溃了...... 如果一个程序能够正常处理异常输入,异常数据等,那么就给刚才说的高级流控系统创造了条件。可以把其他的用户流量导入过来,把问题流量发到一边去,不会造成太大的容量损失。

第五级:Partial or limited service, with good to medium service quality.

这一级就还好了,如果多个业务跑在同一个实例上,那么起码不要全部坏掉。有部分服务,比完全没有服务要好

第六级:Failover with significant user visible delay, near full quality of service

上升到这一级别,才摸到高可用的门,也就是有容灾措施。但是可能自动化程度不高,或者是一些关键性问题没有解决,所以业务能恢复,就是比较慢。

第七级:Failover with minimal to none user visible delay, near full quality

of service.

这边蝴蝶扇了一下翅膀,天空落了个打雷,打掉了一整个机房,结果业务完全没受影响。蓝翔技校一铲子下去,互联网都要抖一抖。嘿嘿, 高可用就是为了这种事情做准备。

Q & A

1. 有什么评测系统吗?

评测系统的第一步是收集足够的信息。想知道自己的服务是不是高可用,必须得先监测啊!不光黑盒监测,还要有白盒监测。如果有一个自动化的 SLA 监控系统,能显示实时的 SLA 变化 ,会对系统的开发计划有很强烈的指导作用。

2. 能详细说一下做到 “crash without data loss” 需要在哪些点上下功夫吗?

这个事情说起来简单,实际实现起来非常复杂。 因为很多东西深究起来都有无数的坑。 比如说:

OS 的 Cache 如何绕过。
系统硬件可能也有内置的 Cache,Firmware 也可能有 BUG 等等等等。还有一些集群系统为了所谓的性能实现的 fake sync。

这里是列不全的。我提出这个等级的意思,是想让大家有这个意识去系统化的应对这个问题。比如说关键数据是不是要多存几分,然后做一些 destruction 测试。比如多模拟断电等等的极端情况,这样才能有备无患。扫雷比触雷要容易多了。

3. 现在 Coding.net 到几个 9 了,7 张图中第几级了,改造花了多长时间,有哪些坑分享下?

首先高可用是按业务来的,不是所有业务都能做到高可用,也不是所有都需要做到高可用。我们下了很大精力在关键业务上,比如说 Git 系统的流控,数据安全等等,其他的就没办法啦。

4. 开发团队要怎样配合?周期怎么样配合?侧重点各自在哪 (开发更侧重业务)?

首先就是要确定一个共同目标。高可用是有代价的,你的业务需要做到什么程度,一定是一个系统性的考虑。给大家举一个例子,Youtube 这么多视频, 但是每个视频的每种格式,只存了 1 份。所以可用性肯定受影响了。但是,数据量实在是太大了,然后各种小猫视频实在是不重要。相比之下,广告视频经常存 8 份。所以!想要提高可用性,必须要和开发团队找到一个共同目标。这里再给大家一个秘籍,那就是 error budget。跟开发团队确定一个可用度,比如说 99% 。 如果业务团队搞出来的东西很烂,各种状况,最后达不到这个标准。那么对不起,暂时别发新功能,只修 BUG。

5. 谷歌的 SRE 工程师用了哪些开源工具来管理百万机器?

比较惭愧,我们没用什么开源工具,都是内部自己开发的。企业内部管理用了 Puppet,但是生产系统上没有。

6. 请问一下实现独立对等的 N+2 服务使用什么架构比较好,LVS+Keepalive 的双机热备是否合适?

莫非现在不都用 haproxy / nginx 之类的 7 层代理?但是其实这个原理都差不多。只要达到你的目的,可以动态切换就好。

https://www.jianshu.com/p/fa937b8e6712

四层、七层负载均衡的区别

 

7. “可以把其他的用户流量导入过来。把问题流量发到一边去,不会造成太大的容量损失。” 这句话怎么理解呢? 另外如何区分问题流量?

这句话说的是刚才提到的高可用必不可少的流控系统。任何一个系统都不是完美的,总会有各种各样的 hot spot,weak spot。问题流量的定义是跟业务紧密相关的。我再举一个例子:当年 Youtube 的 CDN 服务器有个问题,后端存储慢了之后,前端的请求会聚在一起,就像水管一样,于是内存就爆了。突然压力过高,肯定就挂了。如何处理这个问题? 最后流控系统升级,每个实例自己汇报自己的内存状况,超标之后流控系统自动绕过他。把这个问题变成了自动化处理的方案,问题面大大缩小了。再举一个例子,搜索系统是典型的热点密集型系统。有的冷僻词, 查一次要去各种读硬盘。而热词,消耗很小。所以流控系统做了个功能每个请求回复都带了 cost 值,流控系统自动均衡了整个集群。——> 就应该强化学习搞

8. 关于回滚那里,如果我要新增一个删除功能,怎么做到把这个操作拆成两半,用户做了删除操作,可是禁止删除数据,那是否会产生数据不一致的?

这个是刚才说的那个秘籍第二条。其实秘籍第二条就是拆!没有什么发布是不能拆的。 拆到可以安全的往前滚再往后滚

9. 100W 台服务器如何自动化管理、及时发现故障、自动修复、做出报警,能否简单介绍介绍?

这个问题其实没那么复杂。就是在每个机器上运行一个 agent,这个 agent 定期进行检查操作,有问题就通知管理系统自动下线。只要注意平时收集问题现象就行了。比如说线上突然出现了一个时间不同的问题,那么就把他加到这个 agent 里去,下次这个问题就是自动检测自动修复的了。

10. 有没有什么好办法处理 query to death?

这个问题比较难,一般是要做一层智能一点的业务 proxy 。业务 proxy 检测到请求发到哪,哪个后端挂,就可以进行一些处理了。还有一个办法是在挂之前后端记 log,处理之前记上。我要处理这个请求了,然后处理一半挂掉了。重启之后,检查 log 发现上次是处理这个请求挂了,那么就可以屏蔽掉这个请求。

转载自 "高可用架构 (ArchNotes)" 微信公众号

 


那 谁/1.9 深入理解同步/异步与阻塞/非阻塞区别84
1.9.1 同步与异步.84
1.9.2 阻塞与非阻塞85
1.9.3 与多路复用I/O 的联系86



第2 章 高可用架构原理与分布式实践.88
黄东旭/2.1 Codis 作者细说分布式Redis 架构设计88
2.1.1 Redis、Redis Cluster 和Codis88
2.1.2 我们更爱一致性90
2.1.3 Codis 在生产环境中的使用经验和坑91
2.1.4 分布式数据库和分布式架构.94
2.1.5 疑问与解惑.95

Codis 作者黄东旭:细说分布式 Redis 架构设计和那些踩过的坑 - 架构 - dbaplus 社群:围绕 Data、Blockchain、AiOps 的企业级专业社群。技术大咖、原创干货,每天精品原创文章推送,每周线上技术分享,每月线下技术沙龙。Redis 是个好东西,但如何平行扩展,如何高可用,是每个 redis 使用者心中的痛。

Codis 是一个分布式 Redis 解决方案,与官方的纯 P2P 模式不同,Codis 采用的是 Proxy-based 的方案。今天我们介绍一下 Codis 以及下一个大版本 RebornDB 的设计,同时会介绍 Codis 在实际应用场景中的一些 tips。最后抛砖引玉,介绍一下我对分布式存储的一些观点和看法。

目录


  • Redis、RedisCluster 和 Codis

  • 我们更爱一致性

  • Codis 在生产环境中的使用的经验和坑们

  • 对于分布式数据库和分布式架构的一些看法

  • 答疑记录


1Redis,RedisCluster 和 Codis

1、Redis:想必大家的架构中,Redis 已经是一个必不可少的部件,丰富的数据结构和超高的性能以及简单的协议,让 Redis 能够很好的作为数据库的上游缓存层。但是我们会比较担心 Redis 的单点问题,单点 Redis 容量大小总受限于内存,在业务对性能要求比较高的情况下,理想情况下我们希望所有的数据都能在内存里面,不要打到数据库上,所以很自然的就会寻求其他方案。 比如,SSD 将内存换成了磁盘,以换取更大的容量。

更自然的想法是将 Redis 变成一个可以水平扩展的分布式缓存服务,在 Codis 之前,业界只有 Twemproxy,但是 Twemproxy 本身是一个静态的分布式 Redis 方案,进行扩容 / 缩容时候对运维要求非常高,而且很难做到平滑的扩缩容。Codis 的目标其实就是尽量兼容 Twemproxy 的基础上,加上数据迁移的功能以实现扩容和缩容,最终替换 Twemproxy。从豌豆荚最后上线的结果来看,最后完全替换了 Twem,大概 2T 左右的内存集群。

2、Redis Cluster  :与 Codis 同期发布正式版的官方 cluster,我认为有优点也有缺点,作为架构师,我并不会在生产环境中使用,原因有两个:


  • cluster 的数据存储模块和分布式的逻辑模块是耦合在一起的,这个带来的好处是部署异常简单,all-in-the-box,没有像 Codis 那么多概念,组件和依赖。但是带来的缺点是,你很难对业务进行无痛的升级。比如哪天 Redis cluster 的分布式逻辑出现了比较严重的 bug,你该如何升级? 除了滚动重启整个集群,没什么好办法。这个比较伤运维。


  • 对协议进行了较大的修改,对客户端不太友好,目前很多客户端已经成为事实标准,而且很多程序已经写好了,让业务方去更换 Redisclient,是不太现实的,而且目前很难说有哪个 Rediscluster 客户端经过了大规模生产环境的验证,从 HunanTV 开源的 Rediscluster proxy 上可以看得出这个影响还是蛮大的,否则就会支持使用 cluster 的 client 了。

3、Codis:和 Redis cluster 不同的是,Codis 采用一层无状态的 proxy 层,将分布式逻辑写在 proxy 上,底层的存储引擎还是 Redis 本身(尽管基于 Redis2.8.13 上做了一些小 patch),数据的分布状态存储于 zookeeper(etcd) 中,底层的数据存储变成了可插拔的部件。这个事情的好处其实不用多说,就是各个部件是可以动态水平扩展的,尤其无状态的 proxy 对于动态的负载均衡,还是意义很大的,而且还可以做一些有意思的事情,比如发现一些 slot 的数据比较冷,可以专门用一个支持持久化存储的 server group 来负责这部分 slot,以节省内存,当这部分数据变热起来时,可以再动态的迁移到内存的 server group 上,一切对业务透明。比较有意思的是,在 Twitter 内部弃用 Twmeproxy 后,t 家自己开发了一个新的分布式 Redis 解决方案,仍然走的是 proxy-based 路线。不过没有开源出来。

可插拔存储引擎这个事情也是 Codis 的下一代产品 RebornDB 在做的一件事情。btw,RebornDB 和它的持久化引擎都是完全开源的,见 https://github.com/reborndb/reborn 和 https://github.com/reborndb/qdb。当然这样的设计的坏处是,经过了 proxy,多了一次网络交互,看上去性能下降了一些,但是记住,我们的 proxy 是可以动态扩展的,整个服务的 QPS 并不由单个 proxy 的性能决定(所以生产环境中我建议使用 LVS/HA Proxy 或者 Jodis),每个 proxy 其实都是一样的。


2我们更爱一致性

很多朋友问我,为什么不支持读写分离,其实这个事情的原因很简单,因为我们当时的业务场景不能容忍数据不一致,由于 Redis 本身的 replication 模型是主从异步复制,在 master 上写成功后,在 slave 上是否能读到这个数据是没有保证的,而让业务方处理一致性的问题还是蛮麻烦的。而且 Redis 单点的性能还是蛮高的,不像 mysql 之类的真正的数据库,没有必要为了提升一点点读 QPS 而让业务方困惑。这和数据库的角色不太一样。所以,你可能看出来了,其实 Codis 的 HA,并不能保证数据完全不丢失,因为是异步复制,所以 master 挂掉后,如果有没有同步到 slave 上的数据,此时将 slave 提升成 master 后,刚刚写入的还没来得及同步的数据就会丢失。不过在 RebornDB 中我们会尝试对持久化存储引擎(qdb)可能会支持同步复制 (syncreplication),让一些对数据一致性和安全性有更强要求的服务可以使用。

说到一致性,这也是 Codis 支持的 MGET/MSET 无法保证原本单点时的原子语义的原因。 因为 MSET 所参与的 key 可能分不在不同的机器上,如果需要保证原来的语义,也就是要么一起成功,要么一起失败,这样就是一个分布式事务的问题,对于 Redis 来说,并没有 WAL 或者回滚这么一说,所以即使是一个最简单的二阶段提交的策略都很难实现,而且即使实现了,性能也没有保证。所以在 Codis 中使用 MSET/MGET 其实和你本地开个多线程 SET/GET 效果一样,只不过是由服务端打包返回罢了,我们加上这个命令的支持只是为了更好的支持以前用 Twemproxy 的业务。

在实际场景中,很多朋友使用了 lua 脚本以扩展 Redis 的功能,其实 Codis 这边是支持的,但记住,Codis 在涉及这种场景的时候,仅仅是转发而已,它并不保证你脚本操作的数据是否在正确的节点上。比如,你的脚本里涉及操作多个 key,Codis 能做的就是将这个脚本分配到参数列表中的第一个 key 的机器上执行。所以这种场景下,你需要自己保证你的脚本所用到的 key 分布在同一个机器上,这里可以采用 hashtag 的方式。

比如你有一个脚本是操作某个用户的多个信息,如 uid1age,uid1sex,uid1name 形如此类的 key,如果你不用 hashtag 的话,这些 key 可能会分散在不同的机器上,如果使用了 hashtag(用花括号扩住计算 hash 的区域):{uid1}age,{uid1}sex,{uid1}name,这样就保证这些 key 分布在同一个机器上。这个是 twemproxy 引入的一个语法,我们这边也支持了。

在开源 Codis 后,我们收到了很多社区的反馈,大多数的意见是集中在 Zookeeper 的依赖,Redis 的修改,还有为啥需要 Proxy 上面,我们也在思考,这几个东西是不是必须的。当然这几个部件带来的好处毋庸置疑,上面也阐述过了,但是有没有办法能做得更漂亮。于是,我们在下一阶段会再往前走一步,实现以下几个设计:


  • 使用 proxy 内置的 Raft 来代替外部的 Zookeeper,zk 对于我们来说,其实只是一个强一致性存储而已,我们其实可以使用 Raft 来做到同样的事情。将 raft 嵌入 proxy,来同步路由信息。达到减少依赖的效果。


  • 抽象存储引擎层,由 proxy 或者第三方的 agent 来负责启动和管理存储引擎的生命周期。具体来说,就是现在 codis 还需要手动的去部署底层的 Redis 或者 qdb,自己配置主从关系什么的,但是未来我们会把这个事情交给一个自动化的 agent 或者甚至在 proxy 内部集成存储引擎。这样的好处是我们可以最大程度上的减小 Proxy 转发的损耗(比如 proxy 会在本地启动 Redis instance)和人工误操作,提升了整个系统的自动化程度。


  • 还有 replication based migration。众所周知,现在 Codis 的数据迁移方式是通过修改底层 Redis,加入单 key 的原子迁移命令实现的。这样的好处是实现简单、迁移过程对业务无感知。但是坏处也是很明显,首先就是速度比较慢,而且对 Redis 有侵入性,还有维护 slot 信息给 Redis 带来额外的内存开销。大概对于小 key-value 为主业务和原生 Redis 是 1:1.5 的比例,所以还是比较费内存的。

在 RebornDB 中我们会尝试提供基于复制的迁移方式,也就是开始迁移时,记录某 slot 的操作,然后在后台开始同步到 slave,当 slave 同步完后,开始将记录的操作回放,回放差不多后,将 master 的写入停止,追平后修改路由表,将需要迁移的 slot 切换成新的 master,主从(半)同步复制,这个之前提到过。


3Codis 在生产环境中的使用的经验和坑们

来说一些 tips,作为开发工程师,一线的操作经验肯定没有运维的同学多,大家一会可以一起再深度讨论。

1、关于多产品线部署:很多朋友问我们如果有多个项目时,codis 如何部署比较好,我们当时在豌豆荚的时候,一个产品线会部署一整套 codis,但是 zk 共用一个,不同的 codis 集群拥有不同的 product name 来区分,codis 本身的设计没有命名空间那么一说,一个 codis 只能对应一个 product name。不同 product name 的 codis 集群在同一个 zk 上不会相互干扰。

2、关于 zk:由于 Codis 是一个强依赖的 zk 的项目,而且在 proxy 和 zk 的连接发生抖动造成 sessionexpired 的时候,proxy 是不能对外提供服务的,所以尽量保证 proxy 和 zk 部署在同一个机房。生产环境中 zk 一定要是 >=3 台的奇数台机器,建议 5 台物理机。

3、关于 HA:这里的 HA 分成两部分,一个是 proxy 层的 HA,还有底层 Redis 的 HA。先说 proxy 层的 HA。之前提到过 proxy 本身是无状态的,所以 proxy 本身的 HA 是比较好做的,因为连接到任何一个活着的 proxy 上都是一样的,在生产环境中,我们使用的是 jodis,这个是我们开发的一个 jedis 连接池,很简单,就是监听 zk 上面的存活 proxy 列表,挨个返回 jedis 对象,达到负载均衡和 HA 的效果。也有朋友在生产环境中使用 LVS 和 HA Proxy 来做负载均衡,这也是可以的。 Redis 本身的 HA,这里的 Redis 指的是 codis 底层的各个 server group 的 master,在一开始的时候 codis 本来就没有将这部分的 HA 设计进去,因为 Redis 在挂掉后,如果直接将 slave 提升上来的话,可能会造成数据不一致的情况,因为有新的修改可能在 master 中还没有同步到 slave 上,这种情况下需要管理员手动的操作修复数据。后来我们发现这个需求确实比较多的朋友反映,于是我们开发了一个简单的 ha 工具:codis-ha,用于监控各个 server group 的 master 的存活情况,如果某个 master 挂掉了,会直接提升该 group 的一个 slave 成为新的 master。 项目的地址是:https://github.com/ngaut/codis-ha

4、关于 dashboard:dashboard 在 codis 中是一个很重要的角色,所有的集群信息变更操作都是通过 dashboard 发起的(这个设计有点像 docker),dashboard 对外暴露了一系列 RESTfulAPI 接口,不管是 web 管理工具,还是命令行工具都是通过访问这些 httpapi 来进行操作的,所以请保证 dashboard 和其他各个组件的网络连通性。比如,经常发现有用户的 dashboard 中集群的 ops 为 0,就是因为 dashboard 无法连接到 proxy 的机器的缘故。

5、关于 go 环境:在生产环境中尽量使用 go1.3.x 的版本,go 的 1.4 的性能很差,更像是一个中间版本,还没有达到 production ready 的状态就发布了。很多朋友对 go 的 gc 颇有微词,这里我们不讨论哲学问题,选择 go 是多方面因素权衡后的结果,而且 codis 是一个中间件类型的产品,并不会有太多小对象常驻内存,所以对于 gc 来说基本毫无压力,所以不用考虑 gc 的问题。

6、关于队列的设计:其实简单来说,就是不要把鸡蛋放在一个篮子里的道理,尽量不要把数据都往一个 key 里放,因为 codis 是一个分布式的集群,如果你永远只操作一个 key,就相当于退化成单个 Redis 实例了。很多朋友将 Redis 用来做队列,但是 Codis 并没有提供 BLPOP/BLPUSH 的接口,这没问题,可以将列表在逻辑上拆成多个 LIST 的 key,在业务端通过定时轮询来实现(除非你的队列需要严格的时序要求),这样就可以让不同的 Redis 来分担这个同一个列表的访问压力。而且单 key 过大可能会造成迁移时的阻塞,由于 Redis 是一个单线程的程序,所以迁移的时候会阻塞正常的访问。

7、关于主从和 bgsave:codis 本身并不负责维护 Redis 的主从关系,在 codis 里面的 master 和 slave 只是概念上的:proxy 会将请求打到「master」上,master 挂了 codis-ha 会将某一个「slave」提升成 master。而真正的主从复制,需要在启动底层的 Redis 时手动的配置。在生产环境中,我建议 master 的机器不要开 bgsave,也不要轻易的执行 save 命令,数据的备份尽量放在 slave 上操作。

8、关于跨机房 / 多活:想都别想。codis 没有多副本的概念,而且 codis 多用于缓存的业务场景,业务的压力是直接打到缓存上的,在这层做跨机房架构的话,性能和一致性是很难得到保证的。

9、关于 proxy 的部署:其实可以将 proxy 部署在 client 很近的地方,比如同一个物理机上,这样有利于减少延迟,但是需要注意的是,目前 jodis 并不会根据 proxy 的位置来选择位置最佳的实例,需要修改。


4对于分布式数据库和分布式架构的一些看法(one more thing)

Codis 相关的内容告一段落。接下来我想聊聊我对于分布式数据库和分布式架构的一些看法。 架构师们是如此贪心,有单点就一定要变成分布式,同时还希望尽可能的透明: P。就 MySQL 来看,从最早的单点到主从读写分离,再到后来阿里的类似 Cobar 和 TDDL,分布式和可扩展性是达到了,但是牺牲了事务支持,于是有了后来的 OceanBase。Redis 从单点到 Twemproxy,再到 Codis,再到 Reborn。到最后的存储早已和最初的面目全非,但协议和接口永存,比如 SQL 和 Redis Protocol。

NoSQL 来了一茬又一茬,从 HBase 到 Cassandra 到 MongoDB,解决的是数据的扩展性问题,通过裁剪业务的存储和查询的模型来在 CAP 上平衡。但是几乎还是都丢掉了跨行事务(插一句,小米上在 HBase 上加入了跨行事务,不错的工作)。

我认为,抛开底层存储的细节,对于业务来说,KV,SQL 查询(关系型数据库支持)和事务,可以说是构成业务系统的存储原语。为什么 memcached/Redis+mysql 的组合如此的受欢迎,正是因为这个组合,几个原语都能用上,对于业务来说,可以很方便的实现各种业务的存储需求,能轻易的写出「正确」的程序。但是,现在的问题是数据大到一定程度上时,从单机向分布式进化的过程中,最难搞定的就是事务,SQL 支持什么的还可以通过各种 mysqlproxy 搞定,KV 就不用说了,天生对分布式友好。

于是这样,我们就默认进入了一个没有(跨行)事务支持的世界里,很多业务场景我们只能牺牲业务的正确性来在实现的复杂度上平衡。比如一个很简单的需求:微博关注数的变化,最直白,最正常的写法应该是,将被关注者的被关注数的修改和关注者的关注数修改放到同一个事务里,一起提交,要么一起成功,要么一起失败。但是现在为了考虑性能,为了考虑实现复杂度,一般来说的做法可能是队列辅助异步的修改,或者通过 cache 先暂存等等方式绕开事务

但是在一些需要强事务支持的场景就没有那么好绕过去了(目前我们只讨论开源的架构方案),比如支付 / 积分变更业务,常见的搞法是关键路径根据用户特征 sharding 到单点 MySQL,或者 MySQLXA,但是性能下降得太厉害。

后来 Google 在他们的广告业务中遇到这个问题,既需要高性能,又需要分布式事务,还必须保证一致性。Google 在此之前是通过一个大规模的 MySQL 集群通过 sharding 苦苦支撑,这个架构的可运维 / 扩展性实在太差。这要是在一般公司,估计也就忍了,但是 Google 可不是一般公司,用原子钟搞定 Spanner,然后在 Spanner 上构建了 SQL 查询层 F1。我在第一次看到这个系统的时候,感觉太惊艳了,这应该是第一个可以真正称为 NewSQL 的公开设计系统。所以,BigTable(KV)+F1(SQL)+Spanner(高性能分布式事务支持),同时 Spanner 还有一个非常重要的特性是跨数据中心的复制和一致性保证(通过 Paxos 实现),多数据中心,刚好补全了整个 Google 的基础设施的数据库栈。这样一来,对于 Google,几乎任何类型的业务系统开发起来都非常方便。我想,这就是未来的方向吧,一个可扩展的 KV 数据库作为缓存和简单对象存储,一个高性能支持分布式事务和 SQL 查询接口的分布式关系型数据库,提供表支持。


Spanner 是Google的全球级的分布式数据库 (Globally-Distributed Database) 。Spanner的扩展性达到了令人咋舌的全球级,可以扩展到数百万的机器,数已百计的数据中心,上万亿的行。更给力的是,除了夸张的扩展性之外,他还能同时通过同步复制和多版本来满足外部一致性,可用性也是很好的。冲破CAP的枷锁,在三者之间完美平衡

Spanner是个可扩展,多版本,全球分布式还支持同步复制的数据库。他是Google的第一个可以全球扩展并且支持外部一致的事务。Spanner能做到这些,离不开一个用GPS和原子钟实现的时间API这个API能将数据中心之间的时间同步精确到10ms以内。因此有几个给力的功能:无锁读事务,原子schema修改,读历史数据无block。


5答疑记录

Q1:我没看过 Codis,您说 Codis 没有多副本概念,请问是什么意思?

A1:Codis 是一个分布式 Redis 解决方案,是通过 presharding 把数据在概念上分成 1024 个 slot,然后通过 proxy 将不同的 key 的请求转发到不同的机器上,数据的副本还是通过 Redis 本身保证。

Q2:Codis 的信息在一个 zk 里面存储着,zk 在 Codis 中还有别的作用吗?主从切换为何不用 sentinel。

A2:Codis 的特点是动态的扩容缩容,对业务透明。zk 除了存储路由信息,同时还作为一个事件同步的媒介服务,比如变更 master 或者数据迁移这样的事情,需要所有的 proxy 通过监听特定 zk 事件来实现可以说 zk 被我们当做了一个可靠的 rpc 的信道来使用。因为只有集群变更的 admin 时候会往 zk 上发事件,proxy 监听到以后,回复在 zk 上,admin 收到各个 proxy 的回复后才继续。本身集群变更的事情不会经常发生,所以数据量不大。Redis 的主从切换是通过 codis-ha 在 zk 上遍历各个 server group 的 master 判断存活情况,来决定是否发起提升新 master 的命令。

Q3:数据分片,是用的一致性 hash 吗?请具体介绍下,谢谢。

A3:不是,是通过 presharding,hash 算法是 crc32(key)%1024

Q4:怎么进行权限管理?

A4:Codis 中没有鉴权相关的命令,在 reborndb 中加入了 auth 指令。

Q5:怎么禁止普通用户链接 Redis 破坏数据?

A5:同上,目前 Codis 没有 auth,接下来的版本会加入。

Q6:Redis 跨机房有什么方案?

A6:目前没有好的办法,我们的 Codis 定位是同一个机房内部的缓存服务,跨机房复制对于 Redis 这样的服务来说,一是延迟较大,二是一致性难以保证,对于性能要求比较高的缓存服务,我觉得跨机房不是好的选择。

Q7:集群的主从怎么做(比如集群 S 是集群 M 的从,S 和 M 的节点数可能不一样,S 和 M 可能不在一个机房)?

A7:Codis 只是一个 proxy-based 的中间件,并不负责数据副本相关的工作。也就是数据只有一份,在 Redis 内部。

Q8:根据你介绍了这么多,我可以下一个结论,你们没有多租户的概念,也没有做到高可用。可以这么说吧?你们更多的是把 Redis 当做一个 cache 来设计

A8:对,其实我们内部多租户是通过多 Codis 集群解决的,Codis 更多的是为了替换 twemproxy 的一个项目。高可用是通过第三方工具实现。Redis 是 cache,Codis 主要解决的是 Redis 单点、水平扩展的问题。把 codis 的介绍贴一下: Auto rebalance Extremely simple to use Support both Redis or rocksdb transparently. GUI dashboard & admin tools Supports most of Redis commands. Fully compatible with twemproxy(https://github.com/twitter/twemproxy). Native Redis clients are supported Safe and transparent data migration, Easily add or remove nodes on-demand. 解决的问题是这些。业务不停的情况下,怎么动态的扩展缓存层,这个是 codis 关注的。

Q9:对于 Redis 冷备的数据库的迁移,您有啥经验没有?对于 Redis 热数据,可以通过 migrate 命令实现两个 Redis 进程间的数据转移,当然如果对端有密码,migrate 就不行了(这个我已经给 Redis 官方提交了 patch)。

A9:冷数据我们现在是实现了完整的 Redissync 协议,同时实现了一个基于 rocksdb 的磁盘存储引擎,备机的冷数据,全部是存在磁盘上的,直接作为一个从挂在 master 上的。实际使用时,3 个 group,keys 数量一致,但其中一个的 ops 是另外两个的两倍,有可能是什么原因造成的?key 的数量一致并不代表实际请求是均匀分布的,不如你可能某几个 key 特别热,它一定是会落在实际存储这个 key 的机器上的。刚才说的 rocksdb 的存储引擎:https://github.com/reborndb/qdb,其实启动后就是个 Redis-server,支持了 PSYNC 协议,所以可以直接当成 Redis 从来用。是一个节省从库内存的好方法。

Q10:Redis 实例内存占比超过 50%,此时执行 bgsave,开了虚拟内存支持的会阻塞,不开虚拟内存支持的会直接返回 err,对吗?

A10:不一定,这个要看写数据(开启 bgsave 后修改的数据)的频繁程度,在 Redis 内部执行 bgsave,其实是通过操作系统 COW 机制来实现复制,如果你这段时间的把几乎所有的数据都修改了,这样操作系统只能全部完整的复制出来,这样就爆了。

Q11:刚读完,赞一个。可否介绍下 codis 的 autorebalance 实现。

A11:算法比较简单,https://github.com/wandoulabs/codis/blob/master/cmd/cconfig/rebalancer.go#L104。代码比较清楚,code talks:)。其实就是根据各个实例的内存比例,分配 slot 好的

Q12:主要想了解对降低数据迁移对线上服务的影响,有没有什么经验介绍?

A12:其实现在 codis 数据迁移的方式已经很温和了,是一个个 key 的原子迁移,如果怕抖动甚至可以加上每个 key 的延迟时间。这个好处就是对业务基本没感知,但是缺点就是慢。

文章来源高可用架构订阅号,经作者同意由 DBA + 社群转发。

作者介绍:黄东旭

  • Ping CAP CTO,开源项目 Codis 的 co-author。

  • 曾在豌豆荚从事 infrastructure 相关的工作,现在在创业公司 PingCAP,方向依然是分布式存储领域 (NewSQL)。

 
   


霍泰稳/2.2 给你介绍一个不一样的硅谷.98
2.2.1 Uber .98
2.2.2 Coursera.99
2.2.3 Airbnb102
2.2.4 硅谷行带给我的一些影响106
2.2.5 疑问与解惑106


金自翔/2.3 解耦的艺术——大型互联网业务系统的插件化改造110
2.3.1 插件化.110
2.3.2 如何处理用户交互115
2.3.3 如何处理数据.115
2.3.4 总结116

解耦的艺术—大型互联网业务系统的插件化改造 | 高可用架构

此文是根据金自翔在【QCON高可用架构群】中的分享内容整理而成,转发请注明出处。

金自翔,百度资深研发工程师。在百度负责商业产品的后端架构,包括基础架构和业务架构。本文主要是根据讲师多年经验,针对业界经常碰到的问题,经过分析与实践提出的一种解决方案。

在大型系统中,“插件化”是对若干类似的子系统进行深度集成的一种方法,“插件化”的特点是能清晰的划分子系统间的边界,从实现上明确的区分系统中“变”与“不变”的部分。

在大的业务系统重构和改造的过程中,使用“插件化”不但能整合底层数据流,还能同时整合上层的流程和交互,在大规模跨团队集成中提供开发者的灵活性、用户体验的一致性和底层系统的安全性。

“插件化”要解决的问题如下图所示

0?wx_fmt=jpeg

图中的差异在不同案例中可能表现为代码思路的差异,用户体验的差异或者是性能的差异。

无论哪种差异,根本问题在于用自然语言描述的规范文档不够形式化,留下了太多不必要的自由发挥的空间。

“插件化”的目的就是尽量减少这些空间的存在。下面结合一个具体案例说下如何具体实施插件化。

这个案例是个源码过千万行的业务系统,整个开发团队规模比较大。该系统集成了很多业务产品,用了很多年,用户很多,需求也一直很频繁,是个核心的业务系统。

讲师观察过业界一些大的系统,经过大的重构拆分成了若干支持系统和业务系统后,拆分出来的系统分别由(组织架构上)独立的团队负责,这样有效减少了团队内沟通的成本。

但正如上图所示,拆分后不可避免的遇到了以下两个问题

1、文档

人员更替,排期压力,都会造成原有设计意图不能得到贯彻。想靠文档规范和约束,文档和代码同步的代价也很大。

尤其是敏捷开发模式下,大量想法没有落实到文档上,初始设计可能不错,但在实施过程中会越走越偏,留下大量不良的耦合与既有实现,维护成本越来越高。以前大团队中通过大规模review能在很大程度上避免这个问题,拆分后跨团队review实施难度很大,基本起不到什么作用。

2、碎片化

技术架构和业务架构的拆分是同时进行的。整个系统架构拆分后,研发和产品团队也拆分组成了垂直的团队,迭代速度快了很多。

但是垂直化不可避免的带来了碎片化的问题。在垂直体系中,每个产品的流程设计、交互设计有着极大的自主权。产品间的差异越来越大,业务流程和用户体验都开始碎片化。

碎片化造成用户的学习和使用成本提高,每个团队都认为自己的设计是最适合自己产品的, 但用户的反馈则是“为啥你们的产品长的都不一样呢?用起来好累。” 然后有些用户就不愿意用这样的系统了。

碎片化的问题越来越严重,开始影响到了整个业务目标的实现。也发现在一些系统中,出现最后老板拍板,把解决碎片化放到最高优先级来解决。

消除碎片化最容易想到的方案是在各产品上再抽一层,作一个新系统(后面称其为U系统),把容易碎片化的流程,交互等工作放到这里统一处理,用户只接触U系统,不再接触各个产品,自然也就没有碎片化的问题。

可是细想想,这方案无非是把问题搬了个地方。因为U系统的需求还是从各产品来的,本来拆完后各产品能自行实现需求(并行),现在只能把需求提到U系统等排期(串行),U系统很可能成为瓶颈,妨碍业务需求的快速响应。

这个方案能保证统一,但丧失了好不容易获得的灵活性,是产品团队不能接受的。

最终解决矛盾的方法就是开始提到的插件化

插件化类似软件设计中的“依赖注入”,将整个系统分成 “引擎”和“插件”两部分。用“引擎”保证统一,用“插件”提供灵活性。

具体实现时,U系统是一套“引擎”(可类比为spring-core这样的框架),自身没有逻辑,只是提供了一组插件规范。

引擎可以解析插件,运行插件中指定的逻辑。

“插件”由接入的产品提供(可类比为spring的配置文件),插件中指定了产品需要的各种逻辑,可随时更改。当“插件”注入到“引擎”后,就完成了新产品接入U系统的工作。

U系统的架构图如下

0?wx_fmt=jpeg

这个设计的好处是, U系统聚焦在作好引擎上就行,大部分提给U系统的需求可以作成配置,而配置的更改可以交给接入产品来完成。这样U系统和接入的产品彼此解耦,有足够的灵活性。至于碎片化的问题,则通过引擎中“用户交互”和“业务流程”两层来解决。

以下详细介绍实现

整个U系统由服务、插件、引擎和通信四大块组成。

其中服务由U系统指定接口,业务产品提供具体实现以供调用。目前业务系统基本都是java实现,RPC框架支持U系统直接发布一个jar包,指定每个接入产品必须提供的一组接口(比如提供基础信息,进行数据校验,提供报表数据等)。每个产品首先要实现这些服务,然后才能接入U系统。

实现服务后,每个产品会提供一个插件(XML)文件,这个文件包含所有定制化的信息,包括

产品使用的流程

产品提供的服务(地址和接口)

交互界面的DSL(控件)

数据处理(展示、格式化、转化)

报表(从何处取,如何处理)

在U系统上传这个插件文件后,系统中就多了一个产品,用户也能看到并使用这个产品。引擎保证了所有插件是可以热插拔的,所以业务变更时只需上传新的插件即可,不用重启和上线,非常方便。

下面说一下引擎,引擎是整个系统最核心的模块,插件的的管理、解析和运行都在这里完成。

引擎模块是独立开发的,并没有采用OSGI的规范实现,而是实现了一套自定义的规范,这是出于以下几点考虑:

1.OSGI更多定位在服务的注册、发现、隔离和调用,而U系统中远程RPC已有成熟的框架完成服务发现和治理的工作。至于引擎自身的代码是可控的,采用进程内调用即可,不需要隔离,进程内的依赖管理用Spring就足够了。

2.OSGI基本没有交互界面相关的功能,而解析插件提供的用DSL处理交互界面和逻辑是引擎很重要的功能。

3.OSGI 的发布采用Bundle方式,可以比较灵活的指定Import和Export功能。但其实并不需要这么灵活,写死引擎提供的接口可以降低使用成本。另外Bundle的构建和发布也没有直接上传XML来的简单。

引擎分层如下:

0?wx_fmt=jpeg

最底层是基础服务。像账户、资金、报表这些功能其实很依赖于外部系统,需要将这些外部系统封装成内部的基础服务供上层调用。这里的难点主要是外部系统经常不稳定甚至出错。所以这层设计时要考虑很多容错的方案。

比如:

1) 异步化,所有的同步接口异步调用,针对某些错误自动重试。

2)自动超时,监控所有未在一定时间内得到处理的请求

3)对账,下游系统支持的情况下对每个请求引入uuid,定时对账

4)数据修复自动化,可恢复的错误尽量不要引入人工干预。

除此之外,为了稳定起见,引擎的基础服务层会提供自己的服务降级/快速失败功能,以适配没有通过RPC框架提供类似功能的外部系统。

基础服务之上是业务流程

U系统不允许具体产品自定义业务流程。而是提供若干标准流程由产品在插件中指定。

考虑到流程会变动,内部实现上使用了工作流引擎,这样流程变更时的工作量会小很多。虽然技术上可行,但短期内不会把工作流引擎开发给业务产品定制。

统一流程这事儿业务价值很大,因为终于有办法用技术手段防止流程碎片化了。业务产品再没办法偷偷地改流程了,毕竟流程图都在U系统,交互也都在U系统的server上进行,业务方想改也改不了。

业务流程之上是自定义逻辑层

接入产品是有很多自定义功能,其中相当一部分用xml很难表示,所以允许在配置文件中直接提交代码,引擎动态编译并执行这些代码。

在实践中,允许用代码实现的功能大致可以有

1)交互界面初始值的获取

2)用户输入的转换、处理

3)系统间交互数据的转换

4)展示界面数据的格式化

允许提交代码,很重要的一点就是要处理好安全性,避免提交代码中有错波及到系统的其它部分.

这里可以做一个沙盒,让所有自定义代码都在沙盒中运行,沙盒可以保证

1.不同的沙盒互相不能感知彼此的存在。

2.插件中的代码无法修改沙盒以外(引擎)中的状态。

在实际的设计中,引擎制定的接口可以在配置文件中用不同的语言实现,只需要用<java> <scala> <python>等标签区分实现是哪种语言即可。

当然支持不同语言会对沙盒机制提出更高的要求,可以采用基于JVM的沙盒,通过区分classloader来实现隔离,也可以考虑引入docker,把沙盒作成一个本机的虚拟环境,这样隔离效果会更好。

至于为什么提交源代码而不是提交编译好的jar?这主要是因为:

1.要支持脚本语言,提交代码的设计更通用。

2.提交代码可以在更新插件时热编译,发现依赖问题,及时反馈;jar包只能在运行期抛异常,反馈置后。

3.通过本机缓存可以避免多次编译,作到相同的运行效率。

如何处理用户交互

交互界面是影响用户体验最大的部分,之前一些产品类似功能的交互界面差别很大,用户会很反感。

但这块完全由引擎作也不合适,因为界面是业务产品最易变的部分,引擎都包下来后续维护成本太高。

推荐的作法是提供控件库,把选择界面元素的自由提供给配置文件,但界面的渲染和逻辑由引擎统一负责。

具体来说,插件中可以像HTML一样指定文本框,下拉列表等控件,自由地构造界面,但不能自定义css和js,而是由平台统一渲染和校验。

假如插件配置中有这么一行

<date key="testDate" title="测试Date" required="true" defaultOffsetDays="2" description="活动开始时间" />

U系统的界面上会渲染出一个日期选择控件,控件的排版和样式由引擎决定,插件不能指定。

引擎会做一些基础校验(比如这里需要非空),更高级的有业务含义的校验规则由引擎把用户输入传给产品异步进行。

引擎的控件库包含20多种通用控件,包括<lable><text><date><checkbox>等交互控件,并通过<row>这样的控件提供简单的排版功能,基本已经可以满足需要。

如果有特殊的交互需求,也是由引擎开发特殊控件而不是由产品提供,这样在提供灵活性的同时最大程度的保证了前端交互的一致性。

从结果来看,因为只提供给产品“满足需求的最小自由”,整个系统交互的用户体验还是很统一的。

如何处理数据

为保证数据的一致性,避免用户看到的数据和其它途径不同。U系统对于产品提供的数据尽量不落地,而是实时调服务去取。

和前面提到的基础服务一样,这里要考虑到产品服务不可用的情况,所以在界面和流程设计以及实现中都要很小心,避免一个服务不可用影响到其它产品功能的正常使用。

出于性能考虑,统计报表的数据是少数的在引擎落地的冗余数据。

报表数据通常不可修改,所以一致性问题不大。

当然极端情况下还可能会存在数据的不一致,因此可以提供一个通知机制来作数据订正,但这不是一个正常的功能,并没有在插件中提供出来,只能算是一个后门。

这也算是业务系统实际落地时没法作的那么“纯粹”的一个例子。

U系统上线后,基本同时达到了设计要求

1.开发高效。引擎和插件解耦后,接入产品可以自助修改服务和开发插件,因为引擎能够快速反馈,发现错误的速度比以前更快,整体开发工作量也比以前更小。同时引擎自身没有业务逻辑,工作少了很多,基本上一到两个人就能完成维护工作。

2.体验统一。以前所有前端要统一的地方都是出个规范文档,希望大家照此执行,但总是渐行渐远。现在这些地方都统一了,很自然的约束住了产品的RD和PM,起到了控制作用。

3.结构清晰。在这套架构下,遇到变更时, RD会很自然的在脑海中将其区分为引擎要作的工作和插件要作的工作。大家的思路和认知统一,跨组的学习代价就小,整个组织架构也能更容易变更。

总结

讨论应用架构时,通常的服务化,包括现在很热的微服务更多地聚焦在后端服务的集成上。

今天分享的插件化在此基础上进了一步,不但要集成后端服务,同时要集成前端用户能感知到的流程和交互界面。

这个项目的实践表明,这种进一步的集成是可行的,是能兼顾灵活性和一致性的。

插件化的集成方案也有其局限性

比如追求个性化的用户产品,UE和PM的话语权会大很多,在这种场景下实施插件化,流程和UI的部分可能会被千奇百怪的业务需求搞的复杂很多。

但通常的业务系统,一致性往往比特立独行更重要,这种场景下插件化的解决方案还是比较合适的。

想进一步讨论插件化解决方案?或想同群专家进一步高可用架构,可回复arch申请进群。

 
   


沈 剑/2.4 从零开始搭建高可用IM 系统117
2.4.1 什么是IM117
2.4.2 协议设计118
2.4.3 WEB 聊天室.122
2.4.4 IM 典型业务场景126
2.4.5 疑问与解惑126

http://www.52im.net/thread-2768-1-1.html


陈宗志/2.5 360 分布式存储系统Bada 的架构设计和应用.129
2.5.1 主要应用场景.129
2.5.2 整体架构130
2.5.3 主要模块131
2.5.4 数据分布策略.132
2.5.5 请求流程133
2.5.6 多机房架构134
2.5.7 FAQ138
2.5.8 疑问与解惑139


张 亮/2.6 新一代分布式任务调度框架:当当Elastic-Job 开源项目
的10 项特性143
2.6.1 为什么需要作业(定时任务).143
2.6.2 当当之前使用的作业系统144
2.6.3 Elastic-Job 的来历.144
2.6.4 Elastic-Job 包含的功能145
2.6.5 Elastic-Job 的部署和使用.146
2.6.6 对开源产品的开发理念.147
2.6.7 未来展望148
2.6.8 疑问与解惑149


付海军/2.7 互联网DSP 广告系统架构及关键技术解析152
2.7.1 优秀DSP 系统的特点152
2.7.2 程序化购买的特点153
2.7.3 在线广告的核心问题156
2.7.4 在线广告的挑战.156
2.7.5 DSP 系统架构.157
2.7.6 RTB 投放引擎的架构.158
2.7.7 DMP160
2.7.8 广告系统DMP 数据处理的架构.160
2.7.9 用户画像的方法.162
2.7.10 广告行业的反作弊.165
2.7.11 P2P 流量互刷166
2.7.12 CPS 引流作弊167
2.7.13 疑问与解惑168


王卫华/2.8 亿级规模的Elasticsearch 优化实战170
2.8.1 索引性能(Index Performance) .170
2.8.2 查询性能(Query Perofrmance) 171
2.8.3 其他173
2.8.4 疑问与解惑174
杨卫华/2.9 微博分布式存储考试题:案例讲解及作业精选179
2.9.1 访问场景179
2.9.2 设计180
2.9.3 sharding 策略180
2.9.4 案例精选181
李 凯/2.10 架构师需要了解的Paxos 原理、历程及实战.184
2.10.1 数据库高可用性难题184
2.10.2 Paxos 协议简单回顾.185
2.10.3 Basic Paxos 同步日志的理论模型186
2.10.4 Multi Paxos 的实际应用.187
2.10.5 依赖时钟误差的变种Paxos 选主协议简单分析190
2.10.6 疑问与解惑191
温 铭/2.11 OpenResty 的现在和未来193
2.11.1 OpenResty 是什么,适合什么场景下使用.193
2.11.2 某安全公司服务端技术选型的标准194
2.11.3 如何在项目中引入新技术.196
2.11.4 如何入门以及学习的正确方法197
2.11.5 OpenResty 中的测试和调试.199
2.11.6 NginScript 是否会替代OpenResty201
2.11.7 未来重点解决的问题和新增特性.202
2.11.8 开源社区建设203
2.11.9 疑问与解惑.203

OpenResty®

 

最新! OpenResty 1.15.8.3 正式版已发布。

最新! OpenResty 1.17.8.1 RC1 已经发布供测试。

最新! 新博客文章OpenResty 和 Nginx 如何分配和管理内存 已发布。

OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。

OpenResty® 的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。

参考 组件 可以知道 OpenResty® 中包含了多少软件。

参考 上路 学习如何从最简单的 hello world 开始使用 OpenResty® 开发 HTTP 业务,或前往 下载 直接获取 OpenResty® 的源代码包开始体验。

 
   


第3 章 电商架构热点专题.205
张开涛/3.1 亿级商品详情页架构演进技术解密.205
3.1.1 商品详情页205
3.1.2 商品详情页发展史209
3.1.3 遇到的一些问题和解决方案220
3.1.4 总结228
3.1.5 疑问与解惑229
杨 超/3.2 大促系统全流量压测及稳定性保证——京东交易架构.232
3.2.1 交易系统的三个阶段232
3.2.2 交易系统的三层结构233
3.2.3 交易系统的访问特征234
3.2.4 应对大促的第1 步:全链路全流量线上压测.234
3.2.5 应对大促的第2 步:根据压力表现进行调优.237
3.2.6 异步和异构240
3.2.7 应对大促的第3 步:分流与限流242
3.2.8 应对大促的第4 步:容灾降级.244
3.2.9 应对大促的第5 步:完善监控.245
3.2.10 疑问与解惑246
吕 毅/3.3 秒杀系统架构解密与防刷设计.248
3.3.1 抢购业务介绍.248
3.3.2 具体抢购项目中的设计.249
3.3.3 如何解耦前后端压力250
3.3.4 如何保证商品库的库存可靠252
3.3.5 如何与第三方多方对账.254
3.3.6 项目总结255
3.3.7 疑问与解惑255
王富平/3.4 Lambda 架构与推荐在电商网站实践.257
3.4.1 Lambda 架构257
3.4.2 1 号店推荐系统实践260
3.4.3 Lambda 的未来262
3.4.4 思考263
3.4.5 疑问与解惑263
杨 硕/3.5 某公司线上真实流量压测工具构建.265
3.5.1 为什么要开发一个通用的压测工具265
3.5.2 常见的压测工具.266
3.5.3 构建自己的压测工具266
3.5.4 疑问与解惑271
第4 章 容器与云计算.273
陈 飞/4.1 微博基于Docker 容器的混合云迁移实战.273
4.1.1 为什么要采用混合云的架构273
4.1.2 跨云的资源管理与调度.275
4.1.3 容器的编排与服务发现.278
4.1.4 混合云监控体系.284
4.1.5 前进路上遇到的那些坑.286
4.1.6 疑问与解惑286
高 磊/4.2 互联网金融创业公司Docker 实践287
4.2.1 背景介绍287
4.2.2 容器选型287
4.2.3 应用迁移288
4.2.4 弹性扩容291
4.2.5 未来规划295
4.2.6 疑问与解惑295
高永超/4.3 使用开源Calico 构建Docker 多租户网络.297
4.3.1 PaaS 平台的网络需求.297
4.3.2 使用Calico 实现Docker 的跨服务器通讯.298
4.3.3 利用Profile 实现ACL301
4.3.4 性能测试306
4.3.5 Calico 的发展308
4.3.6 疑问与解惑309
彭哲夫/4.4 解析Docker 在芒果TV 的实践之路310
4.4.1 豆瓣时期310
4.4.2 芒果TV 的Nebulium Engine .311
4.4.3 Project Eru .312
4.4.4 细节313
4.4.5 网络314
4.4.6 存储315
4.4.7 Scale316
4.4.8 资源分配和集群调度316
4.4.9 服务发现和安全.317
4.4.10 实例317
4.4.11 总结318
4.4.12 疑问与解惑318
王关胜/4.5 微博基于Docker 的混合云平台设计与实践323
4.5.1 微博的业务场景及混合云背景.323
4.5.2 三大基础设施助力微博混合云.326
4.5.3 微博混合云DCP 系统设计核心:自动化、弹性调度328
4.5.4 引入阿里云作为第3 机房,实现弹性调度架构330
4.5.5 大规模集群操作自动化.331
4.5.6 不怕峰值事件.332
第5 章 运维保障333
王 康/5.1 360 如何用QConf 搞定两万以上服务器的配置管理.333
5.1.1 设计初衷333
5.1.2 整体认识334
5.1.3 架构介绍335
5.1.4 QConf 服务端336
5.1.5 QConf 客户端336
5.1.6 QConf 管理端340
5.1.7 其他341
5.1.8 疑问与解惑343
尤 勇/5.2 深度剖析开源分布式监控CAT347
5.2.1 背景介绍347
5.2.2 整体设计348
5.2.3 客户端设计349
5.2.4 服务端设计352
5.2.5 总结感悟357
杨尚刚/5.3 单表60 亿记录等大数据场景的MySQL 优化和运维之道359
5.3.1 前言359
5.3.2 数据库开发规范.360
5.3.3 数据库运维规范.363
5.3.4 性能优化368
5.3.5 疑问与解惑375
秦 迪/5.4 微博在大规模、高负载系统问题排查方法379
5.4.1 背景379
5.4.2 排查方法及线索.379
5.4.3 总结384
5.4.4 疑问与解惑385
秦 迪/5.5 系统运维之为什么每个团队存在大量烂代码387
5.5.1 写烂代码很容易.387
5.5.2 烂代码终究是烂代码388
5.5.3 重构不是万能药.392
5.5.4 写好代码很难.393
5.5.5 悲观的结语394
秦 迪/5.6 系统运维之评价代码优劣的方法395
5.6.1 什么是好代码.395
5.6.2 结语403
5.6.3 参考阅读403
秦 迪/5.7 系统运维之如何应对烂代码404
5.7.1 改善可维护性.404
5.7.2 改善性能与健壮性409
5.7.3 改善生存环境.412
5.7.4 个人感想414
第6 章 大数据与数据库415
王 劲/6.1 某音乐公司的大数据实践.415
6.1.1 什么是大数据.415
6.1.2 某音乐公司大数据技术架构418
6.1.3 在大数据平台重构过程中踩过的坑425
6.1.4 后续的持续改进.430
王新春/6.2 实时计算在点评.431
6.2.1 实时计算在点评的使用场景431
6.2.2 实时计算在业界的使用场景432
6.2.3 点评如何构建实时计算平台433
6.2.4 Storm 基础知识简单介绍.434
6.2.5 如何保证业务运行的可靠性436
6.2.6 Storm 使用经验分享438
6.2.7 关于计算框架的后续想法442
6.2.8 疑问与解惑442
王卫华/6.3 百姓网Elasticsearch 2.x 升级之路.446
6.3.1 Elasticsearch 2.x 变化446
6.3.2 升级之路448
6.3.3 优化或建议451
6.3.4 百姓之道452
6.3.5 后话:Elasticsearch 5.0453
6.3.6 升级2.x 版本成功,5.x 版本还会远吗454
董西成 张虔熙/6.4 Hadoop、HBase 年度回顾457
6.4.1 Hadoop 2015 技术发展457
6.4.2 HBase 2015 年技术发展460
6.4.3 疑问与解惑466
常 雷/6.5 解密Apache HAWQ——功能强大的SQL-on-Hadoop 引擎.469
6.5.1 HAWQ 基本介绍469
6.5.2 Apache HAWQ 系统架构.472
6.5.3 HAWQ 中短期规划.479
6.5.4 贡献到Apache HAWQ 社区479
6.5.5 疑问与解惑480
萧少聪/6.6 PostgresSQL HA 高可用架构实战.482
6.6.1 PostgreSQL 背景介绍.482
6.6.2 在PostgreSQL 下如何实现数据复制技术的HA 高可用集群483
6.6.3 Corosync+Pacemaker MS 模式介绍484
6.6.4 Corosync+Pacemaker M/S 环境配置485
6.6.5 Corosync+Pacemaker HA 基础配置488
6.6.5 PostgreSQL Sync 模式当前的问题492
6.6.6 疑问与解惑492
王晶昱/6.7 从NoSQL 历史看未来.495
6.7.1 前言495
6.7.2 1970 年:We have no SQL496
6.7.3 1980 年:Know SQL 497
6.7.4 2000 年:No SQL .502
6.7.5 2005 年:不仅仅是SQL 504
6.7.6 2013 年:No,SQL .505
6.7.7 阿里的技术选择.505
6.7.8 疑问与解惑506
杨尚刚/6.8 MySQL 5.7 新特性大全和未来展望.508
6.8.1 提高运维效率的特性508
6.8.2 优化器Server 层改进.511
6.8.3 InnoDB 层优化513
6.8.4 未来发展517
6.8.5 运维经验总结.518
6.8.6 疑问与解惑519
谭 政/6.9 大数据盘点之Spark 篇521
6.9.1 Spark 的特性以及功能521
6.9.2 Spark 在Hulu 的实践.525
6.9.3 Spark 未来的发展趋势528
6.9.4 参考文章530
6.9.5 疑问与解惑530
萧少聪/6.10 从Postgres 95 到PostgreSQL 9.5:新版亮眼特性532
6.10.1 Postgres 95 介绍532
6.10.2 PostgresSQL 版本发展历史533
6.10.3 PostgresSQL 9.5 的亮眼特性534
6.10.4 PostgresSQL 还可以做什么544
6.10.5 疑问与解惑547
毕洪宇/6.11 MongoDB 2015 回顾:全新里程碑式的WiredTiger 存储引擎551
6.11.1 存储引擎的发展551
6.11.2 复制集改进.555
6.11.3 自动分片机制556
6.11.4 其他新特性介绍556
6.11.5 疑问与解惑.558
王晓伟/6.12 基于Xapian 的垂直搜索引擎的构建分析561
6.12.1 垂直搜索的应用场景561
6.12.2 技术选型.563
6.12.3 垂直搜索的引擎架构564
6.12.4 垂直搜索技术和业务细节.566
6.12.5 疑问与解惑568
第7 章 安全与网络572
郭 伟/7.1 揭秘DDoS 防护——腾讯云大禹系统572
7.1.1 有关DDoS 简介的问答.574
7.1.2 有关大禹系统简介的问答575
7.1.3 有关大禹系统硬件防护能力的问答576
7.1.4 有关算法设计的问答577
7.1.5 大禹和其他产品、技术的区别.578
冯 磊 赵星宇/7.2 App 域名劫持之DNS 高可用——开源版
HttpDNS 方案详解580
7.2.1 HttpDNSLib 库组成.581
7.2.2 HttpDNS 交互流程582
7.2.3 代码结构583
7.2.4 开发过程中的一些问题及应对.586
7.2.5 疑问与解惑593
马 涛/7.3 CDN 对流媒体和应用分发的支持及优化595
7.3.1 CDN 系统工作原理.595
7.3.2 网络分发过程中ISP 的影响602
7.3.3 防盗链.603
7.3.4 内容分发系统的问题和应对思路604
7.3.5 P2P 穿墙打洞607
7.3.6 疑问与解惑609
马 涛/7.4 HTTPS 环境使用第三方CDN 的证书难题与最佳实践611
蒋海滔/7.5 互联网主要安全威胁分析及应对方案613
7.5.1 互联网Web 应用面临的主要威胁613
7.5.2 威胁应对方案.616
7.5.3 疑问与解惑624

原文地址:https://www.cnblogs.com/cx2016/p/13139990.html