Skip to content

Commit 6be4930

Browse files
committed
Add juicefs-metadata-deep-dive series
1 parent a7bc036 commit 6be4930

15 files changed

+1655
-4
lines changed

_posts/2018-11-28-tcpdump.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
layout : post
33
title : "tcpdump: An Incomplete Guide"
44
date : 2018-11-28
5-
lastupdate: 2024-01-21
5+
lastupdate: 2024-09-12
66
author : ArthurChiao
77
categories: tcpdump
88
---
@@ -314,7 +314,7 @@ $ tcpdump -i eth0 'host 192.168.1.3 and (host 192.168.1.4 and port 80)'
314314
$ tcpdump -i eth0 'src host 192.168.1.3 and (dst host 192.168.1.4 and port 80)'
315315

316316
# capture traffic: 192.168.1.0/24->10.1.1.4
317-
$ tcpdump -i eth0 'src net 192.168.1.0/24 and dst host 10.1.1.4 -w test.pcap'
317+
$ tcpdump -i eth0 'src net 192.168.1.0/24 and dst host 10.1.1.4' -w test.pcap
318318
```
319319

320320
# 3 Advanced matching (header fields/bits matching)

_posts/2023-10-25-gpu-data-sheets.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ some differences. To clarify them,
115115
| Year | 2023 | 2023 | 2023 | 2022 |
116116
| Manufacturing | 7+nm | 4nm | 4nm | 4nm |
117117
| Architecture | HUAWEI Da Vinci | Ada Lovelace | Hopper | Hopper |
118-
| Max Power | 400 watt | 275W | 500W | 350/700 watt |
118+
| Max Power | 400 watt | 350W | 500W | 350/700 watt |
119119
| GPU Mem | 64G HBM2e | 48G GDDR6 | 96G HBM3 | 80G HBM3 |
120120
| GPU Mem BW | | 864GB/s | <mark>4.0TB/s</mark> | 2/3.35 TB/s|
121121
| L2 Cache | | **<mark><code>96MB</code></mark>** | 60MB | 50MB |
@@ -130,7 +130,8 @@ some differences. To clarify them,
130130

131131
Notes:
132132

133-
* `*`: **<mark>with sparsity</mark>**.
133+
* `*`: **<mark>with sparsity</mark>**;
134+
* L20 max power 350W: collected with dcgm-exporter.
134135

135136
# 5 Notes on US "Chip Export Controls" targeting China
136137

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
---
2+
layout : post
3+
title : "JuiceFS 元数据引擎初探:高层架构、引擎选型、读写工作流(2024)"
4+
date : 2024-09-12
5+
lastupdate: 2024-09-12
6+
categories: storage juicefs
7+
---
8+
9+
<p align="center"><img src="/assets/img/juicefs-metadata-deep-dive/juicefs-tikv-cluster.png" width="90%"/></p>
10+
<p align="center">Fig. JuiceFS cluster initialization, and how POSIX file operations are handled by JuiceFS.</p>
11+
12+
* [JuiceFS 元数据引擎初探:高层架构、引擎选型、读写工作流(2024)]({% link _posts/2024-09-12-juicefs-metadata-deep-dive-1-zh.md %})
13+
* [JuiceFS 元数据引擎再探:开箱解读 TiKV 中的 JuiceFS 元数据(2024)]({% link _posts/2024-09-12-juicefs-metadata-deep-dive-2-zh.md %})
14+
* [JuiceFS 元数据引擎三探:从实践中学习 TiKV 的 MVCC 和 GC(2024)]({% link _posts/2024-09-12-juicefs-metadata-deep-dive-3-zh.md %})
15+
* [JuiceFS 元数据引擎四探:元数据大小评估、限流与限速的设计思考(2024)]({% link _posts/2024-09-12-juicefs-metadata-deep-dive-4-zh.md %})
16+
17+
水平及维护精力所限,文中不免存在错误或过时之处,请酌情参考。
18+
**<mark>传播知识,尊重劳动,年满十八周岁,转载请注明<a href="https://arthurchiao.art">出处</a></mark>**
19+
20+
----
21+
22+
* TOC
23+
{:toc}
24+
25+
----
26+
27+
28+
# 1 JuiceFS 高层架构与组件
29+
30+
<p align="center"><img src="/assets/img/juicefs-metadata-deep-dive/juicefs-components-1.png" width="70%"/></p>
31+
<p align="center">Fig. JuiceFS components and architecutre.</p>
32+
33+
如图,最粗的粒度上可以分为三个组件。
34+
35+
## 1.1 JuiceFS client
36+
37+
* `juicefs format ...` 可以创建一个 volume;
38+
* `juicefs config ...` 可以修改一个 volume 的配置;
39+
* `juicefs mount ...` 可以把一个 volume 挂载到机器上,然后用户就可以在里面读写文件了;
40+
41+
## 1.2 Metatdata engine(元数据引擎)
42+
43+
* 用于**<mark>存储 JuiceFS 的元数据</mark>**,例如每个文件的文件名、最后修改时间等等;
44+
* 可选择 etcd、TiKV 等等;
45+
46+
## 1.3. Object store
47+
48+
实际的对象存储,例如 S3、Ceph、阿里云 OSS 等等,存放 JuiceFS volume 内的数据。
49+
50+
# 2 JuiceFS 元数据存储引擎对比:`tikv vs. etcd`
51+
52+
## 2.1 设计与优缺点对比
53+
54+
| | TiKV as metadata engine | etcd as metadata engine |
55+
|:-----|:-----|:-----|
56+
| **<mark>管理节点</mark>**(e.g. leader election)| PD (TiKV cluster manager) | etcd server |
57+
| **<mark>数据节点</mark>**(存储 juicefs metadata) | TiKV server | etcd server |
58+
| **<mark>数据节点对等</mark>** | 无要求 | **<mark>完全对等</mark>** |
59+
| **<mark>数据一致性粒度</mark>** | region-level (TiKV 的概念,`region < node`) | node-level |
60+
| **<mark>Raft 粒度</mark>** | region-level (multi-raft,TiKV 的概念) | node-level |
61+
| **<mark>缓存多少磁盘数据在内存中</mark>** | 一部分 | **<mark>所有</mark>** |
62+
| **<mark>集群支持的最大数据量</mark>** | **<mark><code>PB</code></mark>** 级别 | 几十 GB 级别 |
63+
| **<mark>性能</mark>**(JuiceFS 场景) | 高(猜测是因为 raft 粒度更细,并发读写高) | **<mark>低</mark>** |
64+
| 维护和二次开发门槛 | 高(相比 etcd) ||
65+
| 流行度 & 社区活跃度 | 低(相比 etcd) ||
66+
| 适用场景 | **<mark>大和超大 JuiceFS 集群</mark>** | 中小 JuiceFS 集群 |
67+
68+
## 2.2 几点解释
69+
70+
etcd 集群,
71+
72+
* 每个节点完全对等,既负责管理又负责存储数据;
73+
* 所有数据**<mark>全部缓存在内存中</mark>**,每个节点的数据完全一致。
74+
这一点限制了 etcd 集群支持的最大数据量和扩展性,
75+
例如现在官网还是建议不要超过 8GB(实际上较新的版本在技术上已经没有这个限制了,
76+
但仍受限于机器的内存)。
77+
78+
TiKV 方案可以可以理解成把管理和数据存储分开了,
79+
80+
* PD 可以理解为 **<mark><code>TiKV cluster manager</code></mark>**,负责 leader 选举、multi-raft、元数据到 region 的映射等等;
81+
* 节点之间也**<mark>不要求对等</mark>**,PD 按照 region(比如 96MB)为单位,将 N(默认 3)个副本放到 N 个 TiKV node 上,而实际上 TiKV 的 node 数量是 M,`M >= N`
82+
* 数据放在 TiKV 节点的磁盘,内存中**<mark>只缓存一部分</mark>**(默认是用机器 45% 的内存,可控制)。
83+
84+
## 2.3 例子:TiKV 集群 engine size 和内存使用监控
85+
86+
TiKV 作为存储引擎,总结成一句话就是:**<mark>根据硬件配置干活,能者多劳</mark>** ——
87+
内存大、磁盘大就多干活,反之就少干活。
88+
89+
下面的监控展示是 7 台 TiKV node 组成的一个集群,各 **<mark>node 内存不完全一致</mark>**
90+
3 台 256GB 的,2 台 128GB 的,2 台 64GB 的,
91+
可以看到每个 TiKV server 确实只用了各自所在 node 一半左右的内存:
92+
93+
<p align="center"><img src="/assets/img/juicefs-metadata-deep-dive/tikv-engine-size.png" width="100%"/></p>
94+
<p align="center">Fig. TiKV engine size and memory usage of a 7-node (with various RAMs) cluster.</p>
95+
96+
# 3 JuiceFS + TiKV:集群启动和宏观读写流程
97+
98+
## 3.1 架构
99+
100+
用 TiKV 作为元数据引擎,架构如下(先忽略其中的细节信息,稍后会介绍):
101+
102+
<p align="center"><img src="/assets/img/juicefs-metadata-deep-dive/juicefs-tikv-cluster.png" width="90%"/></p>
103+
<p align="center">Fig. JuiceFS cluster initialization, and how POSIX file operations are handled by JuiceFS.</p>
104+
105+
## 3.2 TiKV 集群启动
106+
107+
### 3.2.1 TiKV & PD 配置差异
108+
109+
两个组件的几个核心配置项,
110+
111+
```shell
112+
$ cat /etc/tikv/pd-config.toml
113+
name = "pd-node1"
114+
data-dir = "/var/data/pd"
115+
116+
client-urls = "https://192.168.1.1:2379" # 客户端(例如 JuiceFS)访问 PD 时,连接这个地址
117+
peer-urls = "https://192.168.1.1:2380" # 其他 PD 节点访问这个 PD 时,连接这个地址,也就是集群内互相通信的地址
118+
119+
# 创建集群时的首批 PD
120+
initial-cluster-token = "<anything you like>"
121+
initial-cluster = "pd-node1=https://192.168.1.3:2380,pd-node2=https://192.168.1.2:2380,pd-node3=https://192.168.1.1:2380"
122+
```
123+
124+
可以看到,**<mark>PD 的配置和 etcd 就比较类似,需要指定其他 PD 节点地址</mark>**,它们之间互相通信。
125+
126+
TiKV 节点(tikv-server)的配置就不一样了,
127+
128+
```shell
129+
$ cat /etc/tikv/tikv-config.toml
130+
[pd]
131+
endpoints = ["https://192.168.1.1:2379", "https://192.168.1.2:2379", "https://192.168.1.3:2379"]
132+
133+
[server]
134+
addr = "192.168.1.1:20160" # 服务地址,JuiceFS client 会直接访问这个地址读写数据
135+
status-addr = "192.168.1.1:20180" # prometheus
136+
```
137+
138+
可以看到,
139+
140+
1. TiKV 会配置所有 PD 节点的地址,以便自己注册到 PD 作为一个数据节点(存储JuiceFS 元数据);
141+
2. TiKV 还会配置一个地址的 server 地址,这个读写本节点所管理的 region 内的数据用的;
142+
正常流程是 JuiceFS client 先访问 PD,拿到 region 和 tikv-server 信息,
143+
然后再到 tikv-server 来读写数据(对应 JuiceFS 的元数据);
144+
3. TiKV **<mark>不会配置其他 TiKV 节点的地址</mark>**,也就是说 TiKV 节点之间不会 peer-to-peer 互连。
145+
146+
### 3.2.2 服务启动
147+
148+
<p align="center"><img src="/assets/img/juicefs-metadata-deep-dive/juicefs-tikv-cluster.png" width="90%"/></p>
149+
<p align="center">Fig. JuiceFS cluster initialization, and how POSIX file operations are handled by JuiceFS.</p>
150+
151+
对应图中 step 1 & 2:
152+
153+
* step 1. PD 集群启动,选主;
154+
* step 2. TiKV 节点启动,向 PD 注册;每个 TiKV 节点称为一个 store,也就是元数据仓库。
155+
156+
## 3.3 宏观读写流程
157+
158+
对应图中 step 3~5:
159+
160+
* step 3. JuiceFS 客户端连接到 PD;发出读写文件请求;
161+
162+
* JuiceFS 客户端中会初始化一个 TiKV 的 transaction kv client,这里面又会初始化一个 PD client,
163+
* 简单来说,此时 JuiceFS 客户端就有了 PD 集群的信息,例如哪个文件对应到哪个 region,这个 region 分布在哪个 TiKV 节点上,TiKV 服务端连接地址是多少等等;
164+
165+
* step 4. JuiceFS (内部的 TiKV 客户端)直接向 TiKV 节点(准确说是 region leader)发起读写请求;
166+
* step 5. 元数据处理完成,JuiceFS 客户端开始往对象存储里读写文件。
167+
168+
# 4 TiKV 内部数据初探
169+
170+
TiKV 内部存储的都是 JuiceFS 的元数据。具体来说又分为两种:
171+
172+
1. 用户文件的元数据:例如用户创建了一个 `foo.txt`,在 TiKV 里面就会对应一条或多条元数据来描述这个文件的信息;
173+
2. JuiceFS 系统元数据:例如每个 volume 的配置信息,这些对用户是不可见的。
174+
175+
TiKV 是扁平的 KV 存储,所以以上两类文件都放在同一个扁平空间,通过 key 访问。
176+
本文先简单通过命令看看里面的元数据长什么样,下一篇再结合具体 JuiceFS 操作来深入解读这些元数据。
177+
178+
## 4.1 简单脚本 `tikv-ctl.sh/pd-ctl.sh`
179+
180+
简单封装一下对应的命令行工具,使用更方便,
181+
182+
```shell
183+
$ cat pd-ctl.sh
184+
tikv-ctl \
185+
--ca-path /etc/tikv/pki/root.crt --cert-path /etc/tikv/pki/tikv.crt --key-path /etc/tikv/pki/tikv.key \
186+
--host 192.168.1.1:20160 \
187+
"$@"
188+
189+
$ cat pd-ctl.sh
190+
pd-ctl \
191+
--cacert /etc/tikv/pki/root.crt --cert /etc/tikv/pki/pd.crt --key /etc/tikv/pki/pd.key \
192+
--pd https://192.168.1.1:2379 \
193+
"$@"
194+
```
195+
196+
## 4.2 `tikv-ctl scan` 扫描 key/value
197+
198+
tikv-ctl **<mark>不支持只列出所有 keys</mark>**,所以只能 key 和 value 一起打印(扫描)。
199+
200+
扫描前缀是 `foo` 开头的所有 key:
201+
202+
```shell
203+
$ ./tikv-ctl.sh scan --from 'zfoo' --to 'zfop' --limit 100
204+
...
205+
key: zfoo-dev\375\377A\001\000\000\000\000\000\000\377\000Dfile3.\377txt\000\000\000\000\000\372
206+
key: zfoo-dev\375\377A\001\000\000\000\000\000\000\377\000Dfile4.\377txt\000\000\000\000\000\372
207+
...
208+
key: zfoo-dev\375\377setting\000\376
209+
default cf value: start_ts: 452330324173520898 value: 7B0A22...
210+
```
211+
212+
扫描的时候一定要在 key 前面加一个 `z` 前缀,这是 TiKV 的一个[设计](https://tikv.org/docs/3.0/reference/tools/tikv-ctl/)
213+
214+
> The raw-scan command scans directly from the RocksDB. Note that to scan data keys you need to add a 'z' prefix to keys.
215+
216+
代码出处 [components/keys/src/lib.rs](https://github.com/tikv/tikv/blob/v5.0.0/components/keys/src/lib.rs#L29)
217+
但对用户来说不是太友好,暴露了太多内部细节,没有 `etcdctl` 方便直接。
218+
219+
## 4.3 `tikv-ctl mvcc` 查看给定 key 对应的 value
220+
221+
```shell
222+
$ ./tikv-ctl.sh mvcc -k 'zfoo-dev\375\377A\001\000\000\000\000\000\000\377\000Dfile1.\377txt\000\000\000\000\000\372' --show-cf default,lock,write
223+
key: zfoo-dev\375\377A\001\000\000\000\000\000\000\377\000Dfile1.\377txt\000\000\000\000\000\372
224+
write cf value: start_ts: 452330816414416901 commit_ts: 452330816414416903 short_value: 010000000000000002
225+
```
226+
227+
## 4.4 `tikv-ctl --decode <key>` 解除字符转义
228+
229+
```shell
230+
# tikv escaped format -> raw format
231+
./tikv-ctl.sh --decode 'foo-dev\375\377A\001\000\000\000\000\000\000\377\000Dfile4.\377txt\000\000\000\000\000\372'
232+
foo-dev\375A\001\000\000\000\000\000\000\000Dfile4.txt
233+
```
234+
235+
## 4.5 `tikv-ctl --to-hex`:转义表示 -> 十六进制表示
236+
237+
```shell
238+
$ ./tikv-ctl.sh --to-hex '\375'
239+
FD
240+
```
241+
242+
## 4.6 `tikv-ctl --to-escaped <value>`:十六进制 value -> 带转义的字符串
243+
244+
```shell
245+
./tikv-ctl.sh scan --from 'zfoo' --to 'zfop' --limit 100
246+
key: zfoo-dev\375\377setting\000\376
247+
default cf value: start_ts: 452330324173520898 value: 7B0A22...
248+
```
249+
250+
其中的 value 是可以解码出来的,
251+
252+
```shell
253+
# hex -> escaped string
254+
$ ./tikv-ctl.sh --to-escaped '7B0A22...'
255+
{\n\"Name\": \"...\",\n\"UUID\": \"8cd1ac73\",\n\"Storage\": \"S3\",\n\"Bucket\": \"http://xxx\",\n\"AccessKey\": \"...\",\n\"BlockSize\": 4096,\n\"Compression\": \"none\",\n\"KeyEncrypted\": true,\n\"MetaVersion\": 1,\n\"UploadLimit\": 0,\n\"DownloadLimit\": 0,\n\"\": \"\"\n}
256+
```
257+
258+
# 5 总结
259+
260+
本文介绍了一些 JuiceFS 元数据引擎相关的内容。
261+
262+
----
263+
264+
<a href="https://notbyai.fyi"><img src="/assets/img/Written-By-Human-Not-By-AI-Badge-white.svg" alt="Written by Human, Not by AI"></a>
265+
<a href="https://notbyai.fyi"><img src="/assets/img/Written-By-Human-Not-By-AI-Badge-black.svg" alt="Written by Human, Not by AI"></a>

0 commit comments

Comments
 (0)