如何应对php高并发高负载系统架构的网络应用访问

“全球最忙碌的网站”12306如何实现高流量高并发的关键技术_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&100W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
“全球最忙碌的网站”12306如何实现高流量高并发的关键技术
云客网www.yuntask.com是SEO优化为切入点提...|
总评分0.0|
阅读已结束,下载本文需要
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
加入VIP
还剩4页未读,
定制HR最喜欢的简历
你可能喜欢& 利用Memcache解决数据库高并发访问的瓶颈问题
利用Memcache解决数据库高并发访问的瓶颈问题
  对于高并发高访问的Web应用程序来说,数据库存取瓶颈一直是个令人头疼的问题。特别当你的程序架构还是建立在单数据库模式,而一个数据池连接数峰值已经达到500的时候,那你的程序运行离崩溃的边缘也不远了。很多小网站的开发人员一开始都将注意力放在了产品需求设计上,缺忽视了程序整体性能,可扩展性等方面的考虑,结果眼看着访问量一天天网上爬,可突然发现有一天网站因为访问量过大而崩溃了,到时候哭都来不及。所以我们一定要未雨绸缪,在数据库还没罢工前,想方设法给它减负,这也是这篇文章的主要议题。  大家都知道,当有一个request过来后,web服务器交给app服务器,app处理并从db中存取相关数据,但db存取的花费是相当高昂的。特别是每次都取相同的数据,等于是让数据库每次都在做高耗费的无用功,数据库如果会说话,肯定会发牢骚,你都问了这么多遍了,难道还记不住吗?是啊,如果app拿到第一次数据并存到内存里,下次读取时直接从内存里读取,而不用麻烦数据库,这样不就给数据库减负了?而且从内存取数据必然要比从数据库媒介取快很多倍,反而提升了应用程序的性能。  因此,我们可以在web/app层与db层之间加一层cache层,主要目的:1.减少数据库读取负担;2.提高数据读取速度。而且,cache存取的媒介是内存,而一台服务器的内存容量一般都是有限制的,不像硬盘容量可以做到TB级别。所以,可以考虑采用分布式的cache层,这样更易于破除内存容量的限制,同时又增加了灵活性。  Memcached介绍  Memcached是开源的分布式cache系统,现在很多的大型web应用程序包括,youtube,wikipedia,等等都在使用memcached来支持他们每天数亿级的页面访问。通过把cache层与他们的web架构集成,他们的应用程序在提高了性能的同时,还大大降低了数据库的负载。  具体的memcached资料大家可以直接从它的官方网站上得到。这里我就简单给大家介绍一下memcached的工作原理:  Memcached处理的原子是每一个(key,value)对(以下简称kv对),key会通过一个hash算法转化成hash-key,便于查找、对比以及做到尽可能的散列。同时,memcached用的是一个二级散列,通过一张大hash表来维护。  Memcached有两个核心组件组成:服务端(ms)和客户端(mc),在一个memcached的查询中,mc先通过计算key的hash值来确定kv对所处在的ms位置。当ms确定后,客户端就会发送一个查询请求给对应的ms,让它来查找确切的数据。因为这之间没有交互以及多播协议,所以memcached交互带给网络的影响是最小化的。  举例说明:考虑以下这个场景,有三个mc分别是X,Y,Z,还有三个ms分别是A,B,C:  设置kv对  X想设置key=&foo&,value=&seattle&  X拿到ms列表,并对key做hash转化,根据hash值确定kv对所存的ms位置  B被选中了  X连接上B,B收到请求,把(key=&foo&,value=&seattle&)存了起来  获取kv对  Z想得到key=&foo&的value  Z用相同的hash算法算出hash值,并确定key=&foo&的值存在B上  Z连接上B,并从B那边得到value=&seattle&  其他任何从X,Y,Z的想得到key=&foo&的值的请求都会发向B  Memcached服务器(ms)  内存分配  默认情况下,ms是用一个内置的叫&块分配器&的组件来分配内存的。舍弃标准的malloc/free的内存分配,而采用块分配器的主要目的是为了避免内存碎片,否则操作系统要花费更多时间来查找这些逻辑上连续的内存块(实际上是断开的)。用了块分配器,ms会轮流的对内存进行大块的分配,并不断重用。当然由于块的大小各不相同,当数据大小和块大小不太相符的情况下,还是有可能导致内存的浪费。  同时,ms对key和data都有相应的限制,key的长度不能超过250字节,data也不能超过块大小的限制---1MB。  因为mc所使用的hash算法,并不会考虑到每个ms的内存大小。理论上mc会分配概率上等量的kv对给每个ms,这样如果每个ms的内存都不太一样,那可能会导致内存使用率的降低。所以一种替代的解决方案是,根据每个ms的内存大小,找出他们的最大公约数,然后在每个ms上开n个容量=最大公约数的instance,这样就等于拥有了多个容量大小一样的子ms,从而提供整体的内存使用率。  缓存策略  当ms的hash表满了之后,新的插入数据会替代老的数据,更新的策略是LRU(最近最少使用),以及每个kv对的有效时限。Kv对存储有效时限是在mc端由app设置并作为参数传给ms的。  同时ms采用是偷懒替代法,ms不会开额外的进程来实时监测过时的kv对并删除,而是当且仅当,新来一个插入的数据,而此时又没有多余的空间放了,才会进行清除动作。  缓存数据库查询  现在memcached最流行的一种使用方式是缓存数据库查询,下面举一个简单例子说明:  App需要得到userid=xxx的用户信息,对应的查询语句类似:  &SELECT*FROMusersWHEREuserid=xxx&  App先去问cache,有没有&user:userid&(key定义可预先定义约束好)的数据,如果有,返回数据;如果没有,App会从数据库中读取数据,并调用cache的add函数,把数据加入cache中。  当取的数据需要更新,app会调用cache的update函数,来保持数据库与cache的数据同步。  从上面的例子我们也可以发现,一旦数据库的数据发现变化,我们一定要及时更新cache中的数据,来保证app读到的是同步的正确数据。当然我们可以通过定时器方式记录下cache中数据的失效时间,时间一过就会激发事件对cache进行更新,但这之间总会有时间上的延迟,导致app可能从cache读到脏数据,这也被称为狗洞问题。(以后我会专门描述研究这个问题)  数据冗余与故障预防  从设计角度上,memcached是没有数据冗余环节的,它本身就是一个大规模的高性能cache层,加入数据冗余所能带来的只有设计的复杂性和提高系统的开支。  当一个ms上丢失了数据之后,app还是可以从数据库中取得数据。不过更谨慎的做法是在某些ms不能正常工作时,提供额外的ms来支持cache,这样就不会因为app从cache中取不到数据而一下子给数据库带来过大的负载。  同时为了减少某台ms故障所带来的影响,可以使用&热备份&方案,就是用一台新的ms来取代有问题的ms,当然新的ms还是要用原来ms的IP地址,大不了数据重新装载一遍。  另外一种方式,就是提高你ms的节点数,然后mc会实时侦查每个节点的状态,如果发现某个节点长时间没有响应,就会从mc的可用server列表里删除,并对server节点进行重新hash定位。当然这样也会造成的问题是,原本key存储在B上,变成存储在C上了。所以此方案本身也有其弱点,最好能和&热备份&方案结合使用,就可以使故障造成的影响最小化。  Memcached客户端(mc)  Memcached客户端有各种语言的版本供大家使用,包括java,c,php,.net等等。  大家可以根据自己项目的需要,选择合适的客户端来集成。& & & &缓存式的Web应用程序架构  有了缓存的支持,我们可以在传统的app层和db层之间加入cache层,每个app服务器都可以绑定一个mc,每次数据的读取都可以从ms中取得,如果没有,再从db层读取。而当数据要进行更新时,除了要发送update的sql给db层,同时也要将更新的数据发给mc,让mc去更新ms中的数据。  假设今后我们的数据库可以和ms进行通讯了,那可以将更新的任务统一交给db层,每次数据库更新数据的同时会自动去更新ms中的数据,这样就可以进一步减少app层的逻辑复杂度。如下图:  不过每次我们如果没有从cache读到数据,都不得不麻烦数据库。为了最小化数据库的负载压力,我们可以部署数据库复写,用slave数据库来完成读取操作,而master数据库永远只负责三件事:1.更新数据;2.同步slave数据库;3.更新cache。如下图:  以上这些缓存式web架构在实际应用中被证明是能有效并能极大地降低数据库的负载同时又能提高web的运行性能。当然这些架构还可以根据具体的应用环境进行变种,以达到不同硬件条件下性能的最优化。  未来的憧憬  Memcached的出现可以说是革命性的,第一次让我们意识到可以用内存作为存储媒介来大规模的缓存数据以提高程序的性能。不过它毕竟还是比较新的东西,还需要很多有待优化和改进的地方,例如:  如何利用memcached实现cache数据库,让数据库跑在内存上。这方面,tangentsoftware开发的memcached_engine已经做了不少工作,不过现在的版本还只是处于实验室阶段。  如何能方便有效的进行批量key清理。因为现在key是散列在不同的server上的,所以对某类key进行大批量清理是很麻烦的。因为memcached本身是一个大hash表,是不具备key的检索功能的。所以memcached是压根不知道某一类的key到底存了多少个,都存在哪些server上。而这类功能在实际应用中却是经常用到。
除非特别注明,文章均为原创
转载请标明本文地址:
作者:鸡啄米
&&( 21:46:49)&&( 21:50:42)
纯技术文啊,看不懂。
学习下。。
好深奥哦,不懂···
牛文章。。。。
支持下博主 谢谢博主分享
这篇文章比较实用呢 博主辛苦了~
给力支持!
文章不错哈!给力支持!
赞一个 加油啊
这个是纯粹的memcache的分布式原理,有没有memcache和mysql数据库交互的资料,最好有相关的代码?
完全随机文章小微金融、场景金融等新兴银行金融业务亟需一种新型的弹性架构来应对高并发、大流量的业务冲击,同时,要满足应用快速版本迭代升级、敏捷运维管理等需求。本文分享了BoCloud博云如何利用互联网应用架构与Docker容器技术帮助银行业应对“互联网+”挑战,建设基于PaaS平台的敏捷IT架构。
移动互联网渠道创新是传统企业无法也不能躲避的业务变革,无论是接入或者自建互联网渠道都需要回答如下问题:现在的IT架构能否应对互联网渠道创新业务的爆炸性冲击?什么样的IT架构才能够解决这个问题并具备应对未来需求的良好扩展能力?以银行业为例,传统的银行渠道比较单一,基本上围绕各个分支机构和营业网点运营,整个IT系统的建设中性能指标在整个指标体系中的重要性往往要低于业务可靠性。然而,这一切正在发生改变,围绕互联网渠道的渠道创新业务已经改变了这种现状。
新金融IT需求
银行业已经告别了传统的以银行业务为中心的业务模式,开始转变成以客户需求为核心进行业务设计与金融创新,这也正是场景金融的内涵。无论是传统的电子银行业务,还是渠道创新的直销银行业务,以及互联网金融的各种宝们,都是满足客户各种场景金融需求而建立的金融业务。下图是现代银行的一些业务及其基于的运营平台。
围绕客户、渠道、数据和平台,银行业CIO们需要解决三个主要问题:
如何快速实现业务上线来应对快速变化的市场?应用架构如何应对互联网渠道带来的瞬时大规模并发请求带来的负载压力?如何实现大量业务应用、服务与数据的统一化管理并确保上述两个问题的解决?
采用过去烟囱式建设模式具有如下三个弊端:
建设周期过长。传统的建设模式从规划、采购、开发、上线、试运行等阶段才能上线一个新的业务应用,时间跨度可以实现从几个月到几年,十分漫长。像基于互联网事件的营销类应用需要及时对事件作出响应,对业务上线周期具有十分苛刻的要求,传统模式显然无法满足。
扩展性不能满足业务需要。传统的应用一般都是基于规划容量进行设计与开发,用户的规模是可以估计,在极端的条件下可以通过排队等机制降低负载压力。然而,“秒杀”、“抢购”等应用模式却不具有这样的前提条件,用户规模会在极短的时间内爆炸性增加。简单的排队策略会让用户大大降低产品和服务的质量评价,无法满足快速扩展的需要。
业务封闭。传统的业务与业务之间很少互相访问,业务服务在设计与运营过程中也缺乏复用的考虑,更不用说满足多个场景并发访问的需求。
为了解决上述问题,我们和多家银行架构部门合作,规划了“重平台、轻应用、服务化”的新金融IT基础平台。
新一代的IT架构应该具备如下特点:
IT基础设施与服务平台已经集成了应用程序所需要的基础件或服务,比如资源申请服务、调度服务、消息服务、数据服务等等。重平台的概念的内涵就在于大量的基础服务或者经验数据能够在“沉积”在平台中,构成应用基础架构的核心。应用的开发、上线、迭代升级都需要足够的敏捷。这一方面依赖与平台集成的基础服务,另一方面需要平台能够快速的实现对于应用封装、发布、迭代升级的支持,具备一键式部署、升级等特性。应用的架构需要由平台服务或组件“封装”而成,服务或组件能够提高系统的并发性,同时具备可并行化特征,除了能降低服务响应延迟外,最重要的是可以通过整个平台服务来支撑大并发访问需求。
从业务需求的角度来说,“轻应用”的平台能够快速“组装”出新的业务形态来满足市场快速变化的需求,“服务化”一方面加强各个业务之间更多的关联提高了服务质量,另一方面可以把优秀的经验和实践固化下来增强企业业务竞争力。“重平台”特性可以通过整个平台的“能力”有效支撑业务负载压力,确保应用的资源需求、扩展性需求、并发需求等得到满足。
当然,上述特性不是天然就具备的,需要从应用架构和平台创新两个方面进行改变来确保目标达到。
应用架构优化
回到移动互联网模式下应用应该具备特点:1,需要能够应对大量用户同时并发访问需求,即应用架构要具有优秀的并发性和弹性;2,应用要能够快速迭代,一方面满足业务发展需要,另一方面可以不断对性能进行调优来改进服务质量;3,应用架构要满足能够快速“组装”出新的业务应用来支撑快速变化的市场需要。也就是说,应用架构要具备:
强大的并发能力;灵活的弹性;敏捷的迭代能力;标准化可组装性;
这几种能力的获得需要从多个角度对系统进行优化,典型的优化包括:流量负载均衡、异步IO、消息队列、读写分离、分库分表、对象缓存、服务拆分、索引服务、分布式内容管理、CDN、空间换时间优化等手段。
i.负载均衡
根据业务模型和业务服务协议,一般可选择的负载均衡方案包括:链路层负载均衡、IP层负载均衡、Http反向代理、DNS域名解析负载均衡、Http重定向负载均衡。大型网站或业务服务往往采用多种手段进行流量的负载均衡,比如先基于DNS实现多数据中心的负载均衡,再根据IP实现数据中心内多业务负载均衡,最后在基于反向代理实现统一业务的不同服务器之间的负载均衡。
异步IO是提高系统并发性的重要技术,和异步IO共同出现的还有任务(消息)队列、线程池和持久化连接等技术。异步IO技术是事件驱动的编程模型实际应用的典范:用户请求先被放入任务队列,然后唤醒任务分发器,任务分发器从任务队列取下任务分发到空闲的线程上,线程触发异步IO操作并注册回调方法,当IO返回后回调方法重新从任务队列中把任务取下并把结果返回。整个过程如下:
iii.消息队列
消息队列对于提高系统并发性能具有四个方面的作用:1,通过消息队列实现异步处理,如上述异步IO中的任务队列就是可以基于消息队列实现;2,任务并行执行,通过消息队列可以把传统串行执行的任务尽量改造成可并行的程序;3,应用解耦,提高系统的扩展性;
4,流量削峰,通过消息队列引入排队机制,可以把尖峰负载尽量平整化。下图为一个Web网站的消息系统。
iv.数据库读写分离/分库分表
随着访问量的增多,数据库系统的压力会越来越大。在一个信息系统中,数据库系统的性能往往是对系统整体性能影响最为关键的指标。从数据库架构设计的角度,常用的优化手段为读写分离与分库分表。前者是采用读写请求分别路由到不同的库中来降低数据库系统压力的一种技术,采用该技术可以最大程度上提高系统的并发读,特别是对读多写少的访问模式十分有效。两个库之间通过数据同步,可以确保数据的一致性。读写分离模式如下图示:
随着业务的运行,数据库中的数据量随之不断增多。当达到一定的记录条目时,一次查询往往需要消耗很长时间才能返回结果。这是分库分表设计就提到了日程。分库设计一般根据业务把不同的内容存到不同的数据库中,也成为垂直拆分。这种拆分模式比较灵活,也易于操作,不足之处在于需要考虑跨多数据库的符合业务查询join问题。分表设计也叫水平拆分,就是把同一个表中的数据拆分到两个甚至多个数据库中。产生数据水平拆分的原因是某个业务的数据量或者更新量到达了单个数据库的瓶颈,这时就可以把这个表拆分到两个或更多个数据库中。Mycat是最为常用的分库分库中间件,下图为Mycat的架构,有兴趣的同学可以前往Mycat官方网站学习了解。
v.服务拆分
服务拆分是把过去全部运行在一个应用容器内部的业务逻辑子系统拆分出来,单独运行在独立的容器内部。这样做有两个好处:1,可以降低系统耦合度,使得业务具备快速迭代能力;2,方便的定位影响性能的子系统,针对性的进行性能优化。例如,短信子系统从整个系统中拆分出来后,系统可以方便的测试短信收发的并发效率及延迟,这样可以针对性的进行设计改进与架构优化。
vi.内存缓存
随着访问量的增加,逐渐出现了许多用户访问同一部分内容的情况,对于这些比较热门的内容,没必要每次都从数据库读取。我们可以使用缓存技术,例如可以使用memcacahe作为应用层的缓存,也可以使用redis作为数据库层的缓存。另外,缓存系统也可以用来保存一些需要分享的数据,比如用户登录的会话信息(Session)。通过缓存系统共享会话是实现单点登录及会话管理的重要技术。加入缓存后的系统架构如下。
vii.索引系统
对于模糊查找,利用读数据库进行查询往往力不从心,即使做了读写分离,这个问题依然是影响性能的一种重要场景。以交易网站型为例,基于关键词查找商品或服务是一种最为常用的功能,尤其是根据商品的标题来查找对应的商品。对于这种需求,在数据库操作中我们都是通过like功能来实现的,但是这种方式的开销很大,且针对大数量查询时非常耗时。此时我们可以使用搜索引擎的索引来完成。
viii.分布式存储系统/CDN
针对非结构化数据的访问优化,一般的策略是构建分布式存储系统。支撑分布式存储系统是具备良好扩展性和并发性能的存储系统,设计良好的分布式存储系统能够实现访问文件的快速定位、加速读写、实现高并发性。例如ceph就是一个优秀的开源分布式存储系统。
CDN是更大尺度的优化手段,通常用户大型或超大型网络服务运营。利用CDN,可以把不常变化的资源放置在网络的边缘,加速终端用户获取资源的速度。
ix. 空间换时间优化
空间换时间的优化一个典型的应用场景是应对不同分辨率屏幕时向用户提供统一图片的不同分辨率的版本,这是根据常见的屏幕分辨率在用户上传图片时自动生成不同分辨率的图片避免用户请求时实时进行转换的开销。这种优化对于视频、多格式存储文件等也非常有用。
综上所述,利用各种优化手段后整个互联网应用架构如下图所示。
上述架构的落地还面临一系列挑战,包括:
1.如何部署实施这么复杂的系统?
2.如何快速的定位高负债压力瓶颈子系统并自动进行扩容处理?
3.版本的迭代升级如何可控有序的得到执行?
上述问题如何解决呢?。回顾前文所说的新一代平台架构的三个特性,即“重平台、轻应用、服务化”,其中重平台和服务化的特性就是上述问题解决思路的方向。
重平台和服务化概念的背后是整个平台已经固化了大量可独立对外提供服务的组件或子系统,应用只需要负责业务逻辑的部分即可完成整个系统的部署上线。要实现这一点,需要做到如下三点:
应用需要进行业务逻辑、数据存储和服务组件的分离,实现业务逻辑、数据和组件服务的独立运行;平台要具备根据业务、数据和服务(组件)定义(编排)业务架构的能力,能够实现业务的编排部署;平台要能够实现对业务、组件(服务)和数据存储个子系统的运维管理,确保其在负载压力增大时能够自动弹性伸缩提升用户体验。
这就涉及应用封装、业务编排和弹性伸缩(自动运维)等方面的技术。BoCloud博云基于Docker的云应用发布与运维管理平台正是基于这样的理念和需求而开发的。下图为BoCloud的BeyondContainer产品架构:
如图所示,BeyondContainer包括三个主要部分:
基础设施子平台:负责管理平台的基础设施,除了服务器、存储、网络等基础设施外,还包括围绕应用相关的基础组件管理,如镜像仓库、容器、组件等。应用管控子平台:负责管理平台上的各类应用,提供应用部署、维护、日志等管理管控,同时实现多租户环境,实现基于服务目录的应用发布服务。一体化监控子平台:负责对整个平台中的资源、应用、通信等进行监控,并以可视化形式对外呈现系统各类监控信息。
限于篇幅,关于BeyondContainer的架构和特性就不再这里进行展开阐述。
本文分享了BoCloud博云在帮助传统企业在应对移动互联网业务冲击时在应用与平台架构上如何进行创新实践的经验,希望能够对大家有所启发。
高并发的socket的高性能设计
高性能的高并发socket设计
本文是从网络上搜集的几篇较好的文章:
主要转载自:
http://blog.csdn.net/qifengzou/article/details/
互联网金融系列-支付清算体系例子-下
笔者上一篇《互联网金融系列-支付清算体系介绍-上》已经比较全面的介绍了以银联为例子的支付清算体系,为了更好的理解里面的运作,本章以两个例子为重点,全面剖析整个清算的过程。
1,记账原则
面试常问问题:银行网上支付项目中怎么控制多线程高并发访问?
银行网上支付项目中怎么控制多线程高并发访问?
从零到百亿互联网金融架构发展史
回想起从公司成立敲出的第一行代码算起到现在也快三年了,平台的技术架构,技术体系也算是经历了四次比较重大的升级转化(目前第四代架构体系正在进行中),临近年底也想抽出时间来回顾一下,一个小公司从最开始的零...
【转载:https://blog.csdn.net/andyliulin/article/details/】synchronized关键字主要解决多线程共享数据同步问题。ThreadL...
1 什么是并发问题。
多个进程或线程同时(或着说在同一段时间内)访问同一资源会产生并发问题。
银行两操作员同时操作同一账户就是典型的例子。比如A、B操作员同时读取一余额为1000元的账...
银行批量可以分为:日间批量和日终批量。
所谓的日间批量,就是处理大批数据时,如果采用联机交易,通常会产生超时现象,同时对核心服务压力也很大。如果采用前台(客户端)通过联机交易调用日间批量,让数据处理...
1,订票系统案例,某航班只有一张机票,假定有1w个人打开你的网站来订票,问你如何解决并发问题(可扩展到任何高并发网站要考虑的并发读写问题)
问题,1w个人来访问,票没出去前要保证大...
一个小型的网站,比如个人网站,可以使用最简单的html静态页面就实现了,配合一些图片达到美化效果,所有的页面均存放在一个目录下,这样的网站对系统架构、性能的要求都很简单,随着互联网业务的不断丰富,网站...
没有更多推荐了,构建高并发高可用的电商平台架构实践 - 文章 - 伯乐在线
& 构建高并发高可用的电商平台架构实践
一、 设计理念
1. 空间换时间
1) 多级缓存,静态化
客户端页面缓存(http header中包含Expires/Cache of Control,last modified(304,server不返回body,客户端可以继续用cache,减少流量),ETag)
反向代理缓存
应用端的缓存(memcache)
内存数据库
Buffer、cache机制(数据库,中间件等)
哈希、B树、倒排、bitmap
哈希索引适合综合数组的寻址和链表的插入特性,可以实现数据的快速存取。
B树索引适合于查询为主导的场景,避免多次的IO,提高查询的效率。
倒排索引实现单词到文档映射关系的最佳实现方式和最有效的索引结构,广泛用在搜索领域。
Bitmap是一种非常简洁快速的数据结构,他能同时使存储空间和速度最优化(而不必空间换时间),适合于海量数据的的计算场景。
2. 并行与分布式计算
1) 任务切分、分而治之(MR)
在大规模的数据中,数据存在一定的局部性的特征,利用局部性的原理将海量数据计算的问题分而治之。
MR模型是无共享的架构,数据集分布至各个节点。处理时,每个节点就近读取本地存储的数据处理(map),将处理后的数据进行合并(combine)、排序(shuffle and sort)后再分发(至reduce节点),避免了大量数据的传输,提高了处理效率。
2) 多进程、多线程并行执行(MPP)
并行计算(Parallel Computing)是指同时使用多种计算资源解决计算问题的过程,是提高计算机系统计算速度和处理能力的一种有效手段。它的基本思想是用多个处理器/进程/线程来协同求解同一问题,即将被求解的问题分解成若干个部分,各部分均由一个独立的处理机来并行计算。
和MR的区别在于,它是基于问题分解的,而不是基于数据分解。
3. 多维度的可用
1) 负载均衡、容灾、备份
随着平台并发量的增大,需要扩容节点进行集群,利用负载均衡设备进行请求的分发;负载均衡设备通常在提供负载均衡的同时,也提供失效检测功能;同时为了提高可用性,需要有容灾备份,以防止节点宕机失效带来的不可用问题;备份有在线的和离线备份,可以根据失效性要求的不同,进行选择不同的备份策略。
2) 读写分离
读写分离是对数据库来讲的,随着系统并发量的增大,提高数据访问可用性的一个重要手段就是写数据和读数据进行分离;当然在读写分离的同时,需要关注数据的一致性问题;对于一致性的问题,在分布式的系统CAP定量中,更多的关注于可用性。
3) 依赖关系
平台中各个模块之间的关系尽量是低耦合的,可以通过相关的消息组件进行交互,能异步则异步,分清楚数据流转的主流程和副流程,主副是异步的,比如记录日志可以是异步操作的,增加整个系统的可用性。
当然在异步处理中,为了确保数据得到接收或者处理,往往需要确认机制(confirm、ack)。
但是有些场景中,虽然请求已经得到处理,但是因其他原因(比如网络不稳定),确认消息没有返回,那么这种情况下需要进行请求的重发,对请求的处理设计因重发因素需要考虑幂等性。
监控也是提高整个平台可用性的一个重要手段,多平台进行多个维度的监控;模块在运行时候是透明的,以达到运行期白盒化。
拆分包括对业务的拆分和对数据库的拆分。
系统的资源总是有限的,一段比较长的业务执行如果是一竿子执行的方式,在大量并发的操作下,这种阻塞的方式,无法有效的及时释放资源给其他进程执行,这样系统的吞吐量不高。
需要把业务进行逻辑的分段,采用异步非阻塞的方式,提高系统的吞吐量。
随着数据量和并发量的增加,读写分离不能满足系统并发性能的要求,需要对数据进行切分,包括对数据进行分库和分表。这种分库分表的方式,需要增加对数据的路由逻辑支持。
对于系统的伸缩性而言,模块最好是无状态的,通过增加节点就可以提高整个的吞吐量。
5. 优化资源利用
1) 系统容量有限
系统的容量是有限的,承受的并发量也是有限的,在架构设计时,一定需要考虑流量的控制,防止因意外攻击或者瞬时并发量的冲击导致系统崩溃。在设计时增加流控的措施,可考虑对请求进行排队,超出预期的范围,可以进行告警或者丢弃。
2) 原子操作与并发控制
对于共享资源的访问,为了防止冲突,需要进行并发的控制,同时有些交易需要有事务性来保证交易的一致性,所以在交易系统的设计时,需考虑原子操作和并发控制。
保证并发控制一些常用高性能手段有,乐观锁、Latch、mutex、写时复制、CAS等;多版本的并发控制MVCC通常是保证一致性的重要手段,这个在数据库的设计中经常会用到。
3) 基于逻辑的不同,采取不一样的策略
平台中业务逻辑存在不同的类型,有计算复杂型的,有消耗IO型的,同时就同一种类型而言,不同的业务逻辑消耗的资源数量也是不一样的,这就需要针对不同的逻辑采取不同的策略。
针对IO型的,可以采取基于事件驱动的异步非阻塞的方式,单线程方式可以减少线程的切换引起的开销,或者在多线程的情况下采取自旋spin的方式,减少对线程的切换(比如oracle latch设计);对于计算型的,充分利用多线程进行操作。
同一类型的调用方式,不同的业务进行合适的资源分配,设置不同的计算节点数量或者线程数量,对业务进行分流,优先执行优先级别高的业务。
4) 容错隔离
系统的有些业务模块在出现错误时,为了减少并发下对正常请求的处理的影响,有时候需要考虑对这些异常状态的请求进行单独渠道的处理,甚至暂时自动禁止这些异常的业务模块。
有些请求的失败可能是偶然的暂时的失败(比如网络不稳定),需要进行请求重试的考虑。
5) 资源释放
系统的资源是有限的,在使用资源时,一定要在最后释放资源,无论是请求走的是正常路径还是异常的路径,以便于资源的及时回收,供其他请求使用。
在设计通信的架构时,往往需要考虑超时的控制。
二、 静态架构蓝图
整个架构是分层的分布式的架构,纵向包括CDN,负载均衡/反向代理,web应用,业务层,基础服务层,数据存储层。水平方向包括对整个平台的配置管理部署和监控。
三、 剖析架构
CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。其目的是使用户可就近取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度。
对于大规模电子商务平台一般需要建CDN做网络加速,大型平台如淘宝、京东都采用自建CDN,中小型的企业可以采用第三方CDN厂商合作,如蓝汛、网宿、快网等。
当然在选择CDN厂商时,需要考虑经营时间长短,是否有可扩充的带宽资源、灵活的流量和带宽选择、稳定的节点、性价比。
2. 负载均衡、反向代理
一个大型的平台包括很多个业务域,不同的业务域有不同的集群,可以用DNS做域名解析的分发或轮询,DNS方式实现简单,但是因存在cache而缺乏灵活性;一般基于商用的硬件F5、NetScaler或者开源的软负载lvs在4层做分发,当然会采用做冗余(比如lvs+keepalived)的考虑,采取主备方式。
4层分发到业务集群上后,会经过web服务器如nginx或者HAProxy在7层做负载均衡或者反向代理分发到集群中的应用节点。
选择哪种负载,需要综合考虑各种因素(是否满足高并发高性能,Session保持如何解决,负载均衡的算法如何,支持压缩,缓存的内存消耗);下面基于几种常用的负载均衡软件做个介绍。
LVS,工作在4层,Linux实现的高性能高并发、可伸缩性、可靠的的负载均衡器,支持多种转发方式(NAT、DR、IP Tunneling),其中DR模式支持通过广域网进行负载均衡。支持双机热备(Keepalived或者Heartbeat)。对网络环境的依赖性比较高。
Nginx工作在7层,事件驱动的、异步非阻塞的架构、支持多进程的高并发的负载均衡器/反向代理软件。可以针对域名、目录结构、正则规则针对http做一些分流。通过端口检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点,不过其中缺点就是不支持url来检测。对于session sticky,可以基于ip hash的算法来实现,通过基于cookie的扩展nginx-sticky-module支持session sticky。
HAProxy支持4层和7层做负载均衡,支持session的会话保持,cookie的引导;支持后端url方式的检测;负载均衡的算法比较丰富,有RR、权重等。
对于图片,需要有单独的域名,独立或者分布式的图片服务器或者如mogileFS,可以图片服务器之上加varnish做图片缓存。
3. App接入
应用层运行在jboss或者tomcat容器中,代表独立的系统,比如前端购物、用户自主服务、后端系统等
协议接口,HTTP、JSON
可以采用servlet3.0,异步化servlet,提高整个系统的吞吐量
http请求经过Nginx,通过负载均衡算法分到到App的某一节点,这一层层扩容起来比较简单。
除了利用cookie保存少量用户部分信息外(cookie一般不能超过4K的大小),对于App接入层,保存有用户相关的session数据,但是有些反向代理或者负载均衡不支持对session sticky支持不是很好或者对接入的可用性要求比较高(app接入节点宕机,session随之丢失),这就需要考虑session的集中式存储,使得App接入层无状态化,同时系统用户变多的时候,就可以通过增加更多的应用节点来达到水平扩展的目的。
Session的集中式存储,需要满足以下几点要求:
a、高效的通讯协议
b、session的分布式缓存,支持节点的伸缩,数据的冗余备份以及数据的迁移
c、session过期的管理
4. 业务服务
代表某一领域的业务提供的服务,对于电商而言,领域有用户、商品、订单、红包、支付业务等等,不同的领域提供不同的服务,
这些不同的领域构成一个个模块,良好的模块划分和接口设计非常重要,一般是参考高内聚、接口收敛的原则,
这样可以提高整个系统的可用性。当然可以根据应用规模的大小,模块可以部署在一起,对于大规模的应用,一般是独立部署的。
业务层对外协议以NIO的RPC方式暴露,可以采用比较成熟的NIO通讯框架,如netty、mina
为了提高模块服务的可用性,一个模块部署在多个节点做冗余,并自动进行负载转发和失效转移;
最初可以利用VIP+heartbeat方式,目前系统有一个单独的组件HA,利用zookeeper实现(比原来方案的优点)
一致性、事务:
对于分布式系统的一致性,尽量满足可用性,一致性可以通过校对来达到最终一致的状态。
5. 基础服务中间件
1) 通信组件
通信组件用于业务系统内部服务之间的调用,在大并发的电商平台中,需要满足高并发高吞吐量的要求。
整个通信组件包括客户端和服务端两部分。
客户端和服务器端维护的是长连接,可以减少每次请求建立连接的开销,在客户端对于每个服务器定义一个连接池,初始化连接后,可以并发连接服务端进行rpc操作,连接池中的长连接需要心跳维护,设置请求超时时间。
对于长连接的维护过程可以分两个阶段,一个是发送请求过程,另外一个是接收响应过程。在发送请求过程中,若发生IOException,则把该连接标记失效。接收响应时,服务端返回SocketTimeoutException,如果设置了超时时间,那么就直接返回异常,清除当前连接中那些超时的请求。否则继续发送心跳包(因为可能是丢包,超过pingInterval间隔时间就发送ping操作),若ping不通(发送IOException),则说明当前连接是有问题的,那么就把当前连接标记成已经失效;若ping通,则说明当前连接是可靠的,继续进行读操作。失效的连接会从连接池中清除掉。
每个连接对于接收响应来说都以单独的线程运行,客户端可以通过同步(wait,notify)方式或者异步进行rpc调用,
序列化采用更高效的hession序列化方式。
服务端采用事件驱动的NIO的MINA框架,支撑高并发高吞吐量的请求。
2) 路由Router
在大多数的数据库切分解决方案中,为了提高数据库的吞吐量,首先是对不同的表进行垂直切分到不同的数据库中,
然后当数据库中一个表超过一定大小时,需要对该表进行水平切分,这里也是一样,这里以用户表为例;
对于访问数据库客户端来讲,需要根据用户的ID,定位到需要访问的数据;
数据切分算法,
根据用户的ID做hash操作,一致性Hash,这种方式存在失效数据的迁移问题,迁移时间内服务不可用
维护路由表,路由表中存储用户和sharding的映射关系,sharding分为leader和replica,分别负责写和读
这样每个biz客户端都需要保持所有sharding的连接池,这样有个缺点是会产生全连接的问题;
一种解决方法是sharding的切分提到业务服务层进行,每个业务节点只维护一个shard的连接即可。
见图(router)
路由组件的实现是这样的(可用性、高性能、高并发)
基于性能方面的考虑,采用mongodb中维护用户id和shard的关系,为了保证可用性,搭建replicatset集群。
biz的sharding和数据库的sharding是一一对应的,只访问一个数据库sharding.
biz业务注册节点到zookeeper上/bizs/shard/下。
router监听zookeeper上/bizs/下节点状态,缓存在线biz在router中。
client请求router获取biz时,router首先从mongodb中获取用户对应的shard,router根据缓存的内容通过RR算法获取biz节点。
为了解决router的可用性和并发吞吐量问题,对router进行冗余,同时client监听zookeeper的/routers节点并缓存在线router节点列表。
传统实现HA的做法一般是采用虚拟IP漂移,结合Heartbeat、keepalived等实现HA,
Keepalived使用vrrp方式进行数据包的转发,提供4层的负载均衡,通过检测vrrp数据包来切换,做冗余热备更加适合与LVS搭配。Linux Heartbeat是基于网络或者主机的服务的高可用,HAProxy或者Nginx可以基于7层进行数据包的转发,因此Heatbeat更加适合做HAProxy、Nginx,包括业务的高可用。
在分布式的集群中,可以用zookeeper做分布式的协调,实现集群的列表维护和失效通知,客户端可以选择hash算法或者roudrobin实现负载均衡;对于master-master模式、master-slave模式,可以通过zookeeper分布式锁的机制来支持。
4) 消息Message
对于平台各个系统之间的异步交互,是通过MQ组件进行的。
在设计消息服务组件时,需要考虑消息一致性、持久化、可用性、以及完善的监控体系。
业界开源的消息中间件主要RabbitMQ、kafka有两种,
RabbitMQ,遵循AMQP协议,由内在高并发的erlanng语言开发;kafka是Linkedin于2010年12月份开源的消息发布订阅系统,它主要用于处理活跃的流式数据,大数据量的数据处理上。
对消息一致性要求比较高的场合需要有应答确认机制,包括生产消息和消费消息的过程;不过因网络等原理导致的应答缺失,可能会导致消息的重复,这个可以在业务层次根据幂等性进行判断过滤;RabbitMQ采用的是这种方式。还有一种机制是消费端从broker拉取消息时带上LSN号,从broker中某个LSN点批量拉取消息,这样无须应答机制,kafka分布式消息中间件就是这种方式。
消息的在broker中的存储,根据消息的可靠性的要求以及性能方面的综合衡量,可以在内存中,可以持久化到存储上。
对于可用性和高吞吐量的要求,集群和主备模式都可以在实际的场景应用的到。RabbitMQ解决方案中有普通的集群和可用性更高的mirror queue方式。 kafka采用zookeeper对集群中的broker、consumer进行管理,可以注册topic到zookeeper上;通过zookeeper的协调机制,producer保存对应topic的broker信息,可以随机或者轮询发送到broker上;并且producer可以基于语义指定分片,消息发送到broker的某分片上。
总体来讲,RabbitMQ用在实时的对可靠性要求比较高的消息传递上。kafka主要用于处理活跃的流式数据,大数据量的数据处理上。
5) Cache&Buffer
在一些高并发高性能的场景中,使用cache可以减少对后端系统的负载,承担可大部分读的压力,可以大大提高系统的吞吐量,比如通常在数据库存储之前增加cache缓存。
但是引入cache架构不可避免的带来一些问题,cache命中率的问题, cache失效引起的抖动,cache和存储的一致性。
Cache中的数据相对于存储来讲,毕竟是有限的,比较理想的情况是存储系统的热点数据,这里可以用一些常见的算法LRU等等淘汰老的数据;随着系统规模的增加,单个节点cache不能满足要求,就需要搭建分布式Cache;为了解决单个节点失效引起的抖动 ,分布式cache一般采用一致性hash的解决方案,大大减少因单个节点失效引起的抖动范围;而对于可用性要求比较高的场景,每个节点都是需要有备份的。数据在cache和存储上都存有同一份备份,必然有一致性的问题,一致性比较强的,在更新数据库的同时,更新数据库cache。对于一致性要求不高的,可以去设置缓存失效时间的策略。
Memcached作为高速的分布式缓存服务器,协议比较简单,基于libevent的事件处理机制。
Cache系统在平台中用在router系统的客户端中,热点的数据会缓存在客户端,当数据访问失效时,才去访问router系统。
当然目前更多的利用内存型的数据库做cache,比如redis、mongodb;redis比memcache有丰富的数据操作的API;redis和mongodb都对数据进行了持久化,而memcache没有这个功能,因此memcache更加适合在关系型数据库之上的数据的缓存。
Buffer系统
用在高速的写操作的场景中,平台中有些数据需要写入数据库,并且数据是分库分表的,但对数据的可靠性不是那么高,为了减少对数据库的写压力,可以采取批量写操作的方式。
开辟一个内存区域,当数据到达区域的一定阀值时如80%时,在内存中做分库梳理工作(内存速度还是比较快的),后分库批量flush。
在电子商务平台中搜索是一个非常的重要功能,主要有搜索词类目导航、自动提示和搜索排序功能。
开源的企业级搜索引擎主要有lucene, sphinx,这里不去论述哪种搜索引擎更好一些,不过选择搜索引擎除了基本的功能需要支持外,非功能方面需要考虑以下两点:
a、 搜索引擎是否支持分布式的索引和搜索,来应对海量的数据,支持读写分离,提高可用性
b、 索引的实时性
Solr是基于lucene的高性能的全文搜索服务器,提供了比lucene更为丰富的查询语言,可配置可扩展,对外提供基于http协议的XML/JSON格式的接口。
从Solr4版本开始提供了SolrCloud方式来支持分布式的索引,自动进行sharding数据切分;通过每个sharding的master-slave(leader、replica)模式提高搜索的性能;利用zookeeper对集群进行管理,包括leader选举等等,保障集群的可用性。
Lucene索引的Reader是基于索引的snapshot的,所以必须在索引commit的后,重新打开一个新的snapshot,才能搜索到新添加的内容;而索引的commit是非常耗性能的,这样达到实时索引搜索效率就比较低下。
对于索引搜索实时性,Solr4的之前解决方案是结合文件全量索引和内存增量索引合并的方式,参见下图。
Solr4提供了NRT softcommit的解决方案,softcommit无需进行提交索引操作,就可以搜素到最新对索引的变更,不过对索引的变更并没有sync commit到硬盘存储上,若发生意外导致程序非正常结束,未commit的数据会丢失,因此需要定时的进行commit操作。
平台中对数据的索引和存储操作是异步的,可以大大提高可用性和吞吐量;只对某些属性字段做索引操作,存储数据的标识key,减少索引的大小;数据是存储在分布式存储HBase 中的,HBase对二级索引搜索支持的不好,然而可以结合Solr搜索功能进行多维度的检索统计。
索引数据和HBase数据存储的一致性,也就是如何保障HBase存储的数据都被索引过,可以采用confirm确认机制,通过在索引前建立待索引数据队列,在数据存储并索引完成后,从待索引数据队列中删除数据。
7) 日志收集
在整个交易过程中,会产生大量的日志,这些日志需要收集到分布式存储系统中存储起来,以便于集中式的查询和分析处理。
日志系统需具备三个基本组件,分别为agent(封装数据源,将数据源中的数据发送给collector),collector(接收多个agent的数据,并进行汇总后导入后端的store中),store(中央存储系统,应该具有可扩展性和可靠性,应该支持当前非常流行的HDFS)。
开源的日志收集系统业界使用的比较多的是cloudera的Flume和facebook的Scribe,其中Flume目前的版本FlumeNG对Flume从架构上做了较大的改动。
在设计或者对日志收集系统做技术选型时,通常需要具有以下特征:
a、 应用系统和分析系统之间的桥梁,将他们之间的关系解耦
b、 分布式可扩展,具有高的扩展性,当数据量增加时,可以通过增加节点水平扩展
日志收集系统是可以伸缩的,在系统的各个层次都可伸缩,对数据的处理不需要带状态,伸缩性方面也比较容易实现。
c、 近实时性
在一些时效性要求比较高的场景中,需要可以及时的收集日志,进行数据分析;
一般的日志文件都会定时或者定量的进行rolling,所以实时检测日志文件的生成,及时对日志文件进行类似的tail操作,并支持批量发送提高传输效率;批量发送的时机需要满足消息数量和时间间隔的要求。
d、 容错性
Scribe在容错方面的考虑是,当后端的存储系统crash时,scribe会将数据写到本地磁盘上,当存储系统恢复正常后,scribe将日志重新加载到存储系统中。
FlumeNG通过Sink Processor实现负载均衡和故障转移。多个Sink可以构成一个Sink Group。一个Sink Processor负责从一个指定的Sink Group中激活一个Sink。Sink Processor可以通过组中所有Sink实现负载均衡;也可以在一个Sink失败时转移到另一个。
e、 事务支持
Scribe没有考虑事务的支持。
Flume通过应答确认机制实现事务的支持,参见下图,
通常提取发送消息都是批量操作的,消息的确认是对一批数据的确认,这样可以大大提高数据发送的效率。
f、 可恢复性
FlumeNG的channel根据可靠性的要求的不同,可以基于内存和文件持久化机制,基于内存的数据传输的销量比较高,但是在节点宕机后,数据丢失,不可恢复;而文件持久化宕机是可以恢复的。
g、 数据的定时定量归档
数据经过日志收集系统归集后,一般存储在分布式文件系统如Hadoop,为了便于对数据进行后续的处理分析,需要定时(TimeTrigger)或者定量(SizeTrigger的rolling分布式系统的文件。
8) 数据同步
在交易系统中,通常需要进行异构数据源的同步,通常有数据文件到关系型数据库,数据文件到分布式数据库,关系型数据库到分布式数据库等。数据在异构源之间的同步一般是基于性能和业务的需求,数据存储在本地文件中一般是基于性能的考虑,文件是顺序存储的,效率还是比较高的;数据同步到关系型数据一般是基于查询的需求;而分布式数据库是存储越来越多的海量数据的,而关系型数据库无法满足大数据量的存储和查询请求。
在数据同步的设计中需要综合考虑吞吐量、容错性、可靠性、一致性的问题
同步有实时增量数据同步和离线全量数据区分,下面从这两个维度来介绍一下,
实时增量一般是Tail文件来实时跟踪文件变化,批量或者多线程往数据库导出,这种方式的架构类似于日志收集框架。这种方式需要有确认机制,包括两个方面。
一个方面是Channel需要给agent确认已经批量收到数据记录了,发送LSN号给agent,这样在agent失效恢复时,可以从这个LSN点开始tail;当然对于允许少量的重复记录的问题(发生在channel给agent确认的时,agent宕机并未受到确认消息),需要在业务场景中判断。
另外一个方面是sync给channel确认已经批量完成写入到数据库的操作,这样channel可以删除这部分已经confirm的消息。
基于可靠性的要求,channel可以采用文件持久化的方式。
离线全量遵循空间间换取时间,分而治之的原则,尽量的缩短数据同步的时间,提高同步的效率。
需要对源数据比如mysql进行切分,多线程并发读源数据,多线程并发批量写入分布式数据库比如HBase,利用channel作为读写之间的缓冲,实现更好的解耦,channel可以基于文件存储或者内存。参见下图:
对于源数据的切分,如果是文件可以根据文件名称设置块大小来切分。
对于关系型数据库,由于一般的需求是只离线同步一段时间的数据(比如凌晨把当天的订单数据同步到HBase),所以需要在数据切分时(按照行数切分),会多线程扫描整个表(及时建索引,也要回表),对于表中包含大量的数据来讲,IO很高,效率非常低;这里解决的方法是对数据库按照时间字段(按照时间同步的)建立分区,每次按照分区进行导出。
9) 数据分析
从传统的基于关系型数据库并行处理集群、用于内存计算近实时的,到目前的基于hadoop的海量数据的分析,数据的分析在大型电子商务网站中应用非常广泛,包括流量统计、推荐引擎、趋势分析、用户行为分析、数据挖掘分类器、分布式索引等等。
并行处理集群有商业的EMC Greenplum,Greenplum的架构采用了MPP(大规模并行处理),基于postgresql的大数据量存储的分布式数据库。
内存计算方面有SAP的HANA,开源的nosql内存型的数据库mongodb也支持mapreduce进行数据的分析。
海量数据的离线分析目前互联网公司大量的使用Hadoop,Hadoop在可伸缩性、健壮性、计算性能和成本上具有无可替代的优势,事实上已成为当前互联网企业主流的大数据分析平台
Hadoop通过MapReuce的分布式处理框架,用于处理大规模的数据,伸缩性也非常好;但是MapReduce最大的不足是不能满足实时性的场景,主要用于离线的分析。
基于MapRduce模型编程做数据的分析,开发上效率不高,位于hadoop之上Hive的出现使得数据的分析可以类似编写sql的方式进行,sql经过语法分析、生成执行计划后最终生成MapReduce任务进行执行,这样大大提高了开发的效率,做到以ad-hoc(计算在query发生时)方式进行的分析。
基于MapReduce模型的分布式数据的分析都是离线的分析,执行上都是暴力扫描,无法利用类似索引的机制;开源的Cloudera Impala是基于MPP的并行编程模型的,底层是Hadoop存储的高性能的实时分析平台,可以大大降低数据分析的延迟。
目前Hadoop使用的版本是Hadoop1.0,一方面原有的MapReduce框架存在JobTracker单点的问题,另外一方面JobTracker在做资源管理的同时又做任务的调度工作,随着数据量的增大和Job任务的增多,明显存在可扩展性、内存消耗、线程模型、可靠性和性能上的缺陷瓶颈;Hadoop2.0 yarn对整个框架进行了重构,分离了资源管理和任务调度,从架构设计上解决了这个问题。
参考Yarn的架构
10) 实时计算
在互联网领域,实时计算被广泛实时监控分析、流控、风险控制等领域。电商平台系统或者应用对日常产生的大量日志和异常信息,需要经过实时过滤、分析,以判定是否需要预警;
同时需要对系统做自我保护机制,比如对模块做流量的控制,以防止非预期的对系统压力过大而引起的系统瘫痪,流量过大时,可以采取拒绝或者引流等机制;有些业务需要进行风险的控制,比如彩票中有些业务需要根据系统的实时销售情况进行限号与放号。
原始基于单节点的计算,随着系统信息量爆炸式产生以及计算的复杂度的增加,单个节点的计算已不能满足实时计算的要求,需要进行多节点的分布式的计算,分布式实时计算平台就出现了。
这里所说的实时计算,其实是流式计算,概念前身其实是CEP复杂事件处理,相关的开源产品如Esper,业界分布式的流计算产品Yahoo S4,Twitter storm等,以storm开源产品使用最为广泛。
对于实时计算平台,从架构设计上需要考虑以下几个因素:
1、 伸缩性
随着业务量的增加,计算量的增加,通过增加节点处理,就可以处理。
2、 高性能、低延迟
从数据流入计算平台数据,到计算输出结果,需要性能高效且低延迟,保证消息得到快速的处理,做到实时计算。
3、 可靠性
保证每个数据消息得到一次完整处理。
4、 容错性
系统可以自动管理节点的宕机失效,对应用来说,是透明的。
Twitter的Storm在以上这几个方面做的比较好,下面简介一下Storm的架构。
整个集群的管理是通过zookeeper来进行的。
客户端提交拓扑到nimbus。
Nimbus针对该拓扑建立本地的目录根据topology的配置计算task,分配task,在zookeeper上建立assignments节点存储task和supervisor机器节点中woker的对应关系。
在zookeeper上创建taskbeats节点来监控task的心跳;启动topology。
Supervisor去zookeeper上获取分配的tasks,启动多个woker进行,每个woker生成task,一个task一个线程;根据topology信息初始化建立task之间的连接;Task和Task之间是通过zeroMQ管理的;之后整个拓扑运行起来。
Tuple是流的基本处理单元,也就是一个消息,Tuple在task中流转,Tuple的发送和接收过程如下:
发送Tuple,Worker提供了一个transfer的功能,用于当前task把tuple发到到其他的task中。以目的taskid和tuple参数,序列化tuple数据并放到transfer queue中。
在0.8版本之前,这个queue是LinkedBlockingQueue,0.8之后是DisruptorQueue。
在0.8版本之后,每一个woker绑定一个inbound transfer queue和outbond queue,inbound queue用于接收message,outbond queue用于发送消息。
发送消息时,由单个线程从transferqueue中拉取数据,把这个tuple通过zeroMQ发送到其他的woker中。
接收Tuple,每个woker都会监听zeroMQ的tcp端口来接收消息,消息放到DisruptorQueue中后,后从queue中获取message(taskid,tuple),根据目的taskid,tuple的值路由到task中执行。每个tuple可以emit到direct steam中,也可以发送到regular stream中,在Reglular方式下,由Stream Group(stream id–&component id –&outbond tasks)功能完成当前tuple将要发送的Tuple的目的地。
通过以上分析可以看到,Storm在伸缩性、容错性、高性能方面的从架构设计的角度得以支撑;同时在可靠性方面,Storm的ack组件利用异或xor算法在不失性能的同时,保证每一个消息得到完整处理的同时。
11) 实时推送
实时推送的应用场景非常多,比如系统的监控动态的实时曲线绘制,手机消息的推送,web实时聊天等。
实时推送有很多技术可以实现,有Comet方式,有websocket方式等。
Comet基于服务器长连接的“服务器推”技术,包含两种:
Long Polling:服务器端在接到请求后挂起,有更新时返回连接即断掉,然后客户端再发起新的连接
Stream方式: 每次服务端数据传送不会关闭连接,连接只会在通信出现错误时,或是连接重建时关闭(一些防火墙常被设置为丢弃过长的连接, 服务器端可以设置一个超时时间, 超时后通知客户端重新建立连接,并关闭原来的连接)。
Websocket:长连接,全双工通信
是 Html5 的一种新的协议。它实现了浏览器与服务器的双向通讯。webSocket API 中,浏览器和服务器端只需要通过一个握手的动作,便能形成浏览器与客户端之间的快速双向通道,使得数据可以快速的双向传播。
Socket.io是一个NodeJS websocket库,包括客户端的JS和服务端的的nodejs,用于快速构建实时的web应用。
12) 推荐引擎
6. 数据存储
数据库存储大体分为以下几类,有关系型(事务型)的数据库,以oracle、mysql为代表,有keyvalue数据库,以redis和memcached db为代表,有文档型数据库如mongodb,有列式分布式数据库以HBase,cassandra,dynamo为代表,还有其他的图形数据库、对象数据 库、xml数据库等。每种类型的数据库应用的业务领域是不一样的,下面从内存型、关系型、分布式三个维度针对相关的产品做性能可用性等方面的考量分析。
1) 内存型数据库
内存型的数据库,以高并发高性能为目标,在事务性方面没那么严格,以开源nosql数据库mongodb、redis为例
多线程方式,主线程监听新的连接,连接后,启动新的线程做数据的操作(IO切换)。
数据库–&collection–&record
MongoDB在数据存储上按命名空间来划分,一个collection是一个命名空间,一个索引也是一个命名空间。
同一个命名空间的数据被分成很多个Extent,Extent之间使用双向链表连接。
在每一个Extent中,保存了具体每一行的数据,这些数据也是通过双向链接连接的。
每一行数据存储空间不仅包括数据占用空间,还可能包含一部分附加空间,这使得在数据update变大后可以不移动位置。
索引以BTree结构实现。
如果你开启了jorunaling日志,那么还会有一些文件存储着你所有的操作记录。
持久化存储
MMap方式把文件地址映射到内存的地址空间,直接操作内存地址空间就可以操作文件,不用再调用write,read操作,性能比较高。
mongodb调用mmap把磁盘中的数据映射到内存中的,所以必须有一个机制时刻的刷数据到硬盘才能保证可靠性,多久刷一次是与syncdelay参数相关的。
journal(进行恢复用)是Mongodb中的redo log,而Oplog则是负责复制的binlog。如果打开journal,那么即使断电也只会丢失100ms的数据,这对大多数应用来说都可以容忍了。从1.9.2+,mongodb都会默认打开journal功能,以确保数据安全。而且journal的刷新时间是可以改变的,2-300ms的范围,使用 –journalCommitInterval 命令。Oplog和数据刷新到磁盘的时间是60s,对于复制来说,不用等到oplog刷新磁盘,在内存中就可以直接复制到Sencondary节点。
Mongodb只支持对单行记录的原子操作
用的比较多的是Replica Sets,采用选举算法,自动进行leader选举,在保证可用性的同时,可以做到强一致性要求。
当然对于大量的数据,mongodb也提供了数据的切分架构Sharding。
丰富的数据结构,高速的响应速度,内存操作
因都在内存操作,所以逻辑的操作非常快,减少了CPU的切换开销,所以为单线程的模式(逻辑处理线程和主线程是一个)。
reactor模式,实现自己的多路复用NIO机制(epoll,select,kqueue等)
单线程处理多任务
hash+bucket结构,当链表的长度过长时,会采取迁移的措施(扩展原来两倍的hash表,把数据迁移过去,expand+rehash)
持久化存储
a、全量持久化RDB(遍历redisDB,读取bucket中的key,value),save命令阻塞主线程,bgsave开启子进程进行snapshot持久化操作,生成rdb文件。
在shutdown时,会调用save操作
数据发生变化,在多少秒内触发一次bgsave
sync,master接受slave发出来的命令
b、增量持久化(aof类似redolog),先写到日志buffer,再flush到日志文件中(flush的策略可以配置的,而已单条,也可以批量),只有flush到文件上的,才真正返回客户端。
要定时对aof文件和rdb文件做合并操作(在快照过程中,变化的数据先写到aof buf中等子进程完成快照&内存snapshot&后,再进行合并aofbuf变化的部分以及全镜像数据)。
在高并发访问模式下,RDB模式使服务的性能指标出现明显的抖动,aof在性能开销上比RDB好,但是恢复时重新加载到内存的时间和数据量成正比。
通用的解决方案是主从备份切换,采用HA软件,使得失效的主redis可以快速的切换到从redis上。主从数据的同步采用复制机制,该场景可以做读写分离。
目前在复制方面,存在的一个问题是在遇到网络不稳定的情况下,Slave和Master断开(包括闪断)会导致Master需要将内存中的数据全部重新生成rdb文件(快照文件),然后传输给Slave。Slave接收完Master传递过来的rdb文件以后会将自身的内存清空,把rdb文件重新加载到内存中。这种方式效率比较低下,在后面的未来版本Redis2.8作者已经实现了部分复制的功能。
2) 关系型数据库
关系型数据库在满足并发性能的同时,也需要满足事务性,以mysql数据库为例,讲述架构设计原理,在性能方面的考虑,以及如何满足可用性的需求。
? mysql的架构原理(innodb)
在架构上,mysql分为server层和存储引擎层。
Server层的架构对于不同的存储引擎来讲都是一样的,包括连接/线程处理、查询处理(parser、optimizer)以及其他系统任务。存储引擎层有很多种,mysql提供了存储引擎的插件式结构,支持多种存储引擎,用的最广泛的是innodb和myisamin;inodb主要面向OLTP方面的应用,支持事务处理,myisam不支持事务,表锁,对OLAP操作速度快。
以下主要针对innodb存储引擎做相关介绍。
在线程处理方面,Mysql是多线程的架构,由一个master线程,一个锁监控线程,一个错误监控线程,和多个IO线程组成。并且对一个连接会开启一个线程进行服务。io线程又分为节省随机IO的insert buffer,用于事务控制的类似于oracle的redo log,以及多个write,多个read的硬盘和内存交换的IO线程。
在内存分配方面,包括innodb buffer pool ,以及log buffer。其中innodb buffer pool包括insert buffer、datapage、index page、数据字典、自适应hash。Log buffer用于缓存事务日志,提供性能。
在数据结构方面,innodb包括表空间、段、区、页/块,行。索引结构是B+tree结构,包括二级索引和主键索引,二级索引的叶子节点是主键PK,根据主键索引的叶子节点指向存储的数据块。这种B+树存储结构可以更好的满足随机查询操作IO要求,分为数据页和二级索引页,修改二级索引页面涉及到随机操作,为了提高写入时的性能,采用insert buffer做顺序的写入,再由后台线程以一定频率将多个插入合并到二级索引页面。为了保证数据库的一致性(内存和硬盘数据文件),以及缩短实例恢复的时间,关系型数据库还有一个checkpoint的功能,用于把内存buffer中之前的脏页按照比例(老的LSN)写入磁盘,这样redolog文件的LSN以前的日志就可以被覆盖了,进行循环使用;在失效恢复时,只需要从日志中LSN点进行恢复即可。
在事务特性支持上,关系型数据库需要满足ACID四个特性,需要根据不同的事务并发和数据可见性要求,定义了不同的事务隔离级别,并且离不开对资源争用的锁机制,要避免产生死锁,mysql在Server层和存储引擎层做并发控制,主要体现在读写锁,根据锁粒度不同,有各个级别的锁(表锁、行锁、页锁、MVCC);基于提高并发性能的考虑,使用多版本并发控制MVCC来支持事务的隔离,并基于undo来实现,在做事务回滚时,也会用到undo段。mysql 用redolog来保证数据的写入的性能和失效恢复,在修改数据时只需要修改内存,再把修改行为记录到事务日志中(顺序IO),不用每次将数据修改本身持久化到硬盘(随机IO),大大提高性能。
在可靠性方面,innodb存储引擎提供了两次写机制double writer用于防止在flush页面到存储上出现的错误,解决磁盘half-writern的问题。
? 对于高并发高性能的mysql来讲,可以在多个维度进行性能方面的调优。
a、硬件级别,
日志和数据的存储,需要分开,日志是顺序的写,需要做raid1+0,并且用buffer-IO;数据是离散的读写,走direct IO即可,避免走文件系统cache带来的开销。
存储能力,SAS盘raid操作(raid卡缓存,关闭读cache,关闭磁盘cache,关闭预读,只用writeback buffer,不过需要考虑充放电的问题),当然如果数据规模不大,数据的存储可以用高速的设备,Fusion IO、SSD。
对于数据的写入,控制脏页刷新的频率,对于数据的读取,控制cache hit率;因此而估算系统需要的IOPS,评估需要的硬盘数量(fusion io上到IOPS 在10w以上,普通的硬盘150)。
Cpu方面,单实例关闭NUMA,mysql对多核的支持不是太好,可以对多实例进行CPU绑定。
b、操作系统级别,
内核以及socket的优化,网络优化bond、文件系统、IO调度
innodb主要用在OLTP类应用,一般都是IO密集型的应用,在提高IO能力的基础上,充分利用cache机制。需要考虑的内容有,
在保证系统可用内存的基础上,尽可能的扩大innodb buffer pool,一般设置为物理内存的3/4
文件系统的使用,只在记录事务日志的时候用文件系统的cache;尽量避免mysql用到swap(可以将vm.swappiness=0,内存紧张时,释放文件系统cache)
IO调度优化,减少不必要的阻塞,降低随机IO访问的延时(CFQ、Deadline、NOOP)
c、server以及存储引擎级别(连接管理、网络管理、table管理、日志)
包括cache/buffer、Connection、IO
d、应用级别(比如索引的考虑,schema的优化适当冗余;优化sql查询导致的CPU问题和内存问题,减少锁的范围,减少回表扫描,覆盖索引)
? 在高可用实践方面,
支持master-master、master-slave模式,master-master模式是一个作为主负责读写,另外一个作为standby提供灾备,maser-slave是一个作为主提供写操作,其他几个节点作为读操作,支持读写分离。
对于节点主备失效检测和切换,可以采用HA软件,当然也可以从更细粒度定制的角度,采用zookeeper作为集群的协调服务。
对于分布式的系统来讲,数据库主备切换的一致性始终是一个问题,可以有以下几种方式:
a、集群方式,如oracle的rack,缺点是比较复杂
b、共享SAN存储方式,相关的数据文件和日志文件都放在共享存储上,优点是主备切换时数据保持一致,不会丢失,但由于备机有一段时间的拉起,会有短暂的不可用状态
c、主备进行数据同步的方式,常见的是日志的同步,可以保障热备,实时性好,但是切换时,可能有部分数据没有同步过来,带来了数据的一致性问题。可以在操作主数据库的同时,记录操作日志,切换到备时,会和操作日志做个check,补齐未同步过来的数据;
d、还有一种做法是备库切换到主库的regolog的存储上,保证数据不丢失。
数据库主从复制的效率在mysql上不是太高,主要原因是事务是严格保持顺序的,索引mysql在复制方面包括日志IO和relog log两个过程都是单线程的串行操作,在数据复制优化方面,尽量减少IO的影响。不过到了Mysql5.6版本,可以支持在不同的库上的并行复制。
? 基于不同业务要求的存取方式
平台业务中,不同的业务有不同的存取要求,比如典型的两大业务用户和订单,用户一般来讲总量是可控的,而订单是不断地递增的,对于用户表首先采取分库切分,每个sharding做一主多读,同样对于订单因更多需求的是用户查询自己的订单,也需要按照用户进行切分订单库,并且支持一主多读。
在硬件存储方面,对于事务日志因是顺序写,闪存的优势比硬盘高不了多少,所以采取电池保护的写缓存的raid卡存储;对于数据文件,无论是对用户或者订单都会存在大量的随机读写操作,当然加大内存是一个方面,另外可以采用高速的IO设备闪存,比如PCIe卡 fusion-io。使用闪存也适合在单线程的负载中,比如主从复制,可以对从节点配置fusion-IO卡,降低复制的延迟。
对于订单业务来讲,量是不断递增的,PCIe卡存储容量比较有限,并且订单业务的热数据只有最近一段时间的(比如近3个月的),对此这里列两种解决方案,一种是flashcache方式,采用基于闪存和硬盘存储的开源混合存储方式,在闪存中存储热点的数据。另外一种是可以定期把老的数据导出到分布式数据库HBase中,用户在查询订单列表是近期的数据从mysql中获取,老的数据可以从HBase中查询,当然需要HBase良好的rowkey设计以适应查询需求。
3) 分布式数据库
对于数据的高并发的访问,传统的关系型数据库提供读写分离的方案,但是带来的确实数据的一致性问题提供的数据切分的方案;对于越来越多的海量数据,传统的数据库采用的是分库分表,实现起来比较复杂,后期要不断的进行迁移维护;对于高可用和伸缩方面,传统数据采用的是主备、主从、多主的方案,但是本身扩展性比较差,增加节点和宕机需要进行数据的迁移。对于以上提出的这些问题,分布式数据库HBase有一套完善的解决方案,适用于高并发海量数据存取的要求。
基于列式的高效存储降低IO
通常的查询不需要一行的全部字段,大多数只需要几个字段
对与面向行的存储系统,每次查询都会全部数据取出,然后再从中选出需要的字段
面向列的存储系统可以单独查询某一列,从而大大降低IO
提高压缩效率
同列数据具有很高的相似性,会增加压缩效率
Hbase的很多特性,都是由列存储决定的
强一致的数据访问
HBase的一致性数据访问是通过MVCC来实现的。
HBase在写数据的过程中,需要经过好几个阶段,写HLog,写memstore,更新MVCC;
只有更新了MVCC,才算真正memstore写成功,其中事务的隔离需要有mvcc的来控制,比如读数据不可以获取别的线程还未提交的数据。
HBase的数据存储基于HDFS,提供了冗余机制。
Region节点的宕机,对于内存中的数据还未flush到文件中,提供了可靠的恢复机制。
可伸缩,自动切分,迁移
通过Zookeeper定位目标Region Server,最后定位Region。
Region Server扩容,通过将自身发布到Master,Master均匀分布。
存在单点故障,Region Server宕机后,短时间内该server维护的region无法访问,等待failover生效。
通过Master维护各Region Server健康状况和Region分布。
多个Master,Master宕机有zookeeper的paxos投票机制选取下一任Master。Master就算全宕机,也不影响Region读写。Master仅充当一个自动运维角色。
HDFS为分布式存储引擎,一备三,高可靠,0数据丢失。
HDFS的namenode是一个SPOF。
为避免单个region访问过于频繁,单机压力过大,提供了split机制
HBase的写入是LSM-TREE的架构方式,随着数据的append,HFile越来越多,HBase提供了HFile文件进行compact,对过期数据进行清除,提高查询的性能。
Schema free
HBase没有像关系型数据库那样的严格的schema,可以自由的增加和删除schema中的字段。
HBase分布式数据库,对于二级索引支持的不太好,目前只支持在rowkey上的索引,所以rowkey的设计对于查询的性能来讲非常关键。
7. 管理与部署配置
统一的配置库
8. 监控、统计
大型分布式系统涉及各种设备,比如网络交换机,普通PC机,各种型号的网卡,硬盘,内存等等,还有应用业务层次的监控,数量非常多的时候,出现错误的概率也会变大,并且有些监控的时效性要求比较高,有些达到秒级别;在大量的数据流中需要过滤异常的数据,有时候也对数据会进行上下文相关的复杂计算,进而决定是否需要告警。因此监控平台的性能、吞吐量、已经可用性就比较重要,需要规划统一的一体化的监控平台对系统进行各个层次的监控。
平台的数据分类
应用业务级别:应用事件、业务日志、审计日志、请求日志、异常、请求业务metrics、性能度量
系统级别:CPU、内存、网络、IO
时效性要求
阀值,告警:
实时计算:
近实时分钟计算
按小时、天的离线分析
节点中Agent代理可以接收日志、应用的事件以及通过探针的方式采集数据,agent采集数据的一个原则是和业务应用的流程是异步隔离的,不影响交易流程。
数据统一通过collector集群进行收集,按照数据的不同类型分发到不同的计算集群进行处理;有些数据时效性不是那么高,比如按小时进行统计,放入hadoop集群;有些数据是请求流转的跟踪数据,需要可以查询的,那么就可以放入solr集群进行索引;有些数据需要进行实时计算的进而告警的,需要放到storm集群中进行处理。
数据经过计算集群处理后,结果存储到Mysql或者HBase中。
监控的web应用可以把监控的实时结果推送到浏览器中,也可以提供API供结果的展现和搜索。}

我要回帖

更多关于 高并发高负载分布式编程 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信