Skip to main content

容错

MCCL 提供了一组功能,允许应用程序从网络故障、节点故障或进程故障等致命错误中恢复。当发生此类错误时,应用程序应该能够调用 mcclCommAbort 在通信器上释放所有资源,然后创建新的通信器以继续。

为了安全地中止 MCCL 通信器,MCCL 要求应用程序将通信器设置为非阻塞,并确保在调用 mcclCommAbort 时没有线程调用任何 MCCL 操作。设置非阻塞后,所有 MCCL 调用(除了 mcclCommDestroy/mcclCommAbort)都变为非阻塞,以便可以在任何时候调用 mcclCommAbort,在初始化、通信或最终确定通信器期间。如果 MCCL 通信器被设置为阻塞,线程可能因网络错误而卡在 MCCL 调用中;在这种情况下,MCCL 通信器可能会永远挂起。

要正确中止,当通信器中的任何 rank 失败(例如,由于段错误),所有其他 rank 都需要调用 mcclCommAbort 来中止自己的 MCCL 通信器。用户可以实现方法来决定何时以及是否中止通信器并重新启动 MCCL 操作。以下示例显示了如何以非阻塞方式初始化和分割通信器,允许在任何时候中止:

bool globalFlag;
bool abortFlag = false;
mcclConfig_t config = MCCL_CONFIG_INITIALIZER;
/* 将通信器设置为非阻塞 */
config.blocking = 0;
CHECK(mcclCommInitRankConfig(&comm, nRanks, id, myRank, &config));
do {
CHECK(mcclCommGetAsyncError(comm, &state));
} while(state == mcclInProgress && checkTimeout() != true);

if (checkTimeout() == true || state != mcclSuccess) abortFlag = true;

/* 在所有健康 rank 之间同步 abortFlag。 */
reportErrorGlobally(abortFlag, &globalFlag);

if (globalFlag) {
/* 时间超时或初始化失败:每个 rank 都需要中止并重新启动。 */
mcclCommAbort(comm);
/* 重新启动 MCCL;这是一个用户实现的函数,它可能包括资源清理和 mcclCommInitRankConfig() 来创建新的通信器。 */
restartMCCL(&comm);
}

/* 非阻塞通信器分割。 */
CHECK(mcclCommSplit(comm, color, key, &childComm, &config));
do {
CHECK(mcclCommGetAsyncError(comm, &state));
} while(state == mcclInProgress && checkTimeout() != true);

if (checkTimeout() == true || state != mcclSuccess) abortFlag = true;

/* 在所有健康 rank 之间同步 abortFlag。 */
reportErrorGlobally(abortFlag, &globalFlag);

if (globalFlag) {
mcclCommAbort(comm);
/* 如果 `childComm` 不是 MCCL_COMM_NULL,用户应该在这里中止子通信器以回收资源。 */
if (childComm != MCCL_COMM_NULL) mcclCommAbort(childComm);
restartMCCL(&comm);
}
/* 应用程序工作负载 */

相关链接:

checkTimeout 函数需要由用户提供,以确定应用程序应该等待 MCCL 初始化的最长时间;同样,用户可以应用其他方法来检测错误,而不仅仅是超时函数。类似的方法也可以应用于 MCCL 最终确定(使用 mcclCommFinalize)。