Oracle RAC 19c Masterclass — Part 20: RAC Services & Workload Management: Designing RAC for Real Applications

Part 19 covered the RAC interconnect and showed why network health alone isn’t enough. We also saw an important performance principle:

Where an application runs inside RAC can directly affect Cache Fusion traffic.

That brings us to RAC Services.

Services are one of the most powerful mechanisms for controlling how applications use a RAC database.

A well-designed RAC environment doesn’t simply distribute sessions randomly across nodes.

It deliberately controls:

Application
     ↓
Service
     ↓
RAC Instance
     ↓
Workload
     ↓
Data locality
     ↓
Cache Fusion

1. What Is a RAC Service?

A RAC service is a logical database workload entity.

For example:

SALES_APP
REPORTING
BATCH
ETL
ERP
PAYMENTS

Instead of applications connecting directly to:

rac1
rac2

they connect through a service:

salesdb.wadhahdaouehi.tn        |
↓
SALES_APP
|
+----+----+
| |
RAC1 RAC2

The service determines where that workload can run.

2. Why Services Matter

Imagine:

RAC1
 ├── SALES
 └── PAYMENTS

RAC2
 ├── REPORTING
 └── BATCH

Now the workloads are separated.

Compare this with:

RAC1
 ├── SALES
 ├── PAYMENTS
 ├── REPORTING
 └── BATCH

RAC2
 ├── SALES
 ├── PAYMENTS
 ├── REPORTING
 └── BATCH

The second design may provide excellent distribution, but it can also create more cross-instance data access.

The first design can improve workload locality when the data access patterns support it.

3. Services Are More Than Connection Strings

A common mistake is to think:

“A service is just another database name.”

No.

A service can influence:

  • Connection routing
  • Load balancing
  • Failover
  • Application behavior
  • Workload isolation
  • Resource management
  • Application Continuity
  • RAC availability

Services are an important architecture layer.

4. Preferred and Available Instances

Suppose:

SALES_APP

has:

Preferred:
RAC1

Available:
RAC2

Conceptually:

             SALES_APP
                 |
          +------+------+
          |             |
       Preferred     Available
          |             |
        RAC1          RAC2

Normal workload:

SALES_APP → RAC1

If RAC1 becomes unavailable:

RAC1
  X
  |
  ↓
SALES_APP
  |
  ↓
RAC2

The service can relocate/fail over according to its configuration.

5. Why Not Put Everything Everywhere?

You could create:

SALES_APP
Preferred: RAC1,RAC2

and allow both nodes to process everything.

But ask:

Does the workload benefit from being distributed?

If both instances constantly modify the same blocks:

RAC1 ↔ RAC2
     |
Cache Fusion
     |
gc current request

you may create unnecessary global cache traffic.

6. The Principle of Workload Locality

Think about this:

Application
    ↓
Service
    ↓
Instance
    ↓
Data

If those four layers align well:

SALES_APP
    ↓
RAC1
    ↓
SALES tables

you can potentially reduce cross-instance block transfers.

This is called workload locality.

7. But Don’t Over-Isolate

There is another mistake:

“I’ll put every application on a different node.”

For example:

RAC1 → SALES
RAC2 → PAYMENTS
RAC3 → REPORTING
RAC4 → BATCH

This can create poor resource utilization.

If SALES consumes 90% CPU:

RAC1 → 90% CPU
RAC2 → 15%
RAC3 → 20%
RAC4 → 10%

You haven’t necessarily designed a balanced RAC system.

So the goal is:

Balance workload while preserving locality where it matters.

8. Check Existing Services

Start with:

srvctl status service -db PROD

You might see:

Service SALES_APP is running on instance(s) RAC1
Service REPORTING is running on instance(s) RAC2
Service BATCH is running on instance(s) RAC2

Then:

srvctl config service -db PROD

This is extremely important.

It shows the configured service properties.

9. Service Configuration

A more targeted command:

srvctl config service -db PROD -service SALES_APP

Depending on the exact Grid Infrastructure release, the output can include properties related to:

  • Preferred instances
  • Available instances
  • Service role
  • Management policy
  • Connection load balancing
  • Failover
  • Notification settings
  • Edition
  • PDB association

Always check the syntax available in your installed 19c version with:

srvctl -help

10. Creating a Service

For example:

srvctl add service \
  -db PROD \
  -service SALES_APP \
  -preferred RAC1 \
  -available RAC2

Then:

srvctl start service \
  -db PROD \
  -service SALES_APP

Verify:

srvctl status service \
  -db PROD \
  -service SALES_APP

11. Important Production Warning

Don’t run:

srvctl add service ...

against production without first checking whether the service already exists.

Use:

srvctl config service -db PROD

first.

And before modifying an existing service:

srvctl config service \
  -db PROD \
  -service SALES_APP

Document the current configuration.

12. Service Design Example

Suppose you have:

RAC1
RAC2

and four workloads:

SALES
ERP
REPORTING
BATCH

A possible design:

                 PROD
                  |
        +---------+---------+
        |                   |
      RAC1                 RAC2
        |                   |
   +----+----+         +----+----+
   |         |         |         |
 SALES      ERP    REPORTING    BATCH

But perhaps REPORTING also needs access to SALES data.

Then you need to consider whether:

REPORTING → RAC2
SALES      → RAC1

creates excessive cross-instance block access.

This is where AWR/ASH becomes important.

13. Don’t Design Services by Guessing

The correct process is:

Current workload
      ↓
Measure
      ↓
Identify SQL
      ↓
Identify objects
      ↓
Identify instances
      ↓
Identify GC waits
      ↓
Design service placement
      ↓
Measure again

This is much better than:

“Let’s move SALES to RAC1 because RAC1 has fewer sessions.”

Session count alone is not enough.

14. Session Count Is a Bad Load Metric

Imagine:

RAC1 → 500 sessions
RAC2 → 100 sessions

You might think:

RAC1 is overloaded.

But:

RAC1
500 mostly idle sessions

RAC2
100 CPU-intensive sessions

RAC2 could be much busier.

Look at:

  • DB CPU
  • DB Time
  • Active sessions
  • I/O
  • GC waits
  • Service-level workload

not simply connection count.

15. Service-Level Monitoring

ASH can help:

SELECT service_name,
       instance_number,
       COUNT(*) samples
FROM dba_hist_active_sess_history
WHERE sample_time BETWEEN
      TIMESTAMP '2026-08-08 10:00:00'
  AND TIMESTAMP '2026-08-08 11:00:00'
GROUP BY service_name,
         instance_number
ORDER BY samples DESC;

This gives you an idea of where active workload is occurring.

16. Find Top SQL by Service

SELECT service_name,
       sql_id,
       COUNT(*) samples
FROM dba_hist_active_sess_history
WHERE sample_time BETWEEN
      TIMESTAMP '2026-08-08 10:00:00'
  AND TIMESTAMP '2026-08-08 11:00:00'
AND sql_id IS NOT NULL
GROUP BY service_name,
         sql_id
ORDER BY samples DESC
FETCH FIRST 50 ROWS ONLY;

Now you can say:

SALES_APP
   ↓
SQL_ID 8a12abc
   ↓
High DB activity

17. Service + GC Waits

This is particularly useful for RAC:

SELECT service_name,
       instance_number,
       event,
       COUNT(*) samples
FROM dba_hist_active_sess_history
WHERE sample_time BETWEEN
      TIMESTAMP '2026-08-08 10:00:00'
  AND TIMESTAMP '2026-08-08 11:00:00'
AND event LIKE 'gc %'
GROUP BY service_name,
         instance_number,
         event
ORDER BY samples DESC;

Example:

SERVICE      INSTANCE EVENT
-----------  -------- -----------------------
SALES_APP    2        gc current request
SALES_APP    2        gc current block busy
BATCH        1        gc current request

Now you have a direct relationship between:

Service
   ↓
Instance
   ↓
GC activity

18. Connection Load Balancing

Oracle RAC can distribute new connections intelligently.

This is known as:

Connection Load Balancing

The goal is not necessarily:

50% / 50%

Instead, Oracle can consider instance workload.

For example:

RAC1
CPU = 20%

RAC2
CPU = 80%

New connections can favor RAC1.

19. Client-Side vs Server-Side Load Balancing

There are multiple mechanisms involved.

At a high level:

Client
  |
  ↓
SCAN
  |
  ↓
Listener
  |
  ↓
Service
  |
  ↓
Instance

Oracle RAC uses listener and service information to help direct connections.

20. CLB_GOAL

One important service attribute is:

CLB_GOAL

Connection Load Balancing Goal.

Typical concepts include:

SHORT
LONG

The appropriate setting depends on the workload.

For example:

  • Short transactions may benefit from connection-aware load balancing.
  • Long-running sessions may need different considerations.

Don’t blindly choose a value because it appears in another RAC environment.

21. Runtime Load Balancing

RAC can also provide runtime workload information to applications.

This is related to:

RLB_GOAL

Runtime Load Balancing Goal.

Conceptually:

RAC
 |
 +-- RAC1 → 20% workload
 |
 +-- RAC2 → 80% workload
 |
 ↓
Application receives workload advice

A connection pool can then use this information when selecting an instance.

22. FAN

FAN means:

Fast Application Notification

The basic idea:

RAC1
  X
  |
  ↓
FAN event
  |
  ↓
Application / Connection Pool
  |
  ↓
Stop sending work to RAC1

Without appropriate event handling, an application may continue trying to use a failed instance.

With FAN-aware infrastructure, applications can react much faster.

23. FAN Architecture

Conceptually:

                  RAC
                   |
          +--------+--------+
          |                 |
        RAC1              RAC2
          |
        Failure
          |
          ↓
        FAN
          |
          ↓
 Connection Pool
          |
          ↓
 Stop using RAC1

This becomes especially important in large enterprise applications.

24. Application Continuity

Now we move into a more advanced feature.

Suppose:

Application
     |
     ↓
RAC1
     |
     X

The application may lose its connection.

Application Continuity can allow supported applications to recover certain in-flight requests by replaying them under appropriate conditions.

Conceptually:

Application
     |
     ↓
RAC1
     X
     |
     ↓
RAC2
     |
     ↓
Replay / continue

This can dramatically improve application availability.

But it requires:

  • Compatible application architecture
  • Appropriate Oracle configuration
  • Correct connection pool support
  • Careful transaction semantics

25. Transparent Application Continuity

Transparent Application Continuity, or TAC, builds on the same general objective:

Make applications more resilient to database service failures without requiring extensive application changes.

However, you should not treat TAC as:

“Oracle automatically fixes every failed transaction.”

There are restrictions around:

  • Non-replayable operations
  • External side effects
  • Transaction semantics
  • Application behavior

This needs to be tested with the actual application.

26. Service Failover

Suppose:

SALES_APP

Preferred:
RAC1

Available:
RAC2

If RAC1 fails:

Before:

SALES_APP → RAC1

After:

RAC1
 X

SALES_APP → RAC2

The service is therefore an important unit of RAC availability.

27. Planned Maintenance

Services also help with maintenance.

Suppose you need to patch RAC1.

You can move:

SALES_APP

to RAC2 before maintenance.

Conceptually:

Before:
SALES_APP → RAC1

Maintenance

After:
SALES_APP → RAC2

This can reduce application disruption when the application architecture supports it.

28. Service Relocation

You can relocate a service with:

srvctl relocate service \
  -db PROD \
  -service SALES_APP \
  -oldinst RAC1 \
  -newinst RAC2

Before doing this in production:

srvctl config service \
  -db PROD \
  -service SALES_APP

and confirm the service topology and failover behavior.

29. Checking Service Status

Use:

srvctl status service \
  -db PROD \
  -service SALES_APP \
  -verbose

This can provide more detailed runtime information depending on your 19c version.

30. Service Management Policy

A service can be configured with management behavior such as:

AUTOMATIC
MANUAL

The idea is straightforward.

AUTOMATIC

Clusterware manages service startup according to configuration.

MANUAL

You have more explicit control over when the service is started.

For production application services, automatic management is commonly appropriate, but the correct choice depends on operational requirements.

31. Services and Database Roles

Now consider Data Guard.

You might have:

PRIMARY
   |
   ↓
Standby

Services can be configured according to database role.

For example:

SALES_APP
Role = PRIMARY

The service should normally run only when the database is primary.

After failover:

Old Primary
     ↓
Standby
     ↓
Becomes Primary
     ↓
SALES_APP starts

This is an important concept for RAC + Data Guard architectures.

32. Role-Based Services

You can inspect service configuration with:

srvctl config service \
  -db PROD \
  -service SALES_APP

Look for role-related configuration.

Typical roles include:

PRIMARY
PHYSICAL_STANDBY
LOGICAL_STANDBY
SNAPSHOT_STANDBY

The exact supported options depend on the configuration.

33. RAC + Data Guard Architecture

A mature Oracle architecture can look like:

             Production
          +-------------+
          | RAC PRIMARY |
          |             |
          | RAC1 RAC2   |
          +------+------+
                 |
            Data Guard
                 |
                 ↓
          +-------------+
          | RAC STANDBY |
          |             |
          | RAC1 RAC2   |
          +-------------+

Services then provide the application abstraction:

Application
     |
     ↓
SERVICE
     |
     ↓
Current Primary

This is much cleaner than hard-coding individual database instances.

34. Resource Manager + Services

Now we can combine services with another powerful Oracle feature:

Database Resource Manager

Suppose:

SALES_APP
REPORTING
BATCH

all run on the same database.

You can use Resource Manager to control resource consumption.

Conceptually:

Database
   |
Resource Manager
   |
+-- SALES      → high priority
+-- REPORTING  → medium
+-- BATCH      → controlled

This is extremely useful in mixed OLTP/reporting environments.

35. Services + Resource Manager

This gives us:

Application
     |
   Service
     |
Resource Manager
     |
     ↓
CPU / Parallelism / I/O management

This is much more powerful than simply distributing sessions across RAC nodes.

36. Example Production Architecture

Imagine an insurance database:

PROD
 |
 +-- POLICY_APP
 |
 +-- CLAIMS_APP
 |
 +-- REPORTING
 |
 +-- ETL

Possible service topology:

RAC1                    RAC2

POLICY_APP              CLAIMS_APP
CLAIMS_APP              POLICY_APP

REPORTING               REPORTING
ETL                     ETL

This is only an example.

The actual placement should be driven by:

  • CPU
  • I/O
  • data access
  • GC waits
  • application behavior
  • availability requirements

37. Service Placement and Cache Fusion

Let’s connect this to Part 18.

Suppose:

POLICY_APP → RAC1

and most policy data is accessed by that workload.

Then:

POLICY_APP
     ↓
RAC1
     ↓
Local blocks

Potentially:

Less cross-instance traffic

But if CLAIMS_APP constantly updates the same blocks:

RAC2
  |
  ↓
Same POLICY blocks
  |
  ↓
Cache Fusion

then service separation alone isn’t enough.

You still need to investigate the SQL and data model.

38. Service Placement Is Not a Magic Fix

This is critical.

If you see:

gc current request

and move a service from RAC1 to RAC2 without understanding the workload, you may simply move the problem.

Always measure before and after.

39. Before/After Measurement

Before changing service placement:

SELECT instance_number,
       service_name,
       event,
       COUNT(*) samples
FROM dba_hist_active_sess_history
WHERE sample_time BETWEEN
      :start_time AND :end_time
GROUP BY instance_number,
         service_name,
         event
ORDER BY samples DESC;

After the change, run the same analysis over a comparable workload period.

You want to know:

GC waits ↓ ?
DB time ↓ ?
CPU balanced ?
Application latency ↓ ?

40. Connection Distribution

Check current sessions:

SELECT inst_id,
       service_name,
       COUNT(*) sessions
FROM gv$session
WHERE username IS NOT NULL
GROUP BY inst_id, service_name
ORDER BY service_name, inst_id;

Example:

SERVICE       INST  SESSIONS
------------  ----  --------
SALES_APP       1       220
SALES_APP       2        12
REPORTING       1         5
REPORTING       2        80

This tells you where connections currently live.

But remember:

Session count is not the same as workload.

41. Active Sessions by Service

A better measure:

SELECT inst_id,
       service_name,
       COUNT(*) active_sessions
FROM gv$session
WHERE status = 'ACTIVE'
GROUP BY inst_id, service_name
ORDER BY active_sessions DESC;

Now you see active workload rather than simply connections.

42. DB Time by Service

For historical analysis, ASH can approximate workload by service:

SELECT service_name,
       instance_number,
       COUNT(*) ash_samples
FROM dba_hist_active_sess_history
WHERE sample_time BETWEEN
      :start_time AND :end_time
GROUP BY service_name,
         instance_number
ORDER BY ash_samples DESC;

ASH samples are a powerful way to compare service workload.

43. Service + SQL + Instance

One of my favorite RAC diagnostic queries:

SELECT service_name,
       instance_number,
       sql_id,
       COUNT(*) samples
FROM dba_hist_active_sess_history
WHERE sample_time BETWEEN
      :start_time AND :end_time
AND sql_id IS NOT NULL
GROUP BY service_name,
         instance_number,
         sql_id
ORDER BY samples DESC
FETCH FIRST 50 ROWS ONLY;

This answers:

Which SQL is consuming workload, through which service, on which RAC instance?

44. Service + GC + Object

Now combine everything:

SELECT ash.service_name,
       ash.instance_number,
       ash.sql_id,
       ash.event,
       o.owner,
       o.object_name,
       COUNT(*) samples
FROM dba_hist_active_sess_history ash
LEFT JOIN dba_objects o
       ON o.object_id = ash.current_obj#
WHERE ash.sample_time BETWEEN
      :start_time AND :end_time
AND ash.event LIKE 'gc %'
GROUP BY ash.service_name,
         ash.instance_number,
         ash.sql_id,
         ash.event,
         o.owner,
         o.object_name
ORDER BY samples DESC
FETCH FIRST 50 ROWS ONLY;

This is where our previous parts start connecting.

45. RAC Workload Investigation Model

We now have:

                    APPLICATION
                         |
                       SERVICE
                         |
                +--------+--------+
                |                 |
              RAC1              RAC2
                |                 |
              SQL               SQL
                |                 |
             OBJECT            OBJECT
                |                 |
             BLOCK             BLOCK
                \                 /
                 \               /
                  Cache Fusion
                       |
                    GCS/GES
                       |
                  Interconnect

This is the complete RAC performance chain we’ve been building throughout Parts 17–20.

46. Practical Service Design Example

Let’s design a two-node production RAC.

Nodes

RAC1
RAC2

Applications

OLTP
REPORTING
BATCH

Requirements

OLTP is business-critical.

Reporting can tolerate some delay.

Batch should not consume all CPU during business hours.

Possible design:

OLTP
Preferred: RAC1
Available: RAC2

REPORTING
Preferred: RAC2
Available: RAC1

BATCH
Preferred: RAC2
Available: RAC1

Then Resource Manager can further control:

OLTP     → high priority
REPORTING → medium
BATCH     → limited

47. Why This Is Better

Instead of:

Everything → everything

we now have an intentional architecture:

OLTP
 ↓
RAC1

REPORTING
 ↓
RAC2

BATCH
 ↓
RAC2

with failover capability.

This can improve:

  • Predictability
  • Resource management
  • Troubleshooting
  • Availability
  • Workload isolation

48. But Test Failover

A service configuration isn’t production-ready until you’ve tested failure.

Test:

RAC1 failure

Then verify:

SALES_APP
     ↓
RAC2

Also verify:

Application reconnect
Connection pool
Transactions
FAN
Application Continuity

if those features are part of your architecture.

49. Planned Service Relocation Test

Before maintenance:

srvctl status service \
  -db PROD \
  -service SALES_APP

Then relocate:

srvctl relocate service \
  -db PROD \
  -service SALES_APP \
  -oldinst RAC1 \
  -newinst RAC2

Verify:

srvctl status service \
  -db PROD \
  -service SALES_APP

Then test the application.

Don’t consider the test complete until the application team confirms behavior.

50. What to Capture During the Test

Capture:

Application response time
Connection errors
Active sessions
Service status
Listener status
GC waits
CPU
I/O

For example:

SELECT inst_id,
       service_name,
       COUNT(*)
FROM gv$session
GROUP BY inst_id, service_name
ORDER BY inst_id, service_name;

Then compare before/after.

51. A Senior DBA’s Service Checklist

For every important RAC service, document:

Identity
  • Service name
  • Application
  • Business owner
Placement
  • Preferred instances
  • Available instances
Availability
  • Failover behavior
  • Restart policy
  • Database role
Performance
  • CLB goal
  • RLB goal
  • GC behavior
  • Resource Manager plan
Application
  • FAN support
  • Connection pool
  • Application Continuity
  • TAC where applicable
Operations
  • Start/stop procedure
  • Relocation procedure
  • Failure test
  • Monitoring

52. Service Troubleshooting Script

Here’s a practical starting point:

#!/bin/bash

DB=PROD
SERVICE=SALES_APP

echo "======================================"
echo "RAC SERVICE HEALTH CHECK"
echo "======================================"

echo
echo "SERVICE CONFIGURATION"
srvctl config service \
    -db "$DB" \
    -service "$SERVICE"

echo
echo "SERVICE STATUS"
srvctl status service \
    -db "$DB" \
    -service "$SERVICE"

echo
echo "VIP STATUS"
srvctl status vip

echo
echo "SCAN STATUS"
srvctl status scan

echo
echo "SCAN LISTENER STATUS"
srvctl status scan_listener

echo
echo "CLUSTER STATUS"
crsctl check cluster -all

echo
echo "======================================"

Again, adapt the command syntax to your exact Grid Infrastructure version.

53. Database Service Monitoring Script

SET LINESIZE 220
SET PAGESIZE 100

PROMPT =========================================
PROMPT SESSIONS BY SERVICE AND INSTANCE
PROMPT =========================================

SELECT inst_id,
       service_name,
       COUNT(*) sessions
FROM gv$session
WHERE username IS NOT NULL
GROUP BY inst_id, service_name
ORDER BY service_name, inst_id;

PROMPT =========================================
PROMPT ACTIVE SESSIONS
PROMPT =========================================

SELECT inst_id,
       service_name,
       COUNT(*) active_sessions
FROM gv$session
WHERE status = 'ACTIVE'
GROUP BY inst_id, service_name
ORDER BY active_sessions DESC;

PROMPT =========================================
PROMPT GC WAITS BY INSTANCE
PROMPT =========================================

SELECT inst_id,
       event,
       COUNT(*) sessions
FROM gv$session
WHERE status = 'ACTIVE'
AND event LIKE 'gc %'
GROUP BY inst_id, event
ORDER BY sessions DESC;

54. Production Architecture We Are Building

At this point in the series, our architecture is becoming:

                         USERS
                           |
                           ↓
                         SCAN
                           |
                           ↓
                        SERVICE
                           |
              +------------+------------+
              |                         |
            RAC1                      RAC2
              |                         |
          Workload A                Workload B
              |                         |
             SQL                       SQL
              |                         |
           Objects                   Objects
              |                         |
              +-----------+-------------+
                          |
                     Cache Fusion
                          |
                         GCS
                          |
                    Interconnect
                          |
                     Clusterware

Each layer has a different troubleshooting methodology.

55. What You Should Know After Part 20

You should now understand why:

RAC ≠ simply two Oracle instances

A production RAC architecture is:

Clusterware
+
Network
+
Storage
+
Cache Fusion
+
Services
+
Application
+
Workload Management

And services are the bridge between:

RAC infrastructure

and:

Application workload.

56. The Most Important Lesson

If you remember only one thing from this part:

Do not design RAC services around node names. Design them around business workloads.

For example:

SALES_APP
PAYMENTS
REPORTING
BATCH

are meaningful service boundaries.

Then decide:

Where should they run?
How should they fail over?
How should they be load-balanced?
How much resource should they receive?
How much cross-instance traffic do they generate?

That is RAC workload engineering.

Part 20 Summary

We’ve covered:

  • RAC Services
  • Preferred instances
  • Available instances
  • Service placement
  • Workload locality
  • Connection Load Balancing
  • CLB_GOAL
  • Runtime Load Balancing
  • RLB_GOAL
  • FAN
  • Application Continuity
  • Transparent Application Continuity
  • Service failover
  • Service relocation
  • Role-based services
  • RAC + Data Guard services
  • Resource Manager + Services
  • Service-level ASH analysis
  • Service + SQL + object analysis
  • Production service architecture
Bookmark the permalink.
Loading Facebook Comments ...

Leave a Reply