Ceph动态更新参数机制浅析

说明:本篇中所有代码分析,都是基于Jewel 10.2.9版本。本篇都是个人理解,其中有些理解或者解释有不合理的,还请指正。

 

在Ceph的使用中,运行时调整参数值是个高频的操作,使用起来简单方便,最重要的是不用重启服务即可生效。

如何使用

Ceph动态调整参数有两种方式:

第一种:

1. ceph daemon <mon/osd/mds>.<id> config set <参数名> <参数值>

 

比如,设置OSD 1的heartbeat超时时间:

ceph daemon osd.1 config set osd_heartbeat_grace 60

第二种:

2. ceph tell <mon/osd/mds>.<id> injectargs '--<参数名> <参数值>'

 

设置OSD 1的heartbeat超时时间:

ceph tell osd.1 injectargs '--osd_heartbeat_grace 60'

第二种还有两个比较好用的地方:

  1. 单条命令可以改变所有的实例的某个参数值:

    ceph tell <mon/osd/mds>.* injectargs '--<参数名> <参数值>'

     

    设置所有OSD的heartbeat超时时间:

    ceph tell osd.* injectargs '--osd_heartbeat_grace 60'

  2. 单条命令可以改变多个参数:

    ceph tell <mon/osd/mds>.1 injectargs '--<参数名> <参数值> --<参数名> <参数值>'

     

    设置OSD 1的heartbeat超时时间,及发起heartbeat的时间间隔

    ceph tell osd.1 injectargs '--osd_heartbeat_grace 60 --osd_heartbeat_interval 10'

  3. 当然,上面两个可以结合使用:

    ceph tell <mon/osd/mds>.* injectargs '--<参数名> <参数值> --<参数名> <参数值>'

     

    设置所有OSD的heartbeat超时时间,及发起heartbeat的时间间隔

    ceph tell osd.* injectargs '--osd_heartbeat_grace 60 --osd_heartbeat_interval 10'

源码分析

那么Ceph内部是如何实现上面提到的动态更新呢?我们来深入代码中一探究竟。

tell方式的实现

我们先看tell...injectargs方式的实现:

ceph命令行的输入,源码入口都是ceph.in文件,是python文件,也就是/usr/bin/下的可执行文件ceph。

ceph.in中有关tell的代码:

def main():

    ...

    // 如果命令行中有'injectargs'字串,就进行切分成两个:'injectargs'之前的部分是childargs,之后的部分是injectargs。

   if 'injectargs' in childargs:

        position = childargs.index('injectargs')

        injectargs = childargs[position:]

        childargs = childargs[:position]

        if verbose:

            print('Separate childargs {0} from injectargs {1}'.format(childargs, injectargs),

                file=sys.stderr)

    else:

        injectargs = None

    ...

 

    if injectargs and '--' in injectargs

        injectargs.remove('--')

    ...

    

    // 如果childargs有'tell'命令,或者前面已经确定有injectargs,就将childargs重新赋值,也就是说childargs是真正要去发送给server端的命令。

    // 在这里,和tell就没关系了,tell关键字并不会发到后端。

    is_tell = False

    if len(childargs) and childargs[0] == 'tell':

        childargs = childargs[2:]

        is_tell = True

 

    if is_tell:

        if injectargs:

            childargs = injectargs

        if not len(childargs):

            print('"{0} tell" requires additional arguments.'.format(sys.argv[0]),

                'Try "{0} tell <name> <command> [options...]" instead.'.format(sys.argv[0]),

                file=sys.stderr)

            return errno.EINVAL

    ...

 

    // 每个命令执行,都有目标端,如果命令行指明了目标server,就向具体的server发;如果是'*',会先把所有的instance id拿到,然后在后面的for循环中,逐个去发送命令。

    if target[1] == '*':                               

        if target[0] == 'osd':                         

            targets = [(target[0], o) for o in osdids()]

        elif target[0] == 'mon':                       

            targets = [(target[0], m) for m in monids()]

    ...

 

    for target in targets:

        ...

从上面的代码,可知,tell命令,并没有走daemon的admin socket来进行通信,而是走正常的client->server的通信,而且,'*'也没有那么高效,就是拿到所有的id,然后逐个发送消息。

然后再经过librados、osdc等模块,将消息发送给具体的Monitor、OSD、MDS。

我们接下来直接看OSD端收到injectargs命令后,如何处理。

在OSD.cc中,do_command函数就是专门处理各种命令的,我们直接看injectargs分支:

void OSD::do_command(Connection *con, ceph_tid_t tid, vector<string>& cmd, bufferlist& data)

{

  ...

 else if (prefix == "injectargs") {

    vector<string> argsvec;

    cmd_getval(cct, cmdmap, "injected_args", argsvec);

 

    if (argsvec.empty()) {

      r = -EINVAL;

      ss << "ignoring empty injectargs";

      goto out;

    }

    string args = argsvec.front();

    // 获取所有的要进行更新的参数

    for (vector<string>::iterator a = ++argsvec.begin(); a != argsvec.end(); ++a)

      args += " " + *a;

    osd_lock.Unlock();

    cct->_conf->injectargs(args, &ss);

    osd_lock.Lock();

  }

  ...

}

拿到client想要更新的所有参数,然后调用了injectargs,每个OSD都有一个CephContext类变量cct,md_config_t类型的_conf变量也是CephContext类的成员。

int md_config_t::injectargs(co

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值