海量数据下的分布式存储与计算

YLIMHHMILY 2012-12-02

转自:http://blog.csdn.net/larrylgq/article/details/7851207

存储

从理论角度

提到大数据存储nosql是不得不提的一个部分,CAP,BASE,ACID这些原理在过去的一些年对其有着一定的指导作用(近年来随着各种实时计算模型的发展,CAP也被渐渐打破)

CAP:(Consistency-Availability-Partition Tolerance

数据一致性(C):等同于所有节点访问同一份最新的数据副本;

对数据更新具备高可用性(A):在可写的时候可读,可读的时候可写,最少的停工时间

能容忍网络分区(P)

eg:

传统数据库一般采用CA即强一致性和高可用性

nosql,云存储等一般采用降低一致性的代价来获得另外2个因素

ACID:按照CAP分法ACID是许多CA型关系数据库多采用的原则:

A:Atomicity原子性,事务作为最小单位,要么不执行要么完全执行

C:Consistency一致性,一个事务把一个对象从一个合法状态转到另一个合法状态,如果交易失败,把对象恢复到前一个合法状态。即在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏

I:Isolation独立性(隔离性),事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据。

D:Durability:事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚

BASE:一般是通过牺牲强一致性,来换取可用性和分布式

BA:BasicallyAavilable基本可用:允许偶尔的失败,只要保证绝大多数情况下系统可用

S:SoftState软状态:无连接?无状态?

E:EventualConsistency最终一致性:要求数据在一定的时间内达到一致性

以云存储为例:目前的云存储多以整体上采用BASE局部采用ACID,由于使用分布式使用多备份所以多采用最终一致性

Nosql常见的数据模型有key/value和Schema Free(自由列表模式)两种,

key/value,每条记录由2个域组成,一个作为主键,一个存储记录的数据(mongodb)

SchemaFree,每条记录有一个主键,若干条列组成,有点类似关系型数据库(hbase)

在实现这些模型的时候基本使用2种实现方式:哈希加链表,或者B+树的方式

哈希加链表:通过将key进行哈希来确定存储位置,相同哈希值的数据存储成链表

海量数据下的分布式存储与计算

基本的hash寻址算法有除法散列法,平方散列法,斐波那契(Fibonacci)散列法等,但是java是这样做的

static int indexFor(int h, int length) {  

returnh&(length-1);

}

java会用key的hashcode值与数组的槽数-1进行与运算

这里会有一个问题只有当数组的槽数为2的n次方-1,其二进制全是1的(如2的2次方-1=11)的时候哈希值产生碰撞的概率是最小的

所以在java中hashmap的数组的初始大小是16(2的4次方)

hashmap的问题

hashmap的resize:

当不断put数据使数据慢慢变大的时候,刚开始的数组已经不能满足需求了,我们需要扩大数组的槽数

hashmap中有loadFactor属性,该属性默认为0.75,即元素个数达到数组的百分之七十五的时候,数组槽数会进行翻倍,并且之前已存入的数据会重新进行计算。

so:如果我们可以预估我们会在hashmap中存放1000个数据,那么我们就要确保数组的槽数乘上0.75大于1000,我们得到1366,如果我们这样写newHashMap(1366),java会自动帮我们转换成newHashMap(2048)(2的n次方)

B+树:B+树的特点

1.节点中关键字数量与字节点数相同。  

2.所有叶子结点中包含全部指向记录的指针

3.叶子结点按照自小而大顺序链接

5通常在B+树上有两个头指针,一个指向根结点,一个指向关键字最小的叶子结点

(爬虫会有深度优先,广度优先的算法)

来自百度的图

海量数据下的分布式存储与计算

so:hash查找单条非常快

b+树,范围查找很快(深度优先,广度优先的遍历等)

需要一个可以排序的hash结构

空间换时间:跳表+hashtable实现可排序的hash

跳表结构

海量数据下的分布式存储与计算

so:增,删,改(通过跳表)的复杂度为o(log(n))

查(通过hashtable)的复杂度为O(1)

当然我们不知道有结构化的数据,特别我们存储的数据是需要拿来进行复杂的数据挖掘算法,所以有的时候nosql并不能满足我们的需要

实际的数据

结构化

半结构化(我们的数据)

非结构化

海量(百T级别)

数据偶尔丢掉几条没关系

数据质量差

选择hdfs的原因

hdfs在设计之初考虑到了以下几个方面:

1,hdfs将采用大量稳定性差的廉价pc来做为文件存储设备,所以pc发生死机或硬盘故障的几率极高,应看作是常态,所以hdfs应该提供数据多备份,自动检测节点存活,和故障机器的自动修复

2,hdfs存储的大多是大文件,所以针对大文件的读写会作出优化

3,对于写入数据来说,系统会有很多追加操作,而很少会有随机读写

4,对于读取数据来说,大多数的操作是顺序读,很少有随机读

计算

从理论角度

离线计算      :针对海量的,对实时性要求不是很高的数据

实时流计算:数据清洗,topn等应用场景

列存储:大表jion,海量数据实时查找

key-value:对半结构化,非结构化数据的实时查找(结构灵活,适合项目初期的试错阶段)

内存和磁盘计算的区别

寻址

内存是通过电子工作的,所以搜索速度和物理结构无关,进行寻址时只需要微秒级别既可以

磁盘在寻址时需要1,移动磁头2,旋转磁盘因为磁盘旋转的速度有限,所以寻址消耗毫秒别时间

*操作系统会将一个连续的数据存放在一起(win一般是4KB),这样磁盘旋转一周读取的数据就会多些,从而提高效率

传输速度

内存和硬盘的数据都会被读到cpu的缓存中,但是从内存到缓存和从硬盘到缓存的传输速度是差别很大的

内存到缓存的速度大概有7-8GB/秒,而磁盘到缓存的速度大概只有60MB/秒

so:因此内存计算和磁盘计算的速度差可以达到百万倍以上

离线计算

hadoop现了mapreduce的思想,将数据切片计算来处理大量的离线数据数据。

hadoop处理的数据必须是已经存放在支持的分布式文件系统上或者类似hbase的数据库中,所以hadoop实现的时候是通过移动计算到这些存放数据的机器上来提高效率

ps:针对hadoop我们的使用是开发一个类似pig的mdx框架,与pig的区别是我们的框架会更加的针对业务友好,业务人员只需要了解维度信息和需要的度量即可

实时流计算

storm是一个流计算框架,处理的数据是实时消息队列中的,所以需要我们写好一个topology逻辑放在那,接收进来的数据来处理,所以是通过移动数据平均分配到机器资源来获得高效率

列存储

提出region和Xfile概念(如hbase的HFILE和hive的rcfile以及yuntable的YFile)

根据key将数据分到不同的region,保存log,数据压缩并行列转置后存到Xfile,定期或使用内存到了一定阙值flash到硬盘

列存优点举例-

eg1:通过region和XFile过滤掉大量数据,如果对100g的数据做分析

通过region会过滤掉一大批数据

对于数值类型,每个xfile会有一个预统计(最大最小值)又会过滤掉一部分数据

假设还剩下2.5g的数据

对于频繁使用的数据会在内存中有缓存

假设命中2g

剩下的0.5g会已压缩的方式存放在硬盘(定长字段压缩比更大,当然数字的压缩比最大)

so-100g的查询=》2g的内存查找+0.5g的硬盘查找(内存寻址是硬盘寻址的几百万倍)

eg2:通过动态扩展列来进行大表的jion

google的bigtable进行cookie的join,是将一个几千万的用户行为的表jion到一张100亿行的cookie大表,它只需要将新的表根据cookie重新做一下索引即可,因为数据是列存储所以具体的数据存储不需要实际的硬盘移动,大大减少了jion的时间,尽管这个表有几十万的列但对查找几乎是没有影响的

key-value

存储非结构化数据

-eg:评论,问答

再看下数据

结构化

半结构化(我们的数据)

非结构化

海量(百T级别)

数据偶尔丢掉几条没关系

数据质量差

到目前为止我们的处理方案是:

离线分析(对实时性要求不高-hadoop)-结构化,半结构化,非结构化

实时分析(对实时性要求极高-storm)-结构化,半结构化,非结构化

实时查找(经常性对大量数据进行count等操作-infobright,hbase)-结构化,部分支持半结构化

有时我们需要对非结构化的数据做一些实时搜索的功能keyvalue搞不定怎么办--实时搜索(巧妙设计数据结构)

我们的做法是:

倒排索引

+关键字的前缀冗余

具体关键字的前缀冗余使用redis的zset完成,其本质也是一个hashtable+跳表的所以结构

这样存的时候需要切词,存储,key和关键字映射的存储,前缀和关键字映射的存储

但是读的时候是非常迅速的,如下图当用户输入J 就可以很快的找到关于java等的信息(当然还需要一些评分,权重算法)

海量数据下的分布式存储与计算

服务架构需要考虑的问题:

CPU负载和I/O负载(计算密集型和io密集型)

CPU负载-计算密集型

所谓CPU负载就是通常的web服务等,这些服务基本上只消耗cpu,所以只要增加安装相同服务的服务器,然后就可已通过负载均衡器工作了

I/O负载-io密集型

1.数据的切割和在机器间的分配策略(原则是尽量移动计算而不是移动数据)

2.如何通过多备份来确保数据的可用性(确保多备份的一致性)

3.如何使集群针对性强的响应客户端的读写请求

4.如何实现集群中单台机器的热拔插

5.好的负载均衡策略

6.网络通信延迟,因为计算机运行的速度是微秒甚至纳秒,所以毫秒级别的延迟对程序来说性能损害是极大的

ps:我们平常使用的路由器一般pps(每秒转发数为几十万左右),所以一般的千兆以太网的极限就在几十万/秒

除此之外由于正常的路由器的ARP表上限为900左右

两个原因导致一个子网中机器不能过多,当集群中机器过多时就需要进行网络的层次话

虚拟化优点

1,扩展性-可以动态的迁移和复制,使得服务器增加变得更简单

2,提高资源利用率

3,降低运维成本(远程管理,环境更单一

异常行为局部化,使得主机控制更简单)

4,提高可用性(抽象硬件差异)

5,  调整负载(软件层面对负载进行控制,当监测到负载消耗异常可重启进程或者虚拟机)

缺点

1,虚拟机本身的损耗(cpu,内存)

2,网络性能损耗近一半

3,I/O性能略微降低0.5%左右

相关推荐