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…
[...] Exceptionfault Exceptionfaults Blog « Erste Versuche mit Oracle 11g [...]