Oracle RAC 环境下的连接管理.docx
《Oracle RAC 环境下的连接管理.docx》由会员分享,可在线阅读,更多相关《Oracle RAC 环境下的连接管理.docx(30页珍藏版)》请在冰豆网上搜索。
OracleRAC环境下的连接管理
OracleRAC环境下的连接管理
这篇文章详细介绍了OracleRAC环境下的连接管理,分别介绍了什么是ConnectTimeLoadBalancing、RuntimeConnectionLoadBalancing、ConnectTimeConnectionFailover和RuntimeConnectionFailover,以及里面所涉及到的TAF、ONS、FCF、FAN、LBA等诸多知识点。
本文主要是针对OracleRAC11gR2环境下的连接管理,但同时也会对比说明一下OracleRAC10gR2/9iR2,以体现他们之间在连接管理上的差异。
所谓“连接管理”,主要体现在LoadBalancing和Failover两方面。
OracleRAC11gR2下的LoadBalancing和Failover,根据是否使用了事先已经存在的连接(如连接池中的连接)又分为ConnectTimeLoadBalancing、RuntimeConnectionLoadBalancing、ConnectTimeConnectionFailover和RuntimeConnectionFailover这4种类型,凡是带上了“Runtime”前缀的,就是指连接已经存在的情况,比如使用了连接池。
一、首先来介绍ConnectTimeConnectionFailover
ConnectTimeConnectionFailover是指不从连接池中取得已有连接,而是直接连接Oracle数据库时的Failover。
在OracleRAC11gR2之前,ConnectTimeConnectionFailover是非常容易实现的,只需要在相关的tnsnames.ora中指定多个vip,同时指定FAILOVER=ON就好了。
如下所示:
(DESCRIPTION=
(FAILOVER=ON)
(ADDRESS_LIST=
(LOAD_BALANCE=OFF)
(ADDRESS=(PROTOCOL=TCP)(HOST=RAC1-vip)(PORT=1521))
(ADDRESS=(PROTOCOL=TCP)(HOST=RAC2-vip)(PORT=1521))
(ADDRESS=(PROTOCOL=TCP)(HOST=RAC3-vip)(PORT=1521))
(ADDRESS=(PROTOCOL=TCP)(HOST=RAC4-vip)(PORT=1521))
)
(CONNECT_DATA=(SERVICE_NAME=RAC10g))
)
这里客户端进程首先会尝试连接RAC1-vip,如果连不上,则会尝试RAC2-vip,再连不上,则会继续往下尝试,直到所有出现在ADDRESS_LIST中的vip地址全部顺序尝试完为止。
这种客户端在连接Oracle数据库时的Failover,不仅适用于RAC环境,也适用于DataGuard环境。
如下所示:
DESCRIPTION=
(FAILOVER=ON)
(ADDRESS_LIST=
(LOAD_BALANCE=OFF)
(ADDRESS=(PROTOCOL=TCP)(HOST=primary-ip)(PORT=1521))
(ADDRESS=(PROTOCOL=TCP)(HOST=standby-ip)(PORT=1521))
)
(CONNECT_DATA=(SERVICE_NAME=service10g))
)
OracleRAC11gR2引入了SCAN(SingleClientAccessName),并且客户端缺省是通过SCAN来连接整个RAC环境的,如下是SCAN的架构图:
如上图所示,如果使用了DNS或者GNS(GridNamingService),那么最多可以有3个SCANVIP和3个SCANListener;如果没有使用DNS或者GNS,而是选择使用hosts文件,则只会有1个SCANVIP和1个SCANListener。
这里假设在tnsnames.ora中这样配置:
(DESCRIPTION=
(FAILOVER=ON)
(ADDRESS=(PROTOCOL=TCP)(HOST=MySCAN)(PORT=1521))
(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=RAC11g)))
严格意义上说,只有在RAC环境有1个以上SCANVIP的时候,上述FAILOVER=ON才有意义——它表示的是客户端在连接SCANVIP的时候,如果其中的一个SCANVIP连不上,则马上会尝试另外一个SCANVIP。
当使用了hosts文件来指定SCANVIP的时候,即在整个RAC环境只有1个SCANVIP的情况下,Failover其实也存在,只不过这种情况下Failover的速度会慢一些。
因为当SCANVIP所在的节点宕掉后,SCANVIP会和相关的SCANListener一起整体Failover到其他节点,只不过这个Failover需要时间,而客户端需要等待这个Failover过程完毕后才能重新连上RAC。
二、接下来介绍RuntimeConnectionFailover
RuntimeConnectionFailover是指连接已经存在的情况下的Failover。
这个已存在的连接,可能是连接池中正在用的连接,也可能是不通过连接池、直接通过OCI客户端(如sqlplus)连上Oracle数据库后的连接。
这种RuntimeConnectionFailover,就是指在连接已经存在的情况下,如果Oracle数据库端出现了异常的情况(比如Service宕了、Instance崩溃了、Session断了)而导致已有连接中断,怎样Failover的问题。
有两种手段来实现RuntimeConnectionFailover,分别为TAF(TransparentApplicationFailover)和FCF(FastConnectionFailover)。
首先来介绍TAF。
TAF有如下一些知识点需要我们注意:
1、它可以在client端的tnsnames.ora中的连接串里定义,也可以在server端的service中定义,只不过service端的设置会取代(override)客户端tnsnames.ora中的设置:
客户端可以这样设置TAF:
(DESCRIPTION=
(FAILOVER=ON)
(ADDRESS=(PROTOCOL=TCP)(HOST=MySCAN)(PORT=1521))
(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=Email)
(FAILOVER_MODE=(TYPE=select)(METHOD=basic)(RETRIES=180)(DELAY=5)))
Server端可以这样设置TAF:
srvctlmodifyservice-dRAC11g-sEmail-qTRUE-PBASIC-eSELECT-z180-w5-jLONG具体各个参数的含义可参见如下注释:
Usage:
srvctlmodifyservice-d-s[-c{UNIFORM|
SINGLETON}][-P{BASIC|PRECONNECT|NONE}][-l
[PRIMARY][,PHYSICAL_STANDBY][,LOGICAL_STANDBY][,SNAPSHOT_STANDBY]][-y
{AUTOMATIC|MANUAL}][-q{true|false}][-x{true|false}][-j{SHORT|LONG}][-B
{NONE|SERVICE_TIME|THROUGHPUT}][-e{NONE|SESSION|SELECT}][-m
{NONE|BASIC}][-z][-w]
-dUniquenameforthedatabase
-sServicename
-c{UNIFORM|SINGLETON}Servicerunsoneveryactiveserverintheserver
poolhostingthisservice(UNIFORM)orjustoneserver(SINGLETON)
-P{NONE|BASIC|PRECONNECT}TAFpolicyspecification
-lRoleoftheservice(primary,physical_standby,
logical_standby,snapshot_standby)
-yManagementpolicyfortheservice(AUTOMATICorMANUAL)
-eFailovertype(NONE,SESSION,orSELECT)
-mFailovermethod(NONEorBASIC)
-wFailoverdelay
-zFailoverretries
-jConnectionLoadBalancingGoal(SHORTorLONG).DefaultisLONG.
-BRuntimeLoadBalancingGoal(SERVICE_TIME,
THROUGHPUT,orNONE)
-xDistributedTransactionProcessing(TRUEorFALSE)
-qAQHAnotifications
(TRUEorFALSE)
-hPrintusage
2、当TAF的TYPE设置为select的时候,单纯select操作(不包括select…forupdate)可以做到“断点续传”,即单纯的select操作在利用TAF实现Failover后是可以从中断的地方继续往下执行的;
3、TAF对DML操作不能做到“断点续传”,即如果一个transaction在使用TAF实现Failover后,该transaction不能从中断的地方继续执行,需要再次从头开始执行;
4、TAF仅对使用OCI连接的客户端和连接池有效,这里的OCI连接可以是在OCI连接上的封装,比如JDBC-OCIdriver就支持TAF,但JDBCthindriver就不支持TAF(因为JDBCthindriver不是基于OCI的)。
接下来,在介绍FCF(FastConnectionFailover)之前,我们必须要先介绍FAN(FastApplicationNotification)。
FAN是OracleRAC里的一种消息主动通知机制。
当RAC里出现servicedown/up,instancedown/up,节点负载变化时,Oracle数据库都能通过FANevents将这些信息发布出去,订阅这些FANevents的客户端在第一时间收到这些FANevents后就能做出相应的动作来响应这些FANevents。
FANevents分为两种,第一种是FANHAevents,第二种是LBAevents,这里的LBA是指LoadBalancingAdvisory。
当RAC里出现servicedown/up、instancedown/up时就会触发FANHAevents。
FANHAevents的示例如下所示:
Event1:
FANeventtype:
instance
Properties:
version=1.0service=PRODdatabase=PRODinstance=PROD1host=node1status=down
Event2:
FANeventtype:
service_member
Properties:
version=1.0service=ERPdatabase=PRODinstance=PROD1host=node1status=down
Event3:
FANeventtype:
service_member
Properties:
version=1.0service=ERPdatabase=PRODinstance=PROD3host=node3status=up
RAC里节点的负载变化后也会产生LBAevents,LBAevents的示例如下所示:
Event4:
FAN-eventtype:
service_metrics
Properties:
version=2.0service=ERPdatabase=PRODinstance=PROD1percent=70
service_quality=GOODinstance=PROD2percent=30service_quality=GOOD
Event5:
FAN-eventtype:
service_metrics
Properties:
version=2.0service=CRMdatabase=PRODinstance=PROD2percent=30
service_quality=GOODinstance=PROD3percent=70service_quality=GOOD
上述FANevents可能会通过多种渠道传播出去,这些渠道包括ONS(OracleNotificationService),AQ(AdvancedQueue),PMON等。
下面是关于FANevents架构和传播途径的两张图,它们就直观的说明了FANevents的传播途径:
订阅FANHAevents的客户端包括:
JDBCImplicitConnectionCache,OCI,ODP.NETConnectionPools,Listener,ServerSideCallouts等;
订阅LBAevents的客户端包括:
JDBCImplicitConnectionCache,ODP.NETConnectionPools,Listener,OCISessionPools等;
介绍完FAN,现在可以开始介绍FCF:
FCF的意思是FastConnectionFailover,它实际上是客户端通过订阅FANHAevents来实现的。
如下是两个客户端通过订阅FANHAevents来实现FCF的例子:
例一:
JDBCFastConnectionFailover(FCF)
这里的JDBC连接是指JDBCthin连接。
因为JDBCthin连接不是基于OCI的,所以这种情况下的RuntimeConnectionFailover不能使用TAF,只能用FCF。
并且要做如下几件事情后才可以正常使用FCF:
1、把implicitconnectioncache打开;
2、把FastConnectionFailoverEnabled打开;
3、最好是直接订阅远程的ONS(在Oracle10gR2之前的版本不能直接订阅远程的ONS,只能通过在本地安装ONS后来实现FANevents的中转);
4、最好是在Java程序里设置一下TCPtimeout(后面专门会讲到在Oracle数据库里如何调整TCPtimeout);
演示代码如下:
OracleDataSourceods=newOracleDataSource()
...
ods.setUser(“Scott”)
ods.setPassword(“tiger”)
ods.setConnectionCachingEnabled(true);
ods.setFastConnectionFailoverEnabled(true);
ods.setConnectionCacheName(“MyCache”)
ods.setConnectionCacheProperties(cp);
ods.setONSConfiguration("nodes=racnode1:
6201,racnode2.:
6201");
ods.setURL("jdbc:
oracle:
thin:
@sales1-scan:
1521/oltp");
//TCPconnecttimeout
Propertiesprop=newProperties();
prop.setProperty("MinLimit",MIN_CONN);
prop.setProperty("MaxLimit",MAX_CONN);
prop.setProperty("InitialLimit",INIT_CONN);
prop.put(.ns.SQLnetDef.TCP_CONNTIMEOUT_STR,"1000"));//
这里是表示把TCPtimeout设为1000毫秒,即1秒
ods.setConnectionCacheProperties(prop);
例二:
ODP.NETFastConnectionFailover(FCF)
对于ODP.NET而言,通常做了如下几件事情后就可以使用FCF了:
1、把对应service的AQNotification打开:
srvctlmodifyservice-dRAC11g-sEmail-qTRUE
2、把aq_tm_processes的值设为1;
3、赋予指定用户de-queue的权限:
execdbms_aqadm.grant_queue_privilege('DEQUEUE','SYS.SYS$SERVICE_METRICS',);
4、在.NET连接串里设置HAevents=true;
演示代码如下:
//C#
usingSystem;
usingOracle.DataAccess.Client;
classConnectionPoolingSample
{
staticvoidMain()
{
OracleConnectioncon=newOracleConnection();
//OpenaconnectionusingConnectionStringattributes
//relatedtoconnectionpooling.
con.ConnectionString=
"UserId=scott;Password=tiger;DataSource=crm;"+
"MinPoolSize=10;ConnectionLifetime=120;ConnectionTimeout=60;"+
"HAevents=true","IncrPoolSize=5;DecrPoolSi=2";
con.Open();
Console.WriteLine("Connectionpoolsuccessfullycreated");
//CloseandDisposeOracleConnectionobject
con.Close();
con.Dispose();
Console.WriteLine("Connectionisplacedbackintothepool.");
}
}
FCF跟TAF有一个很大的不同就是即便是单纯select操作,FCF也不能像TAF那样做到“断点续传”。
对于配置好了FCF的连接池而言,当它接收到包含instance/service宕掉的FANHAevents后,原先cache在连接池里的跟这个instance/service相关的连接马上会被标记为失效(invalid)同时这些连接会被清除,使用这些连接的transaction也会马上中止并回滚。
当应用捕捉到这个中止的transaction所产生的错误信息后,要么直接把相关错误返回给最终用户,要么从连接池中重新取得一个有效连接并重新执行这个被中止的transaction。
在启用了FCF的情况下,如果连接错误被返回给了最终用户,那么应该如何判断错误信息的来源呢(即是否是FCF返回的错误)?
很简单,用isFatalConnectionError(SQLExceptione)来判断一下就好了,演示代码如下:
try{
conn=getConnection();
//这里取得连接后做相关的工作
}catch(SQLExceptione){
handleSQLException(e)
}
...
voidhandleSQLException(SQLExceptione)
{
if
(OracleConnectionCacheManager.isFatalConnectionError(e))
ConnRetry=true;//这里表示捕捉到FCF返回的错误
…
}
三、接着介绍ConnectTimeLoadBalancing
ConnectTimeLoadBalancing就是指不从连接池中取得已有连接,而是直接连接Oracle数据库时的LoadBalance。
ConnectTimeLoadBalancing又细分为两种,分别是客户端的ConnectTimeLoadBalancing和Server端的ConnectTimeLoadBalancing。
在OracleRAC11gR2之前,客户端的ConnectT