上海网站备案管理中心,深圳市官网网站建设报价,眼科医院网站开发,一个简单的app多少钱静态架构蓝图
整个架构是分层的分布式的架构#xff0c;纵向包括CDN#xff0c;负载均衡/反向代理#xff0c;web应用#xff0c;业务层#xff0c;基础服务层#xff0c;数据存储层。水平方向包括对整个平台的配置管理部署和监控。
剖析架构
1. CDN
CDN系统能够实时…静态架构蓝图
整个架构是分层的分布式的架构纵向包括CDN负载均衡/反向代理web应用业务层基础服务层数据存储层。水平方向包括对整个平台的配置管理部署和监控。
剖析架构
1. CDN
CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。其目的是使用户可就近取得所需内容解决 Internet网络拥挤的状况提高用户访问网站的响应速度。
对于大规模电子商务平台一般需要建CDN做网络加速大型平台如淘宝、京东都采用自建CDN中小型的企业可以采用第三方CDN厂商合作如蓝汛、网宿、快网等。
当然在选择CDN厂商时需要考虑经营时间长短是否有可扩充的带宽资源、灵活的流量和带宽选择、稳定的节点、性价比。
2. 负载均衡、反向代理
一个大型的平台包括很多个业务域不同的业务域有不同的集群可以用DNS做域名解析的分发或轮询DNS方式实现简单但是因存在cache而缺乏灵活性一般基于商用的硬件F5、NetScaler或者开源的软负载lvs在4层做分发当然会采用做冗余(比如lvskeepalived)的考虑采取主备方式。
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
可用性
为了提高模块服务的可用性一个模块部署在多个节点做冗余并自动进行负载转发和失效转移;
最初可以利用VIPheartbeat方式目前系统有一个单独的组件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的连接即可。
路由组件的实现是这样的可用性、高性能、高并发
基于性能方面的考虑采用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节点列表。 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分布式锁的机制来支持。
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) CacheBuffer
Cache系统
在一些高并发高性能的场景中使用cache可以减少对后端系统的负载承担可大部分读的压力可以大大提高系统的吞吐量比如通常在数据库存储之前增加cache缓存。
但是引入cache架构不可避免的带来一些问题cache命中率的问题, cache失效引起的抖动cache和存储的一致性。
Cache中的数据相对于存储来讲毕竟是有限的比较理想的情况是存储系统的热点数据这里可以用一些常见的算法LRU等等淘汰老的数据随着系统规模的增加单个节点cache不能满足要求就需要搭建分布式Cache为了解决单个节点失效引起的抖动 分布式cache一般采用一致性hash的解决方案大大减少因单个节点失效引起的抖动范围而对于可用性要求比较高的场景每个节点都是需要有备份的。数据在cache和存储上都存有同一份备份必然有一致性的问题一致性比较强的在更新数据库的同时更新数据库cache。对于一致性要求不高的可以去设置缓存失效时间的策略。
Memcached作为高速的分布式缓存服务器协议比较简单基于libevent的事件处理机制。
Cache系统在平台中用在router系统的客户端中热点的数据会缓存在客户端当数据访问失效时才去访问router系统。
当然目前更多的利用内存型的数据库做cache比如Redis、mongodbredis比memcache有丰富的数据操作的APIredis和mongodb都对数据进行了持久化而memcache没有这个功能因此memcache更加适合在关系型数据库之上的数据的缓存。 Buffer系统
用在高速的写操作的场景中平台中有些数据需要写入数据库并且数据是分库分表的但对数据的可靠性不是那么高为了减少对数据库的写压力可以采取批量写操作的方式。
开辟一个内存区域当数据到达区域的一定阀值时如80%时在内存中做分库梳理工作(内存速度还是比较快的)后分库批量flush。
6) 搜索
在电子商务平台中搜索是一个非常的重要功能主要有搜索词类目导航、自动提示和搜索排序功能。
开源的企业级搜索引擎主要有lucene, sphinx这里不去论述哪种搜索引擎更好一些不过选择搜索引擎除了基本的功能需要支持外非功能方面需要考虑以下两点
a、 搜索引擎是否支持分布式的索引和搜索来应对海量的数据支持读写分离提高可用性
b、 索引的实时性
c、 性能
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封装数据源将数据源中的数据发送给collectorcollector接收多个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 GreenplumGreenplum的架构采用了MPP(大规模并行处理)基于postgresql的大数据量存储的分布式数据库。
内存计算方面有SAP的HANA开源的nosql内存型的数据库mongodb也支持mapreduce进行数据的分析。
海量数据的离线分析目前互联网公司大量的使用HadoopHadoop在可伸缩性、健壮性、计算性能和成本上具有无可替代的优势事实上已成为当前互联网企业主流的大数据分析平台
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的发送和接收过程如下
发送TupleWorker提供了一个transfer的功能用于当前task把tuple发到到其他的task中。以目的taskid和tuple参数序列化tuple数据并放到transfer queue中。
在0.8版本之前这个queue是LinkedBlockingQueue0.8之后是DisruptorQueue。
在0.8版本之后每一个woker绑定一个inbound transfer queue和outbond queueinbound queue用于接收messageoutbond 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 Groupstream 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有列式分布式数据库以HBasecassandra,dynamo为代表还有其他的图形数据库、对象数据 库、xml数据库等。每种类型的数据库应用的业务领域是不一样的下面从内存型、关系型、分布式三个维度针对相关的产品做性能可用性等方面的考量分析。
1) 内存型数据库
内存型的数据库以高并发高性能为目标在事务性方面没那么严格以开源nosql数据库mongodb、redis为例
Ø Mongodb
通信方式
多线程方式主线程监听新的连接连接后启动新的线程做数据的操作IO切换。
数据结构
数据库--collection--record
MongoDB在数据存储上按命名空间来划分一个collection是一个命名空间一个索引也是一个命名空间。
同一个命名空间的数据被分成很多个ExtentExtent之间使用双向链表连接。
在每一个Extent中保存了具体每一行的数据这些数据也是通过双向链接连接的。
每一行数据存储空间不仅包括数据占用空间还可能包含一部分附加空间这使得在数据update变大后可以不移动位置。
索引以BTree结构实现。
如果你开启了jorunaling日志那么还会有一些文件存储着你所有的操作记录。 持久化存储
MMap方式把文件地址映射到内存的地址空间直接操作内存地址空间就可以操作文件不用再调用write,read操作性能比较高。
mongodb调用mmap把磁盘中的数据映射到内存中的所以必须有一个机制时刻的刷数据到硬盘才能保证可靠性多久刷一次是与syncdelay参数相关的。 journal进行恢复用是Mongodb中的redo log而Oplog则是负责复制的binlog。如果打开journal那么即使断电也只会丢失100ms的数据这对大多数应用来说都可以容忍了。从1.9.2mongodb都会默认打开journal功能以确保数据安全。而且journal的刷新时间是可以改变的2-300ms的范围,使用 --journalCommitInterval 命令。Oplog和数据刷新到磁盘的时间是60s对于复制来说不用等到oplog刷新磁盘在内存中就可以直接复制到Sencondary节点。 事务支持
Mongodb只支持对单行记录的原子操作 HA集群
用的比较多的是Replica Sets采用选举算法自动进行leader选举在保证可用性的同时可以做到强一致性要求。 当然对于大量的数据mongodb也提供了数据的切分架构Sharding。 Ø Redis
丰富的数据结构高速的响应速度内存操作
通信方式
因都在内存操作所以逻辑的操作非常快减少了CPU的切换开销所以为单线程的模式逻辑处理线程和主线程是一个。 reactor模式实现自己的多路复用NIO机制epollselectkqueue等 单线程处理多任务
数据结构 hashbucket结构当链表的长度过长时会采取迁移的措施扩展原来两倍的hash表把数据迁移过去expandrehash 持久化存储
a、全量持久化RDB遍历redisDB,读取bucket中的key,valuesave命令阻塞主线程bgsave开启子进程进行snapshot持久化操作生成rdb文件。 在shutdown时会调用save操作 数据发生变化在多少秒内触发一次bgsave
syncmaster接受slave发出来的命令
b、增量持久化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作者已经实现了部分复制的功能。
2) 关系型数据库
关系型数据库在满足并发性能的同时也需要满足事务性以mysql数据库为例讲述架构设计原理在性能方面的考虑以及如何满足可用性的需求。
Ø mysql的架构原理(innodb)
在架构上mysql分为server层和存储引擎层。
Server层的架构对于不同的存储引擎来讲都是一样的,包括连接/线程处理、查询处理(parser、optimizer)以及其他系统任务。存储引擎层有很多种mysql提供了存储引擎的插件式结构支持多种存储引擎用的最广泛的是innodb和myisamininodb主要面向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包括表空间、段、区、页/块行。索引结构是Btree结构包括二级索引和主键索引二级索引的叶子节点是主键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、硬件级别
日志和数据的存储需要分开日志是顺序的写需要做raid10并且用buffer-IO数据是离散的读写走direct IO即可避免走文件系统cache带来的开销。
存储能力SAS盘raid操作raid卡缓存关闭读cache关闭磁盘cache关闭预读只用writeback buffer不过需要考虑充放电的问题当然如果数据规模不大数据的存储可以用高速的设备Fusion IO、SSD。
对于数据的写入控制脏页刷新的频率对于数据的读取控制cache hit率因此而估算系统需要的IOPS评估需要的硬盘数量(fusion io上到IOPS 在10w以上普通的硬盘150)。
Cpu方面单实例关闭NUMAmysql对多核的支持不是太好可以对多实例进行CPU绑定。
b、操作系统级别
内核以及socket的优化网络优化bond、文件系统、IO调度
innodb主要用在OLTP类应用一般都是IO密集型的应用在提高IO能力的基础上充分利用cache机制。需要考虑的内容有
在保证系统可用内存的基础上尽可能的扩大innodb buffer pool一般设置为物理内存的3/4
文件系统的使用只在记录事务日志的时候用文件系统的cache尽量避免mysql用到swap(可以将vm.swappiness0内存紧张时释放文件系统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有一套完善的解决方案适用于高并发海量数据存取的要求。 Ø 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扩容通过将自身发布到MasterMaster均匀分布。 可用性
存在单点故障Region Server宕机后短时间内该server维护的region无法访问等待failover生效。
通过Master维护各Region Server健康状况和Region分布。
多个MasterMaster宕机有zookeeper的paxos投票机制选取下一任Master。Master就算全宕机也不影响Region读写。Master仅充当一个自动运维角色。
HDFS为分布式存储引擎一备三高可靠0数据丢失。
HDFS的namenode是一个SPOF。
为避免单个region访问过于频繁单机压力过大提供了split机制
HBase的写入是LSM-TREE的架构方式随着数据的appendHFile越来越多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供结果的展现和搜索。