设计理念前端
1 时间换空间node
1.1 多级缓存,静态化mysql
客户端页面缓存(http header中包含Expires/Cache of Control,last modified(304,server不返回body,客户端能够继续用cache,减小流量),ETag),react
反向代理缓存,应用端的缓存(memcache),内存数据库,Buffer、cache机制(数据库,中间件等)。nginx
1.2 索引web
哈希、B树、倒排、bitmapredis
哈希索引:适合综合数组的寻址和链表的插入特性,能够实现数据的快速存取。算法
B树索引:适合于查询为主导的场景,避免屡次的IO,提升查询的效率。sql
倒排索引:实现单词到文档映射关系的最佳实现方式和最有效的索引结构,普遍用在搜索领域。mongodb
Bitmap:是一种很是简洁快速的数据结构,他能同时使存储空间和速度最优化(而没必要空间换时间),适合于海量数据的的计算场景。
2. 并行与分布式计算
2.1 任务切分、分而治之(MR)
在大规模的数据中,数据存在必定的局部性的特征,利用局部性的原理将海量数据计算的问题分而治之。
MR模型是无共享的架构,数据集分布至各个节点。处理时,每一个节点就近读取本地存储的数据处理(map),将处理后的数据进行合并(combine)、排序(shuffle and sort)后再分发(至reduce节点),避免了大量数据的传输,提升了处理效率。
2.2 多进程、多线程并行执行(MPP)
并行计算(Parallel Computing)是指同时使用多种计算资源解决计算问题的过程,是提升计算机系统计算速度和处理能力的一种有效手段。它的基本思想是用多个处理器/进程/线程来协同求解同一问题,即将被求解的问题分解成若干个部分,各部分均由一个独立的处理机来并行计算。
和MR的区别在于,它是基于问题分解的,而不是基于数据分解。
3.多维度的可用
3.1 负载均衡、容灾、备份
随着平台并发量的增大,须要扩容节点进行集群,利用负载均衡设备进行请求的分发;负载均衡设备一般在提供负载均衡的同时,也提供失效检测功能;同时为了提升可用性,须要有容灾备份,以防止节点宕机失效带来的不可用问题;备份有在线的和离线备份,能够根据失效性要求的不一样,进行选择不一样的备份策略。
3.2 读写分离
读写分离是对数据库来说的,随着系统并发量的增大,提升数据访问可用性的一个重要手段就是写数据和读数据进行分离;固然在读写分离的同时,须要关注数据的一致性问题;对于一致性的问题,在分布式的系统CAP定量中,更多的关注于可用性。
3.3 依赖关系
平台中各个模块之间的关系尽可能是低耦合的,能够经过相关的消息组件进行交互,能异步则异步,分清楚数据流转的主流程和副流程,主副是异步的,好比记录日志能够是异步操做的,增长整个系统的可用性。固然在异步处理中,为了确保数据获得接收或者处理,每每须要确认机制(confirm、ack)。
可是有些场景中,虽然请求已经获得处理,可是因其余缘由(好比网络不稳定),确认消息没有返回,那么这种状况下须要进行请求的重发,对请求的处理设计因重发因素须要考虑幂等性。
3.4 监控
监控也是提升整个平台可用性的一个重要手段,多平台进行多个维度的监控;模块在运行时候是透明的,以达到运行期白盒化。
4.伸缩
4.1 拆分
拆分包括对业务的拆分和对数据库的拆分。
系统的资源老是有限的,一段比较长的业务执行若是是一竿子执行的方式,在大量并发的操做下,这种阻塞的方式,没法有效的及时释放资源给其余进程执行,这样系统的吞吐量不高。须要把业务进行逻辑的分段,采用异步非阻塞的方式,提升系统的吞吐量。
随着数据量和并发量的增长,读写分离不能知足系统并发性能的要求,须要对数据进行切分,包括对数据进行分库和分表。这种分库分表的方式,须要增长对数据的路由逻辑支持。
4.2 无状态
对于系统的伸缩性而言,模块最好是无状态的,经过增长节点就能够提升整个的吞吐量。
5. 优化资源利用
5.1 系统容量有限
系统的容量是有限的,承受的并发量也是有限的,在架构设计时,必定须要考虑流量的控制,防止因意外攻击或者瞬时并发量的冲击致使系统崩溃。在设计时增长流控的措施,可考虑对请求进行排队,超出预期的范围,能够进行告警或者丢弃。
5.2 原子操做与并发控制
对于共享资源的访问,为了防止冲突,须要进行并发的控制,同时有些交易须要有事务性来保证交易的一致性,因此在交易系统的设计时,需考虑原子操做和并发控制。
保证并发控制一些经常使用高性能手段有,乐观锁、Latch、mutex、写时复制、CAS等;多版本的并发控制MVCC一般是保证一致性的重要手段,这个在数据库的设计中常常会用到。
5.3 基于逻辑的不一样,采起不同的策略
平台中业务逻辑存在不一样的类型,有计算复杂型的,有消耗IO型的,同时就同一种类型而言,不一样的业务逻辑消耗的资源数量也是不同的,这就须要针对不一样的逻辑采起不一样的策略。
针对IO型的,能够采起基于事件驱动的异步非阻塞的方式,单线程方式能够减小线程的切换引发的开销,或者在多线程的状况下采起自旋spin的方式,减小对线程的切换(好比oracle latch设计);对于计算型的,充分利用多线程进行操做。
同一类型的调用方式,不一样的业务进行合适的资源分配,设置不一样的计算节点数量或者线程数量,对业务进行分流,优先执行优先级别高的业务。
5.4 容错隔离
系统的有些业务模块在出现错误时,为了减小并发下对正常请求的处理的影响,有时候须要考虑对这些异常状态的请求进行单独渠道的处理,甚至暂时自动禁止这些异常的业务模块。有些请求的失败多是偶然的暂时的失败(好比网络不稳定),须要进行请求重试的考虑。
5.5 资源释放
系统的资源是有限的,在使用资源时,必定要在最后释放资源,不管是请求走的是正常路径仍是异常的路径,以便于资源的及时回收,供其余请求使用。在设计通讯的架构时,每每须要考虑超时的控制。
技术架构
整个架构是分层的分布式的架构,纵向包括CDN,负载均衡/反向代理,web应用,业务层,基础服务层,数据存储层。水平方向包括对整个平台的配置管理部署和监控。下面是对架构的剖析。
1. CDN
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的集中式存储,须要知足如下几点要求:
- 高效的通信协议
- session的分布式缓存,支持节点的伸缩,数据的冗余备份以及数据的迁移
- session过时的管理
4. 业务服务
表明某一领域的业务提供的服务,对于电商而言,领域有用户、商品、订单、红包、支付业务等等,不一样的领域提供不一样的服务,这些不一样的领域构成一个个模块,良好的模块划分和接口设计很是重要,通常是参考高内聚、接口收敛的原则,这样能够提升整个系统的可用性。固然能够根据应用规模的大小,模块能够部署在一块儿,对于大规模的应用,通常是独立部署的。
高并发:业务层对外协议以NIO的RPC方式暴露,能够采用比较成熟的NIO通信框架,如netty、mina
可用性:为了提升模块服务的可用性,一个模块部署在多个节点作冗余,并自动进行负载转发和失效转移;
最初能够利用VIP+heartbeat方式,目前系统有一个单独的组件HA,利用zookeeper实现(比原来方案的优势)
一致性&事务:对于分布式系统的一致性,尽可能知足可用性,一致性能够经过校对来达到最终一致的状态。
5. 基础服务中间件
5.1 通讯组件
通讯组件用于业务系统内部服务之间的调用,在大并发的电商平台中,须要知足高并发高吞吐量的要求。整个通讯组件包括客户端和服务端两部分。
- 客户端和服务器端维护的是长链接,能够减小每次请求创建链接的开销,在客户端对于每一个服务器定义一个链接池,初始化链接后,能够并发链接服务端进行rpc操做,链接池中的长链接须要心跳维护,设置请求超时时间。对于长链接的维护过程能够分两个阶段,一个是发送请求过程,另一个是接收响应过程。在发送请求过程当中,若发生IOException,则把该链接标记失效。接收响应时,服务端返回SocketTimeoutException,若是设置了超时时间,那么就直接返回异常,清除当前链接中那些超时的请求。不然继续发送心跳包(由于多是丢包,超过pingInterval间隔时间就发送ping操做),若ping不通(发送IOException),则说明当前链接是有问题的,那么就把当前链接标记成已经失效;若ping通,则说明当前链接是可靠的,继续进行读操做。失效的链接会从链接池中清除掉。每一个链接对于接收响应来讲都以单独的线程运行,客户端能够经过同步(wait,notify)方式或者异步进行rpc调用,序列化采用更高效的hession序列化方式。
- 服务端采用事件驱动的NIO的MINA框架,支撑高并发高吞吐量的请求。
5.2 路由(Router)
在大多数的数据库切分解决方案中,为了提升数据库的吞吐量,首先是对不一样的表进行垂直切分到不一样的数据库中,而后当数据库中一个表超过必定大小时,须要对该表进行水平切分,这里也是同样,这里以用户表为例,对于访问数据库客户端来说,须要根据用户的ID,定位到须要访问的数据;
数据切分算法,根据用户的ID作hash操做,一致性Hash,这种方式存在失效数据的迁移问题,迁移时间内服务不可用
维护路由表,路由表中存储用户和sharding的映射关系,sharding分为leader和replica,分别负责写和读,这样每一个biz客户端都须要保持全部sharding的链接池,这样有个缺点是会产生全链接的问题。一种解决方法是sharding的切分提到业务服务层进行,每一个业务节点只维护一个shard的链接便可。
路由组件的实现是这样的(可用性、高性能、高并发)。基于性能方面的考虑,采用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节点列表。
5.3 HA
传统实现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分布式锁的机制来支持。
5.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.5 Cache&Buffer
5.5.1 Cache系统
在一些高并发高性能的场景中,使用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更加适合在关系型数据库之上的数据的缓存。
5.5.2 Buffer系统
用在高速的写操做的场景中,平台中有些数据须要写入数据库,而且数据是分库分表的,但对数据的可靠性不是那么高,为了减小对数据库的写压力,能够采起批量写操做的方式。开辟一个内存区域,当数据到达区域的必定阀值时如80%时,在内存中作分库梳理工做(内存速度仍是比较快的),后分库批量flush。
5.6 搜索
在电子商务平台中搜索是一个很是的重要功能,主要有搜索词类目导航、自动提示和搜索排序功能。
开源的企业级搜索引擎主要有lucene, sphinx,这里不去论述哪一种搜索引擎更好一些,不过选择搜索引擎除了基本的功能须要支持外,非功能方面须要考虑如下两点:
- 搜索引擎是否支持分布式的索引和搜索,来应对海量的数据,支持读写分离,提升可用性
- 索引的实时性
- 性能
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确认机制,经过在索引前创建待索引数据队列,在数据存储并索引完成后,从待索引数据队列中删除数据。
5.7 日志收集
在整个交易过程当中,会产生大量的日志,这些日志须要收集到分布式存储系统中存储起来,以便于集中式的查询和分析处理。
日志系统需具有三个基本组件,分别为agent(封装数据源,将数据源中的数据发送给collector),collector(接收多个agent的数据,并进行汇总后导入后端的store中),store(中央存储系统,应该具备可扩展性和可靠性,应该支持当前很是流行的HDFS)。
开源的日志收集系统业界使用的比较多的是cloudera的Flume和facebook的Scribe,其中Flume目前的版本FlumeNG对Flume从架构上作了较大的改动。
在设计或者对日志收集系统作技术选型时,一般须要具备如下特征:
- 应用系统和分析系统之间的桥梁,将他们之间的关系解耦
- 分布式可扩展,具备高的扩展性,当数据量增长时,能够经过增长节点水平扩展
日志收集系统是能够伸缩的,在系统的各个层次均可伸缩,对数据的处理不须要带状态,伸缩性方面也比较容易实现。
- 近实时性
在一些时效性要求比较高的场景中,须要能够及时的收集日志,进行数据分析;通常的日志文件都会定时或者定量的进行rolling,因此实时检测日志文件的生成,及时对日志文件进行相似的tail操做,并支持批量发送提升传输效率;批量发送的时机须要知足消息数量和时间间隔的要求。
- 容错性
Scribe在容错方面的考虑是,当后端的存储系统crash时,scribe会将数据写到本地磁盘上,当存储系统恢复正常后,scribe将日志从新加载到存储系统中。
FlumeNG经过Sink Processor实现负载均衡和故障转移。多个Sink能够构成一个Sink Group。一个Sink Processor负责从一个指定的Sink Group中激活一个Sink。Sink Processor能够经过组中全部Sink实现负载均衡;也能够在一个Sink失败时转移到另外一个。
- 事务支持
Scribe没有考虑事务的支持。Flume经过应答确认机制实现事务的支持,参见下图,
一般提取发送消息都是批量操做的,消息的确认是对一批数据的确认,这样能够大大提升数据发送的效率。
- 可恢复性
FlumeNG的channel根据可靠性的要求的不一样,能够基于内存和文件持久化机制,基于内存的数据传输的销量比较高,可是在节点宕机后,数据丢失,不可恢复;而文件持久化宕机是能够恢复的。
- 数据的定时定量归档
数据通过日志收集系统归集后,通常存储在分布式文件系统如Hadoop,为了便于对数据进行后续的处理分析,须要定时(TimeTrigger)或者定量(SizeTrigger的rolling分布式系统的文件。
5.8 数据同步
在交易系统中,一般须要进行异构数据源的同步,一般有数据文件到关系型数据库,数据文件到分布式数据库,关系型数据库到分布式数据库等。数据在异构源之间的同步通常是基于性能和业务的需求,数据存储在本地文件中通常是基于性能的考虑,文件是顺序存储的,效率仍是比较高的;数据同步到关系型数据通常是基于查询的需求;而分布式数据库是存储愈来愈多的海量数据的,而关系型数据库没法知足大数据量的存储和查询请求。
在数据同步的设计中须要综合考虑吞吐量、容错性、可靠性、一致性的问题
同步有实时增量数据同步和离线全量数据区分,下面从这两个维度来介绍一下,
实时增量通常是Tail文件来实时跟踪文件变化,批量或者多线程往数据库导出,这种方式的架构相似于日志收集框架。这种方式须要有确认机制,包括两个方面。
一个方面是Channel须要给agent确认已经批量收到数据记录了,发送LSN号给agent,这样在agent失效恢复时,能够从这个LSN点开始tail;固然对于容许少许的重复记录的问题(发生在channel给agent确认的时,agent宕机并未受到确认消息),须要在业务场景中判断。
另一个方面是sync给channel确认已经批量完成写入到数据库的操做,这样channel能够删除这部分已经confirm的消息。
基于可靠性的要求,channel能够采用文件持久化的方式。参见下图
离线全量遵循空间间换取时间,分而治之的原则,尽可能的缩短数据同步的时间,提升同步的效率。须要对源数据好比mysql进行切分,多线程并发读源数据,多线程并发批量写入分布式数据库好比HBase,利用channel做为读写之间的缓冲,实现更好的解耦,channel能够基于文件存储或者内存。参见下图。
对于源数据的切分,若是是文件能够根据文件名称设置块大小来切分。
对于关系型数据库,因为通常的需求是只离线同步一段时间的数据(好比凌晨把当天的订单数据同步到HBase),因此须要在数据切分时(按照行数切分),会多线程扫描整个表(及时建索引,也要回表),对于表中包含大量的数据来说,IO很高,效率很是低;这里解决的方法是对数据库按照时间字段(按照时间同步的)创建分区,每次按照分区进行导出。
5.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对整个框架进行了重构,分离了资源管理和任务调度,从架构设计上解决了这个问题。
5.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算法在不失性能的同时,保证每个消息获得完整处理的同时。
5.11实时推送
实时推送的应用场景很是多,好比系统的监控动态的实时曲线绘制,手机消息的推送,web实时聊天等。实时推送有不少技术能够实现,有Comet方式,有websocket方式等。Comet基于服务器长链接的“服务器推”技术,包含两种:
Long Polling:服务器端在接到请求后挂起,有更新时返回链接即断掉,而后客户端再发起新的链接
Stream方式: 每次服务端数据传送不会关闭链接,链接只会在通讯出现错误时,或是链接重建时关闭(一些防火墙常被设置为丢弃过长的链接, 服务器端能够设置一个超时时间, 超时后通知客户端从新创建链接,并关闭原来的链接)。
Websocket:长链接,全双工通讯
是 Html5 的一种新的协议。它实现了浏览器与服务器的双向通信。webSocket API 中,浏览器和服务器端只须要经过一个握手的动做,便能造成浏览器与客户端之间的快速双向通道,使得数据能够快速的双向传播。
Socket.io是一个NodeJS websocket库,包括客户端的JS和服务端的的nodejs,用于快速构建实时的web应用。
5.12 推荐引擎
待补充
6. 数据存储
数据库存储大致分为如下几类,有关系型(事务型)的数据库,以oracle、mysql为表明,有keyvalue数据库,以redis和memcached db为表明,有文档型数据库如mongodb,有列式分布式数据库以HBase,cassandra,dynamo为表明,还有其余的图形数据库、对象数据 库、xml数据库等。每种类型的数据库应用的业务领域是不同的,下面从内存型、关系型、分布式三个维度针对相关的产品作性能可用性等方面的考量分析。
6.1 内存型数据库
内存型的数据库,以高并发高性能为目标,在事务性方面没那么严格,以开源nosql数据库mongodb、redis为例
6.1.1 Mongodb
通讯方式:多线程方式,主线程监听新的链接,链接后,启动新的线程作数据的操做(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只支持对单行记录的原子操做
HA集群
用的比较多的是Replica Sets,采用选举算法,自动进行leader选举,在保证可用性的同时,能够作到强一致性要求。
固然对于大量的数据,mongodb也提供了数据的切分架构Sharding。
6.1.2 Redis
丰富的数据结构,高速的响应速度,内存操做
通讯方式:因都在内存操做,因此逻辑的操做很是快,减小了CPU的切换开销,因此为单线程的模式(逻辑处理线程和主线程是一个)。reactor模式,实现本身的多路复用NIO机制(epoll,select,kqueue等)单线程处理多任务
数据结构:hash+bucket结构,当链表的长度过长时,会采起迁移的措施(扩展原来两倍的hash表,把数据迁移过去,expand+rehash)
持久化存储
1)全量持久化RDB(遍历redisDB,读取bucket中的key,value),save命令阻塞主线程,bgsave开启子进程进行snapshot持久化操做,生成rdb文件。在shutdown时,会调用save操做数据发生变化,在多少秒内触发一次bgsave,sync,master接受slave发出来的命令。
2)增量持久化(aof相似redolog),先写到日志buffer,再flush到日志文件中(flush的策略能够配置的,而已单条,也能够批量),只有flush到文件上的,才真正返回客户端。要定时对aof文件和rdb文件作合并操做(在快照过程当中,变化的数据先写到aof buf中等子进程完成快照<内存snapshot>后,再进行合并aofbuf变化的部分以及全镜像数据)。在高并发访问模式下,RDB模式使服务的性能指标出现明显的抖动,aof在性能开销上比RDB好,可是恢复时从新加载到内存的时间和数据量成正比。
集群HA
通用的解决方案是主从备份切换,采用HA软件,使得失效的主redis能够快速的切换到从redis上。主从数据的同步采用复制机制,该场景能够作读写分离。
目前在复制方面,存在的一个问题是在遇到网络不稳定的状况下,Slave和Master断开(包括闪断)会致使Master须要将内存中的数据所有从新生成rdb文件(快照文件),而后传输给Slave。Slave接收完Master传递过来的rdb文件之后会将自身的内存清空,把rdb文件从新加载到内存中。这种方式效率比较低下,在后面的将来版本Redis2.8做者已经实现了部分复制的功能。
关系型数据库在知足并发性能的同时,也须要知足事务性,以mysql数据库为例,讲述架构设计原理,在性能方面的考虑,以及如何知足可用性的需求。
6.2.1 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的问题。
6.2.2 对于高并发高性能的mysql来说,能够在多个维度进行性能方面的调优。
1)硬件级别,
日志和数据的存储,须要分开,日志是顺序的写,须要作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绑定。
2) 操做系统级别,
内核以及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)
3)server以及存储引擎级别(链接管理、网络管理、table管理、日志)
包括cache/buffer、Connection、IO
4)应用级别(好比索引的考虑,schema的优化适当冗余;优化sql查询致使的CPU问题和内存问题,减小锁的范围,减小回表扫描,覆盖索引)
6.2.3 在高可用实践方面
支持master-master、master-slave模式,master-master模式是一个做为主负责读写,另一个做为standby提供灾备,maser-slave是一个做为主提供写操做,其余几个节点做为读操做,支持读写分离。对于节点主备失效检测和切换,能够采用HA软件,固然也能够从更细粒度定制的角度,采用zookeeper做为集群的协调服务。对于分布式的系统来说,数据库主备切换的一致性始终是一个问题,能够有如下几种方式:
1)集群方式,如oracle的rack,缺点是比较复杂
2)共享SAN存储方式,相关的数据文件和日志文件都放在共享存储上,优势是主备切换时数据保持一致,不会丢失,但因为备机有一段时间的拉起,会有短暂的不可用状态
3)主备进行数据同步的方式,常见的是日志的同步,能够保障热备,实时性好,可是切换时,可能有部分数据没有同步过来,带来了数据的一致性问题。能够在操做主数据库的同时,记录操做日志,切换到备时,会和操做日志作个check,补齐未同步过来的数据;
4)还有一种作法是备库切换到主库的regolog的存储上,保证数据不丢失。
数据库主从复制的效率在mysql上不是过高,主要缘由是事务是严格保持顺序的,索引mysql在复制方面包括日志IO和relog log两个过程都是单线程的串行操做,在数据复制优化方面,尽可能减小IO的影响。不过到了Mysql5.6版本,能够支持在不一样的库上的并行复制。
6.2.4 基于不一样业务要求的存取方式
平台业务中,不一样的业务有不一样的存取要求,好比典型的两大业务用户和订单,用户通常来说总量是可控的,而订单是不断地递增的,对于用户表首先采起分库切分,每一个sharding作一主多读,一样对于订单因更多需求的是用户查询本身的订单,也须要按照用户进行切分订单库,而且支持一主多读。
在硬件存储方面,对于事务日志因是顺序写,闪存的优点比硬盘高不了多少,因此采起电池保护的写缓存的raid卡存储;对于数据文件,不管是对用户或者订单都会存在大量的随机读写操做,固然加大内存是一个方面,另外能够采用高速的IO设备闪存,好比PCIe卡 fusion-io。使用闪存也适合在单线程的负载中,好比主从复制,能够对从节点配置fusion-IO卡,下降复制的延迟。
对于订单业务来说,量是不断递增的,PCIe卡存储容量比较有限,而且订单业务的热数据只有最近一段时间的(好比近3个月的),对此这里列两种解决方案,一种是flashcache方式,采用基于闪存和硬盘存储的开源混合存储方式,在闪存中存储热点的数据。另一种是能够按期把老的数据导出到分布式数据库HBase中,用户在查询订单列表是近期的数据从mysql中获取,老的数据能够从HBase中查询,固然须要HBase良好的rowkey设计以适应查询需求。
6.3分布式数据库
对于数据的高并发的访问,传统的关系型数据库提供读写分离的方案,可是带来的确实数据的一致性问题提供的数据切分的方案;对于愈来愈多的海量数据,传统的数据库采用的是分库分表,实现起来比较复杂,后期要不断的进行迁移维护;对于高可用和伸缩方面,传统数据采用的是主备、主从、多主的方案,可是自己扩展性比较差,增长节点和宕机须要进行数据的迁移。对于以上提出的这些问题,分布式数据库HBase有一套完善的解决方案,适用于高并发海量数据存取的要求。
6.3.1 HBase
基于列式的高效存储下降IO
一般的查询不须要一行的所有字段,大多数只须要几个字段
对与面向行的存储系统,每次查询都会所有数据取出,而后再从中选出须要的字段
面向列的存储系统能够单独查询某一列,从而大大下降IO
提升压缩效率
同列数据具备很高的类似性,会增长压缩效率
Hbase的不少特性,都是由列存储决定的
高性能
LSM Tree
适合高速写的场景
强一致的数据访问
MVCC
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供结果的展示和搜索。
本文转载于http://blog.csdn.net/yangbutao/article/details/12242441