tonglin0325的个人主页

Airflow分布式部署

airflow分布式部署所依赖的组件有mysql,redis,web-server,scheduler,worker等,可以将这些组件部署在不同的机器上,来减低单台机器的压力

单机安装请参考:Ubuntu16.04安装apache-airflow

然后在不同的机器上启动不同的组件

1
2
3
4
airflow webserver -D
airflow scheduler -D
airflow worker -D

安装airflow其他支持组件,比如airflow-kerberos,参考

1
2
https://awesome.dbyun.net/study/details?mid=160&id=7427

airflow启用kerberos,参考

1
2
https://github.com/astronomer/airflow-guides/blob/main/guides/kerberos.md

MySQL学习笔记——事务和隔离级别

ACID

ACID数据库事务管理的四个关键属性,用于确保数据在并发环境下的可靠性和一致性。

1.Atomicity(原子性)

原子性指的是一个事务中的所有操作要么全部执行成功,要么全部不执行。换句话说,事务是不可分割的最小单位。ACID模型的原子性主要涉及InnoDB事务。

例如,在银行转账操作中,假设从账户 A 转账到账户 B 是一个事务。如果在从 A 扣款后,B 未能成功入账,整个操作就会回滚到初始状态,A 账户的余额也不会减少。

相关的MySQL功能包括:

  • AUTOCOMMIT设置。
  • COMMIT语句。

    全文 >>

hudi-cli使用

在 Amazon EMR 版本 5.28.0 及更高版本中, Amazon EMR 默认情况下会在安装 Spark、Hive 或 Presto 时安装 Hudi 组件。

参考:创建安装了 Hudi 的集群

Amazon EMR的版本和hudi的版本对应可以参考文档:Hudi 发行版历史记录

可以使用下面命令进入hudi-cli

1
2
/usr/lib/hudi/cli/bin/hudi-cli.sh

hudi-cli如下

退出cli,输入exit

我们可以在hive中注册hudi表,然后使用hive,sparkSQL或者presto对其进行查询

参考:Hudi 的工作原理

常用命令:Apache Hudi数据湖hudi-cli客户端使用

官方文档:

1
https://hudi.apache.org/docs/cli#local-set-up

1.连接hudi表

1
2
connect --path s3://bucket_name/path_xxx

2.查看hudi表的属性

1
2
desc

全文 >>

mongo基本操作

1.安装mongo客户端

参考:ubuntu安装mongodb-4.4(通过apt命令)

2.连接mongodb

1
mongo ip:27017/db_name -u user_name -p

3.创建collection

参考:MongoDB 教程

1
2
use xx_db
db.createCollection("xx_collection")

4.插入数据

insert one

1
2
3
4
5
6
7
8
9
10
use xx_db

db.xx_collection.insertOne(
{
"id":"100000",
"time":new Date(),
"abc":"123456"
}
)

insert many

1
2
3
4
5
6
7
8
9
10
11
12
13
db.xx_collection.insertMany(
[
{
"id":"200000",
"time":new Date(),
"token":"1111111"
}, {
"id":"300000",
"time":new Date(),
"token":"2222222"
}
]
)

5.删除数据

delete one

1
2
3
use xx_db
db.xx_collection.deleteOne({'id':'200000'})

delete many

1
2
db.xx_collection.deleteMany({'token':'1111111'})

6.查看Mongo的collection大小

1
2
db.getCollection("your_collection").stats()

参考:获取mongo 数据大小及collection大小

7.查看collection是否是sharded

1
2
db.getCollection("your_collection").stats()

没有sharded字段,或者sharded值为false,都不是sharded collection

全文 >>

Helm基本操作

Helm是k8s的包管理工具,使用helm可以简化k8s应用部署

而使用了helm之后,helm会提供一个模板,将这些yaml文件作为一个整体进行管理,高效复用,同时方便版本管理

全文 >>

Hudi学习笔记——基本操作

1.Hudi概念

参考:

英文官方文档:https://hudi.apache.org/docs/concepts/

中文官方文档:https://hudi.apache.org/cn/docs/0.9.0/concepts/

Apache Hudi架构设计和基本概念

1.Hudi表的存储类型

hudi表的类型有2种,分成cow和mor

cow是Copy On Write的缩写,含义是写入时复制(只有parquet文件)

mor是Merge On Read的缩写,含义是读取时合并(log文件+parquet文件)

2种hudi表类型的对比

适用场景,参考:ByteLake:字节跳动基于Apache Hudi的实时数据湖平台

COW表适用于批量离线更新场景

MOR表适用于实时高频更新场景

1.写时复制

写时复制存储中的文件片仅包含基本/列文件,并且每次提交都会生成新版本的基本文件。 换句话说,我们压缩每个提交,从而所有的数据都是以列数据的形式储存。在这种情况下,写入数据非常昂贵(我们需要重写整个列数据文件,即使只有一个字节的新数据被提交),而读取数据的成本则没有增加。 这种视图有利于读取繁重的分析工作。

cow类型的hudi表文件目录如下,参考:https://jxeditor.github.io/2021/05/07/Hudi初探/#开始文件分析COW

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.
├── .hoodie
│ ├── .aux
│ │ └── .bootstrap
│ │ ├── .fileids
│ │ └── .partitions
│ ├── .temp
│ ├── 20210511100234.commit
│ ├── 20210511100234.commit.requested
│ ├── 20210511100234.inflight
│ ├── 20210511100304.commit
│ ├── 20210511100304.commit.requested
│ ├── 20210511100304.inflight
│ ├── 20210511100402.commit
│ ├── 20210511100402.commit.requested
│ ├── 20210511100402.inflight
│ ├── 20210511100503.commit.requested
│ ├── 20210511100503.inflight
│ ├── archived
│ └── hoodie.properties
└── par1
├── .hoodie_partition_metadata
├── 48ca22d7-d503-4073-93ec-be7a33e6e8f4_0-1-0_20210511100234.parquet
├── 99aaf2d1-8e82-42d9-a982-65ed8d258f28_0-1-0_20210511100304.parquet
└── 99aaf2d1-8e82-42d9-a982-65ed8d258f28_0-1-0_20210511100402.parquet

使用写时复制的时候,对于update操作,当commit了之后,即使只是update了一行数据的一个字段,hudi会将这行数据所在的文件再copy一遍,然后加个这个更新之后,重新生成一个文件,所以在使用COW表的时候可能会产生写放大的问题,参考:Hudi COW表的数据膨胀(清除历史版本)问题

hudi对于历史数据的保留版本,由hoodie.cleaner.commits.retained参数来控制,默认是24

在查询COW表的时候,可以通过read.start-commit加上read.end-commit参数来按commit时间来控制查询范围,格式为yyyyMMddHHmmss,所有只使用一个参数的话,只有查询最新的一个commit,参考官方配置文档:https://hudi.apache.org/docs/configurations/

2.读时合并

读时合并存储是写时复制的升级版,从某种意义上说,它仍然可以通过读优化表提供数据集的读取优化视图(写时复制的功能)。 此外,它将每个文件组的更新插入存储到基于行的增量日志中,通过文件id,将增量日志和最新版本的基本文件进行合并,从而提供近实时的数据查询。因此,此存储类型智能地平衡了读和写的成本,以提供近乎实时的查询。 这里最重要的一点是压缩器,它现在可以仔细挑选需要压缩到其列式基础文件中的增量日志(根据增量日志的文件大小),以保持查询性能(较大的增量日志将会提升近实时的查询时间,并同时需要更长的合并时间)。

mor类型的hudi表文件目录如下,参考:https://jxeditor.github.io/2021/05/07/Hudi初探/#开始文件分析MOR

可以看到,采用读时合并的目录下除了.parquet文件,还有.log文件,其中.log文件采用的就是avro序列化格式,log文件格式结构可以参考:Hudi Log 文件格式与读写流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
.
├── .hoodie
│ ├── .aux
│ │ ├── .bootstrap
│ │ │ ├── .fileids
│ │ │ └── .partitions
│ │ ├── 20210510175131.compaction.requested
│ │ ├── 20210510181521.compaction.requested
│ │ ├── 20210510190422.compaction.requested
│ │ └── 20210511091552.compaction.requested
│ ├── .temp
│ │ ├── 20210510175131
│ │ │ └── par1
│ │ │ ├── 0a0110a8-b26b-4595-b5fb-b2388263ac54_0-1-0_20210510175131.parquet.marker.CREATE
│ │ │ ├── 39798d42-eb9f-46c7-aece-bdbe9fed3c45_0-1-0_20210510175131.parquet.marker.CREATE
│ │ │ └── 75dff8c0-614a-43e9-83c7-452dfa1dc797_0-1-0_20210510175131.parquet.marker.CREATE
│ │ ├── 20210510181521
│ │ │ └── par1
│ │ │ └── 39798d42-eb9f-46c7-aece-bdbe9fed3c45_0-1-0_20210510181521.parquet.marker.MERGE
│ │ └── 20210510190422
│ │ └── par1
│ │ └── 39798d42-eb9f-46c7-aece-bdbe9fed3c45_0-1-0_20210510190422.parquet.marker.MERGE
│ ├── 20210510174713.deltacommit
│ ├── 20210510174713.deltacommit.inflight
│ ├── 20210510174713.deltacommit.requested
......
│ ├── 20210510181212.rollback
│ ├── 20210510181212.rollback.inflight
......
│ ├── 20210510181521.commit
│ ├── 20210510181521.compaction.inflight
│ ├── 20210510181521.compaction.requested
......
│ ├── 20210511090334.clean
│ ├── 20210511090334.clean.inflight
│ ├── 20210511090334.clean.requested
......
│ ├── archived -- 归档目录,操作未达到默认值时,没有产生对应文件
│ └── hoodie.properties
└── par1
├── .39798d42-eb9f-46c7-aece-bdbe9fed3c45_20210510181521.log.1_0-1-0
├── .39798d42-eb9f-46c7-aece-bdbe9fed3c45_20210510190422.log.1_0-1-0
├── .39798d42-eb9f-46c7-aece-bdbe9fed3c45_20210511091552.log.1_0-1-2
├── .hoodie_partition_metadata
├── 0a0110a8-b26b-4595-b5fb-b2388263ac54_0-1-0_20210510175131.parquet
├── 39798d42-eb9f-46c7-aece-bdbe9fed3c45_0-1-0_20210510181521.parquet
├── 39798d42-eb9f-46c7-aece-bdbe9fed3c45_0-1-0_20210510190422.parquet
└── 75dff8c0-614a-43e9-83c7-452dfa1dc797_0-1-0_20210510175131.parquet

parquet文件什么时候合并由参数 compaction.delta_commits 和

全文 >>

java程序内存泄露排查

1.生成内存快照文件(Heap Profile)

1
2
jmap -dump:format=b,file=heap.hprof ${pid}

2.使用Eclipse Memory Analyzer工具对hprof文件进行分析

1.12.0版本需要jdk11,所以下载1.10.0版本

1
2
http://www.eclipse.org/downloads/download.php?file=/mat/1.10.0/rcp/MemoryAnalyzer-1.10.0.20200225-linux.gtk.x86_64.zip

由于堆栈文件可能会很大,所以需要修改 MemoryAnalyzer.ini 文件中的-Xmx1024m,比如改成-Xmx10240m,否则可能会遇到下面报错

1
2
an internal error occurred during parsing heap dump from

3.分析堆栈文件

全文 >>

kudu学习笔记——建表语句

kudu支持的数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
boolean

8-bit signed integer

16-bit signed integer

32-bit signed integer

64-bit signed integer

date (32-bit days since the Unix epoch)

unixtime_micros (64-bit microseconds since the Unix epoch)

single-precision (32-bit) IEEE-754 floating-point number

double-precision (64-bit) IEEE-754 floating-point number

decimal (see Decimal Type for details)

varchar (see Varchar Type for details)

UTF-8 encoded string (up to 64KB uncompressed)

binary (up to 64KB uncompressed)

参考:Apache Kudu Schema Design

kudu的建表语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE TABLE sales_by_year(					# 列存储
year INT, # 有限固定列,强类型
sale_id INT COLPROPERTIES (encoding=“bitshuffle”), # 每一列均可以设置encoding及压缩方式
amount INT,
PRIMARY KEY (year,sale_id) # 主键索引
)
PARTITION BY HASH (sale_id) PARTITIONS 4,              # 哈希分区
RANGE (year)
(
PARTITION 2014 <= VALUES <= 2016, # 范围分区
PARTITION VALUE = 2017
)
STORED AS KUDU
TBLPROPERTIES (replication=3); # 多副本

或者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
CREATE TABLE xxxx.xxxx(
uuid STRING,
ds string,
`date` string,
`ts` string,
`col1` int,
`col2` bigint,
`col3` int,
PRIMARY KEY (uuid, ds))
PARTITION BY HASH (uuid, ds) PARTITIONS 9,
RANGE(ds) (
PARTITION VALUE="2020-09-05",
PARTITION VALUE="2020-09-06",
PARTITION VALUE="2020-09-07",
PARTITION VALUE="2020-09-08",
PARTITION VALUE="2020-09-09"
)
STORED AS KUDU;

参考:DTCC2017-Kudu介绍-小米张震-final

全文 >>

ubuntu16.04安装minikube

使用原生包管理工具安装kubectl

1.更新 apt 包索引,并安装使用 Kubernetes apt 仓库所需要的包

1
2
3
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl

2.下载 Google Cloud 公开签名秘钥,如果有网络问题的话,可以手动下载apt-key.gpg文件,然后将其改名并移动到/usr/share/keyrings/kubernetes-archive-keyring.gpg目录

1
2
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg

3.添加 Kubernetes apt 仓库:

1
2
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list

如果报错,可以使用中科大的源

1
2
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] http://mirrors.ustc.edu.cn/kubernetes/apt kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list

4.更新 apt 包索引,使之包含新的仓库并安装 kubectl:

1
2
3
sudo apt-get update
sudo apt-get install -y kubectl

参考

1
2
https://kubernetes.io/zh/docs/tasks/tools/install-kubectl-linux/

  

使用minikube在单机上启动一个K8S机器用于测试

1
2
https://github.com/kubernetes/minikube/releases/tag/v1.21.0

1.安装minikube

1
2
3
curl -LO https://github.com/kubernetes/minikube/releases/download/v1.21.0/minikube_1.21.0-0_amd64.deb
sudo dpkg -i minikube_1.21.0-0_amd64.deb

2.创建集群

1
2
minikube start

如果遇到The image ‘xxx’ was not found; unable to add it to cache的报错,可以使用如下命令

1
2
minikube start --image-mirror-country='cn'

删除集群

1
2
minikube delete

创建特定版本的集群

1
2
minikube start --kubernetes-version=v1.21.1

3.查看集群

1
2
3
4
5
6
7
8
9
10
11
12
kubectl get po -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-64897985d-9hqwg 1/1 Running 0 20h
kube-system etcd-minikube 1/1 Running 0 20h
kube-system kube-apiserver-minikube 1/1 Running 0 20h
kube-system kube-controller-manager-minikube 1/1 Running 0 20h
kube-system kube-proxy-gzjgt 1/1 Running 0 20h
kube-system kube-scheduler-minikube 1/1 Running 0 20h
kube-system storage-provisioner 1/1 Running 1 (20h ago) 20h
kubernetes-dashboard dashboard-metrics-scraper-58549894f-sztfp 1/1 Running 0 132m
kubernetes-dashboard kubernetes-dashboard-ccd587f44-bvdc9 1/1 Running 0 132m

minikube一些命令:K8s - Install Minikube in Linux

4.启动kubernetes-dashboard,需要在图形界面中

1
2
minikube dashboard

5.配置dashboard外网访问,address是你的运行minikube的机器ip,port是对外暴露的端口

1
2
kubectl proxy --port=10018 --address='192.168.xx.xx' --accept-hosts='^.*' &amp;

此时就可以访问如下的网址来访问minikube dashboard

1
2
http://master:10018/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/#/workloads?namespace=_all

全文 >>

使用Presto parser解析SQL

Presto的语法解析器是使用ANTLR生成的

PrestoDB的parser g4语法文件

1
2
https://github.com/prestodb/presto/blob/master/presto-parser/src/main/antlr4/com/facebook/presto/sql/parser/SqlBase.g4

PrestoSQL(Trino)的parser g4语法文件

1
2
https://github.com/trinodb/trino/blob/master/core/trino-grammar/src/main/antlr4/io/trino/grammar/sql/SqlBase.g4

如果想在java代码中使用Presto的parser进行语法解析的话,可以引用下面的依赖

PrestoDB(Facebook版本)

1
2
3
4
5
6
<dependency>
<groupId>com.facebook.presto</groupId>
<artifactId>presto-parser</artifactId>
<version>0.285.1</version>
</dependency>

PrestoSQL(社区版本,350及其以下版本叫prestosql,以上改名为Trino)

1
2
3
4
5
6
<dependency>
<groupId>io.prestosql</groupId>
<artifactId>presto-parser</artifactId>
<version>330</version>
</dependency>

Trino(社区版本,版本从351开始)

1
2
3
4
5
6
<dependency>
<groupId>io.trino</groupId>
<artifactId>trino-parser</artifactId>
<version>351</version>
</dependency>

presto parser的使用

可以参考:《Hive、Spark、Presto SQL 输入输出表解析》