Slurm如何应对超大作业的NSS压力?

nss_slurm是一个可选的NSS插件,它允许计算节点上的作业通过本地slurmstepd进程进行passwd和group解析,而不是通过其他基于网络的服务,如LDAP、SSSD或NSLCD。

在集群上启用时,对于每个作业,作业的用户将拥有完整的struct passwd信息——用户名、uid、主gid、gecos信息、主目录和shell——作为每个步骤启动的一部分安全发送,并缓存在slurmstepd进程中。然后,该信息将通过getpwuid()/getpwnam()/getpwent()系统调用提供给该步骤启动的任何进程。

对于组信息(来自getgrgid()/getgrnam()/getgrent()系统调用),将提供struct group的一个简短视图。在给定流程中,响应将只包含用户所属的组,但只将用户本身列为成员。不提供组成员的完整列表。

1. NSS Slurm配置

nss_slurm有一个可选的配置文件-/etc/nss_slurm.conf。仅在以下情况下才需要此配置文件:

a.节点的主机名与NodeName不匹配,在这种情况下,您必须显式设置NodeName选项。

b.SlurmdSpoolDir与Slurm的 /var/spool/slurmd的默认位置不匹配 ,在这种情况下也必须提供它。

NodeName和SlurmdSpoolDir是目前唯一支持的配置选项。

2. 初始测试

在节点上直接启用NSS Slurm之前,应在新启动的作业步骤中使用-s slurm选项来验证其余设置是否已成功完成。 getent的-s选项允许它查询特定数据库 - 即使默认情况下尚未通过系统的nsswitch.conf启用它。 请注意,nss_slurm仅响应作业步骤本身内的进程的请求 - 您必须在作业步骤中启动getent命令以查看返回的任何数据。

相关测试命令:

srun getent -s slurm passwd

srun getent -s slurm group

3. NSS配置

启用nss_slurm非常简单,只需将slurm添加到/etc/nsswitch.conf中的passwd和group数据库即可。建议首先列出slurm,因为顺序(从左到右)决定查询NSS数据库的顺序,这确保slurm在将查询提交给其他源之前能够处理请求。

一旦启用,通过启动getent查询来测试它

相关测试命令:

srun getent passwd tim

srun getent group projecta

步骤:

进入源码contribs/nss_slurm/ 目录执行make && make install

建立软链接:ln -s /opt/gridview/slurm/lib/libnss_slurm.so.2 /usr/lib64/libnss_slurm.so.2

在slurm.conf中设置 LaunchParameters=enable_nss_slurm并重新启动slurmctld

启用后,可以在计算节点上使用scontrol getent命令打印与该节点上的作业步骤关联的所有用户的passwd和group信息。

4. 限制

nss_slurm只返回给定作业步骤中进程的结果。 它不会返回这些步骤之外的进程的任何结果,例如系统监视,节点运行状况检查,prolog或epilog脚本以及相关的节点系统进程。

nss_slurm并不意味着完全替代LDAP之类的网络目录服务,而是作为一种从这些系统中删除负载的方法,以提高大规模作业启动的性能。它通过删除“惊群现象”来实现这一点,该现象表现为如果一个大型作业的所有任务同时发出查找请求(通常是为了查询与用户本身相关的信息,这是NSS Slurm能够提供的唯一信息),并压倒底层目录服务。

5. 源码分析

综和源码分析过程得出如下结论:

(1)srun提交作业时会从slurmctld查询用户相关信息存入作业,而slurmctld通过查询密码数据库(本地密码文件 /etc/passwd和/etc/group或NIS或LDAP)中获取用户相关信息。

(2)计算节点slurmd创建作业步运行作业时,执行scontrol getent 和_nss_slurm_getpwnam_r/_nss_slurm_getgrnam_r相关命令会跟作业步进程通信,通过作业步进程从作业中获取用户相关信息。

5.1 nss_slurm插件中获取用户信息

获取passwd信息过程:

_nss_slurm_getpwnam_r/_nss_slurm_getpwuid_r/_nss_slurm_getpwent_r
(contribs\nss_slurm\libnss_slurm.c)
    _internal_getpw
        _pw_internal
            stepd_available//获取作业步链表,并进行遍历
            stepd_connect//打开和作业步的连接
            stepd_getpw//跟作业步通信,获取作业步保存的user信息(slurm-19.05.1-2\src\common\stepd_api.c)
                REQUEST_GETPW//通信消息类型

获取group组信息过程类似:

_nss_slurm_getgrnam_r/_nss_slurm_getgrgid_r/_nss_slurm_getgrent_r
    _internal_getgr
        _gr_internal
            stepd_available
            stepd_connect
            stepd_getgr
                REQUEST_GETGR//通信消息类型

 5.2 scontrol getent node过程

main(slurm-19.05.1-2\src\scontrol\scontrol.c)
    _process_command
        scontrol_getent(src\scontrol\info_job.c)
            stepd_available
                stepd_connect
                stepd_getpw(REQUEST_GETPW)
                stepd_getgr(REQUEST_GETGR)

以上可以看出用户的passwd和group信息都是从作业步获取。 

5.3  作业步守护进程响应请求过程

struct io_operations msg_socket_ops = {
	.readable = &_msg_socket_readable,
	.handle_read = &_msg_socket_accept
};
源码调用过程,作业步处理IO事件使用了REACTOR模型:
main(slurm-19.05.1-2\src\slurmd\slurmstepd\slurmstepd.c)
msg_thr_create(src\slurmd\slurmstepd\req.c)
    _domain_socket_create//创建一个命名的unix域监听套接字
    fd_set_nonblocking//设置非阻塞
    eio_obj_create(fd, &msg_socket_ops, (void *)job);//创建eio对象,msg_socket_ops里面保存着事件处理回调函数
        _msg_socket_accept//IO事件触发后被调用
            _handle_request(slurm-19.05.1-2\src\slurmd\slurmstepd\req.c)
                case REQUEST_GETPW:
                _handle_getpw//接受请求,从stepd_step_rec_t *job中获取用户信息发出
    job->msg_handle = eio_handle_create(0);//创建job->msg_handle
    eio_new_initial_obj(job->msg_handle, eio_obj);//将eio对象添加到job->msg_handle,注册
    _msg_thr_internal//创建内部消息处理线程
        eio_handle_mainloop
            while(1)//轮训处理
            _poll_setup_pollfds//设置fd
            _poll_internal//IO多路复用,同步事件分离器
            _poll_dispatch//事件分发器
                _poll_handle_event
                    (*obj->ops->handle_read) (obj, objList);//调用_msg_socket_accept

 

typedef struct {
    ...
    uid_t         uid;     /* user id for job                           */
    char          *user_name;
    /* fields from the launch cred used to support nss_slurm	    */
    char *pw_gecos;
    char *pw_dir;
    char *pw_shell;
    gid_t         gid;     /* group ID for job                          */
    int           ngids;   /* length of the following gids array        */
    char **gr_names;
	gid_t        *gids;    /* array of gids for user specified in uid   */
    ...
    eio_handle_t  *msg_handle; /* eio handle for the message thread     */
    ...
} stepd_step_rec_t;

 

 以上分析过程可以看出,用户的信息是事先保存在计算节点上运行的作业步之内的,而这个信息是何时何处存入作业的需要进一步分析作业创建流程。

5.4 作业步创建过程

main(slurm-19.05.1-2\src\slurmd\slurmstepd\slurmstepd.c)

_init_from_slurmd(STDIN_FILENO, argv, &cli, &self, &msg)//从slurmd接收作业参数

    safe_read(sock, incoming_buffer, len)//前面接收各种信息,包括作业步类型LAUNCH_TASKS,直到这一步

    unpack_msg//解包,设置msg

job = _step_setup(cli, self, msg)//设置stepd_step_rec_t *job

    mgr_launch_tasks_setup

        stepd_step_rec_create

            job->uid = (uid_t) msg->uid;

            job->gid = (gid_t) msg->gid;

            job->user_name = xstrdup(msg->user_name);

            _slurm_cred_to_step_rec(msg->cred, job);
//该函数内部设置stepd_step_rec_t* job的用户的passwd和group信息,
//包括user_name/pw_gecos/pw_dir/pw_shell/ngids/gids/gr_names,相关信息源于msg->cred,而msg从slurmd获得。

5.5 slurmd处理消息直到创建作业步过程

main(slurm-19.05.1-2\src\slurmd\slurmd\slurmd.c)

_msg_engine

    _handle_connection

        _service_connection

            slurmd_req(msg)(src\slurmd\slurmd\req.c)

                _rpc_launch_tasks(msg)(REQUEST_LAUNCH_TASKS)

                        _forkexec_slurmstepd(LAUNCH_TASKS)

                            _send_slurmstepd_init

                            //1.实际通信,与作业步_init_from_slurmd相对应

                            //2.发送的msg源于slurmd_req(msg)

                                    msg.msg_type = REQUEST_LAUNCH_TASKS

                                    msg.data = req;

                                    pack_msg(&msg, buffer);

                                        _pack_launch_tasks_request_msg(REQUEST_LAUNCH_TASKS)

                                            slurm_cred_pack

                                                _pack_cred

                                                //1.该步骤打包用户的passwd和group信息,包括user_name/pw_gecos/pw_dir/pw_shell/ngids/gids/gr_names。

                                                //2.此外还有很多其他cred信息,例如job_core_bitmap、cores_per_socket、job_hostlist等,跟本问题不相关,不再赘述

                                    safe_write(fd, get_buf_data(buffer), len);

以上可以看出作业步的msg来源于slurmd接收到的msg,消息类型REQUEST_LAUNCH_TASKS。

5.6 分析srun以定位msg里面的cred信息何时打包

main

srun(slurm-19.05.1-2\src\srun\srun.c)

create_srun_job

    allocate_nodes

    _create_job_step(使用gdb调试确认这步获得了作业的cred)

        create_job_step

            launch_g_create_job_step

                (*(ops.create_job_step))()

                    launch_p_create_job_step(src\plugins\launch\slurm\launch_slurm.c)

                        launch_common_create_job_step

                            slurm_step_ctx_create_timeout

                                slurm_job_step_create(该步跟slurmctld通讯获取cred信息,REQUEST_JOB_STEP_CREATE/RESPONSE_JOB_STEP_CREATE)

_launch_app

    _launch_one_app

        launch_g_step_launch

            (*(ops.step_launch))(job, cio_fds, global_rc, step_callbacks, opt_local);

                launch_p_step_launch

                    slurm_step_launch

                        launch.cred = ctx->step_resp->cred;

                        _launch_tasks

                    slurm_step_launch_add

                        launch.cred = ctx->step_resp->cred;

                        _launch_tasks

p *job->step_ctx->step_resp->cred这步的数据结构关系为:

typedef struct srun_job {

            int fir_nodeid;

            uint32_t jobid; /* assigned job id */

            uint32_t stepid; /* assigned step id */

            uint32_t node_offset; /* pack job node offset or NO_VAL */

            ...

            slurm_step_ctx_t *step_ctx;

            ...

} srun_job_t;

 

typedef struct slurm_step_ctx_struct slurm_step_ctx_t;

 

struct slurm_step_ctx_struct {

            uint16_t magic; /* magic number */

            uint32_t job_id; /* assigned job id */

            uint32_t user_id; /* user the job runs as */

            job_step_create_request_msg_t *step_req;

            job_step_create_response_msg_t *step_resp;

            /* Used by slurm_step_launch() */

            struct step_launch_state *launch_state;

            uint16_t verbose_level;

};

 

typedef struct job_step_create_response_msg {

            uint32_t def_cpu_bind_type; /* Default CPU bind type */

            uint32_t job_step_id; /* assigned job step id */

            char *resv_ports; /* reserved ports */

            slurm_step_layout_t *step_layout;

            slurm_cred_t *cred; /* slurm job credential */

            dynamic_plugin_data_t *select_jobinfo; /* select opaque data type */

            dynamic_plugin_data_t *switch_job; /* switch opaque data type */

            uint16_t use_protocol_ver;

} job_step_create_response_msg_t;

 

typedef struct slurm_job_credential slurm_cred_t;

 

struct slurm_job_credential {

            #ifndef NDEBUG

            # define CRED_MAGIC 0x0b0b0b

            int magic;

            #endif

            pthread_mutex_t mutex;

            uint32_t jobid; /* Job ID associated with this cred */

            uint32_t stepid; /* Job step ID for this credential */

            uid_t uid; /* user for which this cred is valid */

            gid_t gid; /* user's primary group id */

            char *pw_name; /* username */

            char *pw_gecos; /* user information */

            char *pw_dir; /* home directory */

            char *pw_shell; /* user program */

            int ngids; /* number of extended group ids sent in

            * credential. if 0, these will need to

            * be fetched locally instead. */

            gid_t *gids; /* extended group ids for user */

            char **gr_names; /* array of group names matching gids */

            uint64_t job_mem_limit;/* MB of memory reserved per node OR

            * real memory per CPU | MEM_PER_CPU,

            * default=0 (no limit) */

            uint64_t step_mem_limit;

            uint16_t core_array_size; /* core/socket array size */

            uint16_t *cores_per_socket;

            uint16_t *sockets_per_node;

            uint32_t *sock_core_rep_count;

            List job_gres_list; /* Generic resources allocated to JOB */

            List step_gres_list; /* Generic resources allocated to STEP */

            char *job_constraints; /* constraints in job allocation */

            bitstr_t *job_core_bitmap;

            uint16_t job_core_spec; /* Count of specialized cores */

            uint32_t job_nhosts; /* count of nodes allocated to JOB */

            char *job_hostlist; /* list of nodes allocated to JOB */

            bitstr_t *step_core_bitmap;

            time_t ctime; /* time of credential creation */

            char *step_hostlist;/* hostnames for which the cred is ok */

            uint16_t x11; /* x11 flags set on job allocation */

            char *signature; /* credential signature */

            uint32_t siglen; /* signature length in bytes */

};

以上可以看出在使用srun提交作业时,会查询管理节点slurmctld获取cred放入作业中。

5.7 slurmctld处理srun发过来的请求,获取cred信息打包发回

main(slurm-19.05.1-2\src\slurmctld\controller.c)

    _slurmctld_rpc_mgr

        _service_connection

            slurmctld_req(src\slurmctld\proc_req.c)

                case REQUEST_JOB_STEP_CREATE:

                _slurm_rpc_job_step_create

                    step_create

                    _make_step_cred

                        slurm_cred_create

                            _slurm_cred_init//初始化enable_nss_slurm插件功能

                            slurm_getpwuid_r

                                    getpwuid_r

                            gid_to_string

                                    getgrgid_r

                    resp.msg_type = RESPONSE_JOB_STEP_CREATE

                    slurm_send_node_msg(msg->conn_fd, &resp);

以上可以看出用户相关信息由slurmctld通过getpwuid_r、getgrgid_r从密码数据库(本地密码文件 /etc/passwd和/etc/group或NIS或LDAP)中获得。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值