-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
006aa73
commit ece7263
Showing
14 changed files
with
509 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# Overview | ||
|
||
## CAP | ||
|
||
- Consistency 一致性,写操作之后的读操作,必须返回该值。 | ||
- Availability 可用性,意思是只要收到用户的请求,服务器就必须给出回应。 | ||
- Partition tolerance 分区容错,分区容错的意思是,区间通信可能失败。 | ||
|
||
一般来说,分区容错无法避免,因此可以认为 CAP 的 P 总是成立。CAP 定理告诉我们,剩下的 C 和 A 无法同时做到。 | ||
|
||
一致性和可用性,为什么不可能同时成立?答案很简单,因为可能通信失败(即出现分区容错)。 | ||
如果保证 G2 的一致性,那么 G1 必须在写操作时,锁定 G2 的读操作和写操作。只有数据同步后,才能重新开放读写。锁定期间,G2 不能读写,没有可用性不。 | ||
如果保证 G2 的可用性,那么势必不能锁定 G2,所以一致性不成立。 | ||
综上所述,G2 无法同时做到一致性和可用性。系统设计时只能选择一个目标。如果追求一致性,那么无法保证所有节点的可用性;如果追求所有节点的可用性,那就没法做到一致性。 | ||
|
||
## OLAP vs OLTP | ||
数据处理大致可以分成两大类:联机事务处理OLTP(on-line transaction processing)、联机分析处理OLAP(On-Line Analytical Processing)。OLTP是传统的关系型数据库的主要应用,主要是基本的、日常的事务处理,例如银行交易。OLAP是数据仓库系统的主要应用,支持复杂的分析操作,侧重决策支持,并且提供直观易懂的查询结果。 | ||
|
||
## 存储 | ||
### HDFS | ||
|
||
### Parquet | ||
|
||
### CarbonData | ||
|
||
### Kudu | ||
|
||
### Hbase | ||
|
||
## 计算 | ||
### Hadoop | ||
|
||
### Spark | ||
|
||
### Flink | ||
|
||
## 查询 | ||
|
||
### Phoenix | ||
|
||
### Impala | ||
|
||
### Presto |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
# Quick Start | ||
|
||
## Hbase shell | ||
连接 hbase: | ||
``` | ||
$ ./bin/hbase shell | ||
hbase(main):001:0> | ||
``` | ||
|
||
退出: | ||
``` | ||
exit | ||
``` | ||
## ddl 命令 | ||
创建一个 table: | ||
``` | ||
# 语法 | ||
create '表名', {NAME => '列族名1'}, {NAME => '列族名2'}, {NAME => '列族名3'} | ||
# 此种方式是上上面的简写方式,使用上面方式可以为列族指定更多的属性,如VERSIONS、TTL、BLOCKCACHE、CONFIGURATION等属性 | ||
create '表名', '列族名1', '列族名2', '列族名3' | ||
create '表名', {NAME => '列族名1', VERSIONS => 版本号, TTL => 过期时间, BLOCKCACHE => true} | ||
# 示例 | ||
create 'tbl_user', 'info', 'detail' | ||
create 't1', {NAME => 'f1', VERSIONS => 1, TTL => 2592000, BLOCKCACHE => true} | ||
``` | ||
|
||
查看 table 详细信息: | ||
``` | ||
describe 'test' | ||
``` | ||
添加一个列族 | ||
``` | ||
# 语法 | ||
alter '表名', '列族名' | ||
# 示例 | ||
alter 'tbl_user', 'address' | ||
``` | ||
|
||
删除一个列族 | ||
``` | ||
# 语法 | ||
alter '表名', {NAME=> '列族名', METHOD=> 'delete'} | ||
# 示例 | ||
alter 'tbl_user', {NAME=> 'address', METHOD=> 'delete'} | ||
``` | ||
|
||
获取表的描述describe | ||
``` | ||
# 语法 | ||
describe '表名' | ||
# 示例 | ||
describe 'tbl_user' | ||
``` | ||
|
||
命名空间 | ||
``` | ||
# 列举所有命名空间 | ||
list_namespace | ||
# 列举空间里所有 table | ||
list_namespace_tables | ||
# 创建空间 | ||
create_namespace | ||
``` | ||
## dml 命令 | ||
插入或者修改数据put | ||
``` | ||
# 语法 | ||
# 当列族中只有一个列时'列族名:列名'使用'列族名' | ||
put '表名', '行键', '列族名', '列值' | ||
put '表名', '行键', '列族名:列名', '列值' | ||
# 创建表 | ||
create 'tbl_user', 'info', 'detail', 'address' | ||
# 第一行数据 | ||
put 'tbl_user', 'mengday', 'info:id', '1' | ||
put 'tbl_user', 'mengday', 'info:name', '张三' | ||
put 'tbl_user', 'mengday', 'info:age', '28' | ||
``` | ||
|
||
插入数据: | ||
``` | ||
hbase(main):003:0> put 'test', 'row1', 'cf:a', 'value1' | ||
0 row(s) in 0.0850 seconds | ||
``` | ||
|
||
查看数据: | ||
``` | ||
# 获取表的所有数据语法 | ||
scan '表名' | ||
# 示例 | ||
scan 'tbl_user' | ||
# 扫描整个列簇语法 | ||
scan '表名', {COLUMN=>'列族名'} | ||
# 示例 | ||
scan 'tbl_user', {COLUMN=>'info'} | ||
# 扫描整个列簇的某个列语法 | ||
scan '表名', {COLUMN=>'列族名:列名'} | ||
# 示例 | ||
scan 'tbl_user', {COLUMN=>'info:age'} | ||
# 获取数据get语法 | ||
get '表名', '行键' | ||
# 示例 | ||
get 'tbl_user', 'mengday' | ||
# 根据某一行某列族的数据语法 | ||
get '表名', '行键', '列族名' | ||
# 示例 | ||
get 'tbl_user', 'mengday', 'info' | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Hbase 存储原理 | ||
## 对比 | ||
一个例子解释行存储和列存储的不同: | ||
 | ||
|
||
可以看到按“行存储”来存放数据同一行的数据是连续存储的,而按“列存储”来存放数据同一列的数据是连续存储。“列存储”中每一行的数据都被拆开存放, | ||
|
||
写入比较: | ||
- 行式存储一次性写入,列式存储需要把一行拆分成多列并行写入,写入效率行式存储较高。 | ||
- 数据修改也一样,行式存储查找都数据后能一次做完修改,而列式存储对于修改多列的操作需要多次进行。 | ||
- 行式存储写入数据的时候是一次性写入,能保证数据完整。列式存储的一行数据被拆开多列,写入可能会有某列失败,导致数据不完整。 | ||
|
||
读取比较: | ||
- 行式存储每次读取会取出整行的数据,再剔除不需要的列,存在数据读取冗余。列存储按列存放数据,读取的时候只需要取需要的列即可,所以不存在冗余。 | ||
- 行存储一行数据每列的数据类型可能不同,在读取的时候需要进行解析会导致 cpu 消耗较高,尤其是对于大宽表。列存储把同一列的数据放在一起,类型都是一致的不存在这个问题。 | ||
- 列存储做数据压缩更有利,因为数据类型都是一致的对于一些数据类型可以做压缩。比如性别列只有两个值,“男”和“女”,可以对这一列建立位图索引:“男”对应的位图为100101,表示第1、4、6行值为“男”。 | ||
- 很多列式存储有列簇的概念,会把需要经常访问的列放在一起。如果需要读取的列属于同一个列簇可以一次性读出,避免了多列合并。列簇是行列混合的模式,可以同时满足 OLAP 和 OLTP 的需求。 | ||
|
||
## 小结 | ||
行式存储(mysql)写入效率高,适合 OLTP 场景,并且能保证数据完整性。 | ||
|
||
列式存储(Hbase)读取效率高,适合 OLAP 场景。尤其是在查询一个大宽表,需要读取几亿行但是只取其中几行的场景下,列式存储因为没有数据冗余所以效率很高。 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# RoaringBitmap | ||
|
||
 | ||
|
||
每个RoaringBitmap中都包含一个RoaringArray,名字叫highLowContainer。 | ||
highLowContainer存储了RoaringBitmap中的全部数据。 | ||
``` | ||
RoaringArray highLowContainer; | ||
``` | ||
这个名字意味着,会将32位的整形(int)拆分成高16位和低16位两部分(两个short)来处理。 | ||
RoaringArray的数据结构很简单,核心为以下三个成员: | ||
``` | ||
short[] keys; | ||
Container[] values; | ||
int size; | ||
``` | ||
|
||
每个32位的整形,高16位会被作为key存储到short[] keys中,低16位则被看做value,存储到Container[] values中的某个Container中。keys和values通过下标一一对应。size则标示了当前包含的key-value pair的数量,即keys和values中有效数据的数量。 | ||
|
||
keys数组永远保持有序,方便二分查找。 | ||
|
||
## 三种Container | ||
下面介绍到的是RoaringBitmap的核心,三种Container。 | ||
|
||
通过上面的介绍我们知道,每个32位整形的高16位已经作为key存储在RoaringArray中了,那么Container只需要处理低16位的数据。 | ||
|
||
### ArrayContainer | ||
``` | ||
static final int DEFAULT_MAX_SIZE = 4096 | ||
short[] content; | ||
``` | ||
结构很简单,只有一个short[] content,将16位value直接存储。 | ||
|
||
short[] content始终保持有序,方便使用二分查找,且不会存储重复数值。 | ||
|
||
因为这种Container存储数据没有任何压缩,因此只适合存储少量数据。 | ||
|
||
ArrayContainer占用的空间大小与存储的数据量为线性关系,每个short为2字节,因此存储了N个数据的ArrayContainer占用空间大致为2N字节。存储一个数据占用2字节,存储4096个数据占用8kb。 | ||
|
||
根据源码可以看出,常量DEFAULT_MAX_SIZE值为4096,当容量超过这个值的时候会将当前Container替换为BitmapContainer。 | ||
|
||
### BitmapContainer | ||
``` | ||
final long[] bitmap; | ||
``` | ||
这种Container使用long[]存储位图数据。我们知道,每个Container处理16位整形的数据,也就是0~65535,因此根据位图的原理,需要65536个比特来存储数据,每个比特位用1来表示有,0来表示无。每个long有64位,因此需要1024个long来提供65536个比特。 | ||
|
||
因此,每个BitmapContainer在构建时就会初始化长度为1024的long[]。这就意味着,不管一个BitmapContainer中只存储了1个数据还是存储了65536个数据,占用的空间都是同样的8kb。 | ||
|
||
### RunContainer | ||
``` | ||
private short[] valueslength; | ||
int nbrruns = 0; | ||
``` | ||
RunContainer中的Run指的是行程长度压缩算法(Run Length Encoding),对连续数据有比较好的压缩效果。 | ||
|
||
它的原理是,对于连续出现的数字,只记录初始数字和后续数量。即: | ||
|
||
对于数列11,它会压缩为11,0; | ||
对于数列11,12,13,14,15,它会压缩为11,4; | ||
对于数列11,12,13,14,15,21,22,它会压缩为11,4,21,1; | ||
源码中的short[] valueslength中存储的就是压缩后的数据。 | ||
这种压缩算法的性能和数据的连续性(紧凑性)关系极为密切,对于连续的100个short,它能从200字节压缩为4字节,但对于完全不连续的100个short,编码完之后反而会从200字节变为400字节。 | ||
|
||
如果要分析RunContainer的容量,我们可以做下面两种极端的假设: | ||
|
||
最好情况,即只存在一个数据或只存在一串连续数字,那么只会存储2个short,占用4字节 | ||
最坏情况,0~65535的范围内填充所有的奇数位(或所有偶数位),需要存储65536个short,128kb | ||
|
||
## Container性能总结 | ||
读取时间 | ||
只有BitmapContainer可根据下标直接寻址,复杂度为O(1),ArrayContainer和RunContainer都需要二分查找,复杂度O(log n)。 | ||
|
||
内存占用 | ||
 | ||
|
||
这是我画的一张图,大致描绘了各Container占用空间随数据量的趋势。 | ||
其中 | ||
- ArrayContainer一直线性增长,在达到4096后就完全比不上BitmapContainer了 | ||
- BitmapContainer是一条横线,始终占用8kb | ||
- RunContainer比较奇葩,因为和数据的连续性关系太大,因此只能画出一个上下限范围。不管数据量多少,下限始终是4字节;上限在最极端的情况下可以达到128kb。 | ||
|
||
RoaringBitmap针对Container的优化策略 | ||
创建时: | ||
- 创建包含单个值的Container时,选用ArrayContainer | ||
- 创建包含一串连续值的Container时,比较ArrayContainer和RunContainer,选取空间占用较少的 | ||
|
||
转换: | ||
|
||
针对ArrayContainer: | ||
- 如果插入值后容量超过4096,则自动转换为BitmapContainer。因此正常使用的情况下不会出现容量超过4096的ArrayContainer。 | ||
- 调用runOptimize()方法时,会比较和RunContainer的空间占用大小,选择是否转换为RunContainer。 | ||
|
||
针对BitmapContainer: | ||
- 如果删除某值后容量低至4096,则会自动转换为ArrayContainer。因此正常使用的情况下不会出现容量小于4096的BitmapContainer。 | ||
- 调用runOptimize()方法时,会比较和RunContainer的空间占用大小,选择是否转换为RunContainer。 | ||
|
||
针对RunContainer: | ||
- 只有在调用runOptimize()方法才会发生转换,会分别和ArrayContainer、BitmapContainer比较空间占用大小,然后选择是否转换。 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Quick Start | ||
|
||
## Phoenix 特性 | ||
Phoenix实现了相同或更好的性能(更不用说用更少的代码了): | ||
|
||
- 将 SQL 查询编译为本地 HBase 扫描 | ||
- 自动计算 scan 键的最佳开始和停止位置 | ||
- 协调 scan 操作的并行执行 | ||
- 通过以下方式将计算引入数据 | ||
- 将 where 子句中的谓词推送到 hbase 端进行过滤 | ||
- 通过 hbase server 端的协处理器执行聚合查询 | ||
|
||
除了上面这些特性之外,还有额外的性能优化: | ||
- 二级索引,以提高非行键列查询的性能 | ||
- 收集统计信息以改善并行化并指导如何优化 | ||
- 跳过 scan filter 以优化IN,LIKE 和 OR 查询 | ||
- 对行键进行可选的 salt 化,以平均分配写负载 | ||
|
||
## 快速开始 | ||
只需要三步即可开始在 hbase 集群上使用 phoenix: | ||
- 复制 phoenix 服务端 jar 包到 hbase 每个区域服务器的 lib 目录中 | ||
- 重新启动 hbase 区域服务器 | ||
- 将 phoenix 客户端 jar 包添加到 HBase 客户端的类路径中 | ||
使用 phoenix 自带的命令行工具连接 hbase 集群进行临时 sql 查询: | ||
``` | ||
./sqlline.py <your_zookeeper_quorum> | ||
``` |
Oops, something went wrong.