OB 运维 | OAT 初始化报错?原来是 PAM 配置惹的祸!

科技   科技   2024-10-29 16:30   上海  

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

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文约 1200 字,预计阅读需要 4 分钟。


1背景

某客户通过 OAT 初始化服务器时,走到 precheck 步骤时,报错如下:

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

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

具体如下图,虚拟机磁盘和内存规格过低导致的检查报错(信息可忽略)。

2排查过程

① 检查当前服务器的 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 报错。

3解决方法

将配置文件 /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)

4结论

  • OAT 初始化服务器 precheck 报 ulimit 值不符合预期错误是由于目标服务器 sshd_config 不合理导致。
  • sshd_config 中 禁用了 PAM 插件,使得 OAT 读取不到目标服务器优化后的 ULIMIT 配置文件。

本文关键字:#OceanBase# #OAT# #ulimit# #PAM#



一文讲透 OceanBase 单机版【建议收藏】
如何有效使用 outline 功能?
OceanBase 4.X-2F1A 仲裁高可用方案初探
Oracle 中部分不兼容对象迁移到 OceanBase 的处理方式
一个关于 NOT IN 子查询的 SQL 优化案例
Join 估行不准选错执行计划该如何优化?
一个提升本地索引性能的 SQL 优化案例
一则 Oracle 迁移到 OB 后存储过程语法报错问题诊断案例
优化器走对,执行计划导致查询快 1000 倍
如何通过日志观测冻结转储流程?


✨ Github:https://github.com/actiontech/sqle

📚 文档:https://actiontech.github.io/sqle-docs/

💻 官网:https://opensource.actionsky.com/sqle/

👥 微信群:请添加小助手加入 ActionOpenSource

🔗 商业支持:https://www.actionsky.com/sqle


扫描下方的微信扫描小程序码,进行在线咨询预约:



此外,您也可以直接联系我们的商业支持团队获取更多信息,联系方式如下:

400-820-6580 / 13916131869 / 18930110869

爱可生开源社区
爱可生开源社区,提供稳定的MySQL企业级开源工具及服务,每年1024开源一款优良组件,并持续运营维护。
 最新文章