PHP-Entwicklung

PHP-Entwicklung

Posts 1-10 of 12
  • Ulf Wendel
    Ulf Wendel    Premium Member
    The company name is only visible to registered members.
    Ich würde es begrüßen, wenn die MySQL-Extensions automatisch Master-Slave Splits machen....
    .... stimmt jemand der Aussage zu?

    Sollte die Applikation oder der Datenbanktreiber entscheiden welche Query in einem MySQL Replikationssetup an den Master und welche an einen von den Slaves gehen sollte?

    Grüße,
    Ulf
  • Sascha Schumann
    Sascha Schumann    Premium Member
    The company name is only visible to registered members.
    Re: Ich würde es begrüßen, wenn die MySQL-Extensions automatisch Master-Slave Splits machen....
    Nach welcher Logik würde das denn funktionieren?

    Ich frage deswegen weil die Policy dafür ja beliebig komplex werden kann.

    Viele Grüße
    - Sascha
  • Ulf Wendel
    Ulf Wendel    Premium Member
    The company name is only visible to registered members.
    Re^2: Ich würde es begrüßen, wenn die MySQL-Extensions automatisch Master-Slave Splits machen....
    Moin Sascha,

    die Modalitäten der Entscheidungsfindung sind "wie immer". Entweder es ist ein einfaches Replikationssetup, welches automatisch abgedeckt werden kann oder die Anwendung implementiert die Entscheidungsfindung, da nur die Anwendung weiß wie das komplexe Setup zu verwenden ist. Ich kenne keinen Weg außer "Callbacks", um Wissen der Anwendung in den Treiber zu übertragen. In irgendeiner Form muß die Anwendung die Entscheidungsfindung übernehmen.

    In einem ersten Schritt, in einem Prototypen, der nur einen Master (nicht mehrere) abdeckt, könnte folgendes umgesetzt werden:

    a) Automatische Anfrageerkennung

    - Einfacher Anfrage Tokenizer/Parser im Treiber lenkt alle SELECT auf die Slaves
    - Einfacher Anfrage Tokenizer/Parser im Treiber lenkt alles, was kein SELECT ist, auf den Master

    - konfigurierbare Verteilung über die Slaves: Zufall, Round-Robin, benutzerdefiniert, ...

    - Unterstützung von SQL-Hints zur Überstimmung der automatischen Verteilung, um:
    -- gezielt Leseanfragen auf dem Master auszuführen
    -- gezielt Schreibsequenzen, etwa für temporäre Tabellen, auf einem Slave auszuführen
    -- CALL auf den Slaves ausführen zu können
    -- SET @myvar, PREPARE stmt, ... Sequenzen auf einem Server zu halten

    (Anstelle der SQL-Hints könnten auch API-Calls angeboten werden. Es ist eine Frage der Transparenz der Erweiterung, vielleicht sogar eine Frage des Geschmacks, wie die Funktionälität angesteuert wird.)


    b) Manuelle Anfrageerkennung und Verteilung

    Benutzerdefinierter Callback: string host pick_server(string query, list slaves, list master)
    Zugriff auf eingebauten Tokenizer/Parser: bool is_select(string query)

    Du kannst natürlich Master-Slave/Replikation gegen Sharding austauschen. Dies würde Umfang und Einsatzgebiet nennenswert vergrößern. Auf Treibersicht wäre die Aufgabe sehr ähnlich. Master-Slave/Replikation ist jedoch ein schöner, griffiger Aufhänger sich Größerem zu nähern. Und M/S hat genügend Fallstricke...

    Ulf
  • Post visible to registered members
  • Ulf Wendel
    Ulf Wendel    Premium Member
    The company name is only visible to registered members.
    Re^4: Ich würde es begrüßen, wenn die MySQL-Extensions automatisch Master-Slave Splits machen....
    Hallo Wolf,

    es gibt Entwickler in anderen Sprachen, die geradezu verliebt sind in die Vorstellung eines Treibers, der Master-Slave Load Balancing übernimmt. Mich interessiert die Rückmeldung aus der PHP-Praxis, weil ich selbst keine PHP-Anwendungen mehr entwickle oder betreue.

    Alles, was der Treiber automatisch machen könnte, könnte auch die Applikation erledigen. Ist die Funktionalität jedoch bereits im Treiber implementiert, dann erspart dies dem Applikationsentwickler Arbeit. Bei einfachen M/S-Szenarien ist eine treiberbasierte Lösung eine ernsthafte Arbeitserleichterung. Das Wort "einfach" ist eine akzeptable Einschränkung für mich, da die Implementierung der treiberbasierten Lösung ebenfalls als "einfach" zu bezeichnen ist. In Teilbereichen, wie dem Tokenizen/Parsen von SQL-Anfragen ist eine C basierte, treiberintegrierte Lösung Ansätzen überlegen, die versuchen SQL in und mit PHP zu parsen.

    Zum Problem.

    Nimm ein einfaches M/S-Szenario. Die Anwendung sei aufgrund des Schreib-/Leseverhältnisses für M/S-Replikation qualifiziert. Die Anwendung wird beliebt, die Last steigt. Replikation kommt zum Einsatz. Zwei Slaves werden eingefügt. Treiberbasierte Logiken übernehmen den M/S-Split. Der Einsatz der treiberbasierten Lösung erfolgt mittels:

    a) Laden der treiberbasierten Lösung ... = Extension in der php.ini eintragen, Extension aktivieren
    b) Konfiguration der M/S Maschinen ... = Konfigurationsdatei schreiben

    Fertig. M/S-Skalierung abgeschlossen. Keine Applikationsanpassung, nicht mal den im Connect eingetragenen Hostnamen ändern? Nein, nicht unbedingt. Die Konfigurationsdatei der treiberbasierten Lösung kann eine Regel enthalten, welche den bisherigen Hostnamen als Index zur Auswahl der in der Konfigurationsdatei beschriebenen M/S-Server verwendet. Aus einer Verbindung zu "localhost", "myhost.mysystem.mycom", "12.345.78.90" wird automagisch ein M/S-Zugriff. Nicht eine Zeile .php wurde angefasst.

    Die Einrichtung des PHP-Teils dauert 10 Minuten. Danach hast Du 10 Tage Zeit den Kunden zu überzeugen, daß er eine viel bessere M/S-Lösung braucht und bezahlen soll bei der die Anwendung den M/S Split macht.

    Ulf
  • Harald Lapp
    Harald Lapp    Premium Member
    The company name is only visible to registered members.
    Re^4: Ich würde es begrüßen, wenn die MySQL-Extensions automatisch Master-Slave Splits machen....
    Hallo beisammen,

    wir haben eine Master-Slave Verteilung php-seitig in unser Framework eingebaut, wobei keine automatische Steuerung durch das Framework erfolgt, sondern für jeden Fall einzeln bestimmt wird, welche Verbindung benötigt wird -- das funktioniert im Grossen und Ganzen wunderbar. Hierfür haben wir einen einfachen "Pool" implementiert, der die einzelnen Verbindungen verwaltet und dafür sorgt, dass Verbindungen wiederverwendet werden können und die Slaves per Zufall ausgewählt werden.

    Für ein älteres Projekt, bei dem die Code-Basis keine komplexeren Eingriffe in die Datenbankschicht zuliess, haben wir hierfür seit Jahren erfolgreich den MySQL-Proxy + Lua im Einsatz -- wobei man hier dann halt eine zusätzliche Abhängigkeit hat, die Fehlerquelle sein kann.

    Von daher finde ich den Ansatz den Treiber entsprechend zu erweitern um derlei Dinge darüber abwickeln zu können durchaus interessant -- so lange dort nichts automatisch entschieden wird, denn das geht mit ziemlicher Sicherheit in die Hose. Ist halt auch die Frage, wie komplex das ganze am Ende wird und welcher Konfigurationsaufwand damit verbunden ist ... ?

    gruss,

    harald
  • Ulf Wendel
    Ulf Wendel    Premium Member
    The company name is only visible to registered members.
    Re^5: Ich würde es begrüßen, wenn die MySQL-Extensions automatisch Master-Slave Splits machen....
    Hallo Harald,

    danke für die Rückmeldung! Ein paar Worte aus der Praxis sind genau das, wonach ich suchte.

    Automagische Entscheidungen können, müssen jedoch nicht passieren bei einer treiberbasierten Lösung. Desto komplexer die Verteilung, desto größer die Anspruche an die Verwaltung des Connection-Pools, desto größer müssen die Möglichkeiten sein eingebaute Algorithmen zu überstimmen.

    Du schreibst, daß MySQL Proxy und Lua in einem Projekt verwendet wurden. Das Lua des MySQL Proxy verhält sich wie ein Callback (siehe oben, Antwort an Sascha, "b) Manuelle Anfrageerkennung und Verteilung") zum Treiber[plugin]. Der Ansatz ist derselbe. Im Gegensatz zum Einsatz des MySQL Proxy bleibt es jedoch bei einer Programmiersprache: PHP. Natürlich sind mit dem Wechsel von MySQL Proxy zum Treiber noch andere strukturelle Änderungen verbunden: "nur" PHP-Änderungen und kein neues Produkt in Form von MySQL Proxy, Lastkonzentration auf dem Client im Treiber zur hoizontalen Skalierung per Client usw.

    Die Installation/Konfiguration habe ich in der Antwort an Wolf skizziert. Die Antwort ist wortlich zu nehmen. Hier noch einmal etwas weiter ausgeschrieben.

    - Schritt 0: myplugin.so|dll besorgen -

    ;-)

    - Schritt 1: php.ini -

    php.ini:

    extension = myplugin.so|dll
    myplugin.enabled=1
    myplugin.ini_file=myplugin_config.ini

    - Schritt 2 - config schreiben -

    myplugin_config.ini:

    [php_forum]
    master[] = <master_host>
    slave[]=<slave1_host>
    slave[]=<slave2_host>
    pick[]=random

    [my_super_app]
    master = <another_master_host>
    slave[]=<slave1_host>
    slave[]=<slave2_host>
    slave[]=<slave3_host>
    pick[]=user,roundrobin

    - Schritt 3 - die Minimalkonfiguration (siehe Antwort an Wolf) -

    Einsatz von M/S ohne Applikationsanpassung, ggf. temporäre Lösung. Statt "php_forum" könnte in der Config auf eine IP oder ein Hostname stehen, was dann ggf. keinerlei Anpassung der Applikation erfordert.

    mysqli_connect("php_forum", $user, $passwd, ...)
    mysql_connect("php_forum", $user, $passwd, ...)
    new PDO("mysql:host=php_forum;...")

    Fertig.

    - Schritt 3 - mit Eingriff in die Verteilungslogik (die Harald/Sascha/...-Bedenken) -

    php.ini:
    auto_prepend=myprepend.php

    myprepend.php:

    myplugin_register_callback("pick_server");
    function pick_server($query, $slaves, $master) {
    $is_select = myplugin_is_select($query)
    if (stristr($query, "<something that needs master x>"))
    return "master_x_hostname";
    else
    /* fallback to default, built-in logic using round-robin as configured */
    return ""
    }

    Und die obligatorische Hoständerung in der Applikation:

    mysqli_connect("my_super_app", $user, $passwd, ...)
    mysql_connect("my_super_app", $user, $passwd, ...)
    new PDO("mysql:host=my_super_app;...")


    .... ich würde sagen, es dauert keine 10 Minuten die Sachen aus der README zu kopieren und ein Grundkonfiguration zu basteln.

    Ulf
  • Ulf Wendel
    Ulf Wendel    Premium Member
    The company name is only visible to registered members.
    Re^6: Ich würde es begrüßen, wenn die MySQL-Extensions automatisch Master-Slave Splits machen....
    ... nachdem die Idee durchsickert: was soll so ein Ding minimal können, damit es qualifiziert ist in einem Funprojekt am Creative-Friday (ach, wie schön sind doch diese Worte ;-)) bespielt zu werden?
  • Robert Eisele
    Robert Eisele    Premium Member
    The company name is only visible to registered members.
    Re: Ich würde es begrüßen, wenn die MySQL-Extensions automatisch Master-Slave Splits machen....
    Hi Ulf,

    die Idee den M/S-split im Treiber zu erledigen ist ansich recht nett, nur würde ich an der Stelle nicht nur versuchen die Replikation von der Applikation zu trennen, sondern auch größere Setups durch integriertes Sharding auf dem Client abfangen.

    Ich habe meine "Datenbankklasse"/Datenabstrahierung vor einer Weile veröffentlicht, wie ich sie in diversen Projekten (meistens etwas angepasst) verwende: http://www.xarg.org/2010/11/transparent-query-layer-for-mysq...

    Den read/write split habe ich allerdings durch 2 seperate Methoden implementiert. Durch ein parameter-binding ähnliches Interface, besteht die Möglichkeit "transparent" befehle über einen Callback zu übermitteln. Ich habe intern auch eine connection-queue, die nach read/write unterscheidet und nach folgenden Prinzip verwendet wird:

    Jeder Write geht immer auf alle, durch das Callback-Interface in Erfahrung gebrachten, Master. So werden z.B. Benutzernachrichten untereinander automatisch auf verschiedene Cluster-Master verteilt ohne das der Anwendungsprogrammierer sich einen Kopf darüber machen muss, wo die einzelnen User verteilt liegen. Umgedreht bei den Selects, wird versucht die 1. offene read-Verbindung zu nehmen. Durch die natürliche verteilung ergibt sich so automatisch auch gleich der Lastausgleich. Wobei man natürlich auch einen Callback für einen Scheduler implementieren könnte: RR, WRR, ... Fehlt eine Verbindung zum Lesen oder Schreiben wird sie aufgebaut und für weitere Queries aufbewahrt.

    Ich wollte die Klasse evtl. noch als mysqlnd-Plugin entwickeln, sitz aber momentan an einer wichtigeren PHP-Erweiterung. Aber vielleicht hat sich das bald erledigt, wenn du einige der Ideen aufgreifst. Was das Parsen angeht, finde ich prinzipiell nicht verkehrt um eine Vorauswahl zu treffen auf welche Seite die Query nun gehen soll (M oder S). Wenn man sich die Mühe macht und die Query auf dem Client schon zerlegt, könnte man evtl sogar folgendes noch zurecht biegen und eine normale Query in ein prepared Statement umwandeln, damit Traffic und Parse-Zeit gespart wird: http://www.xarg.org/2011/01/is-it-possible-to-avoid-query-pa...

    Würde es Hint's für die Queries geben, wäre das eigentlich genug um weitere Entscheidungen treffen zu können. Nur wie gesagt, käm das für mich nicht in Frage, da ich durch das besagte Callback-Interface versuche eine Zwischenschicht noch einzuschieben, die den Entwicklungsprozess gleich mit erleichtern soll.

    Wenn es sich wirklich nicht vermeiden lässt, hat man manchmal damit zu kämpfen, einen Wert gerade geschrieben sofort in Kombination mit anderen Werten wieder zu lesen zu müssen. Vorallem wenn Trigger involviert sind, die Agregate pflegen. Dann wäre es wirklich notwendig auch von einem gezielten Master zu lesen. Oder stellst du dir das Setup sowieso recht einfach vor, mit einem Master+n Slaves? Was ist mit MMM-Setups? Oder sollte ein Master nicht pauschal auch immer ein Slave darstellen? Schreiben müssen sie schließlich alle und das Binlog kann man zu Not auf eine andere Platte legen um die Schreiblast von der Hauptplatte zu nehmen.

    Ich hoffe, ich habe etwas helfen können bei der Entscheidungsfindung.

    Gruß
    Robert
  • Ulf Wendel
    Ulf Wendel    Premium Member
    The company name is only visible to registered members.
    Re^2: Ich würde es begrüßen, wenn die MySQL-Extensions automatisch Master-Slave Splits machen....
    Vielen Dank, Robert!

    Der Proof-of-Concept (PECL/mysqlnd_ms) unterstützt einfache SQL-Hints: benutze (irgendeinen) Slave, benutze (den) Master, benutze den zuletzt verwendeten Server. Dein Schreibzugriff mit sofortigem Lesezugriff auf die geschriebenen Daten würde beispielsweise mit einer Sequenz USE_MASTER - INSERT, LAST_USED - SELECT, LAST_USED SELECT .... erzielt werden.

    PECL/mysqlnd_ms ist ein Proof-of-concept. Der Funktionsumfang ist beschränkt. Multi-Master ist nicht unterstützt. Es unterstützt die Syntax mehrere Master zu konfigurieren aber der 2...n-Master wird nie angesprochen. Ich mag mich nicht so recht mit dem Thema befassen, weil Anwender, die mehr als einen Master benutzen für mich zu den Power-Usern zählen, die eine 1.0 nur mit dem Wort "benutzerdefiniert" bedienen kann. Mir fehlt die Idee wie Multi-Master standardmäßig unterstützt werden sollte.

    Der PECL/mysqlnd_ms Proof-of-concept ist dazu da zu schauen was man alles im mysqlnd-Plugin machen muß, um Replikation zu unterstützen. Das betrifft sowohl die gewünschten Funktionen aus Benutzersicht als auch die Machbarkeit im Rahmen eines Plugins. Beispielsweise: wie transparent kann das Plugin sein (affected rows, ping, insert id, warning count, Transaktionen, SQL Modes, Charsets = Sicherheit, ...)

    Sind Master auch Slaves? Andrey hat es anfangs so gesehen. Für kleine Setups sicherlich eine interessante Frage. Es sollte konfigurierbar sein.

    Die größten "Sorgen" bereitet mir im Moment die Verwaltung des Connection-Pools. Lazy connect und persistente Verbindungen auf mysqlnd-Ebene stehen auf meiner Wunschliste für einen sauberen Unterbau. Danach "benutzerdefiniert" und "Callback" ausformulieren, damit die werte Nutzerschar das Spielzeug frühzeitig zerlegen kann.

    Grüße,
    Ulf