Frage zur Lastverteilung/Replikation mit MySQL

MySQL, PostgreSQL, SQLite
julia
Posts: 27
Joined: 2008-03-04 19:12

Frage zur Lastverteilung/Replikation mit MySQL

Post by julia » 2008-07-08 21:47

hi

ich habe vor in nächster zeit eine klassische master-slave-replikation mit mysql aufzubauen. dabei stellt sich mir allerdings eine frage zu der ich leider in der dokumentation keine antwort finde.

grundlage ist ein ganz normales forum (zb. wie dieses hier). angenommen ein user schreibt einen beitrag, sendet diesen beitrag ab und und wird direkt danach auf den thread weitergeleitet, in dem er gerade geantwortet hat. kann es dann nicht sein, dass der thread aus der datenbank des slaves geholt wird, der slave den beitrag des users allerdings noch garnicht vom master repliziert hat? d.h. kann es passieren, dass der user seinen eigenen beitrag nicht sieht (bzw. erst nach einem reload ein paar sekunden später)? und gibt es dafür irgendwelche gegenmittel?

freddy36
Posts: 273
Joined: 2008-03-20 17:31

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by freddy36 » 2008-07-08 22:21

Guck da mal unter dem Stichwort "replication lag".
Gibt verschiedene Ansätze.

julia
Posts: 27
Joined: 2008-03-04 19:12

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by julia » 2008-07-09 02:54

ok danke, das hilft mir schonmal weiter!

eine andere frage hab ich zu diesem thema noch:
bei welchem verhältnis von read- und write-queries macht eine replikation sinn und wann nichtmehr? gibt es da eine faustformel?

so sehen die aktuellen werte aus:
73% select
10% change db (was ist das eigentlich genau? der verbindungsaufbau zur datenbank mit mysql_connect()? wäre dann auch ein read-query, oder?)
12% update
4% insert
<1% delete

User avatar
daemotron
Administrator
Administrator
Posts: 2635
Joined: 2004-01-21 17:44

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by daemotron » 2008-07-09 07:56

Faustformel kenne ich keine, aber wenn die schreibenden Queries mehr als den n-ten Teil der Last erzeugen (bei n Servern und schreiben nur auf dem Master) hast Du ein Ungleichgewicht. Das kannst Du teilweise durch vertikale Skalierung (größerer Master) ausgleichen, aber irgendwo kommt dann der Punkt, aber dem Du nicht mehr an einer asynchronen Lösung mit verteiltem Schreibbetrieb vorbeikommst.

In Deinem Fall würde ich sagen, dass dieser Fall nicht eingetreten ist. Aber da nur relative Werte angegeben sind, kann es natürlich sein, dass Dein Master schon mit den knapp 20% Schreibaktivität am Limit oder überfordert ist...

julia
Posts: 27
Joined: 2008-03-04 19:12

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by julia » 2008-07-10 07:19

ok danke

nächste frage:
wo und wie löst man denn am besten die auswahl auf welchen slave eine anfrage gesendet wird? ein hardware loadbalancer ist nicht vorhanden.

User avatar
isotopp
Posts: 471
Joined: 2003-08-21 10:21
Location: Berlin

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by isotopp » 2008-07-10 09:19

julia wrote:hi

ich habe vor in nächster zeit eine klassische master-slave-replikation mit mysql aufzubauen. dabei stellt sich mir allerdings eine frage zu der ich leider in der dokumentation keine antwort finde.

grundlage ist ein ganz normales forum (zb. wie dieses hier). angenommen ein user schreibt einen beitrag, sendet diesen beitrag ab und und wird direkt danach auf den thread weitergeleitet, in dem er gerade geantwortet hat. kann es dann nicht sein, dass der thread aus der datenbank des slaves geholt wird, der slave den beitrag des users allerdings noch garnicht vom master repliziert hat? d.h. kann es passieren, dass der user seinen eigenen beitrag nicht sieht (bzw. erst nach einem reload ein paar sekunden später)? und gibt es dafür irgendwelche gegenmittel?



http://acmqueue.com/modules.php?name=Co ... 540&page=1

"BASE: An ACID Alternative" is an article by Dan Pritchett, eBay from the ACM queue. It is a good introduction to basic horizontal scaling architectures.

Why you should read this:

The article explains architectural patterns that scale better than ACID and two phase commit while over time giving the same guarantees regarding consistency. Applying these ideas you will be able to write code that scales better.




http://www.allthingsdistributed.com/200 ... #trackback
Eventually Consistent

Why you should read this:

The article defines important vocabulary that is used to describe properties of weakly or eventually consistent systems.


Beide Artikel diskutieren genau Dein Problem, auch wenn das auf den ersten Blick unter Umständen nicht sofort offensichtlich ist - Dein Problem ist ein größeres, nämlich das, daß Du entweder ein konsistentes System haben kannst (dann tritt die von Dir beschriebene Situation nicht auf), das häufiger ausfällt oder daß Du ein System haben kannst, das höher verfügbar ist, das dann aber unter Umständen sichtbare Phasen von Inkonsistenz haben kann (so wie Du es oben beschreibst).

Im ersten Fall hättest Du synchrone Replikation wie sie etwa Postgres jetzt bauen will oder wie Google sie in den SemiSync Replication Patches propagiert - Postgres fährt dann N=2, W=2, R=1, und Google mit den Patches ein allgemeines NWR-Modell mit W>1 und N>=W. Dabei kann es passieren, daß ein Write aus W failed und dadurch sinkt die Verfügbarkeit.

Im zweiten Fall hast Du die typische MySQL-Replikation mit W=1, R=1, die zu den o.a. Inkonsistenzen führt und die dafür recht ausfallsicher ist.

Wenn Dir Konsistenz wichtiger ist, kannst Du MySQL mit den Google-Patches fahren (Macht StudiVZ zum Beispiel), oder Du mußt manuell Waits generieren ("Jedes asynchrone System kann durch Waits in ein synchrones System überführt werden" -> das ist die Definition von Eventually Consistent), etwa durch "select wait_master_pos()".
Last edited by isotopp on 2008-07-10 09:24, edited 1 time in total.

User avatar
isotopp
Posts: 471
Joined: 2003-08-21 10:21
Location: Berlin

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by isotopp » 2008-07-10 09:22

julia wrote:so sehen die aktuellen werte aus:
73% select
10% change db (was ist das eigentlich genau? der verbindungsaufbau zur datenbank mit mysql_connect()? wäre dann auch ein read-query, oder?)
12% update
4% insert
<1% delete


change db sind "use" Anweisungen bzw mysql_change_db() Aufrufe.

Wenn Du MyISAM verwendest oder keine Transaktionen in InnoDB verwendet werden, dann kannst Du alle SELECT-Anweisungen auf den Slave schieben, alle anderen Queries laufen auf den Master. 73% der Queries sind dann vom Master weg.

Wenn Du explizite Transaktionen verwendest ("BEGIN WORK; ... COMMIT"), beachte bitte, daß Transaktionen geschlossen laufen müssen - enthält eine Transaktion also einen Schreibzugriff, müssen auch die Select-Queries in dieser Transaktion auf dem Master laufen. Insbesondere wenn es sich um RMW-Zyklen handelt und SELECT ... FOR UPDATE verwendet wird.

User avatar
isotopp
Posts: 471
Joined: 2003-08-21 10:21
Location: Berlin

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by isotopp » 2008-07-10 09:27

julia wrote:ok danke

nächste frage:
wo und wie löst man denn am besten die auswahl auf welchen slave eine anfrage gesendet wird? ein hardware loadbalancer ist nicht vorhanden.


Du kannst in der Anwendung mit zwei Connections arbeiten: Die Schreibverbindung geht immer auf den Master, die Leseverbindung geht auf einen zufällig ausgewählten Slave, der auch online sein muß. Dies ist die Lösung für Arme.

Einen IP-basierten Loadbalancer, der auch Livechecks macht, kann man sich sonst mit dem Linux Virtual Server (LVS) selber bauen. Das ist eine Lösung, die sehr wenig Last braucht und dennoch sehr, sehr weit skaliert (bis auf den Level von großen deutschen Freemail-Providern, etwa).

julia
Posts: 27
Joined: 2008-03-04 19:12

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by julia » 2008-07-12 10:03

danke für die antworten... auch wenn ich so manches nicht verstanden hab :D

isotopp wrote:Wenn Du MyISAM verwendest oder keine Transaktionen in InnoDB verwendet werden, dann kannst Du alle SELECT-Anweisungen auf den Slave schieben, alle anderen Queries laufen auf den Master. 73% der Queries sind dann vom Master weg.

wenn man eine 1-master / 1-slave konfiguration hat, dann bringt es aber doch nichts, wenn man alle SELECTs auf den slave schiebt, oder? das würde doch nur sinn machen wenn man min. 2 slaves hat. oder sehe ich das falsch?

User avatar
isotopp
Posts: 471
Joined: 2003-08-21 10:21
Location: Berlin

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by isotopp » 2008-07-12 10:34

julia wrote:danke für die antworten... auch wenn ich so manches nicht verstanden hab :D

isotopp wrote:Wenn Du MyISAM verwendest oder keine Transaktionen in InnoDB verwendet werden, dann kannst Du alle SELECT-Anweisungen auf den Slave schieben, alle anderen Queries laufen auf den Master. 73% der Queries sind dann vom Master weg.

wenn man eine 1-master / 1-slave konfiguration hat, dann bringt es aber doch nichts, wenn man alle SELECTs auf den slave schiebt, oder? das würde doch nur sinn machen wenn man min. 2 slaves hat. oder sehe ich das falsch?


Die Writes werden ja vom Master und vom Slave ausgeführt. Das muß so sein, damit beide denselben Datenbestand haben. Du mußt also Deine Writes immer an den Master schicken, der sie dann an den Slave weiter leitet.

Deine Reads kannst Du mit 50% Wahrscheinlichkeit an jeden dieser beiden Server senden, dann verteilt sich die Readlast gleichmäßig. Am günstigsten ist ein LB-Algorithmus, der den Zielserver zufällig auswählt.

julia
Posts: 27
Joined: 2008-03-04 19:12

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by julia » 2008-07-12 10:53

genau das meinte ich ja. denn du hast geschrieben: "dann kannst Du alle SELECT-Anweisungen auf den Slave schieben". wenn man aber nur einen slave verwendet macht das doch keinen sinn, oder?

User avatar
Joe User
Project Manager
Project Manager
Posts: 11137
Joined: 2003-02-27 01:00
Location: Hamburg

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by Joe User » 2008-07-12 11:15

julia wrote:genau das meinte ich ja. denn du hast geschrieben: "dann kannst Du alle SELECT-Anweisungen auf den Slave schieben". wenn man aber nur einen slave verwendet macht das doch keinen sinn, oder?

IIRC: Doch, denn der Master muss sich dann nur noch um die meist rechenintensiveren Writes kümmern, während sich der Slave hauptsächlich um die Reads kümmert und nebenbei die (vom Master optimierten) Writes ausführt.
PayPal.Me/JoeUserFreeBSD Remote Installation
Wings for LifeWings for Life World Run

„If there’s more than one possible outcome of a job or task, and one
of those outcomes will result in disaster or an undesirable consequence,
then somebody will do it that way.“ -- Edward Aloysius Murphy Jr.

julia
Posts: 27
Joined: 2008-03-04 19:12

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by julia » 2008-07-12 12:49

Joe User wrote:IIRC: Doch, denn der Master muss sich dann nur noch um die meist rechenintensiveren Writes kümmern, während sich der Slave hauptsächlich um die Reads kümmert und nebenbei die (vom Master optimierten) Writes ausführt.

schreibt der master die queries nicht 1:1 ins Bin-Log? das hier vorher noch großartig optimiert wird hab ich bisher nicht gehört

User avatar
isotopp
Posts: 471
Joined: 2003-08-21 10:21
Location: Berlin

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by isotopp » 2008-07-12 12:58

Joe User wrote:
julia wrote:genau das meinte ich ja. denn du hast geschrieben: "dann kannst Du alle SELECT-Anweisungen auf den Slave schieben". wenn man aber nur einen slave verwendet macht das doch keinen sinn, oder?

IIRC: Doch, denn der Master muss sich dann nur noch um die meist rechenintensiveren Writes kümmern, während sich der Slave hauptsächlich um die Reads kümmert und nebenbei die (vom Master optimierten) Writes ausführt.


Writes sind oft nicht rechenintensiv, sondern disk-intensiv. Das sind sie aber auf dem Master genau wie auf dem Slave.

Ein Plattenzugriff mit Seek sind so um die 5ms, wie können also ca. 200 davon pro Plattenpaar und Sekunde durchziehen. Ein RAM-Zugriff sind einige Nanosekunden, also in der Größenordnung eine Million schneller. Die Zugriffsgranularität ist bei Platten jedoch in der Gegend von 1 KB, bei RAM ist sie byteweise, daher hängt der tatsächliche Geschwindigkeitsunterschied von der Rowsize ab und liegt zwischen 10.000 und 100.000.

Reads kann man, genügend RAM und eine sinnvolle locality of reference ("Locality") vorausgesetzt, ohne Plattenzugriffe abfackeln. Writes dagegen müssen immer irgendwann auf einen persistenten Speicher. Datenbanken haben, wenn sie sinnvoll konfiguriert sind, mit Reads keine Probleme - wenn doch ist das leicht mit mehr RAM und ein paar Slaves weg zu skalieren. Writes dagegen sind meistens der harte Skalierungsfall - und sie treten auf dem Master genauso auf wie auf allen Slaves.

Zum Thema Rechenintensiv noch folgende Anmerkung: In einem 5ms Disk-Seek arbeitet ein 3GHz Prozessor in etwa 15 Millionen Befehle ab. Jeder gesparte Disk-Seek ist ein Gewinn.

julia
Posts: 27
Joined: 2008-03-04 19:12

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by julia » 2008-07-12 13:18

sehr informativ... danke!

wie schreibt der master den mysql-befehle wie z.b. UNIX_TIMESTAMP() ins bin-log? gibt er hier beim weitergeben des querys seine write-zeit an oder wie? wenn der slave mal ein paar sekunden zurückliegt hätte man ja damit sonst probleme?!

User avatar
isotopp
Posts: 471
Joined: 2003-08-21 10:21
Location: Berlin

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by isotopp » 2008-07-12 13:19

matzewe01 wrote:Mit zei Mysql Datenbanken könnte man selbiges erreichen Ich meine, dass der Proxy eine Verteilung nach oben genannten Kriterium z.B. unterstützt.


Im mathematischen Sinn ist eine Partition eine vollständige Zerlegung einer Obermenge in eine Menge von überlappungsfreien Untermengen. Eine Obermenge O wird also in eine Menge (Partition) P von Teilnehmen P1 - Pn zerlegt, sodaß Px geschnitten mit Py = leer (für x ungleich y) und daß die Vereinigungsmenge P = Vereinigung von P1 bis Pn genau gleich O ist.

In MySQL 5.1 gibt es partitionierte Tabellen als Nachfolger von MyISAM Merge Tabellen (die so voller Bugs sind, daß man sie besser nicht einsetzt, und wenn doch, dann unbedingt komplett read-only, und schon gar nicht die unterliegenden MyISAMs in irgendeiner Weise direkt anfaßt). Partitionierte Tabellen lösen das MyISAM-Merge Problem generischer, bugfreier und sind auch schneller. Das liegt unter anderem daran, daß die SQL-Engine über den Storage Engines bei MySQL Partitionen die Verteilregel kennt und der Optimizer davon Gebrauch machen kann.

MySQL Partitionen liegen jedoch immer auf demselben Server.


Wenn man eine Tabelle partitioniert und die Partitionen auf mehrere Server verteilt, dann bekommt man Shards (Scherben, Splitter). Sharding bewirkt, daß Writes nicht mehr auf einen Server gehen, sondern je nach Schreibort auf den Server gehen, auf dem die betreffenden Daten liegen. Dadurch kann man auch Writes sinnvoll skalieren. Shards haben jedoch das Problem, daß horizontale Queries über mehr als einen Shard sehr teuer werden. Dafür gibt es verschiedene Workarounds, die alle auf eine starke denormalisierung heraus laufen. Siehe auch http://highscalability.com/flickr-architecture als ein Lehrbuchbeispiel, und die Serie http://www.oreillynet.com/databases/blo ... ories.html für mehr davon.


Sharding kann man effizient nicht automatisch realisieren, sondern es bedeutet immer Änderungen an der Anwendung. Daher werden auch in der Regel klassische Closed Source Anwendungen nicht gesharded, sondern vertikal skaliert. Dies ist die Domain von Dingen wie den großen Sun Enterprise Hobeln, und von klassischen vertikal skalierenden Datenbankservern von IBM und Oracle.

Für Webanwendungen ist, wenn sie sehr viel Erfolg haben, schon von vorneherein absehbar, daß sie irgendwann größer werden als die größte erhältliche Maschine. (http://kris.koehntopp.de/artikel/linuxtag/img9.html aus http://kris.koehntopp.de/artikel/linuxtag/). Webanwendungen sind aber in der Regel auch so gestaltet, daß dem Betreiber der Quelltext zur Verfügung steht - daher findet man in solchen Installationen aber auch kaum vertikale Skalierung, sondern stattdessen horizontales Wachsum.

web.de hatte 2005 zum Beispiel etwa 35 Datenbankserver, von denen 25 je eine Million User beherbergten (Sharding-Beispiel) und die anderen 10 jeweils eine geringere Anzahl von sehr aktiven Usern hielten. Pro Datenbankserver waren zwischen 4 und 8 Web-Frontendserver aktiv. Man kann das heute noch sehen: freemailxxyy.web.de ist die xx-Clusternummer (01-25 oder so für Freemail-Kunden, und höhere Zahlen für Clubkunden) und yy ist die Webserver-Nummer in diesem Cluster. Sie wird beim Login durch Redirect zufällig, aber sticky zugewiesen.

Neckermann.de betreibt eine kleine dreistellige Anzahl von MySQL-Instanzen - auf Blades. Und booking.com betreibt ebenfalls um die 100 Datenbank-Instanzen, auf HP DL 585, DL 385 und vergleichbaren Maschinen, mit 2, 4 oder 8 Cores und zwischen 8 und 32 GB RAM. Andere große MySQL-Installationen (Xing, Puma, Swoodoo, ...) sehen ganz ähnlich aus.


Wenn man den Source der Anwendung nicht oder nicht sofort ändern kann, weil man Versäumnisse der Vergangenheit aufarbeiten muß, dann kann man sich als Interimslösung mit dem MySQL Proxy in der Loadbalancer-Variante behelfen. Damit kommt man dann immerhin sofort weiter, wenn die Lösung auch nicht so fein kontrollierbar und so flexibel ist wie eine Lösung, die komplett unter Kenntnis der Anwendungslogik abgewickelt wird (Dazu kommen Beschränkungen in der internen Logik, die lighttpd und MySQL Proxy gemeinsam sind und die in Extremfällen zum Load-Limit werden können).

Bedeutet jedoch auch im Umkehrschluss, dass 2 physikalisch getrennte Maschinen sinnvoll sind und die Datenfiles auf unterschiedlichem Storage liegen sollten.


Nein. http://www.sun.com/blueprints/1000/layout.pdf ist besser.

Login Daten z.B. würde ich auf einer DB halten, um eindeutig und zuverlässig IDs zu vergeben und redundante abfragen auf mehren Host zu vermeiden zumal Logins vermutlich die kleinste Last erzeugen.


In einer klassischen Architektur, etwa web.de, hat man eine zentrale Datenbank, die ein Tripel (user, password, clusternummer) enthält. Beim Login kann man so zentral (aus dem RAM!) die Authenisierung zunehmen und dann auf den zuständigen Cluster verweisen. Außerdem kann man so User von einem Cluster zum anderen Migrieren. Was man nicht machen sollte: Writes in diese Tabelle (etwa: Das Lastlogin-Date aktualisieren). Solche Daten sollten pro Cluster und nicht zentral geschrieben werden. Sonst hat man jeden Montag morgen um 9 Uhr ca. 4000-5000 Writes pro Sekunde auf der zentralen Tabelle und in einer Krise drei- bis fünfmal so viele.

http://blog.koehntopp.de/archives/1775- ... MySQL.html, Folgerung 4 diskutiert das in ein wenig mehr Detail. Der Rest des Artikels ist unter Umständen auch von Interesse.

User avatar
isotopp
Posts: 471
Joined: 2003-08-21 10:21
Location: Berlin

Re: Frage zur Lastverteilung/Replikation mit MySQL

Post by isotopp » 2008-07-12 13:28

julia wrote:sehr informativ... danke!

wie schreibt der master den mysql-befehle wie z.b. UNIX_TIMESTAMP() ins bin-log? gibt er hier beim weitergeben des querys seine write-zeit an oder wie? wenn der slave mal ein paar sekunden zurückliegt hätte man ja damit sonst probleme?!


Du kannst Dir das mit dem Kommando "mysqlbinlog", das Du auf das Binlog Deines Masters anwendest, leicht selbst ansehen.

Deine Vermutung ist korrekt. Neben der eigentlichen Nutzlast - das ist die Write-Query des Masters wörtlich - finden sich im Binlog noch ein Haufen weiterer Statements, die für die Nutzlast das Environment vorbereiten. Dazu gehört immer mindestens die Anweisung SET TIMESTAMP mit der der Master die Zeit des Masters auf den Slave exportiert, aber unter Umständen noch weitere Befehle.

Du kannst auch spaßeshalber einmal auf Deinem Kommandoprompt:

mysql> SET TIMESTAMP=1;
mysql> SELECT now() AS replicated, sysdate() AS not_replicated;

mysql> SET TIMESTAMP=0;
mysql> SELECT now(), sysdate();

machen. Wie Du siehst setzt SET TIMESTAMP=... für diese Connection (idR der Slave SQL_THREAD) die Uhr auf einen Fake-Wert. Dieser Fakewert wird dann von now() und seinen Synonymen verwendet, nicht jedoch von sysdate() (solange der Server nicht mit der 4.1 Kompatilitätsoption --sysdate-is-now gestartet wird).

Nach SET TIMESTAMP=0 wird die Uhr wieder released und läuft wieder wie eine normale Uhr.

Auch andere Befehle werden unter Umständen nur dann korrekt ausgeführt, wenn das Environment mit exportiert wird (etwa RAND(), bei dem die RAND-Seed eingesetzt wird, damit zufällig auf dem Slave dasselbe wie auf dem Master herauskommt).


In 5.1 bekommen wir statt Statement-Based-Replication (SBR) dann Row-Based-Replication (RBR). Hier werden Primary-Key-Values von Rows und die Werte der geänderten Zellen binär exportiert.

Da MySQL keine RBR kann, muß es einen Befehl (ein Statement) geben, mit dem man Rows ändern kann. Das kannst Du mit einem 5.1 binlog dan auch leicht prüfen: Statt Rows gibt es einen Befehl BINLOG, der die betreffenden Werte BASE64-codiert transportiert. Das Binlog wird dadurch jedoch leicht unlesbar, weil der BASE64-Müll nicht decodiert wird, auch nicht als Kommentar.