Active Standby Pair是TimesTen复制的一种固定模式,就是1个active到1个standby,再到0个或127个subscriber,如下图:
大致步骤如下:
1. 创建数据库
2. 使用CREATE ACTIVE STANDBY PAIR创建复制
3. 调用Call ttRepStateSet('ACTIVE')
,将active数据库的角色设为ACTIVE
4. 调用Call ttRepStart
, 启动复制代理
5. 在active数据库中创建用户(用户名建议为repadmin),并赋予ADMIN权限
6. 克隆active数据库到standby数据库
7. 在standby数据库启动复制代理
8. 等待standby的角色自动变为STANDBY. (call ttrepstateget
)
9. 克隆standby到subscriber数据库,如果有的话
10. 在subscriber数据库上启动复制代理
实验过程如下:
首先设置一个active,standby和subscriber,过程可参见TimesTen 数据库复制学习:2. 配置Active Standby Pair ,确保三个库的状态分别为ACTIVE, STANDBY和IDLE。
master1> call ttrepstop; <- 停止active数据库上的复制代理,模拟其失效
master2> call ttRepStateSet('ACTIVE');
master2> call ttRepStateGet;
< ACTIVE, NO GRID >
1 row found.
master2> call ttRepStateSave('FAILED', 'master1','timesten-hol');
master2> @insert2
INSERT INTO employees VALUES
( 203,
'Judy',
'Fox',
'JFOX',
'603-123-7777',
TO_DATE('17-AUG-1997', 'dd-MON-yyyy'),
'MK_REP',
6000,
NULL,
201,
20
);
1 row inserted. <- 此时active暂时接管了向subscriber的复制
subscriber1> select * from employees;
< 203, Judy, Fox, JFOX, 603-123-7777, 1997-08-17 00:00:00, MK_REP, 6000, <NULL>, 201, 20 >
1 rows found.
[oracle@timesten-hol ~]$ ttdestroy master1
[oracle@timesten-hol ~]$ ttRepAdmin -duplicate -from master2 -host $(hostname) -uid repadmin -pwd timesten master1
master1> call ttrepstart;
master1> call ttrepstateget;
< STANDBY, NO GRID > <-之前失效的active数据库变为standby
1 row found.
master2> @insert2
INSERT INTO employees VALUES
( 203,
'Judy',
'Fox',
'JFOX',
'603-123-7777',
TO_DATE('17-AUG-1997', 'dd-MON-yyyy'),
'MK_REP',
6000,
NULL,
201,
20
);
1 row inserted. <- 在新的active上插入数据后,新的standby,subscriber都可以接受到数据,此时,standby重新接管了向subscriber的复制
master1> select count(*) from employees where employee_id = 203; < 1 > 1 row found. subscriber1> select count(*) from employees where employee_id = 203;
< 1 >
1 row found.
当新的standby同步后,会重写接管向subscriber复制的任务。
实验过程如下:
首先设置一个active,standby和subscriber,过程可参见TimesTen 数据库复制学习:2. 配置Active Standby Pair ,确保三个库的状态分别为ACTIVE, STANDBY和IDLE;以及复制传输策略为TWOSAFE。
master1> call ttrepstop; <- 停止active数据库上的复制代理,模拟其失效;
master2> call ttRepStateSet('ACTIVE');
master2> call ttRepStateGet;
< ACTIVE, NO GRID >
1 row found.
其实如果不停止,若强制把standby提升为ACTIVE,之前的active也会自动变为STANDBY。
[oracle@timesten-hol ~]$ ttRepAdmin -duplicate -from master2 -host $(hostname) -uid repadmin -pwd timesten master1
master1> call ttrepstart;
master1> call ttrepstateget;
< STANDBY, NO GRID > <-之前的active数据库自动变为standby
1 row found.
master1> call ttrepstateget;
< STANDBY, NO GRID >
下略
前述当active失效时,standby接管称为新的active,过程称为failover,如果需要failback,可以参见后面一节:对调active和standby数据库的角色
实验如下:
master2> call ttrepstop; <- 模拟standby故障
master1> call ttRepStateSave('FAILED','master2','timesten-hol');
master1> @insert1
INSERT INTO employees VALUES
( 202,
'Pat',
'Fay',
'PFAY',
'603-123-7777',
TO_DATE('17-AUG-1997', 'dd-MON-yyyy'),
'MK_REP',
6000,
NULL,
201,
20
);
1 row inserted.
此时standby失效,active接管了向subscriber复制的任务
subscriber1> @s
select * from employees;
< 202, Pat, Fay, PFAY, 603-123-7777, 1997-08-17 00:00:00, MK_REP, 6000, <NULL>, 201, 20 >
1 row found.
恢复standby
master2> call ttrepstart;
master2> call ttrepstateget;
< STANDBY, NO GRID >
1 row found.
master1> @insert2
确认master2和subscriber都接收到了数据。
称为dual failure或double failure。如以下的情形:
* standby失效,在standby恢复前或standby与active完全同步前,active又失效
* active失效,standby变为active,然后在恢复过程完成前,新的active又试失效
在两种情形中,subscriber都比standby具有更新的数据。
可以选择从active恢复,或从standby恢复,取决于哪个库的数据最新。
比较简单,可以有两种方法:
1. 连接subscriber数据库,让其自动从日志恢复,然后自动与其源数据库同步
2. 重新从standby克隆到subscriber,如果standby不可用,则从active克隆
通常用于failover之后的failback,步骤如下:
1. 停止应用对数据库的更新
2. 调用ttRepSubscriberWait 确保所有active数据库的更新已同步到standby。也即两个数据库是完全同步的(返回值为0x00)
3. 停止active数据库的复制代理
4. 在active数据库调用ttRepDeactivate,将数据库状态置为IDLE
5. 调用ttRepStateSet('ACTIVE')
将standby角色提升为ACTIVE
6. 在之前的active数据库中启动复制代理
7. 调用ttRepStateGet
确认之前的active数据库的状态变为STANDBY
8. 恢复应用
测试如下:
master2> call ttRepSubscriberWait(NULL, NULL, 'master1', 'timesten-hol', 10);
< 00 >
1 row found. <- 从master2到master1的复制完全同步
说明:对于ASP复制,前面两个参数设成NULL即可,因为ASP复制只有一个DataStore级别的复制schema,即_ACTIVESTANDBY,owner是TTREP。
Command> SELECT REPLICATION_NAME, REPLICATION_OWNER FROM TTREP.REPLICATIONS;
< _ACTIVESTANDBY , TTREP >
1 row found.
master2> call ttrepstop;
master2> call ttRepDeactivate;
master2> call ttRepStateGet;
< IDLE, NO GRID >
1 row found.
master1> call ttRepStateSet('ACTIVE');
master1> call ttRepStateGet;
< ACTIVE, NO GRID >
1 row found.
master2> call ttRepStart;
master2> call ttRepStateGet;
< IDLE, NO GRID >
1 row found.
master2> call ttRepStateGet;
< STANDBY, NO GRID >
1 row found.
master1> @insert1
master1> select count(*) from employees;
< 2 >
1 row found.
确认master2和subscriber1上的数据条数也是为1
dual active和网络中断导致的split brain很类似,会造成数据的不一致。
以下我们模拟以下dual active的场景, 假设之前有一个正常运作的ASP:
master2> call ttrepstop;
master2> call ttrepstateset('active');
master2> call ttrepstateget;
< ACTIVE, NO GRID >
1 row found.
master1> call ttrepstateget;
< ACTIVE, NO GRID >
1 row found.
此时,两个库的状态都是ACTIVE,更危险的是,两个库还都可以更新
master1> @insert1
INSERT INTO employees VALUES
( 202,
'Pat',
'Fay',
'PFAY',
'603-123-7777',
TO_DATE('17-AUG-1997', 'dd-MON-yyyy'),
'MK_REP',
6000,
NULL,
201,
20
);
1 row inserted.
master1> @s
select * from employees;
< 202, Pat, Fay, PFAY, 603-123-7777, 1997-08-17 00:00:00, MK_REP, 6000, <NULL>, 201, 20 >
1 row found.
master2> @insert2
INSERT INTO employees VALUES
( 203,
'Judy',
'Fox',
'JFOX',
'603-123-7777',
TO_DATE('17-AUG-1997', 'dd-MON-yyyy'),
'MK_REP',
6000,
NULL,
201,
20
);
1 row inserted.
master2> @s
select * from employees;
< 203, Judy, Fox, JFOX, 603-123-7777, 1997-08-17 00:00:00, MK_REP, 6000, <NULL>, 201, 20 >
1 row found.
当网络恢复后,TimesTen会自动的判断哪个数据库比较新,由于我们的例子中,standby即master2是最后插入数据的,因此其保留ACTIVE的状态。
不是最新的数据库被置为无效,并且所有的连接被端口。当重新连接此standby时,如果其上没有未复制到对方的交易,那么其就自动成为STANDBY;如果存在未复制的交易,如我们以下的例子,则其状态被置为IDLE。或者你放弃掉此数据,然后从active数据库克隆,或者先手工补齐此数据,然后再从active数据库克隆。
master2> call ttrepstart;
master2> call ttrepstateget;
< ACTIVE, NO GRID >
1 row found.
master1> call ttrepstateget;
994: Data store connection terminated. Please reconnect.
The command failed.
disconnect master1;
Disconnecting...
[oracle@timesten-hol ~]$ ttisql master1
Command> call ttrepstateget;
< IDLE, NO GRID >
1 row found.