tonglin0325的个人主页

Flink学习笔记——读写HBase

1.如果是csa(Cloudera Streaming Analytics)版本的高版本HBase

可以参考Cloudera官方例子,通过引入官方提供的flink-hbase来实现

1
2
3
4
5
6
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-hbase_2.11</artifactId>
<version>1.9.0-csa1.0.0.0</version>
</dependency>

要求flink最低版本1.9.0,hbase最低版本2.1.0-cdh6.3.0,然后就可以使用HBaseSinkFunction来写Hbase

1
2
https://docs.cloudera.com/csa/1.2.0/datastream-connectors/topics/csa-hbase-configuration.html

全文 >>

Hive学习笔记——metastore listener

除了使用hive hook来记录hive上用户的操作之外,还可以使用hive metastore listener来进行记录,参考:

1
2
https://towardsdatascience.com/apache-hive-hooks-and-metastore-listeners-a-tale-of-your-metadata-903b751ee99f

hive metastore的接口有3种,分别是

全文 >>

mac下安装gradle7.3

gradle和maven类似,是一个构建工具

gradle安装和配置

1.mac安装gradle

1
2
brew install gradle

或者下载gradle的二进制安装包

1
2
https://gradle.org/releases/

然后在~/.bash_profile中配置

1
2
3
4
# gradle
export GRADLE_HOME=/Users/lintong/software/gradle-7.3
export PATH=$GRADLE_HOME/bin:$PATH

2.查看是否安装成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
gradle -v

------------------------------------------------------------
Gradle 7.3
------------------------------------------------------------

Build time: 2021-11-09 20:40:36 UTC
Revision: 96754b8c44399658178a768ac764d727c2addb37

Kotlin: 1.5.31
Groovy: 3.0.9
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 1.8.0_211 (Oracle Corporation 25.211-b12)
OS: Mac OS X 10.16 x86_64

使用gradle后,老版本的IDEA 2017.1 对gradle的支持较弱,建议升级到新版本 2021.1

如果需要添加 gradle.properties 配置文件,请放在 $GRADLE_HOME 目录

1
2
3
➜  /Users/lintong/software/gradle-7.3.2 $ ls | grep gradle.properties
gradle.properties

配置文件内容

1
2
3
4
5
/Users/lintong/software/gradle-7.3.2 $ cat gradle.properties
username=xx
password=xx
mavenUser=xx
mavenPassword=xx

gradle处理依赖冲突

使用gradle的时候如果遇到依赖冲突,可以添加如下配置,添加后再编译就能使得有冲突的时候自动失败

1
2
3
4
5
6
configurations.all {
resolutionStrategy {
failOnVersionConflict()
}
}

全文 >>

Spark学习笔记——读写ScyllaDB

Scylla兼容cassandra API,所以可以使用spark读写cassandra的方法来进行读写

1.查看scyllaDB对应的cassandra版本

1
2
3
cqlsh:my_db> SHOW VERSION
[cqlsh 5.0.1 | Cassandra 3.0.8 | CQL spec 3.3.1 | Native protocol v4]

2.查看spark和cassandra对应的版本

参考:https://github.com/datastax/spark-cassandra-connector

3.写scyllaDB

dataset API写scyllaDB

1
2
3
4
5
6
ds2.write
.mode("append")
.format("org.apache.spark.sql.cassandra")
.options(Map("table" -> "my_tb", "keyspace" -> "my_db", "output.consistency.level" -> "ALL", "ttl" -> "8640000"))
.save()

RDD API写scyllaDB

1
2
3
4
5
import com.datastax.oss.driver.api.core.ConsistencyLevel
import com.datastax.spark.connector._

ds.rdd.saveToCassandra("my_db", "my_tb", writeConf = WriteConf(ttl = TTLOption.constant(8640000), consistencyLevel = ConsistencyLevel.ALL))

注意字段的数量和顺序需要和ScyllaDB表的顺序一致,可以使用下面方式select字段

1
2
3
4
5
6
7
8
9
10
11
val columns = Seq[String](
"a",
"b",
"c")
val colNames = columns.map(name => col(name))
val colRefs = columns.map(name => toNamedColumnRef(name))

val df2 = df.select(colNames: _*)
df2.rdd
.saveToCassandra(ks, table, SomeColumns(colRefs: _*), writeConf = WriteConf(ttl = TTLOption.constant(8640000), consistencyLevel = ConsistencyLevel.ALL))

不过官方推荐使用DataFrame API,而不是RDD API

If you have the option we recommend using

全文 >>

DataGrip2017.1连接Hive

在使用低版本的DataGrip的时候,还没有hive的data source,需要自行添加数据源

1.下载hive driver,如果你使用的EMR的大数据集群的话,下载地址

1
2
https://docs.aws.amazon.com/emr/latest/ReleaseGuide/HiveJDBCDriver.html

全文 >>

Kafka学习笔记——Consumer API

参考kafka官方文档,版本1.0.x

1
2
http://kafka.apache.org/10/documentation.html#consumerapi

依赖,选择 Cloudera Rel 中的 1.0.1-kafka-3.1.0

1
2
3
4
5
6
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>1.0.1-kafka-3.1.0</version>
</dependency>

Kafka的消费者有2套API,一个是新版的Java API,在 org.apache.kafka.clients 包中

1
2
http://kafka.apache.org/10/documentation.html#newconsumerconfigs

一个是旧版的Scala API,在 kafka.consumer 包中

1
2
http://kafka.apache.org/10/documentation.html#oldconsumerconfigs

其中new consumer api中文含义参考

1
2
https://tonglin0325.github.io/xml/kafka/1.0.1-kafka-3.1.0/new-consumer-api.xml

kafka consumer参数调优:kafka consumer 参数调优

Kafka消费者不是线程安全的。所有的网络I/O都发生在进行调用的应用程序的线程中。用户有责任确保多线程访问是正确同步的。

zigzag编码原理

在Thrift,Protobuf和avro序列化框架中,不约而同使用了zigzag编码来对数字进行编码,从而达到减少数据传输量的目的。

zigzag算法的核心主要是去除二进制数字中的前导0,因为在绝大多数情况下,我们使用到的整数,往往是比较小的。

参考:小而巧的数字压缩算法:zigzag

在avro编码中,对于字符串Martin,长度为6,而6的二进制为0000 0110,其中首位置的0为符号位,在zigzag编码中,正数的符号位会移动到末尾,其它位往前移动一位,所以会变成0000 1100,即0c,再后面的字节是字符串UTF-8编码后的结果

在protobuf编码中,对于字符串的Martin,刚开始的字节表示其id和数据类型,下一个字节表示其长度,后面的字节是字符串UTF-8编码后的结果

参考:《数据密集型应用系统设计》的 Schema evolution in Avro, Protocol Buffers and Thrift

Avro,Protocol Buffer和Thrift中的模式演化(译)

全文 >>

存储底层数据结构对比

该文章对比了常用的一些存储底层所使用的数据结构。

1.B+树#

MySQL,MongoDB的索引使用的就是B+树

B+树在多读少写(相对而言)的情境下比较有优势。

B+树的主要优点:

  • 1.结构比较扁平,高度低(一般不超过4层),随机寻道次数少;
  • 2.数据存储密度大,且都位于叶子节点,查询稳定,遍历方便;
  • 3.叶子节点形成有序链表,范围查询转化为顺序读,效率高。相对而言B树必须通过中序遍历才能支持范围查询。

B+树的缺点:

  • 1.如果写入的数据比较离散,那么寻找写入位置时,子节点有很大可能性不会在内存中,最终会产生大量的随机写,性能下降。
  • 2.如果B+树已经运行了很长时间,写入了很多数据,随着叶子节点分裂,其对应的块会不再顺序存储,而变得分散。这时执行范围查询也会变成随机读,效率降低了。

参考:从B+树到LSM树,及LSM树在HBase中的应用

2.LSM树(Log-structured Merge-Tree/日志结构的合并树)#

RocksDB,HBase,Cassandra,Kudu底层使用的是LSM树

LSM树的优点

  • 1.LSM树由于数据按顺序存储,因此可以有效地执行区间查询(从最小值到最大值扫描所有的键),并且由于磁盘是顺序写入的(以顺序方式写入紧凑的SSTable文件,而不必重写树中的多个页),所以LSM-Tree可以支持非常高的写入吞吐量。

LSM树的缺点

  • 1.压缩过程中有时会干扰正在进行的读写操作。即使存储引擎尝试增量地执行压缩,并且不影响并发访问,但由于磁盘的并发资源有限,所以当磁盘执行昂贵的压缩操作时,很容易发生读写请求等待的情况。而B-tree的响应延迟则更具确定性。

参考:LSM树由来、设计思想以及应用到HBase的索引 和 数据密集型应用系统设计第3章

3.跳表#

Redis底层使用的是SkipTable

Mysql的索引为什么使用B+树而不使用跳表?#

B+树是多叉树结构,每个结点都是一个16k的数据页,能存放较多索引信息,所以扇出很高。三层左右就可以存储2kw左右的数据(知道结论就行,想知道原因可以看之前的文章)。也就是说查询一次数据,如果这些数据页都在磁盘里,那么最多需要查询三次磁盘IO。

跳表是链表结构,一条数据一个结点,如果最底层要存放2kw数据,且每次查询都要能达到二分查找的效果,2kw大概在2的24次方左右,所以,跳表大概高度在24层左右。最坏情况下,这24层数据会分散在不同的数据页里,也即是查一次数据会经历24次磁盘IO。

因此存放同样量级的数据,B+树的高度比跳表的要少,如果放在mysql数据库上来说,就是磁盘IO次数更少,因此B+树查询更快。

而针对写操作,B+树需要拆分合并索引数据页,跳表则独立插入,并根据随机函数确定层数,没有旋转和维持平衡的开销,因此跳表的写入性能会比B+树要好。

redis为什么使用跳表而不使用B+树或二叉树呢?#

redis支持多种数据结构,里面有个有序集合,也叫ZSET。内部实现就是跳表。那为什么要用跳表而不用B+树等结构呢?

大家知道,redis 是纯纯的内存数据库。

进行读写数据都是操作内存,跟磁盘没啥关系,因此也不存在磁盘IO了,所以层高就不再是跳表的劣势了。

并且前面也提到B+树是有一系列合并拆分操作的,换成红黑树或者其他AVL树的话也是各种旋转,目的也是为了保持树的平衡。

而跳表插入数据时,只需要随机一下,就知道自己要不要往上加索引,根本不用考虑前后结点的感受,也就少了旋转平衡的开销。

因此,redis选了跳表,而不是B+树。

参考:MySQL的索引为什么使用B+树而不使用跳表?