ceph参数配置--正式使用

ceph参数配置

ceph中的可配置参数(日志级别,缓存设置等等)都定义在legacy_config_opts.h中,可以通过ceph daemon命令来查看或者修改这些参数配置。参数配置方式有两种:永久和临时。永久方式,就是在配置文件(如ceph.conf)中添加该参数的配置,重启进程后,参数就生效了。临时方式,就是通过ceph daemon命令设置内存中的参数。

# xxx为 admin_socket = $rundir/$cluster-$id.asok (/run/ceph/ceph-osd.0.asok)
ceph daemon xxx config show 

例如:"log_file"参数可以配置日志文件的路径

Option("log_file", Option::TYPE_STR, Option::LEVEL_BASIC)
    .set_default("")
    .set_daemon_default("/var/log/ceph/$cluster-$name.log")
    .set_description("path to log file")
    .add_see_also({"log_to_stderr", "err_to_stderr", "log_to_syslog", "err_to_syslog"}),
/*
所有选项的头文件包含在src/common/options/legacy_config_opts.h中
xx.cc xx.h文件由对应的xx.yaml配置文件使用src/common/options/y2c.py脚本自动生成
*/
#include "global_legacy_options.h"
#include "cephfs-mirror_legacy_options.h"
#include "mds_legacy_options.h"
#include "mds-client_legacy_options.h"
#include "mgr_legacy_options.h"
#include "mon_legacy_options.h"
#include "osd_legacy_options.h"
#include "rbd_legacy_options.h"
#include "rbd-mirror_legacy_options.h"
#include "immutable-object-cache_legacy_options.h"
#include "rgw_legacy_options.h"
.h文件.cc文件.yaml
global_legacy_options.hglobal_options.ccglobal.yaml
cephfs-mirror_legacy_options.hcephfs-mirror_options.cccephfs-mirror.yaml
mds_legacy_options.hmds_options.ccmds.yaml
mds-client_legacy_options.hmds-client_options.ccmds-client.yaml
mgr_legacy_options.hmgr_options.ccmgr.yaml
mon_legacy_options.hmon_options.ccmon.yaml
osd_legacy_options.hosd_options.ccosd.yaml
rbd_legacy_options.hrbd_options.ccrbd.yaml
rbd-mirror_legacy_options.h.hrbd-mirror_options.ccrbd-mirror.yaml
immutable-object-cache_legacy_options.himmutable-object-cache_options.ccimmutable-object-cache.yaml
rgw_legacy_options.hrgw_options.ccrgw.yaml

参数是以Option结构体存在(src/common/options.h),Option结构体的定义如下

struct Option {
  enum type_t {                  // 参数值的类型         
    TYPE_UINT = 0,
    TYPE_INT = 1,
    TYPE_STR = 2,
    TYPE_FLOAT = 3,
    TYPE_BOOL = 4,
    TYPE_ADDR = 5,
    TYPE_ADDRVEC = 6,
    TYPE_UUID = 7,
    TYPE_SIZE = 8,
    TYPE_SECS = 9,
    TYPE_MILLISECS = 10,
  };
  enum level_t {
    LEVEL_BASIC = 0,
    LEVEL_ADVANCED = 1,
    LEVEL_DEV = 2,
    LEVEL_UNKNOWN = 3,
  };
  using value_t = std::variant<
    std::monostate,
    std::string,
    uint64_t,
    int64_t,
    double,
    bool,
    entity_addr_t,
    entity_addrvec_t,
    std::chrono::seconds,
    std::chrono::milliseconds,
    size_t,
    uuid_d>;
  const std::string name;                   // 参数名
  const type_t type;                        // 参数类型
  const level_t level;                      // 参数级别
  std::string desc;                         // 该参数的含义
  std::string long_desc;
  value_t value;                            // 参数值
  value_t daemon_value;                     // 有daemon的参数值
  std::vector<const char*> services;        // services即服务类型,比如"mds"
  std::vector<const char*> see_also;        // 该参数对应的类似的参数
  std::vector<const char*> enum_allowed;
  ...  
}

在src/common/options/build_options.cc中,定义的参数分为几类

std::vector<Option> get_global_options();
std::vector<Option> get_mgr_options();
std::vector<Option> get_mon_options();
std::vector<Option> get_crimson_options();
std::vector<Option> get_osd_options();
std::vector<Option> get_rgw_options();
std::vector<Option> get_rbd_options();
std::vector<Option> get_rbd_mirror_options();
std::vector<Option> get_immutable_object_cache_options();
std::vector<Option> get_mds_options();
std::vector<Option> get_mds_client_options();
std::vector<Option> get_cephfs_mirror_options();
std::vector<Option> get_ceph_exporter_options();

从函数名可以看出来:get_global_options函数中的参数是global类型的,即基本所有的模块都可以使用这些参数。get_rgw_options函数中的参数是给rgw模块使用。get_rbd_options函数和get_rbd_mirror_options函数中的参数是给rbd相关模块使用。get_mds_options函数中的参数是给mds模块使用。get_mds_client_options函数中的参数是给mds client模块使用。

全局变量ceph_options

ceph_options包含了所有的参数,ceph_options = { Option{“log_file”}, Option(“***”)}

const std::vector<Option> ceph_options = build_options();

在build_options中将所有的Option类放入ceph_options这个vector里面。

std::vector<Option> build_options()
{
  std::vector<Option> result = get_global_options();

  auto ingest = [&result](std::vector<Option>&& options, const char* svc) {
    for (auto &o : options) {
      if (std::none_of(o.services.begin(), o.services.end(),
                       [svc](const char* known_svc) {
                         return std::strcmp(known_svc, svc) == 0;
                       })) {
        o.add_service(svc);
      }
      result.push_back(std::move(o));
    }
  };

  ingest(get_crimson_options(), "osd");
  ingest(get_mgr_options(), "mgr");
  ingest(get_mon_options(), "mon");
  ingest(get_osd_options(), "osd");
  ingest(get_rgw_options(), "rgw");
  ingest(get_rbd_options(), "rbd");
  ingest(get_rbd_mirror_options(), "rbd-mirror");
  ingest(get_immutable_object_cache_options(), "immutable-object-cache");
  ingest(get_mds_options(), "mds");
  ingest(get_mds_client_options(), "mds_client");
  ingest(get_cephfs_mirror_options(), "cephfs-mirror");
  ingest(get_ceph_exporter_options(), "ceph-exporter");

  return result;
}

md_config_t 和 ConfigValues

md_config_t结构体表示当前的Ceph配置,ceph_options中的参数都会存在这里。在ConfigValues中有特殊的成员变量定义。

class ConfigValues {
  using values_t = std::map<std::string_view, std::map<int32_t,Option::value_t>>;
  values_t values;
  // for populating md_config_impl::legacy_values in ctor
  friend struct md_config_t;

public:
  EntityName name;
  /// cluster name
  std::string cluster;
  
  //subsys用来存日志项
  ceph::logging::SubsystemMap subsys;
  bool no_mon_config = false;
  // Set of configuration options that have changed since the last
  // apply_changes
  using changed_set_t = std::set<std::string>;
  changed_set_t changed;

// This macro block defines C members of the md_config_t struct
// corresponding to the definitions in legacy_config_opts.h.
// These C members are consumed by code that was written before
// the new options.cc infrastructure: all newer code should
// be consume options via explicit get() rather than C members.
#define OPTION_OPT_INT(name) int64_t name;
#define OPTION_OPT_LONGLONG(name) int64_t name;
#define OPTION_OPT_STR(name) std::string name;
#define OPTION_OPT_DOUBLE(name) double name;
#define OPTION_OPT_FLOAT(name) double name;
#define OPTION_OPT_BOOL(name) bool name;
#define OPTION_OPT_ADDR(name) entity_addr_t name;
#define OPTION_OPT_ADDRVEC(name) entity_addrvec_t name;
#define OPTION_OPT_U32(name) uint64_t name;
#define OPTION_OPT_U64(name) uint64_t name;
#define OPTION_OPT_UUID(name) uuid_d name;
#define OPTION_OPT_SIZE(name) uint64_t name;
#define OPTION(name, ty)       \
  public:                      \
    OPTION_##ty(name)          
#define SAFE_OPTION(name, ty)       \
  protected:                        \
    OPTION_##ty(name)               
#include "common/options/legacy_config_opts.h"
#undef OPTION_OPT_INT
#undef OPTION_OPT_LONGLONG
#undef OPTION_OPT_STR
#undef OPTION_OPT_DOUBLE
#undef OPTION_OPT_FLOAT
#undef OPTION_OPT_BOOL
#undef OPTION_OPT_ADDR
#undef OPTION_OPT_ADDRVEC
#undef OPTION_OPT_U32
#undef OPTION_OPT_U64
#undef OPTION_OPT_UUID
#undef OPTION
#undef SAFE_OPTION
}

最终md_config_t结构体定义如下

struct md_config_t {
public:
  typedef std::variant<int64_t ConfigValues::*,
                       uint64_t ConfigValues::*,
                       std::string ConfigValues::*,
                       double ConfigValues::*,
                       bool ConfigValues::*,
                       entity_addr_t ConfigValues::*,
                       entity_addrvec_t ConfigValues::*,
                       uuid_d ConfigValues::*> member_ptr_t;

  // For use when intercepting configuration updates
  typedef std::function<bool(
      const std::string &k, const std::string &v)> config_callback;

  /// true if we are a daemon (as per CephContext::code_env)
  const bool is_daemon;

  /*
   * Mapping from legacy config option names to class members
   * 将ceph_options中的Option的name与对应的md_config_t中的成员指针作为key-value保存
   */
  std::map<std::string_view, member_ptr_t> legacy_values;

  /**
   * The configuration schema, in the form of Option objects describing
   * possible settings.
   * schema保存ceph_options中的所有Option参数
   */
  std::map<std::string_view, const Option&> schema;  
  ...
}
  // Populate list of legacy_values according to the OPTION() definitions
  // Note that this is just setting up our map of name->member ptr.  The
  // default values etc will get loaded in along with new-style data,
  // as all loads write to both the values map, and the legacy
  // members if present.
  legacy_values = {
#define OPTION(name, type) \
    {STRINGIFY(name), &ConfigValues::name},
#define SAFE_OPTION(name, type) OPTION(name, type)
#include "options/legacy_config_opts.h"
#undef OPTION
#undef SAFE_OPTION
  };

其中schema保存ceph_options中的所有Option参数,即

schema = { <“host”, Options(“host”)>, …, <“log_file”, Option(“log_file”)>, …}

legacy_values将ceph_options中的Option的name与对应的md_config_t中的成员指针作为key-value保存,即

legacy_values = {<“host”, &md_config_t::host>, … , <“log_file”, &md_config_t::log_file>, …}

subsys用来存日志项,即

subsys = ceph::logging::SubsystemMap( m_subsys[ceph_subsys_ == 0] = Subsystem<name = “none”, log_level = 0, gather_level = 5>, … , m_subsys[ceph_subsys_crush == 3] = Subsystem<name = “crush”, log_level = 1, gather_level = 1>, m_subsys[ceph_subsys_mds == 4] = Subsystem<name = “mds”, log_level = 1, gather_level = 5>, … }。

g_ceph_context和g_conf全局变量

一个模块的进程会有多个线程,比如ceph-mds,进程中有些内容需要整个进程中的所有线程都可以访问,比如参数配置和以及上下文内容,所以就有两个全局变量g_conf和g_ceph_context,在src/global/global_context.cc中定义如下

CephContext *g_ceph_context = NULL;
ConfigProxy& g_conf() {
#if defined(WITH_SEASTAR) && !defined(WITH_ALIEN)
  return crimson::common::local_conf();
#else
  return g_ceph_context->_conf;
#endif
}

md_config_t 实例对象作为ConfigProxy的成员,

配置的代理类ConfigProxy,实际是封装了:
a) ConfigValues values;
b) ObserverMgr<md_config_obs_t> obs_mgr;
c) md_config_t config;

1、如果是set类接口:先通过md_config_t获取option,通过option获取name、类型、默认值、校验等信息,解析value,最后设置到ConfigValues中。

2、如果是get类接口:

​ 2.1、流程也是从md_config_t到ConfigValues, 如果从ConfigValues不能获取到,则获取Option的默认值
​ 2.2、md_config_t::expand_meta 解析${var}到实际的值

class CephContext {
...
public:
  ConfigProxy _conf;
  ceph::logging::Log *_log;
...
}

class ConfigProxy {
  /**
   * The current values of all settings described by the schema
   */
  ConfigValues values;
  using md_config_obs_t = ceph::md_config_obs_impl<ConfigProxy>;
  ObserverMgr<md_config_obs_t> obs_mgr;
  
  // 配置对象
  md_config_t config;
    
  /** A lock that protects the md_config_t internals. It is
   * recursive, for simplicity.
   * It is best if this lock comes first in the lock hierarchy. We will
   * hold this lock when calling configuration observers.  */
  mutable ceph::recursive_mutex lock =
    ceph::make_recursive_mutex("ConfigProxy::lock");
}

每个模块启动时,都需要实例化CephContext,就不需要单独去实例化md_config_t。

在md_config_t的构造函数的入参为is_daemon,它是用来判断该模块是单独起一个守护线程,或者由别的线程去调用对外接口,不单独起线程。构造函数如下

CephContext::CephContext(uint32_t module_type_,
                         enum code_environment_t code_env,
                         int init_flags_)
  : nref(1),
    _conf{code_env == CODE_ENVIRONMENT_DAEMON}
{...}

md_config_t::md_config_t(ConfigValues& values,
			 const ConfigTracker& tracker,
			 bool is_daemon){ ... }

即判断code_env == CODE_ENVIRONMENT_DAEMON,在各个模块的main函数中有code_env的入参。即ceph_mds.cc, ceph_fuse.cc和ceph_mon.cc等中的md_config_t中is_daemon都是true,libcephfs的md_config_t中is_daemon是false。

参数配置其它源码分析

global_init分析

直接看代码,从ceph_mon.cc中开始看

auto cct = global_init(&defaults, args,
		     CEPH_ENTITY_TYPE_MON, CODE_ENVIRONMENT_DAEMON,
			 flags);
boost::intrusive_ptr<CephContext>
global_init(const std::map<std::string,std::string> *defaults,
	    std::vector < const char* >& args,
	    uint32_t module_type, code_environment_t code_env,
	    int flags, bool run_pre_init)
{ // module_type = CEPH_ENTITY_TYPE_MON, code_env = CODE_ENVIRONMENT_DAEMON, flags = 0
  // run_pre_init = true  
  // Ensure we're not calling the global init functions multiple times.
  static bool first_run = true;
  if (run_pre_init) {
    // We will run pre_init from here (default).
    ceph_assert(!g_ceph_context && first_run);
    global_pre_init(defaults, args, module_type, code_env, flags);
  } else {
    // Caller should have invoked pre_init manually.
    ceph_assert(g_ceph_context && first_run);
  }
  first_run = false;
  ...
}

global_pre_init是关键函数:

void global_pre_init(
  const std::map<std::string,std::string> *defaults,
  std::vector < const char* >& args,
  uint32_t module_type, code_environment_t code_env,
  int flags)
{ // module_type = CEPH_ENTITY_TYPE_MON, code_env = CODE_ENVIRONMENT_DAEMON, flags = 0
  std::string conf_file_list;
  std::string cluster = "";

  // ensure environment arguments are included in early processing
  // 环境变里CEPH_ARGS中的选项加入到args中
  env_to_vec(args);

  /*
  解析options来获取对应的值, 预解释命令行参数,对于只是显示版本号的命令,只把
  版本号打出来程序就直接可以exit(0)了;对于其他的参数,解释好后放到
  CephInitParameters里供后面使用。
  */
  CephInitParameters iparams = ceph_argparse_early_args(
    args, module_type,
    &cluster, &conf_file_list);

  // 主要是实例化new CephContext(iparams.module_type, flags); 
  CephContext *cct = common_preinit(iparams, code_env, flags);
  // cct->_conf->cluster = "ceph"
  cct->_conf->cluster = cluster;
  global_init_set_globals(cct);
  auto& conf = cct->_conf;

  if (flags & (CINIT_FLAG_NO_DEFAULT_CONFIG_FILE|
	       CINIT_FLAG_NO_MON_CONFIG)) {
    conf->no_mon_config = true;
  }

  // alternate defaults
  if (defaults) {
    for (auto& i : *defaults) {
      conf.set_val_default(i.first, i.second);
    }
  }

  if (conf.get_val<bool>("no_config_file")) {
    flags |= CINIT_FLAG_NO_DEFAULT_CONFIG_FILE;
  }

  //读取配置文件内容,命令里不指明的话,默认使用/etc/ceph/ceph.conf。
  int ret = conf.parse_config_files(c_str_or_null(conf_file_list),
				    &cerr, flags);
  ...
}

env_to_vec分析

split_dashdash把args根据"–“拆分成两段(注意:–不同于–param),前段为类型为vector的options, 后段为类型为vector的arguments。
get_str_vec。把环境变量值取出来:默认的环境变量是"CEPH_ARGS”,可以通过参数来指定名字。以空格“ ” 为间隔,把环境变量拆分为一个个字符串到g_str_vec中。
g_str_vec腾挪到env 的vector<const char*>中,同args一样以“–”进行拆分。
分别聚合env和args的options和arguments到args中, 还是以“–”来间隔,无论是options还是arguments,env的参数都在前。

void env_to_vec(std::vector<const char*>& args, const char *name)
{
  if (!name)
    name = "CEPH_ARGS";
  //把args根据"--"拆分成两段,前段为options,后段为arguments
  auto [options, arguments] = split_dashdash(args);

  /*
   * We can only populate str_vec once. Other threads could hold pointers into
   * it, so clearing it out and replacing it is not currently safe.
   */
  g_str_vec_lock.lock();
  if (g_str_vec.empty()) {
    char *p = getenv(name);
    if (!p) {
      g_str_vec_lock.unlock();
      return;
    }
    //以空格“ ” 为间隔,把环境变量拆分为一个个字符串到g_str_vec中
    get_str_vec(p, " ", g_str_vec);
  }
  g_str_vec_lock.unlock();

  std::vector<const char*> env;
  for (const auto& s : g_str_vec) {
    env.push_back(s.c_str());
  }
  //同args一样以“--”进行拆分
  auto [env_options, env_arguments] = split_dashdash(env);

  //聚合env和args的options和arguments到args中, 还是以“--”来间隔,无论是options还是arguments,env的参数都在前。
  args.clear();
  args.insert(args.end(), env_options.begin(), env_options.end());
  args.insert(args.end(), options.begin(), options.end());
  if (arguments.empty() && env_arguments.empty()) {
    return;
  }
  args.push_back("--");
  args.insert(args.end(), env_arguments.begin(), env_arguments.end());
  args.insert(args.end(), arguments.begin(), arguments.end());
}

调用ceph_argparse_early_args来解析进程启动时设置的参数,比如ceph-mon启动时设置的参数如下

/usr/bin/ceph-osd -f --cluster ceph --id 0 --setuser ceph --setgroup ceph

common_preinit

CephContext *common_preinit(const CephInitParameters &iparams,
			    enum code_environment_t code_env, int flags)
{
  // set code environment
  ANNOTATE_BENIGN_RACE_SIZED(&g_code_env, sizeof(g_code_env), "g_code_env");
  g_code_env = code_env;

  // Create a configuration object
  /*
  CephContext初始化时最重要的就是实例化md_config_t,md_config_t保存了osd的所有
  默认配置信息,主要是使用OPTION_OPT_INT,OPTION_OPT_LONGLONG等一系列的宏加上
  common/config_opts.h灵活实现配置字段的定义。同时CephContext实例化时还初始化
  了adminsocket,log等模块。
  */
  CephContext *cct = new CephContext(iparams.module_type, code_env, flags);

  auto& conf = cct->_conf;
  // add config observers here

  // Set up our entity name.
  conf->name = iparams.name;
  ...
  return cct;
}

最重要的就是parse_config_files

int md_config_t::parse_config_files(ConfigValues& values,
				    const ConfigTracker& tracker,
				    const char *conf_files_str,
				    std::ostream *warnings,
				    int flags)
{
  if (safe_to_start_threads)
    return -ENOSYS;

  if (values.cluster.empty() && !conf_files_str) {
    values.cluster = get_cluster_name(nullptr);
  }
  // open new conf
  for (auto& fn : get_conffile_paths(values, conf_files_str, warnings, flags)) {
    bufferlist bl;
    std::string error;
    // 将ceph.conf(如/etc/ceph/ceph.conf)中的内容读上来保存在bl中
    if (bl.read_file(fn.c_str(), &error)) {
      parse_error = error;
      continue;
    }
    ostringstream oss;
    //解释配置文件
    int ret = parse_buffer(values, tracker, bl.c_str(), bl.length(), &oss);
    if (ret == 0) {
      parse_error.clear();
      conf_path = fn;
      break;
    }
    parse_error = oss.str();
    if (ret != -ENOENT) {
      return ret;
    }
  }
  // it must have been all ENOENTs, that's the only way we got here
  if (conf_path.empty()) {
    return -ENOENT;
  }
  if (values.cluster.empty()) {
    values.cluster = get_cluster_name(conf_path.c_str());
  }
  update_legacy_vals(values);
  return 0;
}

md_config_t::_expand_meta函数用来替换"$"后面的字符串,比如admin_socket = r u n d i r / rundir/ rundir/cluster-$id.asok,调用expand_meta函数后admin_socket = /var/run/ceph/ceph-mon.node1.asok

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值