• Oracle RAC 环境下的连接管理


    崔华,网名 dbsnake

    Oracle ACE Director,ACOUG 核心专家

    (【崔华文章系列】已获崔华独家授权在云和恩墨官方微信账号陆续发布,请大家持续关注)

    这篇文章详细介绍了 Oracle RAC 环境下的连接管理,分别介绍了什么是 Connect Time Load Balancing、Runtime Connection Load Balancing、Connect Time Connection Failover 和 Runtime Connection Failover,以及里面所涉及到的 TAF、ONS、FCF、FAN、LBA 等诸多知识点。本文主要是针对 Oracle RAC 11gR2 环境下的连接管理,但同时也会对比说明一下 Oracle RAC 10gR2/9iR2,以体现他们之间在连接管理上的差异。

    所谓“连接管理”,主要体现在 Load Balancing 和 Failover 两方面。Oracle RAC 11gR2 下的 Load Balancing 和 Failover,根据是否使用了事先已经存在的连接(如连接池中的连接)又分为 Connect Time Load Balancing、Runtime Connection Load Balancing、Connect Time Connection Failover 和 Runtime Connection Failover 这 4 种类型,凡是带上了“Runtime”前缀的,就是指连接已经存在的情况,比如使用了连接池。

    一、首先来介绍 Connect Time Connection Failover

    Connect Time Connection Failover 是指不从连接池中取得已有连接,而是直接连接 Oracle 数据库时的 Failover。在 Oracle RAC 11gR2 之前,Connect Time Connection Failover 是非常容易实现的,只需要在相关的 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 环境,也适用于 Data Guard 环境。如下所示:

    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))
      )  

    Oracle RAC 11gR2 引入了 SCAN(Single Client Access Name),并且客户端缺省是通过 SCAN 来连接整个 RAC 环境的,如下是 SCAN 的架构图:

    如上图所示,如果使用了 DNS 或者 GNS (Grid Naming Service),那么最多可以有 3 个 SCAN VIP 和 3 个 SCAN Listener;如果没有使用 DNS 或者 GNS,而是选择使用 hosts 文件,则只会有 1 个 SCAN VIP 和 1 个 SCAN Listener。

    这里假设在 tnsnames.ora 中这样配置:

     (DESCRIPTION = 
        (FAILOVER=ON) 
        (ADDRESS = (PROTOCOL = TCP)(HOST = MySCAN)(PORT = 1521)) 
        (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME =RAC11g)))	

    严格意义上说,只有在 RAC 环境有 1 个以上 SCAN VIP 的时候,上述 FAILOVER=ON 才有意义——它表示的是客户端在连接 SCAN VIP 的时候,如果其中的一个 SCAN VIP 连不上,则马上会尝试另外一个 SCAN VIP。

    当使用了 hosts 文件来指定 SCAN VIP 的时候,即在整个 RAC 环境只有 1 个 SCAN VIP 的情况下,Failover 其实也存在,只不过这种情况下 Failover 的速度会慢一些。因为当 SCAN VIP 所在的节点宕掉后,SCAN VIP 会和相关的 SCAN Listener 一起整体 Failover 到其他节点,只不过这个 Failover 需要时间,而客户端需要等待这个 Failover 过程完毕后才能重新连上 RAC。

    二、接下来介绍 Runtime Connection Failover

    Runtime Connection Failover 是指连接已经存在的情况下的 Failover。这个已存在的连接,可能是连接池中正在用的连接,也可能是不通过连接池、直接通过 OCI 客户端(如 sqlplus)连上 Oracle 数据库后的连接。

    这种 Runtime Connection Failover,就是指在连接已经存在的情况下,如果 Oracle 数据库端出现了异常的情况(比如 Service 宕了、Instance 崩溃了、Session 断了)而导致已有连接中断,怎样 Failover 的问题。

    有两种手段来实现 Runtime Connection Failover,分别为 TAF(Transparent Application Failover)和 FCF(Fast Connection Failover)。

    首先来介绍 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:

    srvctl modify service -d RAC11g -s Email -q TRUE -P BASIC -e SELECT -z 180 -w 5 -j LONG 具体各个参数的含义可参见如下注释:

    Usage: srvctl modify service -d <db_unique_name> -s <service_name> [-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 <integer>] [-w <integer>]
        -d <db_unique_name>      Unique name for the database
        -s <service>             Service name
        -c {UNIFORM | SINGLETON} Service runs on every active server in the server 
    pool hosting this service (UNIFORM) or just one server (SINGLETON)
        -P {NONE | BASIC | PRECONNECT}        TAF policy specification
        -l <role>                Role of the service (primary, physical_standby, 
    logical_standby, snapshot_standby)
        -y <policy>              Management policy for the service (AUTOMATIC or MANUAL)
        -e <Failover type>       Failover type (NONE, SESSION, or SELECT)
        -m <Failover method>     Failover method (NONE or BASIC)
        -w <integer>             Failover delay
        -z <integer>             Failover retries
        -j <clb_goal>  Connection Load Balancing Goal (SHORT or LONG). Default is LONG.
        -B <Runtime Load Balancing Goal>     Runtime Load Balancing Goal (SERVICE_TIME, 
    THROUGHPUT, or NONE)
        -x <Distributed Transaction Processing>  Distributed Transaction Processing (TRUE or FALSE)
        -q <AQ HA notifications> AQ HA notifications 
    (TRUE or FALSE)
        -h                       Print usage	

    2、当 TAF 的TYPE 设置为 select 的时候,单纯 select 操作(不包括 select … for update)可以做到“断点续传”,即单纯的 select 操作在利用 TAF 实现 Failover 后是可以从中断的地方继续往下执行的;
    3、TAF 对 DML 操作不能做到“断点续传”,即如果一个 transaction 在使用 TAF 实现 Failover 后,该 transaction 不能从中断的地方继续执行,需要再次从头开始执行;
    4、TAF 仅对使用 OCI 连接的客户端和连接池有效,这里的 OCI 连接可以是在 OCI 连接上的封装,比如 JDBC-OCI driver 就支持 TAF,但 JDBC thin driver 就不支持 TAF(因为 JDBC thin driver 不是基于 OCI 的)。

    接下来,在介绍 FCF(Fast Connection Failover)之前,我们必须要先介绍 FAN(Fast Application Notification)。

    FAN 是 Oracle RAC 里的一种消息主动通知机制。当 RAC 里出现 service down/up,instance down/up,节点负载变化时,Oracle 数据库都能通过 FAN events 将这些信息发布出去,订阅这些 FAN events 的客户端在第一时间收到这些 FAN events 后就能做出相应的动作来响应这些 FAN events。

    FAN events 分为两种,第一种是 FAN HA events,第二种是 LBA events,这里的 LBA 是指 Load Balancing Advisory。

    当 RAC 里出现 service down/up、instance down/up 时就会触发 FAN HA events。FAN HA events 的示例如下所示:

    Event 1: FAN event type: instance 
    Properties:  version=1.0 service=PROD database=PROD instance=PROD1 host=node1 status=down
     
    Event 2: FAN event type: service_member 
    Properties:  version=1.0 service=ERP  database=PROD instance=PROD1 host=node1 status=down
    
    Event 3: FAN event type: service_member 
    Properties: version=1.0 service=ERP database=PROD instance=PROD3 host=node3 status=up

    RAC 里节点的负载变化后也会产生 LBA events,LBA events 的示例如下所示:

    Event 4: FAN-event type: service_metrics 
    Properties: version=2.0 service=ERP database=PROD instance=PROD1 percent=70 
    service_quality=GOOD instance=PROD2 percent=30 service_quality=GOOD  
    
    Event 5 :FAN-event type: service_metrics 
    Properties: version=2.0 service=CRM database=PROD instance=PROD2 percent=30 
    service_quality=GOOD instance=PROD3 percent=70 service_quality=GOOD

    上述 FAN events 可能会通过多种渠道传播出去,这些渠道包括 ONS(Oracle Notification Service),AQ(Advanced Queue),PMON 等。下面是关于 FAN events 架构和传播途径的两张图,它们就直观的说明了 FAN events 的传播途径:

    订阅 FAN HA events 的客户端包括:JDBC Implicit Connection Cache, OCI, ODP.NET Connection Pools, Listener, Server Side Callouts 等;


    订阅 LBA events 的客户端包括:JDBC Implicit Connection Cache, ODP.NET Connection Pools, Listener,OCI Session Pools 等;

    介绍完 FAN,现在可以开始介绍 FCF:FCF 的意思是 Fast Connection Failover,它实际上是客户端通过订阅 FAN HA events 来实现的。如下是两个客户端通过订阅 FAN HA events 来实现 FCF 的例子:

    例一:JDBC Fast Connection Failover (FCF)
    这里的 JDBC 连接是指 JDBC thin 连接。因为 JDBC thin 连接不是基于 OCI 的,所以这种情况下的 Runtime Connection Failover 不能使用 TAF,只能用 FCF。并且要做如下几件事情后才可以正常使用 FCF:
    1、把 implicit connection cache 打开;
    2、把 FastConnectionFailoverEnabled 打开;
    3、最好是直接订阅远程的 ONS(在Oracle 10gR2 之前的版本不能直接订阅远程的 ONS,只能通过在本地安装 ONS 后来实现 FAN events 的中转);
    4、最好是在 Java 程序里设置一下 TCP timeout(后面专门会讲到在 Oracle 数据库里如何调整 TCP timeout);

    演示代码如下:

    OracleDataSource ods = new OracleDataSource() 
    ... 
    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");
    
    //TCP connect timeout
    Properties prop = new Properties();
    prop.setProperty("MinLimit", MIN_CONN);
    prop.setProperty("MaxLimit", MAX_CONN);
    prop.setProperty("InitialLimit", INIT_CONN);
    prop.put (oracle.net.ns.SQLnetDef.TCP_CONNTIMEOUT_STR, "1000")); // 
    这里是表示把TCP timeout设为1000毫秒,即1秒
    ods.setConnectionCacheProperties(prop);

    例二:ODP.NET Fast Connection Failover (FCF)
    对于 ODP.NET 而言,通常做了如下几件事情后就可以使用 FCF 了:
    1、把对应 service 的 AQ Notification 打开:
    srvctl modify service -d RAC11g -s Email -q TRUE
    2、把 aq_tm_processes 的值设为 1;
    3、赋予指定用户 de-queue 的权限:
    exec dbms_aqadm.grant_queue_privilege('DEQUEUE','SYS.SYS$SERVICE_METRICS', <your username=>);
    4、在 .NET 连接串里设置 HA events=true;

    演示代码如下:

    // C# 
    using System; 
    using Oracle.DataAccess.Client; 
    class ConnectionPoolingSample 
    { 
    static void Main() 
    { 
    OracleConnection con = new OracleConnection(); 
    //Open a connection using ConnectionString attributes 
    //related to connection pooling. 
    con.ConnectionString = 
    "User Id=scott;Password=tiger;Data Source=crm;" + 
    "Min Pool Size=10;Connection Lifetime=120;Connection Timeout=60;" + 
    "HA events=true", "Incr Pool Size=5; Decr Pool Si=2"; 
    con.Open(); 
    Console.WriteLine("Connection pool successfully created"); 
    // Close and Dispose OracleConnection object 
    con.Close(); 
    con.Dispose(); 
    Console.WriteLine("Connection is placed back into the pool."); 
    } 
    }

    FCF 跟 TAF 有一个很大的不同就是即便是单纯 select 操作,FCF 也不能像 TAF 那样做到“断点续传”。对于配置好了 FCF 的连接池而言,当它接收到包含 instance/service 宕掉的 FAN HA events 后,原先 cache 在连接池里的跟这个 instance/service 相关的连接马上会被标记为失效(invalid)同时这些连接会被清除,使用这些连接的 transaction 也会马上中止并回滚。当应用捕捉到这个中止的 transaction 所产生的错误信息后,要么直接把相关错误返回给最终用户,要么从连接池中重新取得一个有效连接并重新执行这个被中止的 transaction。

    在启用了 FCF 的情况下,如果连接错误被返回给了最终用户,那么应该如何判断错误信息的来源呢(即是否是 FCF 返回的错误)?很简单,用 isFatalConnectionError(SQLException e)来判断一下就好了,演示代码如下:

    try { 
    conn = getConnection(); 
    //这里取得连接后做相关的工作
    } catch (SQLException e) { 
    handleSQLException(e) 
    } 
    ... 
    void handleSQLException (SQLException e) 
    { 
    if 
    (OracleConnectionCacheManager.isFatalConnectionError(e)) 
    ConnRetry = true; //这里表示捕捉到FCF返回的错误 
    …
    } 
  • 相关阅读:
    环境变量设置set env exportFedora Centos日志我的搜狐
    Hadoop Streaming 编程
    业务开发测试HBase之旅三:通过Java Api与HBase交互
    hadoop+zookeeper+hbase安装_dekar_x的空间_百度空间
    HBase Java客户端编程
    Hadoop应用测试
    HBase vs Cassandra: 我们迁移系统的原因
    关于HBase的一些零碎事
    奔流 | 自由、奔放的技术刊物
    Paxos在大型系统中常见的应用场景
  • 原文地址:https://www.cnblogs.com/timlong/p/7846088.html
Copyright © 2020-2023  润新知