#透明应用程序故障转移

TAF是一项客户端功能,能最大程度地减少数据库连接因实例或网络故障而失败时对最终用户应用程序的中断。

# TAF配置

# 配置参数

参数名以及参数值均不区分大小写,各参数信息如下表所示。

参数名称 参数描述
FAILOVER 是否开启TAF,参数值为ON或OFF,默认为OFF。
* ON:表示开启TAF,当发生故障时应用程序会自动连接到已配置的其他数据库节点。
* OFF:表示关闭TAF。
FAILOVER_TYPE 故障转移的类型,支持NONE、SESSION和SELECT,默认为NONE。
* NONE:表示不使用故障转移。
* SESSION:表示当用户的连接丢失时自动为其创建一个新会话。
* SELECT:表示在SESSION类型的基础上,重连后重新执行因故障而执行出错的SELECT语句(此时,SELECT语句不能为带LOB类型的绑定参数的查询语句),但不支持再对切换前已获取的对象进行二次操作。
FAILOVER_METHOD 故障转移的方式,该值将决定从主节点到备节点的故障转移速度。
* BASIC:表示在故障转移时再建立连接。
FAILOVER_RETRIES 该参数指定故障转移后尝试连接的次数。
若配置了FAILOVER_DELAY参数,则FAILOVER_RETRIES默认为5。
TAF注册回调函数后,该参数将会失效。
FAILOVER_DELAY 该参数指定在连接尝试之间等待的时间(单位:秒)。
若配置了FAILOVER_RETRIES参数,则FAILOVER_DELAY默认为1。
TAF注册回调函数后,该参数将会失效。

Note:

当TAF注册回调函数后,FAILOVER_RETRIES和FAILOVER_DELAY参数将会失效。

# 配置方式

# 方式一

  1. 进入$YASDB_HOME/client路径,在yasc_service.ini文件中新增配置,配置示例如下:
    REMOTE = 192.168.1.2:1688, 192.168.1.3:1688, 192.168.1.4:1688 ? FAILOVER = ON & FAILOVER_TYPE = SESSION & FAILOVER_METHOD = BASIC & FAILOVER_RETRIES = 10 & FAILOVER_DELAY = 2
    
  2. 使用REMOTE数据源连接:
    const YacChar* gSrvStr = "REMOTE";
    YAC_CALL(yacConnect(conn, gSrvStr, YAC_NULL_TERM_STR, user, YAC_NULL_TERM_STR, pwd, YAC_NULL_TERM_STR));
    

# 方式二

直接在连接URL中配置:

const YacChar* gSrvStr = "192.168.1.2:1688, 192.168.1.3:1688, 192.168.1.4:1688 ? FAILOVER = ON & FAILOVER_TYPE = SESSION & FAILOVER_METHOD = BASIC & FAILOVER_RETRIES = 10 & FAILOVER_DELAY = 2";
YAC_CALL(yacConnect(conn, gSrvStr, YAC_NULL_TERM_STR, user, YAC_NULL_TERM_STR, pwd, YAC_NULL_TERM_STR));

# TAF接口与结构

# 数据类型说明

数据类型 合法值 说明
YacTafResult YAC_TAF_SUCCESS:TAF回调函数返回执行成功
YAC_TAF_RETRY:TAF回调函数返回重试,仅当YacTafEvent为YAC_TAF_EVENT_ERROR时,回调函数返回的该值才有意义
YAC_TAF_ERROR:TAF回调函数返回执行失败,返回该值仅表示状态不影响TAF正常流程
TAF回调函数返回值
YacTafType YAC_TAF_TYPE_NONE:不使用透明故障转移
YAC_TAF_TYPE_SESSION:SESSION类型的故障转移
YAC_TAF_TYPE_SELECT:SELECT类型的故障转移
TAF类型
YacTafEvent YAC_TAF_EVENT_BEGIN:透明故障转移开始
YAC_TAF_EVENT_END:透明故障转移结束,成功恢复连接
YAC_TAF_EVENT_ABORT:透明故障转移失败,当前连接断开
YAC_TAF_EVENT_ERROR:透明故障转移失败,可以选择是否重试,即可选返回YAC_TAF_RETRY
TAF的时间节点
YacTafResult - TAF回调函数定义
YacTafCallbackStruct - TAF回调函数注册用上下文

# 数据类型结构

/* YACLI TAF CallBackSet */
typedef enum EnYacTafResult {
    YAC_TAF_SUCCESS = 0,
    YAC_TAF_RETRY = 25410,
    YAC_TAF_ERROR = -1,
} YacTafResult;

typedef enum EnYacTafType {
    YAC_TAF_TYPE_NONE = 0,
    YAC_TAF_TYPE_SESSION = 1,
    YAC_TAF_TYPE_SELECT = 2,
} YacTafType;

typedef enum EnYacTafEvent {
    YAC_TAF_EVENT_BEGIN = 0,
    YAC_TAF_EVENT_END = 1,
    YAC_TAF_EVENT_ABORT = 2,
    YAC_TAF_EVENT_ERROR = 3,
} YacTafEvent;

typedef YacTafResult (*YacTafCallback)(YacHandle hConn, YacHandle hEnv, YacPointer tafCtx, YacTafType tafType, YacTafEvent tafEvent);

typedef struct {
    YacTafCallback tafCallbackFunc;
    YacPointer     tafCtx;
} YacTafCallbackStruct;

# TAF使用示例

# 普通TAF示例

YacResult testConnect()
{
    const YacChar* gSrvStr = "192.168.1.2:1688?FAILOVER = ON & FAILOVER_TYPE = SESSION & FAILOVER_RETRIES = 10 & FAILOVER_DELAY = 1";
    const YacChar* user = "sys";
    const YacChar* pwd = "password";
 
    YacHandle env;
    YacHandle conn;
    YAC_CALL(yacAllocHandle(YAC_HANDLE_ENV, NULL, &env));
    YAC_CALL(yacAllocHandle(YAC_HANDLE_DBC, env, &conn));
    YAC_CALL(yacConnect(conn, gSrvStr, YAC_NULL_TERM_STR, user, YAC_NULL_TERM_STR, pwd, YAC_NULL_TERM_STR));
    printf("connected!");
 
    YacHandle stmt;
    YAC_CALL(yacAllocHandle(YAC_HANDLE_STMT, conn, &stmt));
    // 如果此处发生网络中断,那么下一次的conn请求会触发TAF重连,接下来的请求会成功
    YAC_CALL(yacDirectExecute(stmt, "select 1 from dual", YAC_NULL_TERM_STR));
    YAC_CALL(yacDirectExecute(stmt, "select 1 from dual", YAC_NULL_TERM_STR));
 
    YAC_CALL(yacFreeHandle(YAC_HANDLE_STMT, stmt));
    yacDisconnect(conn);
    YAC_CALL(yacFreeHandle(YAC_HANDLE_DBC, conn));
    YAC_CALL(yacFreeHandle(YAC_HANDLE_ENV, env));
 
    return YAC_SUCCESS;
}

# TAF回调函数使用示例

YacTafResult tafCb(YacHandle hConn, YacHandle hEnv, YacPointer tafCtx, YacTafType tafType, YacTafEvent tafEvent) 
{
    // 该回调函数控制TAF重连次数不超过2次,包括:
    // TAF首次尝试重连+发生YAC_TAF_EVENT_ERROR后返回YAC_TAF_RETRY指定重试
    YacUint32* intRetry = tafCtx;
    if (tafEvent == YAC_TAF_EVENT_BEGIN) {
        *intRetry = 0;
    }

    printf("TAF callback: %d, %d\n", tafType, tafEvent);
    if (tafEvent == YAC_TAF_EVENT_ERROR && *intRetry < 1) {
        (*intRetry)++;
        return YAC_TAF_RETRY;
    }
    return YAC_TAF_SUCCESS;
}

YacResult testConnect1WithCallBack()
{
    const YacChar* gSrvStr = "192.168.1.2:1688?failover = on & FAILOVER_TYPE = SESSION";
    const YacChar* user = "sys";
    const YacChar* pwd = "password";

    YacHandle env;
    YacHandle conn;
    YAC_CALL(yacAllocHandle(YAC_HANDLE_ENV, NULL, &env));
    YAC_CALL(yacAllocHandle(YAC_HANDLE_DBC, env, &conn));

    YacChar* buf = malloc(sizeof(YacUint32));
    if (buf == NULL) {
        return YAC_ERROR;
    }
    YacUint32* intRetry = (YacUint32*)buf;
    YacTafCallbackStruct cbStruct = { .tafCtx = intRetry,.tafCallbackFunc = tafCb };

    YAC_CALL(yacSetConnAttr(conn, YAC_ATTR_TAF_CALLBACK, (YacVoid*)&cbStruct, sizeof(YacTafCallbackStruct)));
    YAC_CALL(yacConnect(conn, gSrvStr, YAC_NULL_TERM_STR, user, YAC_NULL_TERM_STR, pwd, YAC_NULL_TERM_STR));
    printf("connected!");

    YacHandle stmt;
    YAC_CALL(yacAllocHandle(YAC_HANDLE_STMT, conn, &stmt));
    // 如果此处发生网络中断,那么下一次的conn请求会触发TAF重连,接下来的请求会成功
    YAC_CALL(yacDirectExecute(stmt, "select 1 from dual", YAC_NULL_TERM_STR));
    YAC_CALL(yacDirectExecute(stmt, "select 1 from dual", YAC_NULL_TERM_STR));
    
    YAC_CALL(yacFreeHandle(YAC_HANDLE_STMT, stmt));
    yacDisconnect(conn);
    YAC_CALL(yacFreeHandle(YAC_HANDLE_DBC, conn));
    YAC_CALL(yacFreeHandle(YAC_HANDLE_ENV, env));
    free(buf);

    return YAC_SUCCESS;
}