• dataGuard client 自动切换


    使用dataguard作为HA方案,要解决的一个问题在于:后台数据库发生了切换,client连接如何做到自动切到新的primary数据库上?

    如果做通用的方案,需要客户端自己提供自动重连的能力,这点大多数java的occi的连接池都有实现。

    但这些已有实现大多是对同一连接配置发起重连,所以需要考虑为application提供透明的连接方式,而不让应用看到具体dataguard的多个ip和service name,这就需要做些额外的配置工作。

    一种方式通过vip,真实转发的ip只挂靠在有效数据库的ip上。这种方式切换发生后,application在断连的旧connection上发起dml会获得ORA-3113 "end of file on communication channel"的错误,此时application可以尝试重连机制和新的primary建立连接。

    在f5上可以通过设置心跳sql和期望的返回结果内容,以类似ping方式获取远端数据库是否可用,来决定ip是否应该转发到该物理ip上。

    另一种方式是通过设置tns和数据库暴露的service name来访问,通过合理设置,甚至可以做到在发生切换时的select操作仅仅被阻塞一会,而完全意识不到数据库已经完成了主备切换。

    步骤如下:

     1.客户端的tnsnames.ora中tns配置成

    Xml代码  收藏代码
    1. MYAPP =  
    2.  (DESCRIPTION =  
    3.  (ADDRESS_LIST =  
    4.  (ADDRESS = (PROTOCOL = TCP)(HOST = HostA)(PORT = 1521))  
    5.  (ADDRESS = (PROTOCOL = TCP)(HOST = HostB)(PORT = 1521))  
    6.  )  
    7.  (CONNECT_DATA =  
    8.  (SERVICE_NAME = <span style="color: #ff0000;">myapp</span>)  
    9.  )  
    10.  )  

    2.在primary数据库运行

    Sql代码  收藏代码
    1.  begin  
    2.  dbms_service.create_service('myapp','myapp');  
    3. end;  
    4. /  
    5. begin  
    6.  DBMS_SERVICE.START_SERVICE('myapp');  
    7. end;  
    8. /  

     3.在primary数据库创建触发器:

    Sql代码  收藏代码
    1. create trigger myapptrigg after startup on database  
    2. declare  
    3.  v_role varchar(30);  
    4. begin  
    5.  select database_role into v_role from v$database;  
    6.  if v_role = 'PRIMARY' then  
    7.  DBMS_SERVICE.START_SERVICE('myapp');  
    8.  else  
    9.  DBMS_SERVICE.STOP_SERVICE('myapp');  
    10.  end if;  
    11. end;  
    12. /  

    解释下:这个方案的思路就是将两边的数据库的service name都设置成'myapp',当发生切换时,由触发器在数据库startup的时候把primary的实例以'myapp'的名字暴露,而把 standby的'myapp'服务名给停掉,这样任何时刻只有主节点暴露名字为'myapp'的服务。

    注意这里的plsql都是跑在primary,无需在standby上做任何设置,因为dataguard会自动将变化同步到standby数据库。

    通过在primary数据库运行下面程序,可以让客户端在做select的时候甚至意识不到数据库的切换:

    Sql代码  收藏代码
    1. begin  
    2.  dbms_service.modify_service  
    3.  ('myapp',  
    4.  FAILOVER_METHOD => 'BASIC',  
    5.  FAILOVER_TYPE => 'SELECT',  
    6.  FAILOVER_RETRIES => 200,  
    7.  FAILOVER_DELAY => 1);  
    8. end;  
    9. /  

    注意如果在切换时有comit的提交事务发生,还是会出现失误提交失败,要求回滚的情况。

    下面tns是另一种配置方式,使用这种方式,不需要在oracle server中跑任何plsql脚本,在DESCRIPTION_LIST中的两个数据库甚至根本不需要处于dataguard中,可以是任意两个数据 库。driver会按顺序遍历list中的数据库,一直到能连接上为止。

    Xml代码  收藏代码
    1. MYAPP =   
    2. (DESCRIPTION_LIST=  
    3.  (LOAD_BALANCE=off)   
    4.   (FAILOVER=on)   
    5.   (DESCRIPTION =(CONNECT_TIMEOUT=5)(TRANSPORT_CONNECT_TIMEOUT=3)(RETRY_COUNT=10)  
    6.     (ADDRESS_LIST =  
    7.       (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))  
    8.     )  
    9.     (CONNECT_DATA =  
    10.       (SERVICE_NAME = myapp1)  
    11.     )  
    12.   )  
    13.   (DESCRIPTION =(CONNECT_TIMEOUT=5)(TRANSPORT_CONNECT_TIMEOUT=3)(RETRY_COUNT=10)  
    14.     (ADDRESS_LIST =  
    15.       (ADDRESS = (PROTOCOL = TCP)(HOST = otherIP)(PORT = 1521))  
    16.     )  
    17.     (CONNECT_DATA =  
    18.       (SERVICE_NAME = myapp2)  
    19.     )  
    20.   )  
    21. )  

    这种方式需要注意的地方:

    1.jdbc必须走oci的方式,如果为jdbc:thin+tns方式,则会出现

    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 545
     at oracle.net.nl.NVTokens.parseTokens(Unknown Source)
     at oracle.net.nl.NVFactory.createNVPair(Unknown Source)

    其原因在于jdbc的driver本身无法识别这种格式的tns内容。

    此时即使以jdbc:thin+tns的方式访问其他正常的tns也会一样抛出这个错误,因为这导致了jdbc根本无法正确解析整个tnsnames.ora文件。

    而jdbc:oci实际上负责解析tnsnames.ora和处理通信的是依赖oci.lib,因此就不存在这个问题。

    2.这种配置适用于任何依赖oci通信的客户端,包括oci,occi,一些基于它们的wrap库,以及pl/sql developer此类的工具软件。

    3.注意如果连接的数据库组属于manually switch的模式,而不是fail down导致的切换,比如tns中的a数据库是mount状态,b是primary,而tns的列表顺序是先a后b,则会出现尽管客户端连a时,抛出ORA-0133错误,但是不会按顺序去尝试连接b。

    原因是在处理这个链接时,oci客户端会尝试通过listener和service建立连接。

    如果listener是关闭的,或者客户端能连上listener但是找不到对应service,则都会尝试连接处于第二个的b,但是如果通过 listener找到了对端的service,只是无法建立连接(如数据库处于mount状态),则此时不会尝试连接b,而直接会以抛出

    ORA-0133:ORACLE initialization or shutdown in progress

    终止连接尝试。

    所以在使用这种tns的时候要确保通过tns列表能访问到的所有数据库都不会一直处于mount状态,否则连接它会打断对后面正常open数据库的连接尝试。

    这也是为何手动切换的dataguard数据库,客户端不能依赖这种tns配置方法做自动切换,因为手动切换的dataguard数据库状态肯定是一个open一个mount,如果mount处于tns的列表靠前的位置,在连接它失败后会抛出ORA-0133异常阻止客户端尝试连接正常open的那个数据库。

  • 相关阅读:
    【转】MySQL导入数据乱码的分析与解决
    查看MySQL的warning
    修改MySQL字符集
    【转】PHP乱码问题,UTF8(乱码)
    马哥Linux——第一周作业
    马哥Linux——第二周作业
    .Net内部运行过程
    Html那些事
    面向对象图解、类型转换图解,写给.Net新手
    javascript对于DOM加强
  • 原文地址:https://www.cnblogs.com/ruiy/p/4270965.html
Copyright © 2020-2023  润新知