OAT 初始化时出错?问题可能出在 PAM 配置上|OceanBase 故障排查实践

本文作者:爱可生数据库工程师,任仲禹,擅长故障分析和性能优化。

背景

某客户在使用 OAT 初始化OceanBase 服务器的过程中,进行到 precheck步骤时,遇到了如下报错信息:

ERROR - check current session hard limit of open_files (ulimit -H -n): 4096 != 655350 ... EXPECT 655350 ... FAIL

错误大意:OAT 需要服务器的 ulimit -H -n 命令返回值是 655350,实际得到的是 4096。

下图所示,虚拟机因磁盘和内存规格不足而触发了检查错误提示(此信息可以忽略)。

排查过程

① 检查当前服务器的 ulimit 值

使用 SSH 登录到目标服务器检查。

结果:【不符合预期】

使用 su 切换到服务器 admin 用户检查。

结果:【符合预期】

这里就有问题,OAT 在 prepare 之前,已经有步骤对服务器的内核参数完成了调整,如下图所示。

这里的 oceanbase_limits.conf 是 OAT 生成的,属于全局配置生效。

理论上不应该出现 SSH 到服务器与 SU 到服务器查出 ulimit 结果不一致的情况。

② 检查 OAT 对于 ulimit 的检查机制

OAT 检查该步骤是运行的程序是 init_server_with_tag.py

复制代码
[2024-09-27T16:34:52.775+0800] INFO - Running: ['airflow', 'tasks', 'run', 'init_server_with_tag', 'precheck', 'manual__2024-09-27T08:34:21.675314+00:00', '--job-id', '39950', '--raw', '--subdir', 'DAGS_FOLDER/init_server_with_tag.py', '--cfg-path', '/tmp/tmp5ni__moh']

登录到 OAT 容器,查看程序最终的调用如下。

复制代码
# 脚本 task_engine/dags/init_server_with_tag.py
    def precheck():
        ctx = get_current_context()
        common.server_precheck(ctx, logger=logger)

# 脚本 task_engine/plugins/common.py
def server_precheck(ctx, logger):
    init_tag = ctx['params']['init_tag']
    role = _get_server_role(init_tag)
    envs = _get_custom_user_env(ctx['params'])
    with ServerRemoteExecute(server_id=ctx['params']['server_id']) as client:
        precheck_sh = SHELL_PATH / 'precheck.sh'
        ret_code, _ = client.execute_script(
            precheck_sh, args=('-m', role), control_master=False, logger=logger,
            env={'LC_ALL': 'en_US.UTF-8', 'OB_IP': client.server['ip'], **envs}
        )
        if ret_code != 0:
            raise RuntimeError('server precheck failed, please see the summary info above for details')
            
# 脚本 task_engine/shells/precheck.sh
check_limit() {
    limit_type_list=(-H/hard -S/soft)
    for limit in "${EXPECT_LIMITS[@]}"
    do
        limit_option=$(echo $limit | awk -F'/' '{print $1}')
        expect_limit=$(echo $limit | awk -F'/' '{print $2}')
        limit_description=$(echo $limit | awk -F'/' '{print $3}')
        limit_item=$(echo $limit | awk -F'/' '{print $4}')
        for limit_type in "${limit_type_list[@]}"
        do
            limit_type_option=$(echo $limit_type | awk -F'/' '{print $1}')
            limit_type_description=$(echo $limit_type | awk -F'/' '{print $2}')
            get_limit_cmd="ulimit $limit_type_option $limit_option"
            # check new session
            current_limit=$(runuser - "$EXPECT_USER" -c "$get_limit_cmd")
            if ! compare_ulimit "$current_limit" "$expect_limit"; then
                echo_fail "check permanent $limit_type_description limit of $limit_description ($get_limit_cmd): $current_limit != $expect_limit ... EXPECT $expect_limit"
                echo_hint "modify /etc/security/limits.d/oceanbase_limits.conf\n  echo \"*   $limit_type_description    $limit_item    $expect_limit\" >> /etc/security/limits.d/oceanbase_limits.conf"
            else
                echo_pass "check $limit_type_description limit of new session $limit_description ($get_limit_cmd): $current_limit"
            fi
            # check current session
            current_limit=$($get_limit_cmd)
            if ! compare_ulimit "$current_limit" "$expect_limit"; then
                echo_fail "check current session $limit_type_description limit of $limit_description ($get_limit_cmd): $current_limit != $expect_limit ... EXPECT $expect_limit"
                echo_hint "excute: ulimit $limit_type_option $limit_option $expect_limit"
            else
                echo_pass "check $limit_type_description limit of $limit_description ($get_limit_cmd): $current_limit"
            fi

        done
    done
}

这里 OAT 获取 ulimit 结果不符合预期的原因已清楚:

通过检查脚本,OAT 是通过 ServerRemoteExecute 模块(使用 SSH 方式)去目标服务器上执行 prepare.sh 脚本做 *ulimit 检查(与预期的 ulimit 值进行对比)。

但是,通过 SSH 连到服务器上执行 ulimit 命令的执行结果不符合预期,甩出报错。

③ 疑问:为何 SSH 连接时 ulimit 值不正确?

先使用 strace 命令查看下 su 时的系统调用。

复制代码
strace -o /root/l1 su - admin
SU 的结果

SU 时,将调用 /usr/lib64/security/pam_limits.so 文件,继而获取到如下两个文件的 ulimit 配置:/etc/security/limits.conf/etc/security/limits.d/oceanbase_limits.conf

所以,su - admin 命令执行的结果【符合预期】。

通过系统日志 /var/log/secure 可以看到,SU 操作加载了 pam 插件。

复制代码
Oct 14 17:44:44 10-186-58-85 su: pam_unix(su-l:session): session opened for user admin by root(uid=0)

从结果反推下,为什么 SSH 不去读取 /usr/lib64/security/pam_limits.so 文件?

根据关键字,猜测跟 SSH 的 PAM 插件有关,继续检查 ssh_config 配置文件如下。

UsePAM no
  • 目标服务器的 PAM 确实是关闭的。

  • 通过系统日志 /var/log/secure 可以看到,SSH 操作没有加载 pam 插件。

    Oct 14 17:50:40 10-186-58-85 sshd[25117]: Accepted publickey for root from 10.186.58.85 port 19118 ssh2: RSA SHA256:+TtbeuvInWm90vrJG7cHHm2G2a2FULFE0Uq+imx2m30

引申:PAM 的作用?

这里 ChatGPT 了一下,解释非常清楚如下图,总结一句就是:

关闭 PAM,用户 SSH 到服务器时,将不会读取 *limits.conf 的配置,继而导致获取到默认配置而使 OAT 报错。

解决方法

将配置文件 /etc/ssh/sshd_config 中的 UsePAM 修改为 yes ,重启 SSHD 服务即可。

启用 PAM 插件后,再次 SSH 可以看到系统日志如下多了加载 pam_unix(sshd:session) 的操作。

复制代码
Oct 14 17:51:56 10-186-58-85 sshd[26147]: Accepted publickey for root from 10.186.58.85 port 19480 ssh2: RSA SHA256:+TtbeuvInWm90vrJG7cHHm2G2a2FULFE0Uq+imx2m30
Oct 14 17:51:56 10-186-58-85 sshd[26147]: pam_unix(sshd:session): session opened for user root by (uid=0)

原因分析总结

  • OAT 在初始化服务器预检查过程中报告了 ulimit 值不符合预期的错误,这一问题的根源在于目标服务器的 sshd_config 配置不当。
  • sshd_config 中 禁用了 PAM 插件,导致 OAT 无法读取到目标服务器上经过优化的 ULIMIT 配置文件。
相关推荐
Edingbrugh.南空2 天前
Flink OceanBase CDC 环境配置与验证
大数据·flink·oceanbase
丶意冷2 天前
mybatisPlus分页方言设置错误问题 mybatisPlus对于Oceanbase的Oracle租户分页识别错误
java·数据库·oracle·oceanbase
漫步者TZ14 天前
【StarRocks系列】建表优化
starrocks·分布式数据库
.Eyes14 天前
OBCP第二章 OceanBase 存储引擎高级技术学习笔记
笔记·学习·oceanbase
漫步者TZ15 天前
【StarRocks系列】StarRocks vs Mysql
数据库·starrocks·mysql·分布式数据库
Tapdata 钛铂数据17 天前
信创 CDC 实战|国产数据库的数据高速通道:OceanBase 实时入仓 StarRocks
数据库·oceanbase
Dnui_King23 天前
OceanBase (DBA)一面面经
数据库·oceanbase·dba
OceanBase数据库官方博客24 天前
OceanBase v4.3.5 特性解读:通过OSS WORM特性进行备份归档
oceanbase·分布式数据库·存储
OceanBase数据库官方博客24 天前
常用的OceanBase调优配置参数
oceanbase·分布式数据库·参数