File size: 8,549 Bytes
2abfccb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
Petrel OSS SDK 2.0
===

注意:该版本SDK需要python3.6环境

若之前安装过旧版本,请先运行

```bash
$ pip uninstall pycephs3client
$ rm -rf ~/.local/lib/python3.6/site-packages/petrel_client
```

## 建议在安装之前先升级 pip

```bash
source /mnt/lustre/share/platform/env/<pat... or pt...> # 请根据实际情况确定是否需要 source
python3 -m pip install --upgrade pip # 请根据实际情况确定是否需要 `sudo` 或添加 `--user` 参数
```

## 训练集群环境上安装

```bash
$ source /mnt/lustre/share/platform/env/<pat... or pt...>
$ python setup.py sdist
$ pip install --user dist/*
```

## 通过修改 PYTHONPATH 安装

```bash
$ source /mnt/lustre/share/platform/env/<pat... or pt...>

# 安装SDK依赖
$ python setup.py egg_info
$ pip install -r *.egg-info/requires.txt

# 将SDK编译到 ./build 目录
$ python setup.py build

# 修改 PYTHONPATH 环境变量
$ export PYTHONPATH=<path_to_sdk>/build/lib:$PYTHONPATH
```

## venv环境上安装

```bash
$ python3 -m venv your_venv_name # 若已创建venv环境则无需执行
$ source your_venv_name/bin/active
$ python setup.py sdist
$ pip install dist/*
```

## 系统环境上安装

```bash
$ python3 setup.py sdist
$ python3 -m pip install dist/* # 请根据实际情况确定是否需要 `sudo` 或添加 `--user` 参数
```

## 使用

SDK 提供 `get``put` 接口,使用方式为

```python
data = client.get(url)                      # 默认情况由配置文件决定是否使用 MC
data = client.get(url, no_cache=True)       # 本次 get 直接从 ceph 读取
data = client.get(url, update_cache=True)   # 本次 get 直接从 ceph 读取,并将数据缓存至 MC
```

```python
client.put(url, data)                       # 默认 put 不会更新 MC
client.put(url, data, update_cache=True)    # 本次 put 将数据存入 ceph 之后并更新 MC
```

``注意:``若配置文件中没有启用 `MC` ,则 `no_cache` 和 `update_cache` 参数将被忽略

以下为使用 SDK 读取图片、进行图片处理后并保存图片的简单例子

```python
import cv2
import numpy as np
from os.path import splitext
from petrel_client.client import Client

conf_path = '~/petreloss.conf'
client = Client(conf_path) # 若不指定 conf_path ,则从 '~/petreloss.conf' 读取配置文件
img_url = 's3://bucket1/image.jpeg'
img_gray_url = 's3://bucket1/image_gray.jpeg'
img_ext = splitext(img_gray_url)[-1]

# 图片读取
img_bytes = client.get(img_url)
assert(img_bytes is not None)
img_mem_view = memoryview(img_bytes)
img_array = np.frombuffer(img_mem_view, np.uint8)
img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)

# 图片处理
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 图片存储
success, img_gray_array = cv2.imencode(img_ext, img_gray)
assert(success)
img_gray_bytes = img_gray_array.tostring()
client.put(img_gray_url, img_gray_bytes)
```

配置文件请参考 [petreloss.conf](./conf/petreloss.conf)

``请注意:配置文件中 `key = value` 的 key 前面不能有空格,否则该行视为上一行配置项 value 的一部分``

使用样例请参考 [multi_cluster_test.py](./tests/multi_cluster_test.py)

## `Tensor` 和 `Json` 数据保存与读取
使用样例 [tensor_json_test.py](./tests/tensor_json_test.py)

## 数据过大无法上传,则需要分片上传
使用样例 [multipart_test.py](./tests/multipart_test.py)

## 创建 Bucket
```python
client.create_bucket('s3://mybucket')
```

## 顺序的读取某个前缀的数据
```python
cluster = 'cluster1'
files = client.get_file_iterator('cluster1:s3://lili1.test2/test3')
for p, k in files
    key = '{0}:s3://{1}'.format(cluster, p)
    data = client.get(key)
```
## 使用 anonymous 账户访问数据
若在配置文件中不设置 `access_key``secret_key`,将以 `anonymous` 账户访问数据。


## McKeySizeExceed 错误

默认情况下,`MC` 所支持 `key` 的最大长度为250个字节。如果路径过长,将会出现 `McKeySizeExceed` 错误。
此时需要用户定义 `key` 的转换规则来避免该错误。

``注意:``中文字符对应多个字节。

例如:

```python
def trim_key(key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    else:
        assert isinstance(key, bytes)

    return key[-249:]

client = Client('~/petreloss.conf', mc_key_cb=trim_key)
```

此外,可使用内置函数 `md5``sha256` 等,例如:

```python
client = Client('~/petreloss.conf', mc_key_cb='sha256')
```

或在配置文件中指定:

```conf
[mc]
mc_key_cb = sha512
```

``请注意``

- 用户需要保证转换规则结果的唯一性,内置转换函数也有可能发生哈希碰撞。
- 如果 `key``str` 类型且其中出现中文字符,请务必用 `encode('utf-8')` 对其进行编码。


## 使用伪客户端

在对应客户端添加如下配置:

```conf
fake = True
```

配置文件请参考 [fake_client.conf](./conf/fake_client.conf)

使用样例请参考 [fake_client_test.py](./tests/fake_client_test.py)

## 强制更新MC

使用 `get_and_update` 接口或在 `get` 中传入 `update_cache=True` 参数将直接从存储系统读取数据并更新MC。

## IO 统计信息

IO 统计信息可通过以下三种方式修改其`log`输出频度:
- 由环境变量 `count_disp` 设置
- 由配置文件 `count_disp` 设置 (若已设置环境变量,则该方式无效)
- 调用 `client.set_count_disp(count_disp)` (该方式将覆盖上述两种方式),但限于`parrots``pytorch`的运行机制,在某些使用场景下可能无法有效修改。

若 `count_disp``0` ,则将关闭 IO 统计信息打印。

若需要在 `console` 中打印 IO 统计信息,则需要设置 `console_log_level``INFO` 或更低级别,且 `count_disp` 需大于 `0`## DataLoader

`SDK` 提供的 `DataLoader` 额外支持如下参数:

- `prefetch_factor`,默认2。每个 `worker` 预读 `batch` 数目。
- `persistent_workers`,默认 `False`。如果为 `True`,则每轮 `epoch` 迭代完毕后 `worker` 进程将不会关闭,下轮 `epoch` 将复用该 `worker` 进程。

用例:

```python
from petrel_client.utils.data import DataLoader
dataloader = DataLoader(dataset=xxx, ..., prefetch_factor=4, persistent_workers=True)
```

## SSL 验证

使用 `https` 协议时默认不会对 `SSL` 进行验证。若需要开启验证,请在配置文件中进行如下设置
```conf
verify_ssl = True
```

## Presigned URL,生成签名链接

```python
presigned_url = client.generate_presigned_url(url, client_method ='get_object', expires_in=3600)
```

`client_method` 取值为 `get_object` (默认值) 或 `put_object`

`expires_in` 单位为秒,默认值为 3600

## Presigned POST,生成签名 POST

```python
presigned_post = client.generate_presigned_post(url, fields=None, conditions=None, expires_in=3600)
```

参数及返回值详见 [generate_presigned_post](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.generate_presigned_post),其中参数 bucket 和 key 从 url 中提取。

## 以流的形式读取数据
```python
stream = client.get(url, enable_stream=True)
```
返回的 `stream``StreamingBody`,使用方法详见
https://botocore.amazonaws.com/v1/documentation/api/latest/reference/response.html

## 判断对象是否存在
```python
exists = client.contains(url)
```

## 删除对象
```python
client.delete(url)
```

## 列出当前路径包含的对象或目录
```python
contents = client.list(url)
for content in contents:
    if content.endswith('/'):
        print('directory:', content)
    else:
        print('object:', content)
```

## 判断目录是否存在
```python
client.isdir(url)
```

注意:`Ceph`中没有目录的概念,本函数返回`True`时代表存在以该`url`作为前缀的对象,其他情况返回`False`## 使用 `/mnt/cache` 目录下的 `Python` 环境
相对于 `/mnt/lustre` 目录,在 `/mnt/cache` 目录执行 `Python` 有一定的性能提升。
使用方式如下:
- `source` `/mnt/cache` 目录下的 `Python` 环境
```bash
### 例如 pt1.3v1
source /mnt/cache/share/platform/env/pt1.3v1
### 或 s0.3.3
source /mnt/cache/share/spring/s0.3.3
```

- 检查 `Python` 路径是否正确
```bash
which python
### 结果应为 /mnt/cache/...
```

- 设定 `PYTHONUSERBASE` 环境变量
```bash
export PYTHONUSERBASE=/mnt/cache/<username>/.local
```

- 重新安装相关依赖库(仅需首次使用时执行)
```
python -m pip install --user <packages>
```