Erste Versuche mit Oracle 11g

Auch ich komme natürlich nicht umhin mich ein bisschen in das neue Oracle Release 11g einzuarbeiten und ein paar der zahlreichen neuen Features zu testen. Mein erstes Interesse galt dem Database Resident Connection Pooling, kurz: DRCP. Oracle implementiert hiermit eine dritte Variante der “Verbindungsoptionen” neben SHARED Server und DEDICATED Server. Der DRCP stellt ein Datenbank basiertes Connection Pooling zur Verfügung und soll damit insbesonders verbindungslose Webapplikationen wie PHP beschleunigen, da aufwendige Connects wegfallen. Ausserdem sollen Resourcen geschont werden, da Verbindungen wiederverwendet werden können.

Das Dokument “PHP Scalability and High Availability” beschreibt z.B. dass bei 5000 Connections anstatt 21GB Speicher mit DEDICATED Server nur 610MB mit DRCP benötigt werden. Durchaus ein Grund sich DRCP etwas genauer anzuschauen…

Die Konfiguration

DRCP wird automatisch mit der Datenbank mitinstalliert, jedoch nicht aktiviert. Netterweise genügt ein einfaches “execute dbms_connection_pool.start_pool;” als user SYS um das Connection Pooling zu aktivieren. Wichtig ist, dass auch der Client beim Connect die Option “POOLED” verwendet. Ich habe mir zu Testzwecken zwei annähernd identische TNSNAMES.ORA Einträge erstellt. Einer verwendet DEDICATED Server, die ander POOLED.

ORADEV =
   (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = schulung-vm)(PORT = 1521))
   (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = ORADEV.XX.LIDL.NET)
   )
)
ORADEV_POOL =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = schulung-vm)(PORT = 1521))
   (CONNECT_DATA =
      (SERVER = POOLED)
      (SERVICE_NAME = ORADEV.XX.LIDL.NET)
   )
)

Die erste Auffälligkeit nach dem Connect über DRCP zeigt sich in der View V$SESSION. Während über DEDICATED Server folgende Informationen bereitstehen

User    MACHINE     OSUSER  Program       SID  Serial Proc
------- ----------- ------- ------------ ---- ------- -----
SYSTEM  INT-PC3022  habel   sqlplus.exe   136      29 1660

findet sich beim connect über DRCP nur

User    MACHINE      OSUSER  Program              SID  Serial Proc
------- ------------ ------- ------------------ ----- ------- -----
SYSTEM  SCHULUNG-VM  SYSTEM  ORACLE.EXE (L002)    136      15 416

INT-PC3022 ist der Rechner von dem aus ich mit SQL*Plus teste, SCHULUNG-VM ist der virtuelle Server, auf dem die Datenbank läuft. Auch der OSUSER und das PROGRAM die bei DRCP angegeben werden zeigen, dass keine direkte Verbindung mehr in die Datenbank besteht, sondern ein vorgelagerter Prozess die Session geöffnet hat. Dies lässt sich auch durch die Spalte Proc beweisen, welche die System Prozess ID (SPID aus V$PROCESS), also die Prozess# unter Unix oder die Thread ID unter Windows enthält. Bei DEDICATED Server ändert sich die Proc bei jedem Connect, da jedesmal ein neuer Thread (ich bin auf Windows) gestartet werden muss. Mit DRCP bleibt die Proc und somit auch der Thread erhalten.

Wenn der Connection Pool nun aber Sessions wiederverwendet, wie verhält sich dann mein Session State? Also was machen Sequences, Package Variablen oder Temporäre Tabellen?

TEST @oradev_pool> create global temporary table test ( id number ) on commit preserve rows;

Table created.

TEST @oradev_pool> select  s.sid, s.serial#, p.spid
2  from    v$session s join v$process p
3  on      s.paddr = p.addr
4  where   s.sid = SYS_CONTEXT('USERENV', 'SID');

SID  Serial Proc
----- ------- -----
146      30 2032

1 row selected.

TEST @oradev_pool> insert into test values ( 1 );

1 row created.

TEST @oradev_pool> commit;

Commit complete.

TEST @oradev_pool> select * from test;

ID
---------------
1

1 row selected.

TEST @oradev_pool> conn test/test@oradev_pool
Connected.

TEST @oradev_pool> select  s.sid, s.serial#, p.spid
2  from    v$session s join v$process p
3  on      s.paddr = p.addr
4  where   s.sid = SYS_CONTEXT('USERENV', 'SID');

SID  Serial Proc
----- ------- -----
146      34 2032

1 row selected.

no rows selected

TEST @oradev_pool>

Das Beispiel zeigt, dass durch ein Reconnect die Temporary Table geleert wurde.

TEST @oradev_pool> create sequence sq;

Sequence created.

TEST @oradev_pool> select sq.nextval from dual;

NEXTVAL
---------------
1

1 row selected.

TEST @oradev_pool> conn test/test@oradev_pool
Connected.
TEST @oradev_pool> select sq.currval from dual;
select sq.currval from dual
*
ERROR at line 1:
ORA-08002: Sequenz SQ.CURRVAL ist in dieser Session noch nicht definiert

Auch hier bleibt das Verhalten wie erwartet und völlig transparent für die Applikation.

create or replace package tp
is
n_id number;
procedure set_number( id number );
function get_number return number;
end;
/

create or replace package body tp
is
procedure set_number( id number ) is
begin
n_id := id;
end;

function get_number return number is
begin
return n_id;
end;
end;
/

TEST @oradev_pool> exec tp.set_number(5);

PL/SQL procedure successfully completed.

TEST @oradev_pool> select tp.get_number from dual;

GET_NUMBER
---------------
5

1 row selected.

TEST @oradev_pool> conn test/test@oradev_pool
Connected.
TEST @oradev_pool> select tp.get_number from dual;

GET_NUMBER
---------------

1 row selected.

Selbst der Zustand von PL/SQL Variablen in Packages wird mit einer neuen Session zurückgesetzt. Ein Verhalten, mit dem allerdings die wenigsten Applikationen rechnen ist folgendes:

TEST @oradev_pool> conn test/test@oradev_pool
Connected.
TEST @oradev_pool> -- an dieser Stelle hole ich mir einen Kaffee

TEST @oradev_pool> select 1 from duaL;
select 1 from duaL
*
ERROR at line 1:
ORA-03113: Unerwartetes Übertragungsende in Kommunikation
Prozess-ID: 2032

Was ist passiert? Ein Blick in die neue 11g View DBA_CPOOL_INFO bringt Licht ins Dunkel:

TEST @oradev_pool> select status, minsize, maxsize, INACTIVITY_TIMEOUT from DBA_CPOOL_INFO;

Status            MINSIZE         MAXSIZE INACTIVITY_TIMEOUT
--------- --------------- --------------- ------------------
ACTIVE                  4              40                300

DRCP unterstützt ein konfigurierbares INACTIVITY_TIMEOUT. D.h. ist eine Session länger als 300 Sekunden untätig wird sie getrennt. Dies sollte im Falle einer PHP Anwendung nicht auffallen, denn wer möchte denn schon 300 Sekunden und mehr auf eine Webseite warten? Wird DRCP allerdings im Application Server Umfeld oder z.B. bei Ruby on Rails verwendet, ist dies durchaus ein Punkt den man beim Applikationsdesign beachten sollte.

Nun aber zur spannensten Frage: Wieviel Performance bringt mit DRCP beim Verbindungsaufbau?

Mein Testszenario ist in Ruby geschrieben. 1000 Connects mit jeweils einem SELECT SYSDATE FROM DUAL.

require 'rubygems'
require 'oci8'

start_time = Time.now
for i in 1 .. 1000
db = OCI8.new("test", "test", "oradev")
db.exec("SELECT SYSDATE FROM DUAL")
db.logoff
end
end_time = Time.now

puts end_time - start_time
1000 Connects ohne Session Pooling:	30.406
1000 Connects mit Session Pooling:     111.39

Hä? Sollte es nicht genau anders herum sein? Warum dauert es über den Connection Pool annähernd 4 mal länger?

Die Antwort lieferte mir die View V$CPOOL_CC_STATS.

SYSTEM @oradev_pool> select NUM_REQUESTS, NUM_HITS, NUM_MISSES from V$CPOOL_CC_STATS;

NUM_REQUESTS        NUM_HITS      NUM_MISSES
--------------- --------------- ---------------
2009               0            2009
2               0               2

Von 2000 Connect Versuchen konnte keine Session wiederverwendet werden. Grund hierfür ist das OCI Flag “PURITY” welches per Default auf “NEW” steht und sich durch SQL*Plus auch nicht ändern lässt. Auch andere Blogs kamen zu der Erkenntins, dass SQL*Plus wohl nicht das richtige Werkzeug zum Test von DRCP ist…

Schlagworte: , , , , ,

1 Kommentar zu „Erste Versuche mit Oracle 11g“

  1. [...] Exceptionfault Exceptionfaults Blog « Erste Versuche mit Oracle 11g [...]

Kommentieren