0%

Avocado是一组工具和库, 用于自动化测试。

以下是基于tag61版本的源码部署方式:

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
编译安装方式:
sudo yum install -y python2 git gcc python-devel python-pip libvirt-devel libffi-devel openssl-devel libyaml-devel redhat-rpm-config xz-devel libvirt-python

pip install --upgrade setuptools

git clone https://github.com/avocado-framework/avocado.git
cd avocado/
git checkout -b my61 61.0

make develop
sudo make requirements
sudo python setup.py install


遇到问题:
[root@cephL avocado]# avocado -v
Avocado 61.0
[root@cephL avocado]# avocado -h
usage: avocado [-h] [-v] [--config [CONFIG_FILE]] [--show [STREAM[:LVL]]] [-s]

{config,diff,distro,exec-path,list,multiplex,plugins,run,sysinfo,variants}
...

Avocado Test Runner

optional arguments:
-h, --help show this help message and exit
-v, --version show program's version number and exit
--config [CONFIG_FILE]
Use custom configuration from a file
--show [STREAM[:LVL]]
List of comma separated builtin logs, or logging
streams optionally followed by LEVEL (DEBUG,INFO,...).
Builtin streams are: "test": test output; "debug":
tracebacks and other debugging info; "app":
application output; "early": early logging of other
streams, including test (very verbose); "remote":
fabric/paramiko debug; "all": all builtin streams;
"none": disables regular output (leaving only errors
enabled). By default: 'app'
-s, --silent disables regular output (leaving only errors enabled)

subcommands:
valid subcommands

{config,diff,distro,exec-path,list,multiplex,plugins,run,sysinfo,variants}
subcommand help
config Shows avocado config keys
diff Shows the difference between 2 jobs.
distro Shows detected Linux distribution
exec-path Returns path to avocado bash libraries and exits.
list List available tests
multiplex Tool to analyze and visualize test variants and params
plugins Displays plugin information
run Runs one or more tests (native test, test alias,
binary or script)
sysinfo Collect system information
variants Tool to analyze and visualize test variants and params
Failed to load plugin from module "avocado_runner_remote": ImportError('No module named api',)
Failed to load plugin from module "avocado_runner_docker": ImportError('No module named api',)
Failed to load plugin from module "avocado_runner_vm": ImportError('No module named api',)

fabric库升级导致No module named api,以下为解决办法:
[root@cephL avocado]# pip list | grep fabric
fabric (2.0.1)
[root@cephL avocado]# pip uninstall fabric
Uninstalling fabric-2.0.1:
/root/.local/lib/python2.7/site-packages/fabric-2.0.1-py2.7.egg
Proceed (y/n)? y
Successfully uninstalled fabric-2.0.1
[root@cephL avocado]# pip install fabric==1.14.0

测试avocado运行状态
[root@cephL avocado]# avocado run /bin/true
JOB ID : 7c46b08f9cc78635ef6d4c0b1109da7c5429812a
JOB LOG : /root/avocado/job-results/job-2018-05-24T21.58-7c46b08/job.log
(1/1) /bin/true: PASS (0.02 s)
RESULTS : PASS 1 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0 | CANCEL 0
JOB TIME : 0.12 s
JOB HTML : /root/avocado/job-results/job-2018-05-24T21.58-7c46b08/results.html

python依赖,以下版本运行正常

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
[root@cephL scripts]# pip list 
aexpect (1.4.0)
asn1crypto (0.24.0)
avocado-framework (61.0, /usr/lib/python2.7/site-packages/avocado_framework-61.0-py2.7.egg)
avocado-framework-plugin-glib (61.0, /root/github/avocado/optional_plugins/glib)
avocado-framework-plugin-golang (61.0, /root/github/avocado/optional_plugins/golang)
avocado-framework-plugin-loader-yaml (61.0, /root/github/avocado/optional_plugins/loader_yaml)
avocado-framework-plugin-result-html (61.0, /root/github/avocado/optional_plugins/html)
avocado-framework-plugin-result-upload (61.0, /root/github/avocado/optional_plugins/result_upload)
avocado-framework-plugin-resultsdb (61.0, /root/github/avocado/optional_plugins/resultsdb)
avocado-framework-plugin-robot (61.0, /root/github/avocado/optional_plugins/robot)
avocado-framework-plugin-runner-docker (61.0, /root/github/avocado/optional_plugins/runner_docker)
avocado-framework-plugin-runner-remote (61.0, /root/github/avocado/optional_plugins/runner_remote)
avocado-framework-plugin-runner-vm (61.0, /root/github/avocado/optional_plugins/runner_vm)
avocado-framework-plugin-varianter-pict (61.0, /root/github/avocado/optional_plugins/varianter_pict)
avocado-framework-plugin-varianter-yaml-to-mux (61.0, /root/github/avocado/optional_plugins/varianter_yaml_to_mux)
Babel (0.9.6)
backports.lzma (0.0.11)
backports.ssl-match-hostname (3.5.0.1)
bcrypt (3.1.4)
Beaker (1.5.4)
ceph-deploy (2.0.0)
ceph-detect-init (1.0.1)
ceph-disk (1.0.0)
ceph-volume (1.0.0)
cephfs (2.0.0)
cffi (1.11.5)
chardet (2.2.1)
CherryPy (3.2.2)
configobj (4.7.2)
cryptography (2.2.2)
decorator (3.4.0)
Django (1.6.11.7)
django-filter (0.9.2)
djangorestframework (2.4.3)
djangorestframework-bulk (0.2)
enum34 (1.1.6)
Fabric (1.14.0)
Flask (0.10.1, /usr/lib/python2.7/site-packages)
idna (2.6)
iniparse (0.4)
invoke (1.0.0)
ipaddress (1.0.16)
IPy (0.75)
itsdangerous (0.23)
Jinja2 (2.7.2)
kmod (0.1)
libvirt-python (3.9.0)
M2Crypto (0.21.1)
m2ext (0.1)
Mako (0.8.1)
MarkupSafe (0.11)
netaddr (0.7.5)
netifaces (0.10.4)
nose (1.3.7)
numpy (1.7.1)
pam (0.1.4)
paramiko (2.4.1)
Paste (1.7.5.1)
pbr (4.0.3)
pecan (0.4.5)
perf (0.1)
Pillow (2.0.0)
pip (8.1.2)
policycoreutils-default-encoding (0.1)
prettytable (0.7.2)
psycopg2 (2.5.1)
pudb (2017.1.4)
pyasn1 (0.4.3)
pycparser (2.18)
pycurl (7.19.0)
Pygments (2.2.0)
pygobject (3.22.0)
pygpgme (0.3)
pyliblzma (0.5.3)
PyNaCl (1.2.1)
pyOpenSSL (0.13.1)
pyparsing (1.5.6)
pystache (0.5.4)
python-linux-procfs (0.4.9)
python-memcached (1.48)
pyudev (0.15)
pyxattr (0.5.1)
PyYAML (3.12)
rados (2.0.0)
rbd (2.0.0)
requests (2.6.0)
resultsdb-api (2.0.0)
rgw (2.0.0)
robotframework (3.0.4)
rtslib-fb (2.1.63)
schedutils (0.4)
seobject (0.1)
sepolicy (1.1)
setuptools (0.9.8)
simplegeneric (0.8)
simplejson (3.15.0)
singledispatch (3.4.0.2)
six (1.11.0)
slip (0.4.0)
slip.dbus (0.4.0)
stevedore (1.28.0)
Tempita (0.5.1)
urlgrabber (3.10)
urllib3 (1.10.2)
urwid (2.0.1)
virtualenv (16.0.0)
WebOb (1.2.3)
WebTest (1.3.4)
Werkzeug (0.9.1)
wheel (0.31.0)
yum-metadata-parser (1.1.4)

debug方式

1
avocado --show test run examples/tests/sleeptest.py

添加测试case方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@cephL ~]# mkdir testcase && cd testcase
[root@cephL ~]# vi sleeptest.py (添加如下代码,http://avocado-framework.readthedocs.io/en/61.0/WritingTests.html)

import time
from avocado import Test
class SleepTest(Test):
def test(self):
sleep_length = self.params.get('sleep_length', default=1)
self.log.debug("Sleeping for %.2f seconds", sleep_length)
time.sleep(sleep_length)
运行case
[root@cephL ~]# avocado run /root/mac/testcase
JOB ID : b5fcd62a2baf4c3b94adb6cfd14fe6e8e767dc4a
JOB LOG : /root/avocado/job-results/job-2018-06-06T00.59-b5fcd62/job.log
(1/1) /root/mac/testcase/sleeptest.py:SleepTest.test: PASS (1.01 s)
RESULTS : PASS 1 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0 | CANCEL 0
JOB TIME : 1.13 s
JOB HTML : /root/avocado/job-results/job-2018-06-06T00.59-b5fcd62/results.html

Accessing test parameters

每个test都有一组参数,可以通过self.params.get($name, $path=None, $default=None)进行访问,其中:

1
2
3
name - name of the parameter (key) --- 参数的名称(键)
path - where to look for this parameter (when not specified uses mux-path) --- 在何处查找此参数(未指定时使用mux-path)
default - what to return when param not found --- 未找到参数时返回的内容

path有点棘手。Avocado使用tree来表示参数。在简单的场景中,您不必担心,您将在默认路径中找到所有值(values),但最终您可能需要check-out Test parameters以了解详细信息。

假设您的test收到以下参数 (在下一节中您将学习如何执行这些参数):

1
2
3
4
5
6
7
$ avocado variants -m examples/tests/sleeptenmin.py.data/sleeptenmin.yaml --variants 2
...
Variant 1: /run/sleeptenmin/builtin, /run/variants/one_cycle
/run/sleeptenmin/builtin:sleep_method => builtin
/run/variants/one_cycle:sleep_cycles => 1
/run/variants/one_cycle:sleep_length => 600
...

在test中, 您可以通过以下方法访问这些参数:

1
2
3
self.params.get("sleep_method")    # returns "builtin"
self.params.get("sleep_cycles", '*', 10) # returns 1
self.params.get("sleep_length", "/*/variants/*" # returns 600

注意:在可能发生冲突的复杂情况下,path非常重要,因为当有多个具有相同key的values匹配查询时,avocado会引发异常。如前所述,您可以通过使用特定path或定义custom mux-path来避免这些情况,它允许指定解析层次结构。更多细节可以在Test parameters中找到。

Running multiple variants of tests

在上一节中, 我们描述了如何处理参数。现在, 让我们来看看如何生成它们, 并使用不同的参数执行测试。

variants subsystem允许创建参数的多个variants(变体), 以及使用这些参数variants(变体)执行测试。此subsystem是可插拔的, 因此您可以使用自定义插件来生成variants(变体)。为了简单起见,我们使用Avocado的主要实现,名为”yaml_to_mux”。

该”yaml_to_mux”插件接受YAML文件。这将创建一个树状结构,将变量存储为参数,并使用自定义标记(tags)将locations标记为”multiplex” domains。

1
The “yaml_to_mux” plugin accepts YAML files. Those will create a tree-like structure, store the variables as parameters and use custom tags to mark locations as “multiplex” domains.

让我们使用examples/tests/sleeptenmin.py.data/sleeptenmin.yaml文件作为示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sleeptenmin: !mux
builtin:
sleep_method: builtin
shell:
sleep_method: shell
variants: !mux
one_cycle:
sleep_cycles: 1
sleep_length: 600
six_cycles:
sleep_cycles: 6
sleep_length: 100
one_hundred_cycles:
sleep_cycles: 100
sleep_length: 6
six_hundred_cycles:
sleep_cycles: 600
sleep_length: 1

其产生以下结构和参数:

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
$ avocado variants -m examples/tests/sleeptenmin.py.data/sleeptenmin.yaml --summary 2 --variants 2
Multiplex tree representation:
┗━━ run
┣━━ sleeptenmin
┃ ╠══ builtin
┃ ║ → sleep_method: builtin
┃ ╚══ shell
┃ → sleep_method: shell
┗━━ variants
╠══ one_cycle
║ → sleep_length: 600
║ → sleep_cycles: 1
╠══ six_cycles
║ → sleep_length: 100
║ → sleep_cycles: 6
╠══ one_hundred_cycles
║ → sleep_length: 6
║ → sleep_cycles: 100
╚══ six_hundred_cycles
→ sleep_length: 1
→ sleep_cycles: 600

Multiplex variants (8):

Variant builtin-one_cycle-f659: /run/sleeptenmin/builtin, /run/variants/one_cycle
/run/sleeptenmin/builtin:sleep_method => builtin
/run/variants/one_cycle:sleep_cycles => 1
/run/variants/one_cycle:sleep_length => 600

Variant builtin-six_cycles-723b: /run/sleeptenmin/builtin, /run/variants/six_cycles
/run/sleeptenmin/builtin:sleep_method => builtin
/run/variants/six_cycles:sleep_cycles => 6
/run/variants/six_cycles:sleep_length => 100

Variant builtin-one_hundred_cycles-633a: /run/sleeptenmin/builtin, /run/variants/one_hundred_cycles
/run/sleeptenmin/builtin:sleep_method => builtin
/run/variants/one_hundred_cycles:sleep_cycles => 100
/run/variants/one_hundred_cycles:sleep_length => 6

Variant builtin-six_hundred_cycles-a570: /run/sleeptenmin/builtin, /run/variants/six_hundred_cycles
/run/sleeptenmin/builtin:sleep_method => builtin
/run/variants/six_hundred_cycles:sleep_cycles => 600
/run/variants/six_hundred_cycles:sleep_length => 1

Variant shell-one_cycle-55f5: /run/sleeptenmin/shell, /run/variants/one_cycle
/run/sleeptenmin/shell:sleep_method => shell
/run/variants/one_cycle:sleep_cycles => 1
/run/variants/one_cycle:sleep_length => 600

Variant shell-six_cycles-9e23: /run/sleeptenmin/shell, /run/variants/six_cycles
/run/sleeptenmin/shell:sleep_method => shell
/run/variants/six_cycles:sleep_cycles => 6
/run/variants/six_cycles:sleep_length => 100

Variant shell-one_hundred_cycles-586f: /run/sleeptenmin/shell, /run/variants/one_hundred_cycles
/run/sleeptenmin/shell:sleep_method => shell
/run/variants/one_hundred_cycles:sleep_cycles => 100
/run/variants/one_hundred_cycles:sleep_length => 6

Variant shell-six_hundred_cycles-1e84: /run/sleeptenmin/shell, /run/variants/six_hundred_cycles
/run/sleeptenmin/shell:sleep_method => shell
/run/variants/six_hundred_cycles:sleep_cycles => 600
/run/variants/six_hundred_cycles:sleep_length => 1

您可以看到它为每个multiplex domain创建了所有可能的variants(变体)。它们由YAML文件中的!mux 标签(tag)定义,并在树视图中以单行显示(与具有values的单个nodes的双线进行比较)。总共它会为每个test产生8个variants(变体):

1
2
3
4
5
6
7
8
9
10
11
12
13
$ avocado run --mux-yaml examples/tests/sleeptenmin.py.data/sleeptenmin.yaml -- passtest.py
JOB ID : cc7ef22654c683b73174af6f97bc385da5a0f02f
JOB LOG : /home/medic/avocado/job-results/job-2017-01-22T11.26-cc7ef22/job.log
(1/8) passtest.py:PassTest.test;builtin-one_cycle-f659: PASS (0.01 s)
(2/8) passtest.py:PassTest.test;builtin-six_cycles-723b: PASS (0.01 s)
(3/8) passtest.py:PassTest.test;builtin-one_hundred_cycles-633a: PASS (0.01 s)
(4/8) passtest.py:PassTest.test;builtin-six_hundred_cycles-a570: PASS (0.01 s)
(5/8) passtest.py:PassTest.test;shell-one_cycle-55f5: PASS (0.01 s)
(6/8) passtest.py:PassTest.test;shell-six_cycles-9e23: PASS (0.01 s)
(7/8) passtest.py:PassTest.test;shell-one_hundred_cycles-586f: PASS (0.01 s)
(8/8) passtest.py:PassTest.test;shell-six_hundred_cycles-1e84: PASS (0.01 s)
RESULTS : PASS 8 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0
JOB TIME : 0.16 s

还有其他选项可以影响参数(params),请使用命令avocado run -h查看详细信息,或查看使用文档Test parameters

执行case

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
[root@cephL]# vi examples/tests/sleeptenmin.py.data/sleeptenmin.yaml
sleeptenmin: !mux
builtin:
sleep_method: builtin
shell:
sleep_method: shell
variants: !mux
one_cycle:
sleep_cycles: 1
sleep_length: 600
six_cycles:
sleep_cycles: 6
sleep_length: 100
one_hundred_cycles:
sleep_cycles: 100
sleep_length: 6
six_hundred_cycles:
sleep_cycles: 600
sleep_length: 1

[root@cephL]# vi /root/mac/examples/tests/passtest.py
#!/usr/bin/env python
from avocado import main
from avocado import Test
class PassTest(Test):
"""
Example test that passes.
:avocado: tags=fast
"""
def test(self):
"""
A test simply doesn't have to fail in order to pass
"""
pass
if __name__ == "__main__":
main()

[root@cephL]# avocado run --mux-yaml /root/mac/examples/tests/sleeptenmin.py.data/sleeptenmin.yaml -- /root/mac/examples/tests/passtest.py
JOB ID : 2ae9467667984d8c686087859e953a20bfd294a2
JOB LOG : /root/avocado/job-results/job-2018-06-06T02.37-2ae9467/job.log
(1/8) /root/mac/examples/tests/passtest.py:PassTest.test;builtin-one_cycle-f659: PASS (0.01 s)
(2/8) /root/mac/examples/tests/passtest.py:PassTest.test;builtin-six_cycles-723b: PASS (0.01 s)
(3/8) /root/mac/examples/tests/passtest.py:PassTest.test;builtin-one_hundred_cycles-633a: PASS (0.02 s)
(4/8) /root/mac/examples/tests/passtest.py:PassTest.test;builtin-six_hundred_cycles-a570: PASS (0.01 s)
(5/8) /root/mac/examples/tests/passtest.py:PassTest.test;shell-one_cycle-55f5: PASS (0.01 s)
(6/8) /root/mac/examples/tests/passtest.py:PassTest.test;shell-six_cycles-9e23: PASS (0.01 s)
(7/8) /root/mac/examples/tests/passtest.py:PassTest.test;shell-one_hundred_cycles-586f: PASS (0.01 s)
(8/8) /root/mac/examples/tests/passtest.py:PassTest.test;shell-six_hundred_cycles-1e84: PASS (0.02 s)
RESULTS : PASS 8 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0 | CANCEL 0
JOB TIME : 0.50 s
JOB HTML : /root/avocado/job-results/job-2018-06-06T02.37-2ae9467/results.html

实例妙解Sed和Awk的秘密笔记

课程地址:http://www.imooc.com/learn/819

课程教师:annieose

正则

课程介绍

Linux工程师面对的问题

  • 面对一堆文本要分析?

  • 面对乱乱的数据要处理?

  • 面对长长的服务器日志找报错?

sed和awk应用场景

  • 例如:在服务器日志fresh.log中,找到所有报错的日期
1
sed -n '/Error/p' fresh.log | awk '{print $1}'

Linux三大利器

  • grep:查找 |

  • sed:行编辑器 | 一行指令,轻松搞定

  • awk:文本处理工具 |

学习目标

  • 掌握sed/awk常用处理方法
  • 得心应手使用工具
  • 提高效率,事半功倍

正则表达式

主要内容

  • 正则表达式的应用与学习方法
  • 正则中的字符/字符串
  • 正则中的表达式

正则表达式目标

  • 查找 |

  • 取出 | 符合条件的某个字符或字符串

  • 匹配 |

正则单字符的表示方式

字符 ==》 特定字符、范围内字符、任意字符 ==》 组合

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
特定字符:某个具体的字符。例如:'a','1'
grep 'a' passwd
grep '1' passwd

范围内字符:单个字符[]
数字字符:[0-9],[259]
grep [0-9] passwd
grep [259] passwd

小写字符:[a-z]
grep '[a-z]' passwd

大写字符:[A-Z]
grep '[A-Z]' passwd

扩大范围举例:
grep '[a-zA-Z]' passwd
grep '[,:/_]' passwd

范围内字符:反向字符^
取反:[^0-9],[^0]

任意字符:
代表任何一个字符:'.'
grep '.' passwd
注意与[.]和\.的区别
grep '[.]' passwd 代表小数点,而不是任意字符
grep '\.' passwd 代表小数点,而不是任意字符

正则其他符号的表示方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
边界字符:头尾字符
^:^root 注意与[^]的区别
grep '^root' passwd

$:bash$
grep 'bash$' passwd

空行的表示:^$
grep '^$' passwd

元字符(代表普通字符或特殊字符)
\w:匹配任何字类字符,包括下划线([A-Za-z0-9])
\W:匹配任何非字类字符,([^A-Za-z0-9])
grep '\w' passwd
grep '\W' passwd

\b:代表单词的分隔
grep '\bx\b' passwd

正则组合-重复字符表示

1
2
3
4
字符串 'root'   '1000'   'm..c'
grep 'm..c' passwd (以m开头c结尾,长度为4的字符串)
grep '[A-Z][a-z]' passwd (大写字符与小写字符放在一起的字符串组合)
grep '\b[0-9][0-9]\b' passwd (两位数字的组合)

字符串 ==》 重复 + 逻辑 ==》 组合表达式

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
重复:
*:零次或多次匹配前面的字符或子表达式
+:一次或多次匹配前面的字符或子表达式
?:零次或一次匹配前面的字符或子表达式
[root@cephL ~]# cat test.txt
sesesese
se
seeeeeeeee
eeeeee
soooooooo
+se+se+
[root@cephL ~]# grep 'se*' test.txt
sesesese
se
seeeeeeeee
soooooooo
+se+se+
[root@cephL ~]# grep 'se\+' test.txt
sesesese
se
seeeeeeeee
+se+se+
[root@cephL ~]# grep 'se\?' test.txt
sesesese
se
seeeeeeeee
soooooooo
+se+se+
[root@cephL ~]# grep '\(se\)\+' test.txt
sesesese
se
seeeeeeeee
+se+se+

重复特定次数:{n,m}
*:{0,}
+:{1,}
?:{0,1}
[root@cephL ~]# grep '\b[0-9]\{2,3\}\b' passwd (截取2位或3位数字)

正则组合-逻辑符合表示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
任意字符串的表示:.*
例如:^r.* m.*c
注意与m..c区别
grep '^r.*' passwd
grep 'm.*c' passwd
grep 'm..c' passwd
grep '\bm.*c\b' passwd
grep '\bm[a-z]*c\b' passwd
逻辑的表示:
|:'/bin\(false\|true\)'
grep 'bin/\(bash\|nologin\)' passwd (或者包含bash,或者包含nologin)

正则表达式字符组合小结:
重复的表示:* + ? {,}
逻辑的表示:|

正则-案例演

1
2
3
4
5
6
7
8
9
案例一
匹配4-10位qq号
grep '^[0-9]\{4,10\}$' qq.txt
案例二
匹配15位或18位身份证号(支持带X的)
grep '^[1-9]\([0-9]\{13\}\|[0-9]\{16\}\)[0-9xX]$' qq.txt
案例三
匹配密码(由数字、26个字母和下划线组成)
grep '^\w\+$' qq.txt

正则总结

巧妙破解sed

主要内容和原理介绍

sed工具用途

1
2
3
自动处理文件
分析日志文件
修改配置文件

sed是如何进行文本处理的?

我们称sed是一个流处理编辑器

实际的处理流程是行处理

  • sed一次处理一行内容
  • sed不改变文件内容(除非重定向)

sed应用的基本格式介绍

正则选定文本 ==》 sed进行处理

1
2
3
4
5
6
7
使用sed格式:
命令行格式
`sed [options] 'command' file(s)`
`options: -e ; -n`
`command: 行定位(正则)+ sed命令(操作)`
脚本格式
`sed -f scriptfile file(s)`

使用sed举例

1
2
sed -n '/root/p'
sed -e '10,20d' -e 's/false/true/g'

sed基本操作命令-p命令

基本操作命令(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-p(打印相关的行)与-n配合使用
sed -n 'p' passwd

定位一行:x;/pattern/ (x代表行号)
sed -n '10p' passwd (打印第10行)
nl passwd | sed -n '10p' (nl打印行号)
sed -n '/root/p' passwd (打印)

定位几行:x,y;/pattern/,x; (x,y代表行号)
/pattern1/,/pattern2/;
x,y! (取反)

nl passwd | sed -n '10,20p' (打印10行到20行)
nl passwd | sed -n '/operator/,/games/p'
nl passwd | sed -n '10!p' (不选择第10行)
nl passwd | sed -n '10,20!p' (不选择10行到20行)

定位间隔几行:first~step
nl passwd | sed -n '1~2p' (从第1行开始,间隔2-1行,再打印)

基本操作命令(2)

1
2
3
4
5
6
7
8
9
10
11
-a (新增行)/ i(插入行)
-c (替代行)
-d(删除行)
nl passwd | sed '5a ===========' (第5行和第6行之间增加分隔符===========)
nl passwd | sed '1,5a===========' (第1行和第5行之间,每一行都增加分隔符===========)
nl passwd | sed '5i===========' (第5行之前插入分隔符===========)
nl passwd | sed '1,5i===========' (第1行和第5行之前,每一行都插入分隔符===========)
nl passwd | sed '40c 123123' (将40行替换成123123)
nl passwd | sed '35,40c 123123' (将35行到40行替换成123123,35行以后的内容就没有了,只有123123这一行,并不是每一行进行替换,而是对这些行做一个整体的替换)
nl passwd | sed '/mooc/d' (删除mooc所在行)
sed不会改变源文件的内容,如果要保存结果需要重定向

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
案例一:优化服务器的配置
在ssh的配置文件加入相应文本:
"
Port 52113
PermitRootLogin no
PermitEmptyPasswords no
"
sed '$a \ port\ 52113 \n permitroologin no' sshd_config (空格需要\转义)

案例二:文本处理
删除文本中空行
sed '/^$/d' sshd_config (空行用正则/^$/表示)

案例三:服务器日志处理
服务器log中找出error报错
sed -n '/Error/p'

基本操作命令(3)

1
2
3
4
5
6
7
8
9
10
11
-s(替换):分隔符/,#等
sed 's/nologin/l/' passwd (nologin替换为l)
-g(全局):替换标志
sed 's/:/%/' passwd (只是把每一行的第一个':'替换为'%')
sed 's/:/%/g' passwd (所有的':'都被替换为'%')

案例四:数据筛选
获取enp0s8的ip
ifconfig enp0s8 | sed -n '/inet /p' | sed 's/inet//' (centos7)
ifconfig enp0s8 | sed -n '/inet /p' | sed 's/inet.*r://' (Ubuntu上有:)
ifconfig enp0s8 | sed -n '/inet /p' | sed 's/inet//' | sed 's/n.*$//'

高级操作命令(1)

1
2
-{}:多个sed命令,用;分开
nl passwd | sed '{20,30d;s/nologin/login/}' (先删除20行到30行,然后剩下的行nologin替换成login)

高级操作命令(2)

1
2
3
4
5
-n:读取下一个输入行(用下一个命令处理)
nl passwd | sed -n '{n;p}' (你会发现跳行,输出2、4、6、8行。执行过程是sed读入一行后,接着n又读入下一行。输出偶数行)
nl passwd | sed -n '2~2p' (输出偶数行)
nl passwd | sed -n '{p;n}' (输出奇数行)
nl passwd | sed -n '1~2p' (输出奇数行,与上一条命令相等)

高级操作命令(3)

1
2
3
4
5
-&:替换固定字符串
sed 's/^[a-z_-]\+/& /' passwd (用户名后面加上空格)
root:x:0:0:root:/root:/bin/bash (源字符串)
root :x:0:0:root:/root:/bin/bash (替换后字符串)
如果替换的字符串与源字符串有重复串,可以用&。类似于在源字符串后追加

案例:

1
2
3
4
5
6
7
8
9
10
11
12
案例一:大小写转换
将用户名的首字母转换为大写/小写
(元字符\u \l \U \L:转换为大写/小写字符,小写的\u和\l是对首字母的转换,大写的\U和\L是对一串字符的转换)
sed 's/^[a-z_-]\+/\u&/' passwd

案例二:大小写转换
将文件夹下的.txt文件名转换为大写
ls *.txt | sed 's/^\w\+/\U&/'

案例三:数据筛选
获取passwd中USER、UID和GID
sed 's/\(^[a-z_-]\+\):x:\([0-9]\+\):\([0-9]\+\):.*$/USER:\1 UID:\2 GID:\3/' passwd

高级操作命令(4)

1
2
3
4
-\( \):替换某种(部分)字符串(\1,\2)
案例二:数据筛选
"获取eth0的ip"
ifconfig enp0s9 | sed -n '/inet /p' | sed 's/inet \([0-9.]\+\) .*$/\1/' (centos 7)

高级操作命令(5)

1
2
3
4
5
-r:复制指定文件插入到匹配行(不改变文件内容只改变输出,如果想改变文件内容需要重定向)
-w:复制匹配行拷贝指定文件里(改变目标文件)
用处:源文件和目标文件互相操作。
sed '1r 123.txt' abc.txt (从123.txt中读取内容,插入到abc.txt的第1行后 )
sed '1w abc.txt' 123.txt (从123.txt中读入,写入到abc.txt。1w是指定123.txt中的哪一行写入到abc.txt)

高级操作命令(6)

1
2
3
q:退出sed
nl passwd | sed '10q' (执行到第10行就结束)
nl passwd | sed '/false/q' (找到第一个false就结束)

awk

主要用途:统计、制表

awk处理方式:awk一次处理一行内容、awk对每行可以切片处理

1
awk '{print $1}'	//输出首个单词

使用awk的格式:

1
2
3
4
5
6
7
8
9
10
1、命令行格式:
awk [options] 'command' file(s)
command: pattern {awk 操作命令}
pattern: 正则表达式; 逻辑判断式
command1: pattern {awk 操作命令}
操作命令: 内置函数: print() printf() getline..;
控制指令: if(){...}else{...};while(){...};

2、脚本格式:
awk -f awk-script-file file(s)

awk内置参数应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
awk 内置变量1
$0:表示整个当前行
$1:每行第一个字段
$2:每行第二个字段
这些字段是怎样划分的呢?我们用分隔符
awk内置参数:分隔符
options:-F field-separator(默认为空格)
例如:awk -F ':' '{print $3}' /etc/passwd

[root@cephL]# awk -F ':' '{print $1,$3}' passwd
awk -F ':' '{print $1" "$3}' passwd
awk -F ':' '{print $1"\t"$3}' passwd
awk -F ':' '{print "User:"$1"\t""UID:"$3}' passwd
awk内置变量:
NR:每行的记录号(行)
NF:字段数量变量(列)
FILENAME:正在处理的文件名
例如:awk -F ':' 'print FILENAME' passwd

awk内置参数应用案例:

1
2
3
4
5
6
7
8
9
10
11
12
案例一:
显示/etc/passwd每行的行号,每行的列数,对应行的用户名(print,printf)
awk -F ':' '{print "Line: "NR,"Col: "NF,"User: "$1}' passwd
awk -F ':' '{printf("Line: %3s Col: %s User: %s\n",NR,NF,$1)}' passwd

案例二:
显示/etc/passwd中用户ID大于100的行号和用户名(if...else...)
awk -F ':' '{if ($3>100) print "Line: "NR,"User: "$1}' passwd
案例三:
在服务器log中找出'Error'的发生日期
sed '/Error/p' fresh.log | awk '{print $1}'
awk '/Error/{print $1}' fresh.log

使用awk——逻辑判断式

1
2
3
4
5
6
7
8
9
10
11
12
13
command: pattern {awk 操作命令}
pattern: 正则表达式;逻辑判断式

awk逻辑
~,!~: 匹配正则表达式
==,!=,<,>: 判断逻辑表达式

1、第一个字段是'm'开头的
awk -F ':' '$1~/^m.*/{print $1}' passwd
2、第一个字段不是'm'开头的
awk -F ':' '$1!~/^m.*/{print $1}' passwd
3、第三个字段大于100
awk -F ':' '$3>100{print $1,$3}' passwd

使用awk——扩展格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1、命令行格式:
awk [options] 'command' file(s)
command2扩展
BEGIN{print "start"} pattern{commands} END{print "end"}
awk是以行为操作单位的,BEGIN是在没有读入第一行之间执行的,END是处理完最后一行执行的

案例一:
制表显示/etc/passwd每行的行号,每行的列数,对应行的用户名
awk -F ':' 'BEGIN{print "Line\tCol\tUser"}{print NR"\t"NF"\t"$1}END{print "---"FILENAME"---"}' passwd

案例二:
统计当前文件夹下的文件/文件夹占用的大小
ls -l | awk 'BEGIN{size=0}{size+=$5}END{print "size is "size/1024/1024"M"}'

案例三:
统计显示/etc/passwd的账户总人数
awk -F ':' 'BEGIN{count=0}$1!~/^$/{count++}END{print "count = "count}' passwd
统计显示UID大于100的用户名
awk -F ':' 'BEGIN{count=0}{if ($3 > 100) name[count++]=$1}END{for(i=0;i<count;i++) print i,name[i]}' passwd

案例四:
统计netstat -anp 状态下为LISTEN和CONNECTED的连接数量
netstat -anp | awk '$6~/CONNECTED|LISTEN/{sum[$6]++}END{for(i in sum)print i,sum[i]}'

awk VS sed

1
2
3
4
5
awk和sed都可以处理文本
awk侧重于复杂逻辑处理
sed侧重于正则处理

awk和sed可以共同使用

CEPH-VOLUME

使用pluggable(可插拔)工具将 OSDs 与 lvm 或physical disks等不同的device技术部署在一起(lvm本身被视为plugin), 并尝试采用predictable、robust的方法来preparing、activating和starting OSDs。

Overview|Plugin Guide

Command Line Subcommands

目前支持lvm,以及已经使用ceph-disk部署的普通磁盘(带有GPT分区)。

Node inventory

inventory子命令提供有关节点物理磁盘inventory(清单)的信息和元数据。

MIGRATING

从Ceph版本13.0.0开始,不推荐使用ceph-disk。弃用警告中的link会链接到此页面。强烈建议用户开始使用ceph-volume。有两种迁移途径:

1、保留使用ceph-disk部署的OSD:simple 命令在禁用ceph-disk触发的同时,提供了接管管理的方法。

2、用ceph-volume重新部署现存的OSD:详细信息请参照 Replacing an OSD

有关为何删除ceph-disk的详细信息,请参阅Why was ceph-disk replaced? 章节。

NEW DEPLOYMENTS

对于新的部署,推荐使用lvm,它可以使用任何logical volume作为data OSD 的输入, 也可以从device中设置minimal/naive logical volume。

EXISTING OSDS

如果群集已经具有ceph-disk提供的OSDs,则ceph-volume可以用simple的方式接管。在data device或OSD directory上完成扫描,并且ceph-disk被完全禁用。完全支持加密。

LVM

实现此功能需要通过lvm子命令来部署OSDs:ceph-volume lvm

Command Line Subcommands

prepare

prepare

该子命令允许filestorebluestore设置。 建议在使用ceph-volume lvm之前预先配置逻辑卷。除添加额外元数据外,逻辑卷不会改变。

为了帮助识别volumes,preparing的过程中该工具使用LVM tags分配一些元数据信息。

LVM tags使volume易于发现,帮助识别它们作为Ceph系统的一部分,扮演着什么角色(journal, filestore, bluestore, etc…)

虽然最初支持filestore(默认情况下支持),但可以使用以下命令指定:

FILESTORE

这是OSD backend,允许为filestore objectstore OSD 准备逻辑卷。

它可以使用逻辑卷作为OSD data和带分区的physical device或逻辑卷作为journal。除了遵循data和journal的最小大小要求外,这些卷不需要特殊准备。

API调用如下所示:

1
ceph-volume lvm prepare --filestore --data volume_group/lv_name --journal journal

启用encryption(加密),需要使用–dmcrypt标志:

1
ceph-volume lvm prepare --filestore --dmcrypt --data volume_group/lv_name --journal journal

activate

create

list

Internal functionality

lvm子命令的其他部分是internal的,不向用户公开,这些部分解释了如何协同工作,阐明了工具的工作流程。

Systemd Units | lvm

SIMPLE

实现此功能需要通过simple子命令来管理OSD:ceph-volume simple

Command Line Subcommands

通过接管管理,它会disable所有用于在startup时触发device的ceph-disk systemd units,依赖基本的(可定制的)JSON配置和systemd来启动OSD。

此过程包括两个步骤:

1、Scan(扫描)正在运行的OSD或data device

2、Activate(激活)扫描的OSD

扫描将推断出ceph-volume启动OSD所需的所有内容,因此当需要激活时,OSD可以正常启动而不会受到来自ceph-disk的干扰。

作为激活过程的一部分,负责对udev事件作出反应的ceph-disk的systemd units链接到/dev/null,以便它们完全处于非活动状态。

备注

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
ceph-volume lvm(使用LVM和LVM-based技术,像dmcache去部署OSD)
1、activate Discover and mount the LVM device associated with an OSD ID and start the Ceph OSD(Discover并mount与OSD ID关联的LVM设备,然后启动Ceph OSD)
2、prepare Format an LVM device and associate it with an OSD(Format LVM device并将其与OSD关联)
3、create Create a new OSD from an LVM device(从LVM device创建新的OSD)
4、list list logical volumes and devices associated with Ceph(列出与Ceph相关的logical volumes和devices)
5、batch Automatically size devices for multi-OSD provisioning with minimal interaction(自动调整devices大小,以最少的交互进行多OSD配置)
6、trigger systemd helper to activate an OSD(systemd助手来激活OSD)
7、zap Removes all data and filesystems from a logical volume or partition.(从logical volume或分区中删除所有数据和文件系统。)

ceph-volume simple(使用ceph-volume管理已部署的OSD)
1、trigger systemd helper to activate an OSD(systemd助手来激活OSD)
2、activate Enable systemd units to mount configured devices and start a Ceph OSD(使systemd units可以mount已配置的devices,并启动Ceph OSD)
3、scan Capture metadata from all running ceph-disk OSDs, OSD data partition or directory(从所有正在运行的ceph-disk OSDs,OSD数据分区或目录中捕获元数据)

例如:
# ceph-volume simple scan
执行命令后,会生成类似/etc/ceph/osd/0-ab0a204a-42e3-4a47-ab4c-0888edf429cb.json文件,文件内容为:
{
"active": "ok",
"block": {
"path": "/dev/disk/by-partuuid/0818811f-d70e-4ff0-91c9-58cd701c9a19",
"uuid": "0818811f-d70e-4ff0-91c9-58cd701c9a19"
},
"block_uuid": "0818811f-d70e-4ff0-91c9-58cd701c9a19",
"bluefs": 1,
"ceph_fsid": "c4051efa-1997-43ef-8497-fb02bdf08233",
"cluster_name": "ceph",
"data": {
"path": "/dev/vdc1",
"uuid": "ab0a204a-42e3-4a47-ab4c-0888edf429cb"
},
"fsid": "ab0a204a-42e3-4a47-ab4c-0888edf429cb",
"keyring": "AQB1FLFdXVHVARAARTKkxT1xgrDNU/QECUqdxA==",
"kv_backend": "rocksdb",
"magic": "ceph osd volume v026",
"mkfs_done": "yes",
"ready": "ready",
"systemd": "",
"type": "bluestore",
"whoami": 0
}

# ceph-volume simple activate --all
--> activating OSD specified in /etc/ceph/osd/1-fe327306-54a4-4362-870d-92d28cf65e42.json
Running command: ln -snf /dev/vdc2 /var/lib/ceph/osd/ceph-1/block
Running command: chown -R ceph:ceph /dev/vdc2
Running command: systemctl enable ceph-volume@simple-1-fe327306-54a4-4362-870d-92d28cf65e42
Running command: ln -sf /dev/null /etc/systemd/system/ceph-disk@.service
--> All ceph-disk systemd units have been disabled to prevent OSDs getting triggered by UDEV events
Running command: systemctl enable --runtime ceph-osd@1
Running command: systemctl start ceph-osd@1
--> Successfully activated OSD 1 with FSID fe327306-54a4-4362-870d-92d28cf65e42

ceph-volume inventory(获取此节点可用的disk清单)
例如:
ceph-volume inventory
Device Path Size rotates available Model name
/dev/vdb 64.00 MB True True
/dev/vdc 50.00 GB True True
/dev/vda 100.00 GB True False

shec plugin封装了multiple SHEC库。它允许ceph比Reed Solomon codes更有效地恢复数据。

CREATE AN SHEC PROFILE

创建一个新的shec erasure code profile:

1
2
3
4
5
6
7
8
9
10
ceph osd erasure-code-profile set {name} \
plugin=shec \
[k={data-chunks}] \
[m={coding-chunks}] \
[c={durability-estimator}] \
[crush-root={root}] \
[crush-failure-domain={bucket-type}] \
[crush-device-class={device-class}] \
[directory={directory}] \
[--force]

其中:

k={data-chunks}

1
2
3
4
Description:	每个object都分为多个data-chunks parts,每个part存储在不同的OSD上。
Type: Integer
Required: No.
Default: 4

m={coding-chunks}

1
2
3
4
Description:	计算每个object的coding chunks并将它们存储在不同的OSD上。coding chunks的数量也是在不丢失数据的情况下,允许损失OSD的数量。
Type: Integer
Required: No.
Default: 3

c={durability-estimator}

1
2
3
4
5
Description:	校验chunk的数量,每个data chunk都包含在计算范围内。该数字被用作耐久性估算。例如,如果c = 2,则可以在不丢失数据的情况下down掉2个OSD。
The number of parity chunks each of which includes each data chunk in its calculation range. The number is used as a durability estimator. For instance, if c=2, 2 OSDs can be down without losing data.
Type: Integer
Required: No.
Default: 2

crush-root={root}

1
2
3
4
Description:	crush bucket名字用于CRUSH rule的first step。"take"为step的默认值。
Type: String
Required: No.
Default: default

crush-failure-domain={bucket-type}

1
2
3
4
Description:	确保不要有两个chunks位于相同故障域的bucket中。例如,如果故障域是host,则不会在同一主机上存储两个chunks。它用于创建CRUSH rule step,比如step chooseleaf host。
Type: String
Required: No.
Default: host

crush-device-class={device-class}

1
2
3
4
Description:	使用CRUSH map中的crush device class名称,限定存储到特定class devices(例如SSD或HDD)。
Type: String
Required: No.
Default:

directory={directory}

1
2
3
4
Description:	设置加载erasure code plugin的目录名。
Type: String
Required: No.
Default: /usr/lib/ceph/erasure-code

–force

1
2
3
Description:	用相同的名称覆盖已有的profile。
Type: String
Required: No.

BRIEF DESCRIPTION OF SHEC’S LAYOUTS

SPACE EFFICIENCY

Space efficiency是data chunks与object中所有chunks的比率,表示为k /(k + m)。为了提高space efficiency,您应该增加k或减少m。

1
2
space efficiency of SHEC(4,3,2) = 4/(4+3) = 0.57
SHEC(5,3,2) or SHEC(4,2,2) improves SHEC(4,3,2)'s space efficiency

DURABILITY

SHEC(= c)的第三个参数是一个耐久性估算,它近似于在不丢失数据的情况下可以丢失OSD的数量。SHEC(4,3,2)的耐久性估算= 2

RECOVERY EFFICIENCY

描述recovery efficiency的计算超出了本文件的范围,但至少在不增加c的情况下增加m可以提高恢复效率。(但是,在这种情况下,我们必须牺牲space efficiency。)

SHEC(4,2,2)→SHEC(4,3,2):提高了recovery efficiency

ERASURE CODE PROFILE EXAMPLES

1
2
3
4
5
$ ceph osd erasure-code-profile set SHECprofile \
plugin=shec \
k=8 m=4 c=3 \
crush-failure-domain=host
$ ceph osd pool create shecpool 256 256 erasure SHECprofile

通过jerasure plugin,当erasure coded的object存储在多个OSD中时,恢复丢失的1个OSD数据需要从所有其他OSD读取数据并修复。例如,如果jerasure配置为k = 8和m = 4,则丢失1个OSD需要从其他11个OSD读取并修复。

lrc erasure code plugin创建本地奇偶校验chunks,以便能够使用较少的OSD恢复。例如,如果lrc配置为k = 8,m = 4和l = 4,则会为每4个OSD创建一个附加奇偶校验chunk。当1个OSD丢失时,只需要使用4个OSD而不是11个来恢复。

ERASURE CODE PROFILE EXAMPLES

REDUCE RECOVERY BANDWIDTH BETWEEN HOSTS

当所有主机连接到相同的交换机时,实际上可以观察到减少的带宽。

1
2
3
4
5
$ ceph osd erasure-code-profile set LRCprofile \
plugin=lrc \
k=4 m=2 l=3 \
crush-failure-domain=host
$ ceph osd pool create lrcpool 12 12 erasure LRCprofile

REDUCE RECOVERY BANDWIDTH BETWEEN RACKS

在Firefly中,只有当primary OSD与丢失chunk在同一个rack中时,才会观察到减少的带宽。

1
2
3
4
5
6
$ ceph osd erasure-code-profile set LRCprofile \
plugin=lrc \
k=4 m=2 l=3 \
crush-locality=rack \
crush-failure-domain=host
$ ceph osd pool create lrcpool 12 12 erasure LRCprofile

CREATE AN LRC PROFILE

创建新的lrc erasure code profile:

1
2
3
4
5
6
7
8
9
10
11
ceph osd erasure-code-profile set {name} \
plugin=lrc \
k={data-chunks} \
m={coding-chunks} \
l={locality} \
[crush-root={root}] \
[crush-locality={bucket-type}] \
[crush-failure-domain={bucket-type}] \
[crush-device-class={device-class}] \
[directory={directory}] \
[--force]

其中:

k={data chunks}

1
2
3
4
Description:	每个object都分为多个data-chunks parts,每个part存储在不同的OSD上。
Type: Integer
Required: Yes.
Example: 4

m={coding-chunks}

1
2
3
4
Description:	计算每个object的coding chunks并将它们存储在不同的OSD上。coding chunks的数量也是在不丢失数据的情况下,允许损失OSD的数量。
Type: Integer
Required: Yes.
Example: 2

l={locality}

1
2
3
4
5
6
Description:	将coding和data chunks分组为指定size locality的sets。例如,对于k = 4和m = 2,当locality = 3时,创建2个groups,每个group中3个。每个set都可以在不读取另一set中chunks的情况下恢复。

Group the coding and data chunks into sets of size locality. For instance, for k=4 and m=2, when locality=3 two groups of three are created. Each set can be recovered without reading chunks from another set.
Type: Integer
Required: Yes.
Example: 3

crush-root={root}

1
2
3
4
Description:	crush bucket名字用于CRUSH rule的first step。"take"为step的默认值。
Type: String
Required: No.
Default: default

crush-locality={bucket-type}

1
2
3
4
Description:	crush bucket的type,其中由l定义的每个chunks集合将被存储。例如,如果它被设置为rack,则每个l chunks将被放置在不同的rack中。它用于创建CRUSH rule step,如step选择rack。如果没有设置,则不会进行这样的分组。
The type of the crush bucket in which each set of chunks defined by l will be stored. For instance, if it is set to rack, each group of l chunks will be placed in a different rack. It is used to create a CRUSH rule step such as step choose rack. If it is not set, no such grouping is done.
Type: String
Required: No.

crush-failure-domain={bucket-type}

1
2
3
4
5
6
Description:	确保不要有两个chunks位于相同故障域的bucket中。例如,如果故障域是host,则不会在同一主机上存储两个chunks。它用于创建CRUSH rule step,比如step chooseleaf host。

Ensure that no two chunks are in a bucket with the same failure domain. For instance, if the failure domain is host no two chunks will be stored on the same host. It is used to create a CRUSH rule step such as step chooseleaf host.
Type: String
Required: No.
Default: host

crush-device-class={device-class}

1
2
3
4
Description:	使用CRUSH map中的crush device class名称,限定存储到特定class devices(例如SSD或HDD)。
Type: String
Required: No.
Default:

directory={directory}

1
2
3
4
Description:	设置加载erasure code plugin的目录名。
Type: String
Required: No.
Default: /usr/lib/ceph/erasure-code

–force

1
2
3
Description:	用相同的名称覆盖已有的profile。
Type: String
Required: No.

LOW LEVEL PLUGIN CONFIGURATION

k和m的和必须是l parameter的倍数。low level configuration parameters不会施加这样的限制,并且为了特定目的而使用它可能更加方便。例如可以定义两个groups,一个group有4个chunks,另一个group有3个chunks。还可以递归地定义locality sets,例如datacenters和racks到datacenters。通过生成low level configuration来实现k/m/l。

lrc erasure code plugin递归地应用erasure code技术,以便在大多数情况下从某些chunks的丢失中仅恢复需要的可用chunks的子集。例如,three coding steps被描述为:

1
2
3
4
chunk nr    01234567
step 1 _cDD_cDD
step 2 cDDD____
step 3 ____cDDD

其中c是从data chunks D计算出的coding chunks,丢失的chunk 7,可以用后4个chunks恢复。丢失的chunk 2的chunk可以用前4个chunks恢复。

ERASURE CODE PROFILE EXAMPLES USING LOW LEVEL CONFIGURATION

MINIMAL TESTING

它严格等同于使用默认的erasure code profile。DD意味着K = 2,c意味着M = 1,并且使用默认的jerasure  plugin。

1
2
3
4
5
$ ceph osd erasure-code-profile set LRCprofile \
plugin=lrc \
mapping=DD_ \
layers='[ [ "DDc", "" ] ]'
$ ceph osd pool create lrcpool 12 12 erasure LRCprofile

REDUCE RECOVERY BANDWIDTH BETWEEN HOSTS

当所有主机连接到同一个交换机时,可以观察到减少的带宽使用情况。它相当于k = 4,m = 2和l = 3,尽管chunks的layout不同:

1
2
3
4
5
6
7
8
9
$ ceph osd erasure-code-profile set LRCprofile \
plugin=lrc \
mapping=__DD__DD \
layers='[
[ "_cDD_cDD", "" ],
[ "cDDD____", "" ],
[ "____cDDD", "" ],
]'
$ ceph osd pool create lrcpool 12 12 erasure LRCprofile

REDUCE RECOVERY BANDWIDTH BETWEEN RACKS

在Firefly中,只有当primary OSD与丢失chunk在同一个rack中时,才会观察到减少的带宽。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ ceph osd erasure-code-profile set LRCprofile \
plugin=lrc \
mapping=__DD__DD \
layers='[
[ "_cDD_cDD", "" ],
[ "cDDD____", "" ],
[ "____cDDD", "" ],
]' \
crush-steps='[
[ "choose", "rack", 2 ],
[ "chooseleaf", "host", 4 ],
]'
$ ceph osd pool create lrcpool 12 12 erasure LRCprofile

TESTING WITH DIFFERENT ERASURE CODE BACKENDS

LRC现在使用jerasure作为默认的EC backend。可以使用low level configuration在每个layer基础上指定EC backend/algorithm。layers=’[ [ “DDc”, “” ] ]’ 的第二个参数实际上是用于此level的erasure code profile。下面的例子指定了在lrcpool中使用cauchy technique的ISA backend。

1
2
3
4
5
$ ceph osd erasure-code-profile set LRCprofile \
plugin=lrc \
mapping=DD_ \
layers='[ [ "DDc", "plugin=isa technique=cauchy" ] ]'
$ ceph osd pool create lrcpool 12 12 erasure LRCprofile

您还可以为每个layer使用不同的erasure code profile。

1
2
3
4
5
6
7
8
9
$ ceph osd erasure-code-profile set LRCprofile \
plugin=lrc \
mapping=__DD__DD \
layers='[
[ "_cDD_cDD", "plugin=isa technique=cauchy" ],
[ "cDDD____", "plugin=isa" ],
[ "____cDDD", "plugin=jerasure" ],
]'
$ ceph osd pool create lrcpool 12 12 erasure LRCprofile

ERASURE CODING AND DECODING ALGORITHM

在layers中找到的steps描述:

1
2
3
4
5
chunk nr    01234567

step 1 _cDD_cDD
step 2 cDDD____
step 3 ____cDDD

按顺序应用。例如,如果一个4K的object被encoded,它将首先通过step 1并被分成4个1K的chunk(4个大写D)。它们按顺序存储在chunk 2,3,6和7中。由此计算出两个coding chunks(两个小写字母c)。coding chunks分别存储在chunk 1和5中。

step 2以类似的方式重新使用由step 1创建的内容,并在位置0处存储单个coding chunk c。为了便于阅读,最后四个标记有下划线(_)的chunks将被忽略。

step 3在位置4存储单个coding chunk c。由step 1创建的3个chunks被用于计算该coding chunk,即来自step 1的coding chunk在step 3中变为data chunk。

如果chunk 2丢失:

1
2
3
4
5
chunk nr    01234567

step 1 _c D_cDD
step 2 cD D____
step 3 __ _cDDD

decoding将尝试通过以相反的顺序来执行steps恢复它:step 3然后是step 2,最后是step 1。

step 3对chunk 2(即它是下划线)一无所知并被跳过。

存储在chunk 0中来自step 2的coding chunk允许其恢复chunk 2的内容。没有更多的chunks要恢复,过程停止,不考虑step 1。

恢复chunk 2需要读取chunks 0,1,3,并写回chunk 2。

如果chunk 2,3,6丢失:

1
2
3
4
5
chunk nr    01234567

step 1 _c _c D
step 2 cD __ _
step 3 __ cD D

step 3可以恢复chunk 6的内容:

1
2
3
4
5
chunk nr    01234567

step 1 _c _cDD
step 2 cD ____
step 3 __ cDDD

step 2无法恢复并被跳过,因为缺少两个chunks(2,3),并且它只能从一个缺失的chunk中恢复。

存储在chunk 1,5中的来自step 1的coding chunk允许它恢复chunk 2,3的内容:

1
2
3
4
5
chunk nr    01234567

step 1 _cDD_cDD
step 2 cDDD____
step 3 ____cDDD

CONTROLLING CRUSH PLACEMENT

默认的CRUSH rule提供位于不同hosts上隔离OSD。 例如:

1
2
3
4
5
chunk nr    01234567

step 1 _cDD_cDD
step 2 cDDD____
step 3 ____cDDD

需要8个OSD,每个chunk需要一个OSD。如果hosts位于两个相邻的racks中,则前4个chunks可以放在第一个rack中,最后4个放在第二个rack中。因此,从丢失的单个OSD中恢复并不需要在两个racks之间使用带宽。

例如:

1
crush-steps='[ [ "choose", "rack", 2 ], [ "chooseleaf", "host", 4 ] ]'

将创建一个rule,将选择两个类型rack的crush buckets,为它们每个选择4个OSD,它们中的每一个都位于类型host的不同buckets中。

CRUSH rule也可以手动制作以实现更精细的控制。

ISA plugin封装了ISA库。 它只能在Intel处理器上运行。

CREATE AN ISA PROFILE

创建新的isa erasure code profile:

1
2
3
4
5
6
7
8
9
10
ceph osd erasure-code-profile set {name} \
plugin=isa \
technique={reed_sol_van|cauchy} \
[k={data-chunks}] \
[m={coding-chunks}] \
[crush-root={root}] \
[crush-failure-domain={bucket-type}] \
[crush-device-class={device-class}] \
[directory={directory}] \
[--force]

其中:

k={data chunks}

1
2
3
4
Description:	每个object都分为多个data-chunks parts,每个part存储在不同的OSD上。
Type: Integer
Required: No.
Default: 7

m={coding-chunks}

1
2
3
4
Description:	计算每个object的coding chunks并将它们存储在不同的OSD上。coding chunks的数量也是在不丢失数据的情况下,允许损失OSD的数量。
Type: Integer
Required: No.
Default: 3

technique={reed_sol_van|cauchy}

1
2
3
4
5
6
Description:	ISA插件有两种Reed Solomon形式(https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction)。
如果设置了reed_sol_van,则为Vandermonde,
如果设置了cauchy(https://en.wikipedia.org/wiki/Vandermonde_matrix),则为Cauchy(https://en.wikipedia.org/wiki/Cauchy_matrix)。
Type: String
Required: No.
Default: reed_sol_van

crush-root={root}

1
2
3
4
Description:	crush bucket名字用于CRUSH rule的first step。"take"为step的默认值。
Type: String
Required: No.
Default: default

crush-failure-domain={bucket-type}

1
2
3
4
Description:	确保不要有两个chunks位于相同故障域的bucket中。例如,如果故障域是host,则不会在同一主机上存储两个chunks。它用于创建CRUSH rule step,比如step chooseleaf host。
Type: String
Required: No.
Default: host

crush-device-class={device-class}

1
2
3
4
Description:	使用CRUSH map中的crush device class名称,限定存储到特定class devices(例如SSD或HDD)。
Type: String
Required: No.
Default:

directory={directory}

1
2
3
4
Description:	设置加载erasure code plugin的目录名。
Type: String
Required: No.
Default: /usr/lib/ceph/erasure-code

–force

1
2
3
Description:	用相同的名称覆盖已有的profile。
Type: String
Required: No.

jerasure plugin是最通用和灵活的插件,它也是Ceph erasure coded pools的默认设置。

jerasure plugin封装了Jerasure库。建议阅读Jelasure文档以更好地理解参数。

CREATE A JERASURE PROFILE

创建新的jerasure erasure code profile:

1
2
3
4
5
6
7
8
9
10
ceph osd erasure-code-profile set {name} \
plugin=jerasure \
k={data-chunks} \
m={coding-chunks} \
technique={reed_sol_van|reed_sol_r6_op|cauchy_orig|cauchy_good|liberation|blaum_roth|liber8tion} \
[crush-root={root}] \
[crush-failure-domain={bucket-type}] \
[crush-device-class={device-class}] \
[directory={directory}] \
[--force]

其中:

k={data chunks}

1
2
3
4
Description:	每个object都分为多个data-chunks parts,每个part存储在不同的OSD上。
Type: Integer
Required: Yes.
Example: 4

m={coding-chunks}

1
2
3
4
Description:	计算每个object的coding chunks并将它们存储在不同的OSD上。coding chunks的数量也是在不丢失数据的情况下,允许损失OSD的数量。
Type: Integer
Required: Yes.
Example: 2

technique={reed_sol_van|reed_sol_r6_op|cauchy_orig|cauchy_good|liberation|blaum_roth|liber8tion}

1
2
3
4
Description:	更灵活的technique是reed_sol_van:只需要设置k和m。cauchy_good technique可以更快但您需要调优packetsize。reed_sol_r6_op,liberation,blaum_roth,liber8tion都与RAID6等价,因为它们只能配置m=2。
Type: String
Required: No.
Default: reed_sol_van

packetsize={bytes}

1
2
3
4
Description:	encoding将在一次bytes大小的packets上完成。选择合理的packet大小是困难的。Jeasure文档包含了关于这个topic的大量信息。
Type: Integer
Required: No.
Default: 2048

crush-root={root}

1
2
3
4
5
Description:	crush bucket名字用于CRUSH rule的first step。"take"为step的默认值。
The name of the crush bucket used for the first step of the CRUSH rule. For intance step take default.
Type: String
Required: No.
Default: default

crush-failure-domain={bucket-type}

1
2
3
4
Description:	确保不要有两个chunks位于相同故障域的bucket中。例如,如果故障域是host,则不会在同一主机上存储两个chunks。它用于创建CRUSH rule step,比如step chooseleaf host。
Type: String
Required: No.
Default: host

crush-device-class={device-class}

1
2
3
Description:	使用CRUSH map中的crush device class名称,限定存储到特定class devices(例如SSD或HDD)。
Type: String
Required: No.

directory={directory}

1
2
3
4
Description:	设置加载erasure code plugin的目录名。
Type: String
Required: No.
Default: /usr/lib/ceph/erasure-code

–force

1
2
3
Description:	以相同的名称重写已经存在的profile。
Type: String
Required: No.

Erasure code由profile定义,并在erasure coded pool关联CRUSH rule时使用。

默认的erasure code profile(在Ceph集群初始化时被创建)提供了与两个副本相同的冗余级别,但相比两副本需要的磁盘空间减少了25%。它被描述为k = 2和m = 1的profile,这意味着信息分布在三个OSD(k + m == 3)上,其中一份可以被丢失。

为了在不增加raw space的情况下提高冗余度,可以创建新的profile。例如,k = 10和m = 4的profile可以通过在14(k + m = 14)个OSD上分散一个object来支撑4个(m = 4)OSD的丢失。首先将object分成10个chunks(如果object为10MB,每个chunk为1MB)并且计算4个coding chunks用于recovery(每个coding chunk具有与data chunk相同的大小,即1MB)。raw space开销只有40%,即使四个OSD同时中断,object也不会丢失。

OSD ERASURE-CODE-PROFILE SET

创建新的erasure code profile:

1
2
3
4
5
6
ceph osd erasure-code-profile set {name} \
[{directory=directory}] \
[{plugin=plugin}] \
[{stripe_unit=stripe_unit}] \
[{key=value} ...] \
[--force]

其中:

{directory=directory}

1
2
3
4
Description:	设置加载erasure code plugin的目录名。
Type: String
Required: No.
Default: /usr/lib/ceph/erasure-code

{plugin=plugin}

1
2
3
4
Description:	使用erasure code plugin计算coding chunks和recover missing chunks。
Type: String
Required: No.
Default: jerasure

{stripe_unit=stripe_unit}

1
2
3
Description:	data chunk中每个stripe的数据量。例如,具有2个data chunks并且StruPeyUng=4K的profile将在chunk 0中放置0-4K,在chunk 1中放置4K-8K,然后再在chunk 0中放置8K-12K。4K的倍数可以获得最佳的性能。当创建pool时,默认值取自monitor config中的osd_pool_erasure_code_stripe_unit。使用此profile的pool的stripe_width将是data chunks数乘以此stripe_unit的数量。
Type: String
Required: No.

{key=value}

1
2
3
Description:	其余的key/value对semantic由erasure code plugin定义。
Type: String
Required: No.

–force

1
2
3
Description:	以相同的名称覆盖现有的profile,并允许设置非4K对齐的stripe_unit。
Type: String
Required: No.

OSD ERASURE-CODE-PROFILE RM

删除一个erasure code profile:

1
ceph osd erasure-code-profile rm {name}

如果profile被某个pool引用,删除将失败。

OSD ERASURE-CODE-PROFILE GET

显示一个erasure code profile:

1
ceph osd erasure-code-profile get {name}

OSD ERASURE-CODE-PROFILE LS

列出所有erasure code profiles的名称:

1
ceph osd erasure-code-profile ls

cache tier为Ceph Clients读取存储在后端的数据子集提供更好的I/O性能。Cache tiering意味着创建pool时,可以为pool配置一个相对更快/更昂贵的存储设备作为缓存层,并且配置一个经济的后端数据存储pool(由erasure-coded或相对较慢/较便宜的设备组成)。Ceph objecter handles 负责处理放置objects位置,并且tiering agent 决定何时将缓存中的objects刷新到后端存储层。所以cache tier和后端存储层对Ceph clients来说是完全透明的。

cache tiering agent handles自动处理缓存层和后端存储层之间的数据迁移。但是,管理员可以配置此迁移的发生方式。 主要有两种情况:

  • Writeback Mode:

当管理员以writeback mode配置tiers时,Ceph clients将数据写入缓存层并从缓存层接收ACK。经过一段时间后,写入缓存层的数据将迁移到存储层,并从缓存层中清除。从概念上讲,缓存层被覆盖在后端存储层的“前面”。当Ceph client需要驻留在存储层中的数据时,cache tiering agent会在读取数据时将数据迁移到缓存层,然后将其发送到Ceph client。此后,Ceph client可以使用缓存层执行I/O,直到数据变为非活动状态。这对于易变数据(例如照片/视频编辑,交易数据等)是理想的。

  • Read-proxy Mode:

此模式将使用已存在于缓存层中的任何objects,但如果缓存中没有objects,则将请求代理到存储层。这对于从writeback mode转换为禁用缓存非常有用,因为它允许负载在缓存耗尽时正常运行,而无需向缓存中添加任何新objects。

A WORD OF CAUTION

Cache tiering会降低大多数负载的性能。用户在使用此功能之前应特别小心

  • Workload dependent:

缓存是否会提高性能,高度依赖于负载。由于将objects移入或移出缓存会产生额外成本,因此只有在数据集中访问存在较大偏差时才会生效,这样大多数请求才会命中少量objects。缓存池应该大到足以捕获你的负载,以避免抖动。

  • Difficult to benchmark:

使用cache tiering,用户常规衡量性能的基准测试将显得很糟糕,部分原因是由于很少有人将请求集中在一小部分objects上,所以缓存“预热”可能需要很长时间,同时预热可能带来更高的成本。

  • Usually slower:

对于缓存分层不友好的负载,性能通常比没有设置cache tiering enabled的普通RADOS pool慢。

  • librados object enumeration:

在这种情况下,librados级别的object enumeration API并不一致。如果您的应用程序直接使用librados并依赖于object enumeration,则缓存分层可能无法按预期工作。 (这对于RGW,RBD或CephFS来说不是问题。)

  • Complexity:

启用缓存分层会带来额外的复杂性。这会增加其他用户尚未遇到的错误的可能性,并且会使您的部署处于更高级别的风险中。

KNOWN GOOD WORKLOADS

  • RGW time-skewed:

如果RGW负载几乎所有读取操作都针对最近写入的objects,可配置为一段时间后,将最近写入的对象从缓存层迁移到存储层,这种场景可以很好地工作。

KNOWN BAD WORKLOADS

已知下列配置对cache tiering效果不佳。

  • RBD with replicated cache and erasure-coded base:

这是一个常见的要求,但通常表现不佳。即使合理偏差的负载仍然会向cold objects发送一些small writes操作,由于erasure-coded pool尚不支持small writes操作,因此必须将整个(通常为4 MB)objects迁移到缓存中以满足small write(通常为4 KB)。只有少数用户成功部署了此配置,并且仅适用于他们,因为他们的数据extremely cold(备份)并且对性能没有任何要求。

  • RBD with replicated cache and base:

具有replicated base tier(存储层)的RBD,效果要好于erasure coded base tier(存储层)时的RBD,但它仍高度依赖于负载中的偏差量,而且很难验证。用户需要很好地理解他们的负载,并需要调整缓存分层参数。

SETTING UP POOLS

要设置cache tiering,您必须有两个pool。 一个pool充当backing storage,另一个pool充当cache。

SETTING UP A BACKING STORAGE POOL

设置backing storage pool通常涉及以下两种方案之一:

  • Standard Storage:

在这种情况下,pool在Ceph Storage Cluster中存储object的多个副本。

  • Erasure Coding:

在这种情况下,pool使用erasure coding来更有效地存储数据,并且性能折衷很小。

在standard storage方案中,您可以设置CRUSH rule来建立故障域(例如,osd, host, chassis, rack, row, 等)。当rule中的所有存储驱动器都具有相同的大小,速度(RPM-转速和吞吐量)和类型时,Ceph OSD Daemons会达到最佳性能。有关创建rule的详细信息,请参阅CRUSH Maps。一旦你创建了rule,就可以创建backing storage pool了。

在erasure coding方案中,pool创建参数将自动生成适当的rule。 有关详细信息,请参阅Create a Pool

在随后的例子中,我们将backing storage pool称为cold-storage。

SETTING UP A CACHE POOL

设置cache pool遵循与standard storage方案相同的过程,但有这样的区别:作为cache tier(缓存层)的驱动器通常是服务器中的高性能驱动器,并具有自己的CRUSH rule。在设置这样的rule时,应该考虑具有高性能驱动器的主机,忽略不具有高性能驱动器的主机。有关详细信息,请参阅Placing Different Pools on Different OSDs

在后面的例子中,我们将把cache pool称为hot-storage,将backing pool称为cold-storage。

有关cache tier配置和默认值,请参阅Pools - Set Pool Values

CREATING A CACHE TIER

设置cache tier涉及到关联backing storage pool和cache pool。

1
ceph osd tier add {storagepool} {cachepool}

例如:

1
ceph osd tier add cold-storage hot-storage

要设置cache模式,请执行以下操作:

1
ceph osd tier cache-mode {cachepool} {cache-mode}

例如:

1
ceph osd tier cache-mode hot-storage writeback

cache tiers覆盖backing storage tier,他们需要一个额外的步骤:您必须将所有客户端流量从storage pool引导到cache pool。要将客户端流量直接指向cache pool,请执行以下操作:

1
ceph osd tier set-overlay {storagepool} {cachepool}

例如:

1
ceph osd tier set-overlay cold-storage hot-storage

CONFIGURING A CACHE TIER

Cache tiers有几个配置选项。您可以使用以下方法来设置cache tier配置选项:

1
ceph osd pool set {cachepool} {key} {value}

有关详细信息,请参阅Pools - Set Pool Values

TARGET SIZE AND TYPE

Ceph的cache tiers对hit_set_type使用Bloom Filter

1
ceph osd pool set {cachepool} hit_set_type bloom

例如:

1
ceph osd pool set hot-storage hit_set_type bloom

hit_set_count和hit_set_period限定要存储多少个这样的HitSet,以及每个HitSet应该cover多长时间。

1
2
3
ceph osd pool set {cachepool} hit_set_count 12
ceph osd pool set {cachepool} hit_set_period 14400
ceph osd pool set {cachepool} target_max_bytes 1000000000000
1
注意:更大的hit_set_count会导致ceph-osd进程消耗更多的内存。

分级访问,随着时间的推移,可以让Ceph确定是否一个Ceph client访问某个object至少一次,或者在一段时间内(“age” vs “temperature”)超过一次。

min_read_recency_for_promote决定在处理读取操作时,有多少HitSet检查object的存在。检查结果用于决定是否异步提升object。它的值应该在0到hit_set_count之间。如果它设置为0,则该object总是被提升。如果它设置为1,则检查当前的HitSet。如果这个object在当前的HitSet中,它会被提升。否则不是。对于其他值,将检查存档HitSet的确切数量。如果在最近的min_read_recency_for_promote HitSets中找到该object,则会提升该object。

可以为写入操作设置一个类似的参数,即min_write_recency_for_promote。

1
2
ceph osd pool set {cachepool} min_read_recency_for_promote 2
ceph osd pool set {cachepool} min_write_recency_for_promote 2
1
注意:时间越长,min_read_recency_for_promote和min_write_recency_for_promote`value值越高,ceph-osd daemon消耗的内存就越多。特别是,当agent处于active状态刷新或逐出缓存objects时,所有hit_set_count HitSets都将加载到内存中。

CACHE SIZING

cache tiering agent执行两个主要功能:

  • Flushing:

agent识别修改的(或脏的)objects,并将它们转发到storage pool以进行长期存储。

  • Evicting:

agent标识未被修改(或干净的)的objects,并从缓存中逐出其中不常用的objects。

ABSOLUTE SIZING

cache tiering agent可以基于字节总数或objects总数来flush或者evict objects。要指定最大字节数,请执行以下操作:

1
ceph osd pool set {cachepool} target_max_bytes {#bytes}

例如,以1TB flush或evict,请执行以下操作:

1
ceph osd pool set hot-storage target_max_bytes 1099511627776

要指定objects的最大数量,请执行以下操作:

1
ceph osd pool set {cachepool} target_max_objects {#objects}

例如,要flush或evict 1M个对象,请执行以下操作:

1
ceph osd pool set hot-storage target_max_objects 1000000
1
注意:Ceph无法自动确定cache pool的大小,因此在此需要配置一个绝对值大小,否则flush/evict将不起作用。 如果您指定了这两个限制,则在触发阈值时,cache tiering agent将开始flushing或evicting。
1
注意:只有在达到target_max_bytes或target_max_objects时,所有client请求才会被blocked

RELATIVE SIZING

cache tiering agent可以根据cache pool大小flush或evict objects(由target_max_bytes / target_max_objects指定绝对大小)。当cache pool由(有)一定比例修改过的(或脏)objects组成时,cache tiering agent将其flush到storage pool。要设置cache_target_dirty_ratio,请执行以下操作:

1
ceph osd pool set {cachepool} cache_target_dirty_ratio {0.0..1.0}

例如,将值设置为0.4将在修改过的(脏的)objects达到cache pool的容量40%时开始flushing:

1
ceph osd pool set hot-storage cache_target_dirty_ratio 0.4

当脏objects达到其容量的一定比例时,以较高的速度flush脏objects。要设置cache_target_dirty_high_ratio:

1
ceph osd pool set {cachepool} cache_target_dirty_high_ratio {0.0..1.0}

例如,将值设置为0.6将在脏objects达到cache pool容量的60%时开始大量flush脏objects。显然,我们最好设置dirty_ratio和full_ratio之间的值:

1
ceph osd pool set hot-storage cache_target_dirty_high_ratio 0.6

当cache pool达到其容量的一定比例时,cache tiering agent将驱逐objects以保持可用容量。要设置cache_target_full_ratio,请执行以下操作:

1
ceph osd pool set {cachepool} cache_target_full_ratio {0.0..1.0}

例如,将值设置为0.8,当它们达到cache pool容量的80%时,开始flushing未修改的(干净)objects:

1
ceph osd pool set hot-storage cache_target_full_ratio 0.8

CACHE AGE

您可以在cache tiering agent将最近修改的(或脏的)object刷新到backing storage pool之前指定object的最小age:

1
ceph osd pool set {cachepool} cache_min_flush_age {#seconds}

例如,要在10分钟后flush修改的(或脏的)objects,请执行以下操作:

1
ceph osd pool set hot-storage cache_min_flush_age 600

您可以指定object在缓存层被evict之前的最小age:

1
ceph osd pool {cache-tier} cache_min_evict_age {#seconds}

例如,要在30分钟后evict object,请执行以下操作:

1
ceph osd pool set hot-storage cache_min_evict_age 1800

REMOVING A CACHE TIER

删除cache tier取决于它是writeback cache还是read-only cache。

REMOVING A READ-ONLY CACHE

由于read-only cache中没有修改过的(脏的)数据,因此可以直接禁用并删除它,在缓存中objects的最新更改不会丢失。

1、将cache-mode更改为none以禁用它。

1
ceph osd tier cache-mode {cachepool} none

例如:

1
ceph osd tier cache-mode hot-storage none

2、从backing pool上移除cache pool。

1
ceph osd tier remove {storagepool} {cachepool}

例如:

1
ceph osd tier remove cold-storage hot-storage

REMOVING A WRITEBACK CACHE

由于writeback cache中可能修改了数据,因此必须采取措施,确保在禁用和删除缓存中的objects之前不会丢失任何最新更改。

1、将cache mode更改为forward,以便最新的和修改的objects将flush到backing storage pool。

1
ceph osd tier cache-mode {cachepool} forward

例如:

1
ceph osd tier cache-mode hot-storage forward

2、确保cache pool已被flush。 这可能需要几分钟的时间:

1
rados -p {cachepool} ls

如果cache pool仍有objects,则可以手动flush它们。 例如:

1
rados -p {cachepool} cache-flush-evict-all

3、删除overlay,以便client不会将流量导向缓存。

1
ceph osd tier remove-overlay {storagetier}

例如:

1
ceph osd tier remove-overlay cold-storage

4、最后,从backing storage pool上移除cache tier pool。

1
ceph osd tier remove {storagepool} {cachepool}

例如:

1
ceph osd tier remove cold-storage hot-storage

为了承受OSD丢失,一个Ceph pool与一个类型相关联(大多数情况下每个磁盘有一个OSD)。当创建pool时,默认选择replicate,这意味着每个object都被复制到多个磁盘上。可以使用Erasure Code pool类型替代replicate,以节省空间。

CREATING A SAMPLE ERASURE CODED POOL

最简单的erasure coded pool相当于RAID5,并且至少需要三台主机:

1
2
3
4
5
$ ceph osd pool create ecpool 12 12 erasure
pool 'ecpool' created
$ echo ABCDEFGHI | rados --pool ecpool put NYAN -
$ rados --pool ecpool get NYAN -
ABCDEFGHI

请注意,pool 中的12表示placement groups的数量。

ERASURE CODE PROFILES

默认的erasure code profile会承受丢失1个OSD。它相当于一个大小为2的replicated pool,但需要1.5TB而不是2TB来存储1TB的数据。默认profile显示:

1
2
3
4
5
6
$ ceph osd erasure-code-profile get default
k=2
m=1
plugin=jerasure
crush-failure-domain=host
technique=reed_sol_van

选择正确的profile非常重要,因为在创建pool后无法对其进行修改:需要创建具有不同profile的新pool,并将先前pool中的所有objects都移动到新的pool中。

profile最重要的参数是K,M和crush-failure-domain,因为它们定义了存储开销和数据持久性。例如,期望在系统架构中必须承受两个racks间的损失,并且控制额外增加40%存储开销,则可以定义以下profile:

1
2
3
4
5
6
7
8
$ ceph osd erasure-code-profile set myprofile \
k=3 \
m=2 \
crush-failure-domain=rack
$ ceph osd pool create ecpool 12 12 erasure myprofile
$ echo ABCDEFGHI | rados --pool ecpool put NYAN -
$ rados --pool ecpool get NYAN -
ABCDEFGHI

NYAN object将被分成三部分(K = 3),并创建两个附加chunks(M = 2)。M的值定义了可以同时丢失多少OSD而不损失任何数据。crush-failure-domain = rack将创建一个CRUSH rule,以确保没有两个chunks存储在同一个rack中。

更多信息可以在erasure code profiles documentation中找到。

ERASURE CODING WITH OVERWRITES

默认情况下,erasure coded pools仅适用于像RGW那样,完整object writes和appends的场景。Luminous版本,可以为每个pool设置启用erasure coded pool的partial writes。 这让RBD和CephFS可以将他们的数据存储在erasure coded pool中:

1
ceph osd pool set ec_pool allow_ec_overwrites true

这只能对bluestore OSD上的pool启用,因为bluestore的checksumming用于在deep-scrub过程中检查bitrot或其他corruption。除了不安全之外,使用filestore进行ec overwrites,相对于bluestore性能低。

Erasure coded pools不支持omap(ObjectMap),因此要将它们与RBD和CephFS一起使用,必须明确指示它们将data存储在ec pool中,将metadata存储在replicated pool中。对于RBD,这意味着在创建image时,需要使用–data-pool指定erasure coded pool:

1
rbd create --size 1G --data-pool ec_pool replicated_pool/image_name

对于CephFS,在创建file system时或者通过file layouts设定一个erasure coded pool作为默认的data pool。

ERASURE CODED POOL AND CACHE TIERING

Erasure coded pools需要比replicated pools更多的资源,并且缺少一些功能,如omap。为了克服这些限制,可以在erasure coded pool之前设置一个cache tier

例如,hot-storage pool由fast storage设备组成:

1
2
3
$ ceph osd tier add ecpool hot-storage
$ ceph osd tier cache-mode hot-storage writeback
$ ceph osd tier set-overlay ecpool hot-storage

hot-storage pool作为ecpool的tier,将数据以writeback模式回写至ecpool,所以每次write和read这个ecpool的时候,实际使用的是hot-storage。

更多信息可以在cache tiering documentation中找到。

GLOSSARY

chunk

当encoding function被调用时,它返回相同大小的chunks。Data chunks可以连接起来重建original object和coding chunks,这些chunks可以用来重建丢失的chunk。

K

data chunks的数量,即original object被划分成chunks的数量。例如,如果K = 2,10KB objects分为每个5KB的K个objects。

M

coding chunks的数量,即由encoding functions计算的附加chunks的数量。如果有2个coding chunks,这意味着2个OSD可以在不丢失数据的情况下out。

TABLE OF CONTENT

Erasure code profiles
Jerasure erasure code plugin
ISA erasure code plugin
Locally repairable erasure code plugin
SHEC erasure code plugin

附录

ObjectMap参考链接:

【1】http://bean-li.github.io/ceph-omap

【2】https://my.oschina.net/u/2460844/blog/604530

【3】http://www.wzxue.com/ceph-filestore

ceph中所有块设备、对象存储、文件存储最后都要转化为对象(object),这个object包含3个元素:data、xattr、omap。

  • data是保存对象的数据。
  • xattr是保存对象的扩展属性,每个对象文件都可以设置文件的属性,这个属性是一个key/value值对,但是受到文件系统的限制,key/value对的个数和每个value的大小都进行了限制。
  • 如果要设置的对象的key/value不能存储在文件的扩展属性中,还存在另外一种方式保存omap,omap实际上是保存到了key/vaule 值对的数据库levelDB(L版是RocksDB)中,在这里value的值限制要比xattr中好的多。