I researched an interesting new feature available with Oracle 11g R2, the so called RAC FAN API when writing the workload management chapter for the RAC book. The RAC FAN API is documented in Oracle® Database JDBC Developer’s Guide, 11g Release 2 (11.2) available online, but when it came to the initial documentation following the 11.2.0.1 release on Linux it was pretty useless. The good news is that it improved!
The RAC FAN Java API
The aim of this API is to allow a Java application to listen to FAN events by creating a subscription to the RAC nodes’ ONS processes. The application then registers a FANListener, based on the subscription, which can pick up instances of the following events:
- ServiceDownEvent
- NodeDownEvent
- LoadAdvisoryEvent
All of these are in the oracle.simplefan namespace, the javadoc reference of which you can find in the official documenation.
When it was initially released in 11.2.0.1 I tried to get the FAN subscription to work without any luck, the registration with the ONS didn’t work. Schematically, this is how it should work:
The application (shown on the top) requires an Oracle client for the ONS configuration and libraries, and the setup is very similar to how you’d set up FCF. With the ons.config file pointing to the RAC nodes’ ONS processes you should be able to read FAN events as they occur on the source system. The ons.config in $CLIENT_HOME/opmn/conf/ons.config has to contain the local and remote ONS port, as well as all the RAC nodes with their remote ONS port. When subscribing to the events, you specify the service name you’d like to receive events for.
My 4 node RAC cluster is comprised of node rac11gr2drnode{1,2,3}, with local ONS listing on port 6200 for external, and port 6100 for internal requests. This can be checked using the onsctl debug command on any cluster node.. The client’s ons.config contains these lines:
localport:6100
remoteport:6200
nodes=rac11gr2drnode1:6200, rac11gr2drnode2:6200,rac11gr2drnode3:6200, rac11gr2drnode4:6200
Unfortunately I couldn’t subscribe to the remote ONS-I know that my setup is valid because of my UCP/FCF testing I did previously (check my earlier blog postings about how to get started with UCP and Tomcat 6). Or maybe it doesn’t work on Windows, who knows? Trying to subscribe to the remote ONS my application bails out with the following error:
Exception in thread “main” oracle.ons.SubscriptionException: Subscription request timed out after 30000 millseconds. Possible causes: OPMN may not be running, you may have an OPMN running in an alternate ORACLE_HOME using duplicate port values, or OPMN may be misconfigured.
at oracle.ons.SubscriptionNotification.waitForReply(SubscriptionNotification.java:83)
at oracle.ons.ONS.addSubscriber(ONS.java:956)
at oracle.ons.Subscriber.realStartup(Subscriber.java:103)
at oracle.ons.Subscriber.<init>(Subscriber.java:79)
at oracle.simplefan.impl.FanSubscription.subscribe(FanSubscription.java:228)
at oracle.simplefan.impl.FanSubscription.createFanSubscription(FanSubscription.java:46)
at oracle.simplefan.impl.FanManager.subscribe(FanManager.java:120)
at de.mbh.TestClass.<init>(TestClass.java:21)
at de.mbh.TestClass.main(TestClass.java:53)
I tried my favourite search engine on the Exception but couldn’t find any useful information. This is not a big deal for me, I can start a local ONS on the client. This is shown here:
C:\oracle\product\11.2.0\client_1\opmn\bin>onsctl ping ons is not running ... C:\oracle\product\11.2.0\client_1\opmn\bin>onsctl start onsctl start: ons started C:\oracle\product\11.2.0\client_1\opmn\bin>onsctl debug HTTP/1.1 200 OK Content-Length: 3627 Content-Type: text/html Response: == client:6200 5872 11/05/26 11:47:16 == Home: c:\oracle\product\11.2.0\client_1 ======== ONS ======== IP ADDRESS PORT TIME SEQUENCE FLAGS --------------------------------------- ----- -------- -------- -------- 10.xxx.xx.98 6200 4dde2fb0 00000006 00000008 Listener: TYPE BIND ADDRESS PORT SOCKET -------- --------------------------------------- ----- ------ Local 127.0.0.1 6100 344 Remote any 6200 352 Servers: (3) INSTANCE NAME TIME SEQUENCE FLAGS DEFER ---------------------------------------- -------- -------- -------- ---------- dbInstance_rac11gr2drnode1_6200 4d53d6a4 00029496 00000002 0 10.xxx.xx.155 6200 dbInstance_rac11gr2drnode2_6200 4d3eb9e2 0006cbeb 00000002 0 10.xxx.xx157 6200 dbInstance_rac11gr2drnode3_6200 4d5937d6 0001990f 00000002 0 10.xxx.xx.158 6200 Connection Topology: (4) IP PORT VERS TIME --------------------------------------- ----- ----- -------- 10.xxx.xx.158 6200 4 4dde2fb2 ** 10.xxx.xx.155 6200 ** 10.xxx.xx.157 6200 ** 10.xxx.xx.98 6200 10.xxx.xx.157 6200 4 4dde2fb2 ** 10.xxx.xx.155 6200 ** 10.xxx.xx.158 6200 ** 10.xxx.xx.98 6200 10.xxx.xx.155 6200 4 4dde2fb2 ** 10.xxx.xx.98 6200 ** 10.xxx.xx.157 6200 ** 10.xxx.xx.158 6200 10.xxx.xx.98 6200 4 4dde2fb2= ** 10.xxx.xx.155 6200 ** 10.xxx.xx.158 6200 ** 10.xxx.xx.157 6200 Server connections: ID CONNECTION ADDRESS PORT FLAGS SENDQ REF WSAQ -------- --------------------------------------- ----- ------ ----- --- ---- 0 10.xxx.xx.155 6200 010405 00000 001 --- 1 10.xxx.xx.156 6200 002405 00000 001 2 10.xxx.xx.157 6200 010405 00000 001 -- 3 10.xxx.xx.158 6200 010405 00000 001 --- Client connections: ID CONNECTION ADDRESS PORT FLAGS SENDQ REF SUB W -------- --------------------------------------- ----- ------ ----- --- --- - 4 internal 0 01008a 00000 001 002 request 127.0.0.1 6100 03201a 00000 001 000 Worker Ticket: 28/28, Last: 11/05/26 11:47:15 THREAD FLAGS -------- -------- 120 00000012 124 00000012 128 00000012 Resources: Notifications: Received: Total 12 (Internal 6), in Receive Q: 0 Processed: Total 12, in Process Q: 0 Pool Counts: Message: 1, Link: 1, Ack: 1, Match: 1 C:\oracle\product\11.2.0\client_1\opmn\bin>
With a local ONS started on my client, I can actually subscribe to the ONS and make use of the events. The easiest way is to simply decode the load balancing events, as I did in my code, shown below (modified version of the code in the Oracle documentation to make it work):
package de.mbh; import oracle.simplefan.FanSubscription; import oracle.simplefan.FanEventListener; import oracle.simplefan.FanManager; import oracle.simplefan.LoadAdvisoryEvent; import oracle.simplefan.NodeDownEvent; import oracle.simplefan.ServiceDownEvent; import java.util.Properties; public class TestClass { TestClass() { System.out.println("Hello"); Properties p = new Properties(); p.put("serviceName", "OEMSRV"); System.setProperty("oracle.ons.oraclehome", "c:\\oracle\\product\\11.2.0\\client_1"); System.out.println(System.getProperty("oracle.ons.oraclehome")); FanSubscription sub = FanManager.getInstance().subscribe(p); System.out.println("I'm subscribed!"); sub.addListener(new FanEventListener() { public void handleEvent(ServiceDownEvent arg0) { System.out.println("Service Down registered!"); } public void handleEvent(NodeDownEvent arg0) { System.out.println("Node Down Event Registered"); } public void handleEvent(LoadAdvisoryEvent arg0) { System.out.println("Just got a Load Advisory event"); System.out.println("originating database: " + arg0.getDatabaseUniqueName()); System.out.println("originating instance: " + arg0.getInstanceName()); System.out.println("Service Quality : " + arg0.getServiceQuality()); System.out.println("Percent : " + arg0.getPercent()); System.out.println("Service Name : " + arg0.getServiceName()); System.out.println("Service Quality : " + arg0.getServiceQuality()); System.out.println("Observed at : " + arg0.getTimestamp() + "\n\n"); } } ); } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub TestClass tc = new TestClass(); int i = 0; while ( i < 100000) { try { Thread.sleep(100); i++; } catch (Exception e) { System.out.println(e); } } System.out.println("execution ended"); } }
When compiling or executing the code, you need the simplefan.jar and ons.jar files in your classpath, and chances are that you need ojdbc6.jar as well.
Starting the application reveals Load Balancing events being read:
Hello c:\oracle\product\11.2.0\client_1 I'm subscribed! Just got a Load Advisory event originating database: LNGDS1RD originating instance: dbInstance_rac11gr2drnode3_6200 Service Quality : -1 Percent : 51 Service Name : OEMSRV Service Quality : -1 Observed at : Thu May 26 11:56:03 BST 2011 Just got a Load Advisory event originating database: LNGDS1RD originating instance: dbInstance_rac11gr2drnode3_6200 Service Quality : -1 Percent : 49 Service Name : OEMSRV Service Quality : -1 Observed at : Thu May 26 11:56:03 BST 2011
This proves that you can write your own connection cache, which allows you to react to *down events and rebalance your session differently.
Response
[…] Martin Back researched an interesting new feature available with Oracle 11g R2, the so called RAC FAN API when writing the workload management chapter for the RAC book. […]