PHP: APC oder MySQL MEMORY Table für temporären Cache?

mysql_logoBei einem aktuellen Projekt wurde APC eingesetzt um tausende kleinere Variablen zu cachen da es sich nicht lohnen würde diese in einer persistenten Datenbank zu speichern. Da der 30MB große APC Cache jedoch recht schnell voll wurde habe ich ein paar Nachforschungen angestellt, dabei bin ich zu dem Schluss gekommen dass APC für das Speichern von einzelnen kleinen Variablen viel zu viel Speicher verschwendet.

Code - APC Test

Um zu testen wie viele Variablen in den 30 MB großen SHM Cache von APC passen haben ich in einer Schleife wie dieser einfach den ganzen Speicher vollgeschrieben:

$i = 0;
while($i++ >= 0) {
  if(!apc_store('test_'.$i, $i)) {
    echo "Could save $i variables in 30 MB APC Cache\n";
    $i = -1;
  }
}

Das Script hat mir ausgegeben dass rund 151000 Variablen gespeichert werden konnten. Das heißt jede Variable hat rund 207 Byte Speicher verbraucht (!). Dafür dass nur ein simpler Integer gespeichert wurde ist dies verdammt viel.

Alternative: MySQL MEMORY Tabelle

Eine Mögliche Alternative die mir in den Sinn kam war die MySQL MEMORY Engine welche seine Daten im RAM des Computers lässt und keine Schreiboperationen auf der Festplatte ausführt. Diese MEMORY Tabellen sind auch in ihrer Größe beschränkt welche per Default meist bei 16 MB liegt.

Als Tabellenstruktur habe ich etwa folgende gewählt:

CREATE TABLE memory_test (
`user_id` integer(10) NOT NULL,
`user_data` integer(10) NOT NULL
} ENGINE=MEMORY;

Nach dem Einfügen des ersten Datensatzes wir die Tabelle 124 KB groß, doch dies ändert sich bis bei mir aktuell 3300 Einträge nicht. Die MySQL MEMORY Engine scheint Blöcke a 124 KB zu reservieren.
Nach dem Einfügen von 3000 Einträgen ist die Tabelle immernoch 124 KB groß was für mich bedeutet dass in der MEMORY Tabelle ein Datensatz weniger als 40 Byte verbraucht.

Vergleich

Der Vergleich zwischen 207 Byte in APC und < 40 Byte in MySQL MEMORY spricht für sich. Da die Zugriffsgeschwindigkeit in APC und MySQL MEMORY etwa gleich schnell ist sollte man wenn man die Möglichkeit hat MEMORY Tabellen zu benutzen dies auch machen.
Es wäre vielleicht ratsam um die apc_* Funktionen andere Wrapper Funktionen zu schreiben so dass man diese im Fall eines Wechsels von APC zu MEMORY einfach austauschen kann.

Stolpersteine

Es gibt jedoch auch kleine Stolpersteine die rumliegen können:

  • apc_store() bietet es an eine ttl (Time To Live) mitzugeben nach dem der Cache-Eintrag verfallen soll. Dies ist in einer MEMORY Tabelle mit einer extra Spalte mit einem Timestamp zu realisieren welche zwar wieder Speicher verbraucht, aber wir sicherlich immer noch unter den 207 Byte von APC bleiben.
  • Der Zugriff in einer MEMORY Tabelle ist auch ohne INDEX schnell, doch je nachdem wie viele Einträge gespeichert könnte es sinnvoll sein einen Index zu erzeugen welche dann jedoch den Speicherverbrauch der Tabelle schlagartig verdoppelt. Jeder 124 KB Speicherblock hat anscheinend einen weiteren 124 KB Index Speicherblock wenn ein Index benutzt wird.
  • Was jedoch für die Nutzung von MEMORY spricht ist dass der Inhalt einer MEMORY Tabelle nur bei einem MySQL Server Neustart zwangsläufig geleert wird. Der APC Cache wird bei einem Webserver-Neustart geleert.

Nachtrag zu APC

Zwar lassen meine Ausführungen die Nutzung von APC in einem nicht alzu guten Licht darstehen, doch dies spricht nicht gegen eine allgemeine Verwendung von APC da meine Tests sich nur auf das Speichern von Variablen beziehen. Als Opcode Cache ist es hervorragend und bietet dazu noch andere nützliche Funktionen.

Related posts:


 
 
 

2 Kommentare zu “PHP: APC oder MySQL MEMORY Table für temporären Cache?”

  1. stangl 2. September 2009 um 14:30

    ... aber:

    ein mysql-connect kostet sehr viel, ebenso die sql-verarbeitung. mal abgesehen vom speicherverbrauch ist APC-cache gerne 10x schneller als mysql.

  2. Julius 2. September 2009 um 17:11

    MySQL ist sogar 100x langsamer als APC. Hab dazu einen Artikel geschrieben: APC vs. MySQL MEMORY Speed.
    Bei dem mysql_connect lässt sich jedoch mit Persistenten Verbindungen einiges sparen. Dazu ist MEMORY auch eher eine Alternative für Systeme die eh schon eine MySQL Verbindung offen haben, da wäre es gar kein Overhead mehr eine Verbindung aufzubauen.