Magento SOAP-API: Performancetests zum Produkt-Import

Magentos SOAP-Schnittstelle ist Segen und Fluch zugleich: einerseits ermöglicht sie externen Systemen einen einfachen Zugriff auf den Webshop, andererseits sorgt sie bei Entwicklern aufgrund fehlender Funktionalitäten und vor allem der verbesserungsfähigen Performance immer wieder für munteres Hirnwinden. Magento hat neulich angekündigt, in beiderlei Hinsicht nachzulegen (mehr dazu im Ausblick auf Magento 1.5), doch bis dahin muss man mit der aktuellen API auskommen.

Mit Magento 1.4 bietet das Backend die Möglichkeit, das automatische Index-Management zu deaktivieren. Da ich mir immer schon dachte, dass sich die ständige Neuindizierung nicht positiv auf die Geschwindigkeit des Produktimports auswirken kann, war ich gespannt, welche Unterschiede sich durch die neue Option ergeben. Dieses Wochenende habe ich mir schließlich Zeit genommen, um ein paar grundlegende Tests durchzuführen.

Wer auf das Drumherum verzichten will, kann direkt zum Fazit springen. 🙂

[toc levels=3 title=“Inhalt“]

Ziel

Ich wollte die Frage klären:

Wie wirken sich die Aktivierung bzw. Deaktivierung des Caches und des automatischen Index-Managements auf die Geschwindigkeit des Produkt-Imports via SOAP-API aus?

Je nach Hardware-Setup, Konfiguration und Produktdaten sind die Unterschiede natürlich gravierend, weswegen sich aus den Ergebnissen nur Tendenzen ablesen lassen werden.

Setup

Als Hardware musste der folgende Rechner herhalten:

KomponenteSpezifikation
CPUIntel Core2 Q6600 @ 2.40Ghz
RAM4GB DDR2-800
HDDWestern Digital Caviar Blue, SATA II at 7200rpm, Betrieb im RAID1-Verbund

Das Wirtsystem ist Windows XP Professional SP3. Auf diesem laufen Antivirus-Programm und Software-Firewall (ich will mir doch nichts einfangen ;)). Darauf läuft mittels Oracle VM VirtualBox 3.2.10 folgendes Gastsystem:

KomponenteVersion
BetriebssystemDebian 5.0.6 ("Lenny")
virtualisiert mit Oracle VM VirtualBox 3.2.10
WebserverApache 2.2.9
DBMS (Datenbank)MySQL 5.0.51a-24
PHPPHP 5.2.6-1

Dem Gastsystem werden 4 Prozessoren und 1,5 GB RAM zugestanden. Es handelt sich um eine Debian-Standardinstallation mit den aktuellen Stable-Packages. Die Konfiguration von Webserver, Datenbank etc. wurde nicht verändert.

Shop & Daten

Getestet wird Magento 1.4.1.1 in der Version Community Edition. Für den Cache wird das Dateisystem verwendet.

Pro Test werden über die SOAP-API v1 1.000 simple Produkte mit dem Standard-Attributset angelegt. Die Produkte werden zufällig einer von fünf Kategorien zugeordnet. Bilder werden nicht importiert.

Die Produktdaten sind so simpel wie möglich gehalten, damit das Produkt gültig angelegt wird:

ProduktdatenWerte
KategorieZuordnung zu einer von fünf Kategorien
WebsiteZuordnung zur Main-Website
Name"Produktname" (statischer Text)
Kurzbeschreibung"Kurzbeschreibung" (statischer Text)
Beschreibung"Beschreibung" (Statischer Text9
Preis9.99
Gewicht0
LagerverwaltungArray mit den folgenden Werten:
qty: 1
is_in_stock: 1
use_config_manage_stock: 1
Status1 (aktiviert)
SteuerklasseZufällige Zuordnung zu einer der vorhandenen Steuerklassen
SichtbarkeitKatalog, Suche

Ablauf

Vier Konfigurationen werden getestet:

  • Test 01:
    • Cache-Management: Disabled
    • Index-Management: Update on Save
  • Test 02:
    • Cache-Management: Disabled
    • Index-Management: Manual Update
  • Test 03:
    • Cache-Management: Enabled
    • Index-Management: Update on Save
  • Test 04:
    • Cache-Management: Enabled
    • Index-Management: Manual Update

Wie erwähnt werden pro Test 1.000 Produkte über die SOAP-API in Version 1 erzeugt. Die benötigte Zeit wird für jedes Produkt einzeln protokolliert. Nach jedem Testlauf werden die Ergebnisse exportiert und der Sicherungspunkt des Images vor dem Testlauf wiederhergestellt. Damit hat jeder Lauf dieselben Ausgangsbedingungen.

Die Testreihe wurde 2-mal durchgeführt (an unterschiedlichen Tagen, mit Neustart) und die Ergebnisse zusammengeführt. Damit sollten Seiteneffekte, die durch das Wirtsystem entstehen, vermindert werden.

Ergebnisse

TestDurchschnittStandardabweichungMinimum1. QuartilMedian3. QuartilMaximum
Test 011,1330,0830,9321,1081,1371,1562,117
Test 020,8580,0410,7300,8450,8620,8811,094
Test 030,7730,0380,6920,7520,7670,7871,184
Test 040,6110,0540,4940,5570,6320,6440,926

Der Durchschnittswert (= arithmetisches Mittel) zeigt uns: die Optionen bei Cache- und Index-Management wirken sich beträchtlich auf die Geschwindigkeit des Imports aus.

  • In Test 01 ist das Caching deaktiviert und die automatische Indizierung aktiviert. Das Testsystem benötigt 1,133 Sekunden pro Produkt.
  • Bei Test 02 wird die automatische Indizierung deaktiviert. Siehe da, der Import benötigt nur noch 0,858 Sekunden. Das entspricht einem Minus von 24,27 Prozent! Der Import läuft beinahe um ein Viertel schneller ab.
  • Wird wie in Test 03 stattdessen das Caching aktiviert, sinkt die durchschnittliche Zeit auf 0,773 Sekunden. Wir ersparen uns 31,77 Prozent der Zeit, der Import dauert ca. ein Drittel kürzer als bei der Standardeinstellung.
  • In Test 04 kombinieren wir die Einstellung: die automatische Indizierung ist deaktiviert, das Caching aktiviert. Jedes Produkt wurde durchschnittlich in 0,611 Sekunden eingefügt. Wir sparen uns somit 46,07 Prozent der Importdauer – nicht schlecht, wenn man bedenkt, dass die Konfigurationsänderung in einer halben Minute erledigt ist.

Die Standardabweichung zeigt, dass sich die Schwankungen beim Import in Grenzen halten. Wir können uns die obigen Kennzahlen in einem Boxplot ansehen, da die Zahlen so wesentlich anschaulicher werden:

Die Whisker (= Striche) zeigen in diesem Fall den schnellsten bzw. langsamsten Import. Da einzelne Ausreißer (wie z.B. bei Test 01) das Bild dadurch etwas verzerren, orientieren wir uns lieber an den Boxen. Die Box repräsentiert die mittleren 50 Prozent der Produkt-Inserts. In diesem Bereich liegt die Import-Geschwindigkeit die Hälfte der Zeit. Auch hier sieht man, dass das Caching einen größeren Vorteil als die manuelle Indizierung bringt, man aber nach Möglichkeit beide Einstellungen vornehmen sollte. Gerade für den initialen Import bzw. die Entwicklung bietet sich das an.

Fazit

Wir haben getestet, wie sich die Einstellungen des Index- und Cache-Managements in Magento 1.4.1.1 auf den Import simpler Produkte via SOAP-API auswirken. Die wichtigsten Erkenntnisse:

  • Der Import mit manueller Indizierung spart ca. 25% der Zeit.
  • Der Import mit aktiviertem Caching spart ca. 33% der Zeit.
  • Der Import mit manueller Indizierung und aktiviertem Caching spart fast 50% der Zeit.
  • Wenn möglich sollte man beide Einstellungen vornehmen. Das bietet sich v.a. beim initialen Produktimport an, wenn der Shop noch nicht im Livebetrieb ist. Bei der manuellen Indizierung darf man nicht vergessen, nachher die Reindizierung anzustoßen!

Falls jemand von euch ähnliche Tests vorgenommen hat, bin ich sehr an den Ergebnissen interessiert. Wie verhält sich der Import mit realitätsnahen Daten, größeren Datenbeständen und/oder Optimierungen der Server-Konfiguration? Wie groß ist der Unterschied zwischen verschiedenen Magento-Versionen? Da nur Gott weiß, wann ich Zeit für ausführliche Tests finde, wäre es toll, wenn das schon jemand für mich erledigt hat. 😉

24 Antworten

  1. Tim Schwarz sagt:

    Hallo Mathias,
    wir hängen gerade beim einspielen der Attribute auf Artikelebene für jeden einzelnen Store view (Sprache).
    Die Attribute haben wir auf Store view gesetzt und bei der Ansicht im Backend sind diese Werte „Standardwerte verwenden“ immer auf Store views Standart werte verwenden gesetzt. Diese würden wir gerne komplett deaktivieren. Wie können wir dies über Soap API V2 steuern?

    Kannst Du uns hierzu helfen?

    Gruß

    Timo

    • Hallo Timo,

      wenn du unterschiedliche Werte für die Store-Views haben möchtest, musst du für die Store-Views API-Update-Aufrufe machen und die Werte setzen.

  2. Daniel sagt:

    Wenn man die V2 benutzt muss man den WSDL Cache aktivieren seitens Magento.
    Bei der V2 wird die wsdl dynamisch zusammengesetzt und das geht dann stark auf die Performance (bis zu ca. Faktor 15)

    System -> Configuration -> Magento Core Api -> Enable WSDL Cache

  3. David sagt:

    Hallo zusammen,

    man muss schon sagen dass die Magento SOAP-Api (Mage CE 1.7.2) wirklich alles andere als performant ist und sehr zäh im Ablauf ist.

    Wir importieren per Talend ESB aus einer CSV-Datei Kundendaten inkl. einer Adresse je Kunde ins Magento und das ganze dauert trotz aktiviertem Cache und manuellem Index-Update sage und schreibe 6 Sekunden je Kunde = 600 Kunden / Stunde.

    Bei einem Import von 17.000 Kunden beträgt die Importdauer mehr als 28 Stunden…

    Im Talend ESB flow sieht man deutlich, wie der Soap-Aufruf den Datendurchsatz auf 0,17 Kunden je Sekunde herunterdrückt.

    Da fährt man auf die Dauer besser wenn man die Magento SOAP Api sein lässt und sich den Import manuell per SQL zurecht schustert…

    Die Magento-SOAP ist alles andere als Enterprise-tauglich.

  4. Timo Schwarz sagt:

    Hallo,
    haben hier die Lösung zu dem Problem.

    Erst die Attributsets und die Attribute anlegen und befüllen mit folgendem:

    key = „term_merkmal_13“; //Kapazität ah
    $test->value = „88“;
    $additionalAttrs[’single_data‘][] = $test;

    $test2 = new stdClass();
    $test2->key = „term_merkmal_8“; //Länge (mm)
    $test2->value = „35“;
    $additionalAttrs[’single_data‘][] = $test2;

    $result_productID = $client->catalogProductCreate(
    $session,
    $param_type,
    $param_attributSetID,
    $param_productSKU,
    array(
    ‚categories‘ => array(23),
    ‚websites‘ => array(1),
    ’name‘ => ‚Product name‘,
    ‚description‘ => ‚Product description‘,
    ’short_description‘ => ‚Product short description‘,
    ‚weight‘ => ’10‘,
    ’status‘ => ‚1‘,
    ‚url_key‘ => ‚product-url-key‘,
    ‚url_path‘ => ‚product-url-path‘,
    ‚visibility‘ => ‚4‘,
    ‚price‘ => ‚100‘,
    ‚tax_class_id‘ => 0,
    ‚meta_title‘ => ‚Product meta title‘,
    ‚meta_keyword‘ => ‚Product meta keyword‘,
    ‚meta_description‘ => ‚Product meta description‘,
    ‚additional_attributes‘ => $additionalAttrs
    )
    );
    echo „Inserted Product:“.$result_productID.“\n“;
    }

    //CONFIGURATION NEW SERVER
    $mag_wsdl=“http://mydomain/api/v2_soap?wsdl=1″;
    $mag_apikey=“myapikey“;
    $mag_apiPassword=“myapipassword“;

    $client = new SoapClient($mag_wsdl);

    //If somestuff requires api authentification,then get a session token
    $session = $client->login($mag_apikey, $mag_apiPassword);
    echo „MAGENTO API SESSION START:“.$session.“\n“;

    addProducts();

    echo „MAGENTO API SESSION END\n“;
    //If you don’t need the session anymore
    $client->endSession($session);
    ?>

    • Hallo Timo,

      danke, dass du deine Lösung gepostet hast. Ich konnte mir das noch nicht ansehen, da ich im Ausland war. Schön, dass es geklappt hat.

  5. Timo sagt:

    Sorry, Bildlink vergessen: Bildlink

  6. Timo sagt:

    Hallo,
    ich habe eine Frage. Wir haben mit Api V2 Attributesets und Attribute angelegt. Jetzt wollen wir mit dem import der Artikel beginnen und hängen gerade daran, dass wir nicht wissen wie wir den Artikeln die Attributewerte zufügen können.
    Das ganze müssen wir mit ca. 70.000 Artikeln machen.

    Beispiel:

    Artikel XY anlegen -> Attribute zuweisen und diese mit Werten befüllen.

    Artikel:
    Attributeset: Keilriemen

    Attribute im Anhang als Beispielbild.
    Linke Spalte die Attribute (Namen) und Rechts in der Spalte die Werte.
    Die Werte sind ja von Artikel und Artikelart unterschiedlich.

    Habt Ihr damit schon Erfahrung?

  7. Hümmer Markus sagt:

    Hallo ich habe große Problem mit dem URL-Rewrites, ich lege ein konfigurierbares Produkt an und die rewrite funktioniert. Dann lege ich mehrer einfach Produkte aus dem konfigurierbaren Produkt an und ich versuche den Katalog URL neu aufzubauen und bekomme jedesmal den Fehler:
    Ein Fehlter ist beim Speichern des URL-Rewrites aufgetreten.
    Für Hilfe wäre ich sehr dankbar
    Hümmer Markus

  8. Simone sagt:

    Hello, thanks a lot!
    Here is my code…


    $newProductData = array(
    'name' => (string) $prodotto->descrizione,
    'websites' => array(1),
    'short_description' => (string) $prodotto->descrizione,
    'description' => (string) $prodotto->descrizione,
    'price' => (string) $prodotto->prezzo
    );

    try {
    $newProductId = $soap->call($sessionId, 'catalog_product.create', array('simple', $set_id, $codice, $newProductData));
    } catch (SoapFault $e) {
    echo "Product added: " . $e;
    }

    • Hello,
      the problem is that the API example code is somewhat incomplete. The code below should display the product in „Catalog“ > „Manage Products“. Notice that the product still isn’t assigned to a category!

      $productData = array(
          'name'              => 'name of product',
          'websites'          => array(1), // array(1,2,3,...)
          'short_description' => 'short description',
          'description'       => 'description',
          'price'             => 12.05,
          'status'            => 1, // Product is active
          'stock_data'        => array(
              'is_in_stock'   => 1, // In stock
              'qty'           => $qty, // Quantity
          ),
          'tax_class_id'      => 1, // Tax class
          'visibility'        => 4 // Product is visible in catalog and search
      );
      
      try {
          $productId = $proxy->call($sessionId, 'product.create', array('simple', $attributeSetId, $sku, $productData));
          echo "Product inserted: " . $productId;
      } catch (Exception $e) {
          echo "Error: " . $e->getMessage();
      }
  9. Simone sagt:

    Hi guys,
    I saw this interesting article but unfortunately I read it translated with Google Translator… 🙂

    I’ve got an issue using the API to import product and maybe you can help me solve it. I’m using Magento 1.4 and when I use the API to import products, they aren’t added to the normal product catalogue area, but they appear in „TheFind Feed“ menu just under „Catalogue > Products“. Can you share (or send me by email) the code you use to add products using APIs?

    Thanks a lot.

    • Hi Simone,
      which type of products are you trying to add (simple products, configurable, …)? Did you assign the products to a website, a store, a category and so on?
      Maybe it would be easier if you send your code and we try to find the error in it.

      Best regards, Matthias

  10. vansiegmund sagt:

    Hallo Matthias,

    ich bin neu im PHP5 und Magento Umfeld und dein Blog hilft mehr sehr Fahrt aufzunehmen 🙂
    Deine Infos zur Magento Import API sind wirklich gut. Jedoch habe ich eine Frage:

    Wie kann ich die customer group per API in den Shop einspielen?
    Der Hintergrund sind Kundenspezifische Preise via Tier Price.
    Scheinbar geht es in diesem Shopsystem nicht anders Kundenspezifische Artikelpreise abzubilden, als über das matching via Kundengruppe.
    Wird bestimmt der DB-Hammer, wenn ich plötzlich pro Artikel bis zu 10.000 individuelle Gruppenpreise habe 😀

    Gibt es vill. eine bessere Lösung jedem Customer pro Artikel einen individuellen Preis anzubieten?

    Viele Grüße

    • Hallo,

      danke für die Blumen! 🙂

      Ich fürchte, dass du für die Synchronisierung der Kundengruppen eigene API-Aufrufe implementieren musst (einen Einstieg gibt es im Magento-Wiki. Branko Ajzele hat im letzten Jahr angekündigt, die vorhandene API zu erweitern (Projekt mapy [Update Mai 2017: das Projekt ist nicht mehr öffentlich verfügbar]) – du könntest bei ihm nachfragen, ob er das Projekt abseits von git vorangetrieben hat.

      10.000 individuelle Gruppenpreise pro Artikel sind allerdings ein Hammer. 😉 Eine Möglichkeit wäre, die Produkt-Model-Klassen zu erweitern und sich beim Laden bzw. Speichern des Produkts (oder auch bei getPrice(), setPrice() etc.) einzuschalten, um dort den Preis zu manipulieren. Hier kannst du dann eine andere Quelle für die Preise heranziehen oder den Preis berechnen, wenn sich die Preise aus einem fixen Schlüssel ergeben.
      Auf diese Weise kann man die Handhabung der Artikelpreise stark verändern. Wir haben z.B. bei einem Webshop konfigurierbare Produkte mit zahlreichen simplen Produkten als Varianten umgesetzt, wobei jede Variante eigene Staffelungen und Staffelpreise besitzen kann und jeder Preis absolut festgelegt wird (nicht als Aufpreis/Abschlag gegenüber einem Standardpreis). Die Preistabellen werden dann dynamisch möglichst kompakt dargestellt. Für das konfigurierbare Produkt wird ein bestimmter „ab“-Preis als Preis berechnet.

      Möglichkeit 2 wäre, im Hintergrund einen Request für Kunden X und Produkt Y an die Warenwirtschaft zu schicken. Meiner Erfahrung nach können die Wawis so einer Anfragenflut aber normalerweise nicht Herr werden. Der Ansatz ist nur zu überlegen, wenn bei der Preisbildung so viele Spezialfälle vorliegen, dass die doppelte Umsetzung (Wawi und Shop) unverhältnismäßigen Aufwand verursacht.

      Ich hoffe, die Antwort konnte ein wenig helfen. Für Fragen stehe ich natürlich zur Verfügung!

      lg Matthias

      • vansiegmund sagt:

        Hallo Matthias,

        danke sehr für diese Antwort, Sie hat mir sehr geholfen ^^

        Das Thema“ Performancetests zum Produkt-Import“ habe ich ebenfalls ausgiebig behandelt und habe eine Frage zu „manuelle Indizierung und aktivierter Caching“:

        Kann ich sciptseitig via PHP call eine Re-Indizierung nach dem soap Import veranlassen?

        Hintergrund ist, dass ich nächtlich einen Import fahre, zuvor werden alle notwendigen Tabellen per TRUNCATE geleert.

        Hast du diesen Test schon mit der neuen Version 1.5.0.0 etc. durchgeführt?
        Ich werde gleich einen Test fahren 😉
        Bei der Version 1.4 habe ich für 2.640 simple products:

        real 28m57.434s
        user 0m0.560s
        sys 0m1.740s

        benötigt, ist schon mal ein Anfang, trotzdem noch viel zu lang für den Live-Betrieb.

        Danke & Gruß

        • Hallo,

          gerne doch! Tests mit der stabilen Version 1.5 habe ich noch nicht durchgeführt, aber es wird definitiv Zeit dafür. 😉

          Du kannst eine Re-Indizierung über ein PHP-Skript oder direkt über ein Shell-Skript veranlassen.

          Das PHP-Skript:

          getProcessesCollection();
          $processCollection->walk('reindexAll');

          In einem Shell-Skript kannst du shell/indexer.php verwenden:

          # Informationen zur Nutzung des Skripts ausgeben
          /usr/bin/php -f path/to/magento/shell/indexer.php
          
          # Alle Indizes neu aufbauen
          /usr/bin/php -f path/to/magento/shell/indexer.php reindexall
  11. Robert Erlinger sagt:

    Ich habe gelesen, dass in diesem Test nur die V1 der Magento SOAP API verwendet wurde. Gibt es auch einen Test der V2, bzw. ist dafür einer geplant?

    Wäre echt interressant, da wir planen bei einem Projekt die V2 zu nutzen.

    LG,
    Robert

    • Hallo Robert,

      die V2 habe ich nicht mit demselben Skript getestet, das wäre aber sicher einen Test wert. An sich sollten (vor allem mit Caching) keine großen Unterschiede bemerkbar sein, da der Code von V1 und V2 bei der Produkterstellung sehr ähnlich ist.

      lg Matthias

  12. Hallo Witi,

    danke für den Tipp! Das machen wir bisher nicht, klingt interessant und testenswert. Die Alpha von 1.5.0.0 steht auch schon unmittelbar vor der Tür – wer weiß, vielleicht hat sich das leidige Thema dann bald einmal erledigt. 😉

    lg Matthias

  13. Witi sagt:

    Hallo,

    einen Performancetipp hätte ich für dich: Parallele SOAP-Anfragen.

    Wir fahren in einem Projekt bis zu acht parallele SOAP-Requests an Magento. Läuft erstaunlich gut. Steigert bemerkenswert die Performance, die Last des Servers geht allerdings logischerweise hoch.

    In den parallelen Request sollte man allerdings keine unterschiedlichen Operationen (z.B. Produktattribute und Staffelpreise des Produktes aktualisieren) an einem Produkt durchführen. Das hat in einigen seltenen Fälle zu „duplicate keys“ Fehlern bei INSERT-Statements geführt.

    VG Witi

  1. 14.11.2010

    […] This post was mentioned on Twitter by Webmaster Blog, LimeSoda. LimeSoda said: Blogpost von Matthias: Magento SOAP-API: Performancetests zum Produkt-Import – http://ow.ly/39wyi #limesoda […]