librados是ceph各组件对外暴露的模块,藉由librados接口,可以高效的使用ceph内的组件进行CRUD等操作。

1
2
3
4
5
import rados
cluster = rados.Rados(conffile = 'ceph.conf', conf = dict (keyring = '/path/to/keyring'))
cluster.connect()
cmd = json.dumps({"prefix": "osd safe-to-destroy", "ids": ["2"], "format": "json"})
c.mon_command(cmd, b'')

这里的conf=keyring主要用于当打开了cephx等认证措施时,ceph.conf中又没有记录认证所用到的keyring文件路径时,进行额外设置使用。

最近我在参照python的librados使用,调用C的接口时,就一直遇到cephx认证打开之后,无法成功rados_connect的情况,具体原理还得细看,但应该和cephx及这个keyring存在强相关性是可以确认的了。

连接成功之后,主要使用下属这几个接口来查询pool,osd,pg等一些信息。

1
2
3
4
Rados.mon_command(self, cmd, inbuf, timeout=0, target=None)
Rados.osd_command(self, osdid, cmd, inbuf, timeout=0)
Rados.mgr_command(self, cmd, inbuf, timeout=0, target=None)
Rados.pg_command(self, pgid, cmd, inbuf, timeout=0)

就目前而言,我在抓取IO等指标时,用的比较多的接口是mon_commandmgr_command,使用这几个接口能进行的操作,都有提供cli和rest接口。我主要是在使用cli熟悉接口之后,会去代码中的MonCommands.hMgrCommands.h文件中去找相近的prefix,然后参照着使用。

但是偶尔也是会遇到像ceph osd pool statsceph pg ls-by-pools这类没怎么能找到相关prefix的情况。这个时候可以充分利用起ceph这个cli入口其实是个python文本的功能了。

python -m pgd /bin/ceph osd pool stats执行,在new_style_command函数内的json_command处打断点,进入后,打印cmddict就可以看到cli发送出去的prefix拼接出来是什么样子的了,然后再拿着这个去代码里搜就好了。

开发者模式[^2]

make vstart

async模式

  • mon_command_async
    • 好像RadosClient.cc里有这个异步下发任务, 但是似乎并没有对外提供成librados的接口.
    • 之后有空应该是可以利用这个封装出来使用的应该.

radosstripper理解

rados连接过程

  • 似乎有加载client name.

  • parse_config_files似乎还有指定不读取任何配置文件的时候, 即便是默认配置文件

    • global_pre_init里调用的似乎就是这个.
  • "cdef class Rados(object):"->"name = 'client.admin'"

    • 默认name client.admin
  • context 是什么?

  • rados_create2

    • rados_create_cct()
  • librados::RadosClient::connect理解

    • monclient.init()

源码

  • RadosClient
  • IoctxImpl
  • AioCompletionImpl
  • osdc

超时参数

  • client_mount_timeout
    • client
  • rados_osd_op_timeout
    • 连接上osd后, osd断开的时间
  • rados_mon_op_timeout
    • 连接上mon后,mon响应的超时时间

pacafic版本, 实际超时退出时间为client_mount_timeout的10倍

3c2b30e这次提交, get_monmap_and_config中重构成10次retry, 而这个函数之前就是在oneshot monmap fdde016中引入的monclient过程中get_monmap_and_config以及设置10倍的interval, 之前12版本不存在该项, 所以不会10倍超时.

这个提交13版本就开始有了.

这条commit关联的pr中有144条commit, 该条commit也说了只是解决了问题, 所以设计初衷并不算很清晰

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

int MonClient::get_monmap_and_config()
{
ldout(cct, 10) << __func__ << dendl;
ceph_assert(!messenger);

int tries = 10;

cct->init_crypto();
auto shutdown_crypto = make_scope_guard([this] {
cct->shutdown_crypto();
});

int r = build_initial_monmap();
if (r < 0) {
lderr(cct) << __func__ << " cannot identify monitors to contact" << dendl;
return r;
}

messenger = Messenger::create_client_messenger(
cct, "temp_mon_client");
ceph_assert(messenger);
messenger->add_dispatcher_head(this);
messenger->start();
auto shutdown_msgr = make_scope_guard([this] {
messenger->shutdown();
messenger->wait();
delete messenger;
messenger = nullptr;
if (!monmap.fsid.is_zero()) {
cct->_conf.set_val("fsid", stringify(monmap.fsid));
}
});

want_bootstrap_config = true;
auto shutdown_config = make_scope_guard([this] {
std::unique_lock l(monc_lock);
want_bootstrap_config = false;
bootstrap_config.reset();
});

ceph::ref_t<MConfig> config;
while (tries-- > 0) {
r = init();
if (r < 0) {
return r;
}
r = authenticate(cct->_conf->client_mount_timeout);
if (r == -ETIMEDOUT) {
shutdown();
continue;
}
if (r < 0) {
break;
}
{
std::unique_lock l(monc_lock);
if (monmap.get_epoch() &&
!monmap.persistent_features.contains_all(
ceph::features::mon::FEATURE_MIMIC)) {
ldout(cct,10) << __func__ << " pre-mimic monitor, no config to fetch"
<< dendl;
r = 0;
break;
}
while ((!bootstrap_config || monmap.get_epoch() == 0) && r == 0) {
ldout(cct,20) << __func__ << " waiting for monmap|config" << dendl;
auto status = map_cond.wait_for(l, ceph::make_timespan(
cct->_conf->mon_client_hunt_interval));
if (status == std::cv_status::timeout) {
r = -ETIMEDOUT;
}
}

if (bootstrap_config) {
ldout(cct,10) << __func__ << " success" << dendl;
config = std::move(bootstrap_config);
r = 0;
break;
}
}
lderr(cct) << __func__ << " failed to get config" << dendl;
shutdown();
continue;
}

rados lock

samba/ctdb_mutex_ceph_rados_helper.c at master · samba-team/samba

Reference

  1. Librados (Python) — Ceph Documentation
  2. 深入理解ceph crush(2)—-手动编译ceph集群并使用librados读写文件 · Dovefi never stop
  3. Ceph学习——Librados与Osdc实现源码解析_SEU_PAN的博客-CSDN博客