![5fe750ea91135e4414e36bbda539ef05.png](https://i-blog.csdnimg.cn/blog_migrate/a8138aabda24620be6975efd3766adaa.png)
一、基本概念
1、CAP 理论
CAP 全称 是Consistency Availability and Partition tolerance:
- Consistency(一致性):数据一致更新,所有数据变动都是同步的;
- Availability(可用性):良好的响应性能;
- Partition tolerance(分区容错性):可靠性。
任何分布式系统只可同时满足二点,没法三者兼顾。架构师不要将精力浪费在如何设计能满足三者的完美分布式系统,而是应该进行取舍。
![f7653c0134849e41bd33980968061fd2.png](https://i-blog.csdnimg.cn/blog_migrate/6198eecaf8307210b45eb6f35ae8e1fc.jpeg)
2、NoSQL
很多人以 为 NoSQL 是非 SQL 的意思,其实它是 Not Only SQL 的缩写,意思是不只是 SQL。与关系型数据库正好相反,非关系型数据库 NoSQL 对事务性的要求并不严格,甚至可以说是相当马虎。
有些数据库是保证最终一致性,信息不会立即同步,而是经过了一段时间才达到一致性。比如你发了一篇文章,你的一部分朋友立马看到了这篇文章,另一部分朋友却要等到 5 分钟之后才能刷出这篇文章。
虽然有延时,但是对于一个娱乐性质的 Web 2.0 网站又有谁会在乎这几分钟的延时呢?如果你用传统关系型数据库,网站可能早就宕掉了。
有些数据库可以在部分机器宕机的情况下依然可以正常运行,其实原理就是把同一份数据复制成了好几份放到了好几个地方,正应了那句老话:不要把鸡蛋同时放在一个篮子里。
![d55968662daacb532fb07f13352a1c41.png](https://i-blog.csdnimg.cn/blog_migrate/fc7bdb460e161abd338ba24b66296246.png)
3、列式存储与行式存储
列式存储(Column-based)是相对于传统关系型数据库的行式存储(Row-based)来说的,简单来说两者的区别就是如何组织表。
将表放入存储系统中有两种方法,而我们绝大部分是采用行存储的。行存储法是将各行放入连续的物理位置,这很像传统的记录和文件系统。列存储法是将数据按照列存储到数据库中,与行存储类似,下图是两种存储方法的图形化解释。
![1b8c6323411fe945025de8f56184fec9.png](https://i-blog.csdnimg.cn/blog_migrate/8a0262bf3219c3e9533c3f18971fbcaf.jpeg)
应用行式存储的数据库系统称为行式数据库,同理应用列式存储的数据库系统称为列式数据库。
![ac394c388d04d51a477c30a68e0167bc.png](https://i-blog.csdnimg.cn/blog_migrate/792017d845de57fbbb578b6a3c8608ee.jpeg)
列式存储的主要优点之一就是可以大幅降低系统的 I/O,尤其是在海量数据查询时,通过下面这张图,相信我们能够彻底明白这一点。
![549bd974451a7b5eef704807897bb7f9.png](https://i-blog.csdnimg.cn/blog_migrate/2d39356257ad5c15dbd5f336f867f795.jpeg)
二、什么时候使用 HBase?
HBase 的存储是基于 Hadoop 的,Hadoop 实现了一个分布式文件系统(HDFS)。HDFS 有高容错性的特点,被设计用来部署在低廉的硬件上,而且它提供高吞吐量以访问应用程序的数据,适合那些有着超大数据集的应用程序。基于 Hadoop 意味着 HBase 与生俱来的超强的扩展性和吞吐量。
HBase 采用的是 Key/Value 的存储方式,这意味着,即使随着数据量增大,也几乎不会导致查询的性能下降。
HBase 又是一个列式数据库,当你的表字段很多的时候,你甚至可以把其中几个字段放在集群的一部分机器上,而另外几个字段放到另外一部分机器上,充分分散了负载压力。
然而,如此复杂的存储结构和分布式的存储方式带来的代价就是:哪怕只是存储少量数据,它也不会很快。所以我常常跟人说:HBase 并不快,只是当数据量很大的时候它慢的不明显。
不适合使用 HBase 的场景:
- 主要需求是数据分析,比如做报表。
- 单表数据量不超过千万。
适合使用 HBase 的场景:
- 单表数据量超千万,而且并发还挺高。
- 数据分析需求较弱,或者不需要那么灵活或者实时。
三、HBase 部署架构
1、部署架构
HBase 有两种服务器:Master 服务器和 RegionServer 服务器,一般一个 HBase 集群有一个 Master 服务器和多个 RegionServer 服务器。
Master 服务器负责维护表结构信息,实际的数据都存储在 RegionServer 服务器上,RegionServer 是直接负责存储数据的服务器,RegionServer 保存的表数据直接存储在 Hadoop 的 HDFS 上。
HBase 有一点很特殊:客户端获取数据由客户端直连 RegionServer 的,所以当 Master 挂掉之后你依然可以查询数据,只是丧失了表管理相关的能力。
RegionServer 非常依赖 ZooKeeper 服务,可以说没有 ZooKeeper 就没有 HBase。ZooKeeper 管理了 HBase 所有 RegionServer 的信息,包括具体的数据段存放在哪个 RegionServer 上。客户端每次与 HBase 连接,其实都是先与 ZooKeeper 通信,查询出哪个 RegionServer 需要连接,然后再连接 RegionServer。
![a147a98d9abf69ee2b5a16d9e07fe6d9.png](https://i-blog.csdnimg.cn/blog_migrate/b3ae50bd28c83a172d75c85b1e42d19c.jpeg)
2、Region
Region 就是一段数据的集合,HBase 中的表一般拥有一个到多个 Region,Region 有以下特性:
- Region 不能跨服务器,一个 RegionServer 上有一个或者多个 Region;
- 数据量小的时候,一个 Region 足以存储所有数据;但是,当数据量大的时候,HBase 会拆分 Region;
- 当 HBase 在进行负载均衡的时候,也有可能会从一台 RegionServer 上把 Region 移动到另一台 RegionServer 上;
- Region 是基于 HDFS 的,它的所有数据存取操作都是调用了 HDFS 的客户端接口来实现的。
3、RegionServer
RegionServer 就是存放 Region 的容器,直观上说就是服务器上的一个服务。一般来说,一个服务器只会安装一个 RegionServer 服务。当客户端从 ZooKeeper 获取 RegionServer 的地址后,它会直接从 RegionServer 获取数据。
4、Master
HBase 中 Master 的角色不像领导,更像是打杂的。客户端从 ZooKeeper 获取了 RegionServer 的地址后,会直接从 RegionServer 获取数据。其实不光是获取数据,包括插入、删除等所有的数据操作都是直接操作 RegionServer,而不需要经过 Master。
Master 只负责各种协调工作,比如建表、删表、移动 Region、合并等操作。它们的共性就是需要跨 RegionServer,这些操作由哪个 RegionServer 来执行都不合适,所以 HBase 就将这些操作放到了Master上了。
这种结构的好处是大大降低了集群对 Master 的依赖,而 Master 节点一般只有一个到两个,一旦宕机,如果集群对 Master 的依赖度很大,那么就会产生单点故障问题。在 HBase 中,即使 Master 宕机了,集群依然可以正常地运行,依然可以存储和删除数据。
四、HBase 存储架构
1、存储架构
最基本的存储单位是列(column),一个列或者多个列形成一行(row)。传统数据库是严格的行列对齐,比如这行有三个列 a、b、c,下一行肯定也有三个列 a、b、c。而在 HBase 中,这一行有三个列 a、b、c,下一个行也许是有 4 个列 a、e、f、g。
在 HBase 中,行跟行的列可以完全不一样,这个行的数据跟另外一个行的数据也可以存储在不同的机器上,甚至同一行内的列也可以存储在完全不同的机器上!每个行(row)都拥有唯一的行键(row key)来标定这个行的唯一性。每个列都有多个版本,多个版本的值存储在单元格(cell)中,若干个列又可以被归类为一个列族。
![8486cb1c8c5ef9fdd5b93b29615f9260.png](https://i-blog.csdnimg.cn/blog_migrate/5743c4c9e322252ab60059c6e08484b6.jpeg)
2、行键(rowkey)
rowkey 是由用户指定的一串不重复的字符串,rowkey 会直接决定这个 row 的存储位置的。HBase 中无法根据某个 column 来排序,系统永远是根据 rowkey 来排序的(根据字典排序),rowkey 就是决定 row 存储顺序的唯一凭证。
如果插入 HBase 的时候,不小心用了之前已经存在的 rowkey,这会把之前存在的那个 row 更新掉。之前已经存在的值会被放到这个单元格的历史记录里面,并不会丢掉,只是你需要带上版本参数才可以找到这个值。一个列上可以存储多个版本的单元格(cell),单元格就是数据存储的最小单元。
3、列族(column family)
若干列可以组成列族(column family),建表的时候有几个列族是一开始就定好的。表的很多属性,比如过期时间、数据块缓存以及是否压缩等都是定义在列族上,而不是定义在表上或者列上。
同一个表里的不同列族可以有完全不同的属性配置,但是同一个列族内的所有列都会有相同的属性,因为他们都在一个列族里面,而属性都是定义在列族上的。一个没有列族的表是没有意义的,因为列必须依赖列族而存在。
列名称的规范是列族:列名,比如 brother:age、brother:name。列族存在的意义是:HBase 会把相同列族的列尽量放在同一台机器上,如果想让某几个列被放到一起,你就给他们定义相同的列族。
一个表要设置多少个列族比较合适?官方的建议是:越少越好(一般来说一个就够用了),因为 HBase 并不希望大家指定太多的列族。列族太多会极大程度地降低数据库性能;此外,列族定得太多,容易出 BUG。
4、单元格(cell)
一个列上可以存储多个版本的值,多个版本的值被存储在多个单元格里面,多个版本之间用版本号(Version)来区分,唯一确定一条结果的表达式应该是:行键:列族:列:版本号(rowkey:column family:column:version)
。不过,版本号是可以省略的,如果你不写版本号,HBase 默认返回最后一个版本的数据。
![166d1e7c1d2a242a166775ae14c81952.png](https://i-blog.csdnimg.cn/blog_migrate/9cbfa4446521a018044cb41ae3074724.jpeg)
一个 Region 就是多个行(Row)的集合,在 Region 中行的排序按照行键(rowkey)字典排序。
五、总结
1、HBase 与关系型数据库的功能对比
![417f9c2f9b56200017a5f1e106bdddb6.png](https://i-blog.csdnimg.cn/blog_migrate/fbb3b109927bb7589fd556a92f0f302f.jpeg)
2、主要概念回顾
- Maser
- RegionServer
- HDFS
- Client
- ZooKeeper
- Region
- Row
- Rowkey
- Column Family
- Column
- Cell
![6a9aa02cb4d4efcda030daa87e71e93f.png](https://i-blog.csdnimg.cn/blog_migrate/1d74526f0ace072e460604b4cede0449.jpeg)