一个社交App是如何构建高伸缩性的交互式系统

一个社交App需实现的功能

用户关注的常规社交功能、活动、地理位置、探索功能、新鲜事、视频照片分享等等,需要提供的功能不胜枚举,所以从技术角度来说,开发者需要解决的问题也是异常复杂的。

当一款社交App发布之初,用户访问量比较小,使用一台服务器就能够支撑全部的访问压力和数据存储需求,但是互联网应用具有病毒式的传播特点。一款App很可能会面临一夜爆红的现象,访问量和数据量在短时间内呈现爆发式增长,这时候会面临的局面是每天上亿PV、数百万新增用户和活跃用户、流量飙升至每秒数百兆。这些对于一个只部署了简单后端架构的应用来讲是无法支撑的,会直接导致服务器响应缓慢甚至超时,以及在高峰期时服务呈现瘫痪状态,使得后端的服务完全无法使用,用户体验急剧下降。本文将会通过一个真实的案例来分享一个社交应用如何构建一个具备高伸缩性的后端系统。

社交App最初部署的后端架构解析

社交App在最初的时候,后端架构相对比较简单,最初是部署在基础网络之上。最前面放置一台绑定了公网IP的nginx服务器作负载均衡,后面放置3台应用服务器来负责处理所有业务上的请求,最后面搭建一台MySQL Database数据库。

构建私有网络

随着产品的不断迭代、用户数的持续增长、数据量的积累,App就需要改进自己的后端架构,即开始构建私有网络。用户可以使用私有网络构建自己的网络拓扑——创建路由器和私有网络,将后续加入的用于运行内部服务的主机放置在私用网络中,可以有效地和云平台其他用户主机,在网络上实现100%二层隔离。主机对外开放的仅仅只有80端口,这样系统安全性上多了一层保障。

在上面的架构图中,最前面的是防火墙,后面接负载均衡器,然后接路由器和私有网络,很多互联网应用都存在读多写少的情况,这个比例有时可以达到8:2,所以我们首先通过引入缓存分摊数据库读压力。其次,引入负载均衡器,替换最初架构中的nginx proxy,负责均衡器在这里其主要用于分发请求到后端多台应用服务器,,当其中一台应用服务器挂掉,负载均衡器可以进行自动隔离。

业务分区与扩展

App随着并发访问量和数据量不断增大,首先想到横向扩容Web服务。水平扩容业务服务器的前提是要保证每台服务器都是无状态的,将session信息下放到缓存或数据库中存储,保证请求被负载到任何一台服务器可以正常处理。

从上图中看到,在前一步「构建私有网络」之后,增加了一个新的私有网络来扩展网络层,这里可以利用自有映像功能,将原有的应用服务器制作成模板,后续就可以基于这个模板快速启动新的主机。另外可以利用Auto-scaling(自动横向扩展)功能,根据后端服务器的负载请求,动态调整服务器的数量。

一个社交应用的后端会提供很多服务请求接口,比如添加好友、刷新新鲜事、浏览页面等,可以通过日志分析每一个接口的耗时,将耗时长但非重要业务的请求分到单独的Web服务器上进行处理,从而给主Web服务器留出更多资源去处理关键业务的请求。

面向服务的架构

随着产品功能的不断迭代,业务代码会越来越复杂,出现故障的可能性也在加大,当一个局部功能出现问题时,都会影响整个服务的可用性。此时可以构建面向服务的架构,将一个完整且庞大的服务拆分为一个个的子服务,服务之间通过接口交互。如下图所示:

社交App的服务被拆分成了四个子服务——新鲜事(News Feed)、用户资料(Profile)、广告(Ads)和探索(Explore),不同的服务之间通过消息通信框架(例如ZeroMQ)来进行交互。把一个大服务拆分为几个小的子服务的好处不言而喻,主要是:

  • 故障隔离:子服务出现故障不会影响全局,比如广告业务出现问题并不会让整个App不能使用,依然可以查看新鲜事等;
  • 独立扩展:每一个被拆分出的子服务有着不同的访问压力,比如新鲜事的调用相比一些二级页面的用户资料要高很多,所以前者会被分配更多的Web 服务器;
  • 独立部署:一个大服务的配置因功能过多会异常复杂,一旦被拆分就可根据不同的特性需求定制配置项,从而提高可管理性;
  • 团队协作开发:开发者都有着自己精通的方向,从而提高开发效率;
  • 抽象出数据访问:在后续进行数据层面(数据库、缓存)扩展时,可通过修改子服务的Data Service,实现对下层数据的透明。 

数据库Replication

业务增长也会给数据库带来诸多问题,当最初架构中单台数据库(数据库同时提供读和写)不足已支撑起App访问压力时,首先需要做数据副本Replication。市面上常见的MySQL、MongoDB等数据库都提供Replication功能,以MySQL为例,从高层来看,Replication可分成三步:

  1. Master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events);
  2. Slave将Master的binary log events拷贝到它的中继日志(relay log);
  3. Slave重做中继日志中的事件,将改变反映它自己的数据。

具体实现该过程的第一部分就是Master记录二进制日志。在每个事务更新数据完成之前,Master在二进制日志记录这些改变。MySQL将事务串行的写入二进制日志,即使事务中的语句都是交叉执行的。在事件写入二进制日志完成后,Master通知存储引擎提交事务。

下一步就是Slave将Master的binary log拷贝到它自己的中继日志。首先,Slave开始一个工作线程——I/O线程。I/O线程在Master上打开一个普通的连接,然后开始binlog dump process。Binlog dump process从Master的二进制日志中读取事件,如果已经跟上Master,它会睡眠并等待Master产生新的事件。I/O线程将这些事件写入中继日志。

SQL slave thread处理该过程的最后一步。SQL线程从中继日志读取事件,更新Slave的数据,使其与Master中的数据一致。只要该线程与I/O线程保持一致,中继日志通常会位于OS的缓存中,所以中继日志的开销很小。

此外,在Master中也有一个工作线程:和其它MySQL的连接一样,Slave在Master中打开一个连接也会使得Master开始一个线程。复制过程有一个很重要的限制——复制在Slave上是串行化的,也就是说Master上的并行更新操作不能在Slave上并行操作。

对于云计算使用者来说,只需要知道数据库的IP和端口即可进行使用。具体实现见下图:

第一步要做的是扩充Slave,将单机Master变成Master+3台Slave的架构,而在其中的Slave上搭建一个内网的负载均衡器(Load Balancer),对于最上层的Data Service来说,只要配置一个MySQL Master节点和一个LB节点即可,今后因业务变化进行增减Slave对上层来说完全是透明的。

此做法可以带来两个好处,第一是提高可用性,若是一台Master出现错误,则可以提升某一台的Slave作为Master继续提供服务,从而保证数据可用性;第二个是分摊读压力,对于一个社交App来说,读写分离是在数据层优化第一步要做的事情,利用上面的架构可以很轻易地做到将读的请求分担到MySQL Slave上进行查询,而写留给Master。但是读写分离时会有数据库一致性的问题,即在数据写至Master之后同步到Slave有一个延迟的时间,对于社交应用来说,这是可以接受的,只要保证数据的最终一致性即可。

在上图的最下面有一个Snapshot,即定期对数据进行冷备份,这不同于单纯对MySQL Master进行复制的Slave,因为线上bug或误操作会删除Master上的数据,这时会立即同步到slave上造成数据丢失这时冷备份Snapshot就会起到数据保护作用。

运行过程中肯定需要监控,用户可以利用Linux上的工具进行统计分析top / iotop / df / free / netstat等工具去监控系统里的各个服务和组件是否正常运行,以及通过日志的信息(http access log / application log / database slow log )分析各个服务的性能瓶颈。

数据分区与扩容

下一步业务的调整要进行数据库的分区和扩容。第一,构建缓存集群,在开始的架构中引用了Memcached缓存,是单机数据库缓存。当数据量增长,,需要把数据分散到多台缓存服务器上,常用的是HashRing算法,好处在于不管是添加结点还是删除结点时,只会使得少部分数据失效。还可以引用NoSQL数据库,这里用到了Redis把社交数据里对于关系要求不强但对查询效率要求很高的数据从MySQL里拿到Redis里存。Redis尤其适合存储列表类数据,比如好友关系列表、排行榜数据等。

除此以外可以考虑做数据分区对于MySQL第一步是垂直拆分,把原来单独的数据库按照功能模块分别拆分成:好友新鲜事、用户资料、广告数据以及探索数据。对于Redis也同样,将原来的单台Redis按照功能模块拆成四个,分别为:排行榜数据、好友、广告数据、探索数据。

接下来会遇到的瓶颈是单表过大的问题,这时候我们需要做水平拆分——把一个表拆分成多个表,需要选取一个分区Key,比如对用户表做拆分时,通常选取User ID。分区key的选择主要是看所有的查询语句频繁使用哪个查询字段,就选择那个字段作为分区key这样能保证大部分的查询可以落在单个数据表上,少量没有带分区Key的查询语句,可能要遍历一遍所有切分后的数据表。

构建完整的测试环境

构建完整测试服务器时需要创建新的路由器和私有网络、独立的网络环境和带宽资源、内网GRE隧道打通路由器、VPN拨入网络和SSH密钥管理。

这个过程你可以创建一个包含所有系统服务的all-in-one的环境,将其制作成自有映像。如果后续你的团队来新的人,需要独立的完整开发环境,只需基于自有镜像快速创建主机即可;还可以利用User Data定制化功能,在主机启动执行一段你上传的脚本,来初始化环境。你可以将这两个功能结合起来用,把所有你所需要用的服务全部安装部署完毕后做成映像,并用User Data脚本从代码库里更新代码。因为代码的变动相对于环境的更新更加频繁,不可能每次代码的更新都要构建一个新的自有镜像。通过这种方式构建起一个完整的测试服务器,让每个工程师都可以有自己独立的测试服务器。

在App发布上线时需要连到线上环境怎么办?这两个网络本身完全100%隔离,可利用GRE隧道的功能,把两个路由器打通,实现测试环境网络和线上生产环境网络的完全连通。

多机房部署与混合组网

为了让后端架构更可靠和业务更稳定,就需要实施多机房部署和混合组网。具体原因有以下三点:

  • 异地容灾:在复杂的网络环境下,机房可能会出现网络状况,导致一些比较关键性的业务的可用性降低,备份机房后可保证服务不会出现明显的长时间中断;
  • 负载分摊:单独一个机房可能不足以支撑全部的请求,这时可以把一部分的请求压力分担到另一个机房;
  • 加速区域访问:在国内网络环境下,南方和北方相互之间网络访问时有较高的延迟。通过做多机房部署实现加速区域用户的访问。 

如上所示,有三个机房,中间是QingCloud北京1区机房,负责主营业务。左边是亚太1区机房,主要服务亚太和海外的客户。这两个机房都使用了QingCloud私有网络部署,利用路由器,通过GRE隧道或者IPsec加密隧道的方式进行互通。如果对数据传输过程的安全性要求较高,可以用IPsec的方式把两个机房相互打通,这时的访问只能通过内网IP进行访问。右边是办公室机房,工程师在这个环境下进行开发。

在实现混合组网时,只要机房路由器或者网宽设备支持标准的GRE隧道协议、IP隧道协议,就可以将传统物理世界的机房与路由器连通,并最终打通公有云环境。多机房部署通常见的方案有这些:

异地冷备份

把主机房全套业务在异地重新构建一遍,且不需要提供线上服务,只有在主机房出现故障的时候才切换到备用机房,部署相对要简单一些。但有两方面缺点,一是成本比较高,需要双倍的费用且只是用来做冷备份,平时完全用不上;另外,当主机房突然挂掉时,备用机房再起动起来提供服务,数据需要预热,这是非常缓慢的过程,可能会出现服务响应慢,甚至不能正常提供服务。

异地多活

从易到难有三阶段:第一,反向代理,用户请求到第二个机房,但不做任何处理被转向第一个机房这样会对两地的延时有一定的要求。第二,在第二个机房部署应用服务器和缓存,大部分的数据请求可以从缓存中读取,不用进行跨机房请求,但当缓存失效时,依然落到第一个机房的数据库去查询。所以,这个方式不太彻底;第三,全套服务的部署,包括HTTP服务器、业务服务器、缓存和数据库的 slave。此方式使得进入第二个机房的请求,只需要在机房内就可以完成请求处理,速度更快,但会遇到数据一致性和缓存一致性的问题,针对这点也会有一些解决方法。除了数据同步过程中的不一致问题,还需要面对缓存。

好的系统架构不是设计出来的,而是进化而来的

构建稳定可靠的业务系统需要注意以下这些: 

  • 分析用户行为,理解你的业务,如社交、电商、视频;

不同的业务有不同的行业属性和特点,对于社交来讲,比较典型的特点是数据量庞大、数据查询维度多,比如查询6月11日-7月15日在xx咖啡厅我所有好友里拍过照片的人,查询条件包括好友维度、照片维度、地点维度、隐私状态维度等,这时就需要合理的做数据层面的扩展。

电商的特点是定期举办大促销活动,届时会需要大量的计算资源、应用服务器来扛流量峰值,此时可利用云计算平台的弹性实现快速扩展业务,而在自己业务压力、促销来临时调用API接口,及AutoScaling扩展后端计算资源。视频业务有非常明显的流量高峰期和低峰期,流量高峰期通常是白天或者大家晚上下班回家那段时间,晚上2点到早上6点是流量非常低的时候,可利用云计算弹性优势,来调用API方式调整业务带宽资源,从而达到节省成本目的。

  • 合理规划系统,预估系统容量,如 10w / 100w / 1000w PV(DAU):不同的系统容量有可能对应不同架构的部署方式,找到最适合自己的那一个;
  • 系统是可横向扩展的 scalable;
  • 不遗余力地解决单点问题;
  • 为出错而设计design for failure:App的后端架构在开发支出就要为可能出现的各种问题进行准备,比如异地备份等;
  • 设计面向服务的架构,拆分子系统,API交互,异步处理;
  • 构建无处不在的缓存:页面缓存、接口缓存、对象缓存、数据库缓存;
  • 避免过度设计,好的系统架构不是设计出来的,而是进化而来的。
  • 原文发布时间为:2015-07-14



  • 本文来自合作伙伴“Linux中国
时间: 2024-10-31 09:30:59

一个社交App是如何构建高伸缩性的交互式系统的相关文章

使用Java构建高伸缩性组件

随着多核处理器成为主流,应用开发人员对于如何编写高伸缩性的应用以利用底层硬 件的优势这个问题面临巨大的压力.此外,遗留系统不得不移植到新的架构上.保证应用 伸缩性的一种有效方式是使用高伸缩性组件构建应用.举例来说,在各种应用中, java.util.concurrent.ConcurrentHashMap可以替代同步的HashTable,使应用伸缩性更 好.因此,向应用直接提供一套高伸缩性构造块以引入并行是非常有用的. 我们创建了一套高伸缩性并发Java组件作为Amin库项目的一部分.在本文中,

基于Nginx和Consul构建高可用及自动发现的Docker服务架构

本文讲的是基于Nginx和Consul构建高可用及自动发现的Docker服务架构[编者的话]本文对于Docker和Consul Template以及Nginx如何结合使用做了较为详细的介绍. [上海站|3天烧脑式微服务架构训练营]培训内容包括:DevOps.微服务.Spring Cloud.Eureka.Ribbon.Feign.Hystrix.Zuul.Spring Cloud Config.Spring Cloud Sleuth等. 导读 如果你在大量接触或使用微服务的话,你可能会碰到一个问

Consul实践之Consul结合nginx构建高可用可扩展的Web服务

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://dgd2010.blog.51cto.com/1539422/1730439 前文<Consul实践之Consul是什么>讲述了consul是什么,这篇文档是一个Consul实际应用的一个例子,用Consul结合nginx构建高可用可扩展的Web服务.Consul还能做许多其他的事情,可以根据实际需要构思和使用. 方案概述 nginx提供的负载均衡服务同样支持高可用.可扩展的W

ios-IOS网络APP和社交APP,应该怎么做

问题描述 IOS网络APP和社交APP,应该怎么做 我想做一个基于网络或者社交方面的APP,但是由于缺乏经验,不知道该怎么下手. 首先服务器怎么解决,也就是后台,没有后台,数据无法存储. 再者,网络APP一般都是干什么的,我也想不出来,从什么地方拿数据啊,望有经验的人 指导一下. 解决方案 首先看你的时间如何,对app的要求如何,如果要求较高,那么就要单独开发了,android ios各开发一个,连接你的服务器传递信息. 如果要求不是很高,目前有很多跨平台的框架,基本上是写js代码,生成andr

基于API网关构建高可用、高安全性API

        今天我们来聊聊如何借助API网关构建高可用.高安全性的云API,充分利用API网关给我们带来的便利. 认证         从API定义上我们可以定义多种认证类型的API,除特殊API外建议定义APP认证方式或其有安全认证类型的API,这样一旦发生攻击或者大量非法调用时我们可以知道谁在调用,便于我们通过黑名单等措施及时进行限制 HTTPS 建议对数据传输安全性要求较高的API仅开放HTTPS调用方式,另外在证书选择上,强烈建议大家选购Verisign的安全证书,因为Verisig

陌生人社交聊不起来?他认为都是社交App的错!

放眼望去,陌生人社交市场早已是一片红海.老大陌陌地位稳定程度就不用说了,遇见.对面.比邻等玩家也都有粉丝护身. 不过痛点还在. 向往社交的陌生人之间差距通常很大,即使能聊,兴趣也不强. 应用设计上缺乏有价值的场景和话题,无法引导用户长期交流. 至少秦淮是这么认为的.他创立的陌生人社交App倾倾在2015年10月份已经上线,而倾倾就是想通过创造聊天场景.增强聊天兴趣,让陌生人社交不再那么尴尬. 创造聊天场景 关键一步是在社交关系建立的初期有话可聊. 所以,为用户建立有价值的聊天场景和话题至关重要.

明明高富帅,为什么没人在陌生人社交 APP 上理我

"你要是真的想听我说,首先希望知道的大概是我在哪里出生,我那该死的童年是如何度过的--还有像这样的一堆大卫·科波菲尔式废话.但说实在的,我无心对你讲述这一切."--<麦田里的守望者> 这本书的开头就一顿牢骚.这种体会想必很多在智能手机上使用陌生人社交应用的女性有过,那些千篇一律的搭讪和查户口式的对话让她们从原先的感兴趣到后来的厌烦.与此相反,那些广大男性陌生人社交应用都提出这样一个疑问--为什么我资料里的照片显示我明显是一个极具品味的高富帅,怎么就没人来跟我搭讪. 这就是位

用户痛点其实无处不在! “百事哈哈”社交APP蹭蹭蹭上榜

近日来,一款名为"百事哈哈"的社交APP在朋友圈内悄悄热了起来.这是一个进行精准信息匹配的社交平台,手握这款APP,就能"一站式"解决单个体多需求问题:举例来说,一个货运司机安装了"百事哈哈"APP,既可以找到客户,也可以找到供应商,和同行交流聊天,还可以解决他途中就餐,找旅馆休息,中途汽车维修加油等问题,甚至可以为他妻子找修理工,为孩子找家教等更多需求-- 据百事哈哈开发人员透露,和大众点评网.饿了吗.58同城等不同,这是目前唯一的以"

近日,一款匿名社交App软件“秘密”悄然走红

摘要: 传说人心中有秘密的时候,就会跑到山上找一棵树,在树上挖一个洞,把秘密全说进去,然后再用泥巴把洞封上,秘密就会永远留在那棵树里,没有人会知道.以前人们选择把秘密深埋 "传说人心中有秘密的时候,就会跑到山上找一棵树,在树上挖一个洞,把秘密全说进去,然后再用泥巴把洞封上,秘密就会永远留在那棵树里,没有人会知道."以前人们选择把秘密深埋,如今人们却在将秘密公之于众. 近日,一款匿名社交App软件"秘密"悄然走红.所有平时在微博.微信.QQ或者 其他 渠道不能说的事情