Skip to content

Commit

Permalink
update bigdata
Browse files Browse the repository at this point in the history
  • Loading branch information
linsheng9731 committed Feb 18, 2020
1 parent 006aa73 commit ece7263
Show file tree
Hide file tree
Showing 14 changed files with 509 additions and 1 deletion.
43 changes: 43 additions & 0 deletions big_data/ecosystem/overview.md
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
Binary file added big_data/hbase/2020-02-17-16-40-11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
119 changes: 119 additions & 0 deletions big_data/hbase/Quick Start.md
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'
```
22 changes: 22 additions & 0 deletions big_data/hbase/存储原理.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Hbase 存储原理
## 对比
一个例子解释行存储和列存储的不同:
![](2020-02-17-16-40-11.png)

可以看到按“行存储”来存放数据同一行的数据是连续存储的,而按“列存储”来存放数据同一列的数据是连续存储。“列存储”中每一行的数据都被拆开存放,

写入比较:
- 行式存储一次性写入,列式存储需要把一行拆分成多列并行写入,写入效率行式存储较高。
- 数据修改也一样,行式存储查找都数据后能一次做完修改,而列式存储对于修改多列的操作需要多次进行。
- 行式存储写入数据的时候是一次性写入,能保证数据完整。列式存储的一行数据被拆开多列,写入可能会有某列失败,导致数据不完整。

读取比较:
- 行式存储每次读取会取出整行的数据,再剔除不需要的列,存在数据读取冗余。列存储按列存放数据,读取的时候只需要取需要的列即可,所以不存在冗余。
- 行存储一行数据每列的数据类型可能不同,在读取的时候需要进行解析会导致 cpu 消耗较高,尤其是对于大宽表。列存储把同一列的数据放在一起,类型都是一致的不存在这个问题。
- 列存储做数据压缩更有利,因为数据类型都是一致的对于一些数据类型可以做压缩。比如性别列只有两个值,“男”和“女”,可以对这一列建立位图索引:“男”对应的位图为100101,表示第1、4、6行值为“男”。
- 很多列式存储有列簇的概念,会把需要经常访问的列放在一起。如果需要读取的列属于同一个列簇可以一次性读出,避免了多列合并。列簇是行列混合的模式,可以同时满足 OLAP 和 OLTP 的需求。

## 小结
行式存储(mysql)写入效率高,适合 OLTP 场景,并且能保证数据完整性。

列式存储(Hbase)读取效率高,适合 OLAP 场景。尤其是在查询一个大宽表,需要读取几亿行但是只取其中几行的场景下,列式存储因为没有数据冗余所以效率很高。
Binary file added big_data/model/2020-02-18-17-13-08.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added big_data/model/2020-02-18-17-16-44.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
101 changes: 101 additions & 0 deletions big_data/model/RoaringBitmap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# RoaringBitmap

![](2020-02-18-17-13-08.png)

每个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)。

内存占用
![](2020-02-18-17-16-44.png)

这是我画的一张图,大致描绘了各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比较空间占用大小,然后选择是否转换。
Binary file added big_data/sql/2020-02-18-08-35-07.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added big_data/sql/2020-02-18-08-38-52.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions big_data/sql/phoenix.md
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>
```
Loading

0 comments on commit ece7263

Please sign in to comment.