<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>netz-guru blog &#187; mysql</title>
	<atom:link href="http://www.netz-guru.de/tag/mysql/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.netz-guru.de</link>
	<description>Webtechniken, Sicherheit und Interessantes...</description>
	<lastBuildDate>Fri, 18 Jun 2010 16:17:45 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Die ultimative E-Mail Lösung &#8211; The ultimate E-Mail Solution</title>
		<link>http://www.netz-guru.de/2009/01/12/die-ultimative-e-mail-losung-the-ultimate-e-mail-solution/</link>
		<comments>http://www.netz-guru.de/2009/01/12/die-ultimative-e-mail-losung-the-ultimate-e-mail-solution/#comments</comments>
		<pubDate>Mon, 12 Jan 2009 18:43:27 +0000</pubDate>
		<dc:creator>Florian Wiessner</dc:creator>
				<category><![CDATA[Hosting]]></category>
		<category><![CDATA[dbmail]]></category>
		<category><![CDATA[mail server]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[pgcluster]]></category>
		<category><![CDATA[Postfix]]></category>
		<category><![CDATA[postgres]]></category>

		<guid isPermaLink="false">http://www.netz-guru.de/?p=44</guid>
		<description><![CDATA[Es war einmal ein Mailserver&#8230;
Wenn man Administrator eines produktiv genutzten Mailservers ist, macht man sich schon ab und zu mal Gedanken, wie man die Probleme, welche beim Betrieb des Servers auftreten oder auftreten könnten, mit möglichst wenig Aufwand &#8211; jetzt im Sinne von möglichst wenig Aufwand in der Zukunft &#8211; lösen kann. Ich betreibe einen [...]]]></description>
			<content:encoded><![CDATA[<h2>Es war einmal ein Mailserver&#8230;</h2>
<p>Wenn man Administrator eines produktiv genutzten Mailservers ist, macht man sich schon ab und zu mal Gedanken, wie man die Probleme, welche beim Betrieb des Servers auftreten oder auftreten könnten, mit möglichst wenig Aufwand &#8211; jetzt im Sinne von möglichst wenig Aufwand in der Zukunft &#8211; lösen kann. Ich betreibe einen <a title="Quickemail.de Free E-Mail Accounts" href="http://www.quickemail.de" target="_blank">kostenlosen E-Mail Dienst</a> mit derzeit ca. 12.000 Usern. Seit 1998 hat sich das Setup des Mailservers eigentlich kaum geändert. Damals war <a title="sendmail mta" href="http://www.sendmail.org" target="_blank">sendmail </a>noch das Nonplusultra, man war stolz dass <a title="smtp-auth" href="http://de.wikipedia.org/wiki/SMTP-Auth" target="_blank">SMTP-Auth</a> und diverse Workarounds wie POP-Before-SMTP etc funktionierten, und im Allgemeinen gab es auch weniger <a title="spam" href="http://de.wikipedia.org/wiki/Spam" target="_blank">SPAM</a>. Zu dieser Zeit hatte quickemail.de ca. 500 User und die Welt der Flat-File Konfiguration war noch in Ordnung.</p>
<p>Irgendwann reicht das jedoch nicht mehr aus &#8211; Flat-Files werden schnell unübersichtlich und es musste eine Lösung her, um zumindest die E-Mail Accounts und User zu verwalten. Eine <a title="mysql" href="http://www.mysql.com" target="_blank">mySQL </a>Datenbank war schnell aufgesetzt und mit ein paar Scripts und Cronjobs wuchs die Userbase dann immer weiter an. Da gingen dann aber auch die Probleme los.</p>
<h2>SPAM von Botnets == DDOS?</h2>
<p>Wenn man mehrere tausend User auf einer physikalischen Maschine hat, bringt das diverse Probleme mit sich. Zum einen braucht man ständig größere Festplatten, zum anderen natürlich auch mehr CPU und RAM. Das lässt sich eigentlich auf normaler Hardware noch relativ einfach erweitern. Problematisch wird das ganze dann, wenn man distributed SPAM von diversen <a href="http://de.wikipedia.org/wiki/Botnet" target="_blank">Botnets</a> abbekommt. Nicht nur der Mailserver an sich ist hier dann überfordert &#8211; bei jedem Connect wird ein <a href="http://de.wikipedia.org/wiki/Nslookup" target="_blank">nslookup</a> durchgeführt, was sich auch wieder mit erhöhter Last auf den Nameservern auswirkt. Irgendwann ist dann jedoch Schluss &#8211; bei 200 gleichzeitigen Connects und einer Load von &gt;100 kann es schon mal ein paar Minuten dauern, bis man diverse Services gestoppt hat um zumindest die Maschine wieder administrieren zu können.</p>
<h2><a href="http://de.wikipedia.org/wiki/SPOF" target="_blank">SPOF</a>s am laufenden Band</h2>
<p>Eine einzelne Maschine zu verwenden ist natürlich auch nicht gerade von Vorteil. Fällt die Hardware aus, oder sind die Platten voll, steht die Maschine und nichts geht mehr. Klar kann man solche Ausfälle durch gutes Monitoring minimieren, spätestens jedoch beim nächsten Upgrade steht der Dienst erst mal wieder.</p>
<h2>Wie man diese Probleme in den Griff bekommt?</h2>
<p>Nun, wenn man nicht gerade im Lotto gewonnen hat, braucht man hier eine günstige Lösung die dennoch gut skaliert und fehlertolerant ist, also die Mails an sich redundant speichert, sowie mehrere Server zur Verfügung stellt um bei einem ausgefallenen System dennoch den Dienst aufrecht erhalten zu können. Das gestaltet sich jedoch gar nicht so einfach. Alleine dafür zu sorgen, dass die Daten auf allen Maschinen synchron sind, ist eine Herausforderung.</p>
<p>Es gibt diverse Lösungen mit NAS oder <a href="http://www.drbd.org/" target="_blank">DRBD</a>, proprietäre Lösungen von diversen Herstellern, Backup-Mailserver, etc &#8211; aber eine wirkliche günstige Alternative die mit normaler x86er Hardware auskommt, und bei der man nicht Tausende Euro Lizenzgebühren zahlen muss, hatte ich bisher noch nicht gefunden.</p>
<p>Deshalb habe ich mich mal eine Woche intensiv damit beschäftigt, das Mailproblem, zumindest für mich, ein für alle mal zu Lösen.</p>
<p><span id="more-44"></span></p>
<h2>Daten redundant speichern&#8230;</h2>
<p>kann man zum Beispiel mit mysql-ndb &#8211; Das war auch mein erster Versuch. Da man seit mySQL 5.1.6 bzw. der 6.2er NDB-Engine endlich Tables auch ondisk speichern kann, dachte ich das sei einen Versuch wert. Allerdings gibt es bei mySQL immer noch das Problem, dass die Indizes in-memory sein müssen. Bei einer Mailbase von sagen wir mal ca. 40GB kommt man so locker auf einen RAM-Bedarf von 8GB und mehr.</p>
<p>Dann gibt es noch die Möglichkeit dies einfach mit Master-Slave Replication zu lösen, hier ist jedoch das Problem, dass sobald der Master-Server ausgefallen ist, die User keine Daten mehr schreiben können und man nur noch Read-Only Access hat. Deshalb sind auch Lösungen wie <a href="http://pgpool.projects.postgresql.org/" target="_blank">PG-Pool</a> oder <a href="http://www.slony.info/" target="_blank">Slony </a>nicht wirklich praktikabel. Aber es gibt ja noch <a href="http://pgfoundry.org/projects/pgcluster/" target="_blank">PGCluster</a>. PG-Cluster ist im Vergleich zu mySQL-NDB wesentlich besser geeignet, um Daten redundant in einer Datenbank zu speichern. Hier müssen die Indizies nicht in-memory sein. Das derzeitige Release pgcluster1.9-rc5 basiert auf <a href="http://www.postgresql.org/" target="_blank">postgres 8.3</a> und funktioniert &#8211; sofern richtig konfiguriert &#8211; einwandfrei. Schade ist jedoch, dass auf der offiziellen Webseite von PG-Cluster immer noch die Version 1.3 als aktuell bezeichnet wird und das letzte Update der Seite irgendwann in 2005 war. Deshalb habe ich während der Evaluierungsphase erst PG-Cluster 1.3, dann den Fork cybercluster, und dann erst PG-Cluster 1.9 getestet. Mit PG-Cluster hat man zumindest schon mal das Problem ausgemerzt, dass man sich nicht mehr darum kümmern muss, was mit den Daten passiert. Die Master-Master oder auch Active-Active Replikation von PG-Cluster gewährleistet synchrone Daten über alle Cluster-Nodes hinweg.</p>
<h2>Redundante Daten &#8211; und was machen wir nun damit?</h2>
<p>Nach einiger Zeit googeln bin ich dann auf den <a href="http://www.dbmail.org/" target="_blank">dbmail</a> gestossen &#8211; ein User aus dem IRC-Channel #linux.de hatte mich darauf hingewiesen, dass es soetwas bereits gibt. Bei dbmail werden alle E-Mails, Accounts, Forward etc. in der Datenbank gespeichert. In Verbindung mit PG-Cluster ergibt sich dann hier eben die Möglichkeit, Mailserver-Nodes zu betreiben die synchron sind. Die Last lässt sich dann via DNS-Roundrobin über die Mailserver und bei der Datenbank  mit dem PG-Loadbalancer verteilen. Mein aktuelles Setup sieht wie folgt aus:</p>
<p><img class="aligncenter size-full wp-image-47" src="http://www.netz-guru.de/wp-content/uploads/2009/01/smartweb-mailcluster.png" alt="smartweb-mailcluster" width="402" height="622" /></p>
<p>Mit diesem Setup ist man dann in der Lage, solange zumindest ein Node online ist, die Mail-Services aufrecht zu erhalten. dbmail liefert ein Script mailbox2dbmail mit &#8211; damit lassen sich Mailboxen im mbox, maildir und mhdir Format leicht in dbmail einpflegen. Wie man so ein Setup bewerkstelligt, möchte ich hier nun kundtun. Ich selbst habe für mein aktuelles Setup ca. eine Woche gebraucht &#8211; das liegt aber auch daran, weil ich alles Mögliche getestet habe um herauszufinden, was am Besten funktioniert. Bei dbmail musste ich selbst einige Zeilen im Source-Code ändern. Auch Cyrus SASL muss man patchen, aber am Ende ist es das Alles wert.</p>
<h2>Howto begin?</h2>
<p>Als aller erstes benötigen wir mind. 2 Server. Wer möchte kann das auch zuerst innerhalb eines VServers oder VMware Session testen &#8211; ich rate dringend dazu, um sich mit der Sache etwas vertraut zu machen.</p>
<p>Die Server werden frisch mit Debian Etch installiert. Damit hier pgcluster allerdings kompiliert, müssen einige Pakete nachinstalliert werden &#8211; und nach dem ./configure muss man noch ein Makefile anpasssen. Benötigt wird build-essential libreadline5 libreadline5-dev asciidox flex bison libssl-dev rsync ssh. Sollte hier noch etwas fehlen, werde ich es zu gegebener Zeit ergänzen. Wichtig ist, dass das System eine utf8-Locale installiert hat und diese auch verwendet wird &#8211; sonst gibt es später Probleme mit PostgreSQL.</p>
<pre>wget http://pgfoundry.org/frs/download.php/1705/pgcluster-1.9.0rc5.tar.gz
tar -xvzf pgcluster-1.9.0rc5.tar.gz
cd pgcluster-1.9.0rc5
./configure
make
make install</pre>
<p>Postgres wird dann in /usr/local/pgsql installiert. Wer es woanders haben möchte, gibt einen Prefix beim configure mit an.</p>
<p>User anlegen, Rechte setzen:</p>
<pre>cd /usr/local
useradd -d /usr/local/pgsql postgres
groupadd postgres
chown postgres.postgres pgsql -R</pre>
<p>Hat man dies auf allen Nodes erledigt, wird mit initdb die Datenbank initialisiert:</p>
<pre>su postgres
cd /usr/local/pgsql
./bin/initdb --locale=de_DE.utf8 data</pre>
<p>Im Verzeichnis data legen wir dann auch entsprechend die Konfiguration für den Cluster an. Wichtig ist hierbei dass die Konfiguration bei allen Nodes identisch ist. Zuerst muss man die Datei pg_hba.conf im data Verzeichnis bearbeiten. Hier wird festgelegt, welcher Rechner sich zu der Datenbank verbinden darf. Das Ganze ist IP-basierend. Man sollte in jedem Fall für jeden Host einen eintrag in /etc/hosts machen, um DNS-Problemen innerhalb des Clusters aus dem Weg zu gehen &#8211; ich gehe hier bei diesem Howto mal davon aus, dass zuerst das ganze in einer Testumgebung installiert wird:</p>
<p>In pg_hba.conf unter der Zeile:</p>
<pre># IPv4 local connections:</pre>
<p>muss für jeden Host des Clusters ein Eintrag gemacht sein:</p>
<pre>host  all  all 192.168.0.10/32 trust # node01
host  all  all 192.168.0.20/32 trust # node02</pre>
<p>Dies stellt sicher, dass die Nodes des Clusters gegenseitigen Zugriff auf sich selbst haben. Wichtig: man darf es nicht versäumen auch dem lokalen node Connections von sich selbst zu erlauben &#8211; daher ist auch bei node01 die IP für den node01 freizugeben.</p>
<p>Nun müssen wir die Datei cluster.conf im data Verzeichnis anlegen. Hier wird festgelegt, wohin repliziert werden soll:</p>
<pre>&lt;Replicate_Server_Info&gt;
        &lt;Host_Name&gt; node01 &lt;/Host_Name&gt;
        &lt;Port&gt;           5810 &lt;/Port&gt;
        &lt;Recovery_Port&gt;  5811 &lt;/Recovery_Port&gt;
&lt;/Replicate_Server_Info&gt;
&lt;Replicate_Server_Info&gt;
        &lt;Host_Name&gt; node02 &lt;/Host_Name&gt;
        &lt;Port&gt;           5810 &lt;/Port&gt;
        &lt;Recovery_Port&gt;  5811 &lt;/Recovery_Port&gt;
&lt;/Replicate_Server_Info&gt;
&lt;/Replicate_Server_Info&gt;
&lt;Host_Name&gt; node01 | node02 &lt;/Host_Name&gt;
# Der Host_Name muss dem jeweiligen Node angepasst werden!
#
&lt;Recovery_Port&gt;         5611 &lt;/Recovery_Port&gt;
&lt;Rsync_Path&gt; /usr/bin/rsync &lt;/Rsync_Path&gt;
&lt;Rsync_Option&gt; ssh &lt;/Rsync_Option&gt;
&lt;Rsync_Compress&gt; yes &lt;/Rsync_Compress&gt;
&lt;When_Stand_Alone&gt; read_write  &lt;/When_Stand_Alone&gt;
&lt;Pg_Dump_Path&gt; /usr/local/pgsql/bin/pg_dump&lt;/Pg_Dump_Path&gt;
&lt;Replication_Timeout&gt; 1min&lt;/Replication_Timeout&gt;
&lt;LifeCheck_Timeout&gt;3s&lt;/LifeCheck_Timeout&gt;
&lt;LifeCheck_Interval&gt;15s&lt;/LifeCheck_Interval&gt;</pre>
<p>Nachdem die cluster.conf angelegt wurde, fehlt noch die pgreplicate.conf &#8211; hier wird festgelegt, von welchen Nodes gelauscht werden soll um die Queries zu replizieren:</p>
<pre>&lt;Cluster_Server_Info&gt;
        &lt;Host_Name&gt; node01 &lt;/Host_Name&gt;
        &lt;Port&gt;           5432 &lt;/Port&gt;
        &lt;Recovery_Port&gt;  5611 &lt;/Recovery_Port&gt;
&lt;/Cluster_Server_Info&gt;
&lt;Cluster_Server_Info&gt;
        &lt;Host_Name&gt; node02 &lt;/Host_Name&gt;
        &lt;Port&gt;           5432 &lt;/Port&gt;
        &lt;Recovery_Port&gt;  5611 &lt;/Recovery_Port&gt;
&lt;/Cluster_Server_Info&gt;
&lt;Host_Name&gt; node01 | node02 &lt;/Host_Name&gt;
# Der Host_Name muss dem jeweiligen Node angepasst werden!
#
&lt;Replication_Port&gt;    5810    &lt;/Replication_Port&gt;
&lt;Recovery_Port&gt;       5811    &lt;/Recovery_Port&gt;
&lt;Response_Mode&gt;       normal  &lt;/Response_Mode&gt;
&lt;Use_Replication_Log&gt; yes     &lt;/Use_Replication_Log&gt;
&lt;RLOG_Port&gt;           8301    &lt;/RLOG_Port&gt;
&lt;Replication_Timeout&gt; 1min &lt;/Replication_Timeout&gt;
&lt;LifeCheck_Timeout&gt; 3s &lt;/LifeCheck_Timeout&gt;
&lt;LifeCheck_Interval&gt; 15s &lt;/LifeCheck_Interval&gt;</pre>
<p>Soweit so gut, PG-Cluster sollte jetzt lauffähig sein und Queries replizieren. Starten müssen wir das Ganze auf beiden Nodes noch:</p>
<pre>su postgres
cd /usr/local/pgsql
./bin/pg_ctl -D data start
./bin/pgreplicate -D data</pre>
<p>Man kann jetzt das ganze einmal testen indem man einfach eine Datenbank erzeugt, eine Tabelle anlegt, und von beiden Nodes Inserts durchführt:</p>
<pre>./bin/createdb test
./bin/psql test
<pre>create table test ( test varchar(255));</pre>
</pre>
<pre># Dann jeweils auf beiden Nodes abwechselnd
#
insert into test (test) values (test1);
insert into test (test) values (test2);
select * from test;</pre>
<p>Man kann jetzt beobachten, wie die Queries repliziert werden.</p>
<h2>dbmail Setup</h2>
<p>Auch hier müssen wir zuerst dbmail holen, entpacken und installieren:</p>
<pre>cd /usr/src
wget http://www.dbmail.org/download/2.2/dbmail-2.2.11-rc3.tar.gz
tar -xvzf dbmail-2.2.11-rc3.tar.get
cd dbmail-2.2.11-rc3
./configure --with-pgsql=/usr/local/pgsql

Unter Debian Etch man/Makefile editieren, Zeile 547:
von:         asciidoc -b docbook -d manpage $&lt;
zu:          asciidoc --unsafe -b docbook -d manpage $&lt;

make
make install</pre>
<p>dbmail ist jetzt in /usr/local/sbin installiert. Die Konfiguration dbmail.conf kann man nach /etc/ kopieren und anpassen. Wer pglb (Loadbalancer) verwenden will, muss vor dem kompilieren in modules/dbpgsql.c nach Zeile 110 Folgendes einfügen:</p>
<pre>        g_string_append_printf(cs, " sslmode='disable'");</pre>
<h2>und der eigentliche MTA?</h2>
<p>nun fehlt noch <a href="http://www.postfix.org/" target="_blank">postfix</a>. Postfix wird mit apt-get install postfix postfix-pgsql installiert. Wenn man sasl verwenden möchte, sei darauf hingewiesen, dass man hier ein gepatchtes sasl braucht, welches gecryptete Passwörter in der DB zulässt. Meine main.cf für Postfix sieht dann so aus:</p>
<pre>smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no
append_dot_mydomain = no
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_tls_session_cache_database = btree:${queue_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${queue_directory}/smtp_scache
myhostname = node01
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
mydestination = $myhostname, mysql:/etc/postfix/sql-mydestination.cf
mynetworks = 127.0.0.0/8
mailbox_command = procmail
mailbox_size_limit = 0
recipient_delimiter = +
local_recipient_maps = pgsql:/etc/postfix/dbmail_rcpt.cf, pgsql:/etc/postfix/dbmail_rcpt_alias.cf
local_transport = dbmail-smtp:
broken_sasl_auth_clients = yes
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_recipient_restrictions =
                           permit_mynetworks,
                           reject_invalid_hostname,
                           reject_non_fqdn_sender,
                           reject_non_fqdn_recipient,
                           reject_unknown_recipient_domain,
                           reject_unauth_pipelining,
                           reject_unknown_sender_domain,
                           permit_sasl_authenticated,
                           reject_unauth_destination
smtpd_sender_restrictions =
                           permit_mynetworks,
                           reject_authenticated_sender_login_mismatch,
                           permit_sasl_authenticated,
                           reject_sender_login_mismatch,
                           reject_unknown_sender_domain,
                           reject_unauth_destination,
                           reject_unknown_recipient_domain
check_sender_access = hash:/etc/postfix/sender_access
smtpd_sender_login_maps = pgsql:/etc/postfix/dbmail_sender_login.cf, pgsql:/etc/postfix/dbmail_sender_login_alias.cf
content_filter = smtp-amavis:[127.0.0.1]:10024</pre>
<p>Dann hier noch die Files welche für sasl benötigt werden:</p>
<pre>cat dbmail_rcpt.cf
user = dbmail
password = xxxxxxxxxxx
dbname = dbmail
hosts = node01
query = SELECT userid FROM dbmail_users WHERE userid='%s'

cat dbmail_rcpt_alias.cf
user = dbmail
password = xxxxxxxxxx
dbname = dbmail
hosts = node01
query = SELECT alias FROM dbmail_aliases WHERE alias='%s'

cat dbmail_sender_login.cf
user = dbmail
password = xxxxxxxxxx
dbname = dbmail
hosts = node01
query = SELECT userid FROM dbmail_users WHERE userid='%s'

cat dbmail_sender_login_alias.cf
# SMTP AUTH - check if the alias exists
user = dbmail
password = xxxxxxxxxx
dbname = dbmail
hosts = node01
query = SELECT userid FROM dbmail_users JOIN dbmail_aliases ON ( CAST (dbmail_aliases.deliver_to as bigint)=cast(dbmail_users.user_idnr as bigint)) WHERE dbmail_aliases.alias='%s';

cat sql-recipients.cf
user = dbmail
password = xxxxxxxxxxxxx
hosts = node01
dbname = dbmail
query =  SELECT alias FROM dbmail_aliases WHERE alias='%s' UNION SELECT userid FROM dbmail_users WHERE userid='%s';</pre>
<p>Ich selbst habe meine relay-Domains noch in der mySQL Datenbank stehen, hier kann aber auch einfach nur das Hash-File verwendet werden. Jetzt steht die Postfix Konfiguration auch soweit. Wir müssen jetzt noch das DB-Layout in der Datenbank anlegen:</p>
<pre>su postgres
cd /usr/local/pgsql
./bin/createdb dbmail
./bin/createuser dbmail
./bin/psql -U dbmail dbmail &lt;/usr/src/dbmail-2.2.11-rc3/sql/postgresql/create_tables.pgsql</pre>
<p>Nun kann man postfix starten/restarten. Die pop3 und imap services startet man in /usr/local/sbin mit ./dbmail-imapd sowie ./dbmail-pop3d &#8211; Nützlich ist auch dbmail-users und dbmail-util.</p>
<p>Die amavis Konfiguration sowie das Anlegen und Verwalten von Usern möchte ich hier nicht weiter behandeln, da hier wohl jeder Admin seine eigenen Preferenzen hat. Dennoch hoffe ich hier etwas Wissen in PG-Cluster und dbmail vermittelt zu haben und wünsche viel Spass mit dem neuen Mailsetup. Die bisherigen Probleme sollten damit alle passé sein.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netz-guru.de/2009/01/12/die-ultimative-e-mail-losung-the-ultimate-e-mail-solution/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Nach einem Datenbank Crash fix alle mysql DBs/Tabellen reparieren</title>
		<link>http://www.netz-guru.de/2008/08/12/nach-einem-datenbank-crash-fix-alle-mysql-dbstabellen-reparieren/</link>
		<comments>http://www.netz-guru.de/2008/08/12/nach-einem-datenbank-crash-fix-alle-mysql-dbstabellen-reparieren/#comments</comments>
		<pubDate>Tue, 12 Aug 2008 06:47:34 +0000</pubDate>
		<dc:creator>Florian Wiessner</dc:creator>
				<category><![CDATA[Usefull Things]]></category>
		<category><![CDATA[datenbank]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[repair]]></category>
		<category><![CDATA[reparieren]]></category>
		<category><![CDATA[tabelle]]></category>
		<category><![CDATA[table]]></category>

		<guid isPermaLink="false">http://www.netz-guru.de/?p=37</guid>
		<description><![CDATA[Es kann schon mal vorkommen, dass nach einem Reboot oder Hard-Reset eines Servers der mysql-Server meldet, dass einige Tabellen defekt sind. Die Datenbank startet dann zwar ganz normal, einige Queries auf defekte/korrupte Tabellen können dann jedoch nicht mehr ausgeführt werden.
Um diese defekten Tabellen zu reparieren, kann man z.B. myisamchk mit den Optionen -rf im Datenverzeichnis [...]]]></description>
			<content:encoded><![CDATA[<p>Es kann schon mal vorkommen, dass nach einem Reboot oder Hard-Reset eines Servers der mysql-Server meldet, dass einige Tabellen defekt sind. Die Datenbank startet dann zwar ganz normal, einige Queries auf defekte/korrupte Tabellen können dann jedoch nicht mehr ausgeführt werden.</p>
<p>Um diese defekten Tabellen zu reparieren, kann man z.B. myisamchk mit den Optionen -rf im Datenverzeichnis von mySQL (unter Debian /var/lib/mysql) die Datenbanken reparieren. Alternativ kann man dies jedoch auch direkt mit mySQL erledigen, der Syntax lautet dann REPAIR TABLE &lt;tabellenname&gt;.</p>
<p><span id="more-37"></span></p>
<p>Dies jedoch manuell über alle Tabellen auszuführen, ist lästig, weshalb ich hier einen Code-Schnipsel bereitstelle, der alle Tabellen in allen Datenbanken repariert &#8211; dies funktioniert jedoch nur mit der Datenbank Engine MYISAM:</p>
<blockquote><p><span><span>&lt;?php</span></span></p>
<p><span><span>$db=mysql_connect(&#8220;localhost&#8221;,&#8221;root&#8221;,&#8221;&lt;passwort&gt;&#8221;);</span></span></p>
<p><span><span>$sql = &#8220;show databases;&#8221;;</span></span></p>
<p><span><span>$res_db = mysql_query($sql,$db);</span></span></p>
<p><span><span>while ($dat_db = mysql_fetch_array($res_db)) {</span></span></p>
<p><span><span> $datab = $dat_db["Database"];</span></span></p>
<p><span><span> mysql_select_db($datab,$db);</span></span></p>
<p><span><span> $sql = &#8220;show tables;&#8221;;</span></span></p>
<p><span><span> $res = mysql_query($sql,$db);</span></span></p>
<p><span><span> while ($dat = mysql_fetch_array($res)) {</span></span></p>
<p><span><span> $table = $dat[0];</span></span></p>
<p><span><span> $sql2 = &#8220;repair table $table&#8221;;</span></span></p>
<p><span><span> $res2 = mysql_query($sql2,$db);</span></span></p>
<p><span><span> }</span></span></p>
<p><span><span>}</span></span></p>
<p><span><span>?&gt;</span></span></p></blockquote>
<p>Man kann dieses Script speichern, die Modes auf executable setzen und es am Ende in /etc/init.d/mysql anfügen, damit die Tabellen automatisch nach jedem Start von mysql repariert werden.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netz-guru.de/2008/08/12/nach-einem-datenbank-crash-fix-alle-mysql-dbstabellen-reparieren/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mysqlfs mit mySQL NDB Cluster als verteiltes Dateisystem</title>
		<link>http://www.netz-guru.de/2008/04/03/mysqlfs-mit-mysql-ndb-cluster-als-verteiltes-dateisystem/</link>
		<comments>http://www.netz-guru.de/2008/04/03/mysqlfs-mit-mysql-ndb-cluster-als-verteiltes-dateisystem/#comments</comments>
		<pubDate>Thu, 03 Apr 2008 11:32:43 +0000</pubDate>
		<dc:creator>Florian Wiessner</dc:creator>
				<category><![CDATA[Hosting]]></category>
		<category><![CDATA[Usefull Things]]></category>
		<category><![CDATA[Webtechniken]]></category>
		<category><![CDATA[cluster]]></category>
		<category><![CDATA[cluster dateisystem]]></category>
		<category><![CDATA[clusterfs]]></category>
		<category><![CDATA[dateisystem]]></category>
		<category><![CDATA[fs]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[mysql cluster]]></category>
		<category><![CDATA[mysqlfs]]></category>
		<category><![CDATA[shared nothing]]></category>
		<category><![CDATA[shared nothing filesystem]]></category>

		<guid isPermaLink="false">http://www.netz-guru.de/?p=20</guid>
		<description><![CDATA[Jeder der kritische Anwendungen über das Web laufen hat, wie z.B. einen Onlineshop, stellt sich irgendwann, bei hinreichend großem Umsatz, die Frage, wie man das System noch ausfallsicherer machen kann.
Meist wird dann hierzu ein Loadbalancer (ob Hardware oder Software ist erst mal egal) aufgesetzt, welcher die Anfragen an mehrer Server verteilt, welche sich einen gemeinsammen [...]]]></description>
			<content:encoded><![CDATA[<p>Jeder der kritische Anwendungen über das Web laufen hat, wie z.B. einen Onlineshop, stellt sich irgendwann, bei hinreichend großem Umsatz, die Frage, wie man das System noch ausfallsicherer machen kann.</p>
<p>Meist wird dann hierzu ein Loadbalancer (ob Hardware oder Software ist erst mal egal) aufgesetzt, welcher die Anfragen an mehrer Server verteilt, welche sich einen gemeinsammen Massenspeicher teilen. Dadurch ist es möglich, dass einzelne Server gewartet werden können, bzw. auch ausfallen können, ohne dass die Applikation dadurch gestört wird.</p>
<p>Leider beschränkt sich diese Variante auf nur eine Location, d.h. wird aus irgendwelchen Gründen z.B. die Internetanbindung an das System unterbrochen, ist die Applikation offline.</p>
<p>Dies kann man damit umgehen, dass man das System multihomed aufbaut, d.h. mehrere Server an unterschiedlichen Standorten betreibt, um bei einem Ausfall von einem Standort trotzdem noch erreichbar zu sein. Diese Variante hat den Nachteil, dass die Daten des Systems sehr aufwändig synchronisiert werden müssen, falls ein Standort nicht mehr erreichbar war. Weiterhin muss man auch bei Updates etc. aufpassen, dass es keine Versionskonflikte bei der Applikation gibt, denn man kann die Software nicht an beiden Standorten gleichzeitig aktualisieren.</p>
<p>Benötigt wird für so eine Lösung also zum einen eine Datenbank, welche automatisch repliziert und dies auch über mehr als einen Standort hinweg, weiterhin dazu noch ein Dateisystem, welches verteilten Host-Systemen eine gemeinsame Datenbasis bereitstellen kann.<br />
<span id="more-20"></span><br />
Zu diesem Zweck habe ich auf mehreren Test-Systemen eine solche Umgebung aufgebaut und will hier diesen Test dokumentieren. Ich habe dazu einfach 2 Systeme innerhalb eines VMware Servers erzeugt:</p>
<p>mysqlfsdevelop01 sowie mysqlfsdevelop02, mit folgender Konfiguration:</p>
<ul>
<li>2 GB HDD Space</li>
<li>Netzwerkkarte</li>
<li>256MB RAM</li>
<li>CD-ROM (mit gemountetem Disk-Image Debian-Etch 4.0)</li>
</ul>
<p>Nachdem man die Hosts in VMware angelegt hat, und Debian Etch auf diesen installiert ist, muss man noch einige Pakete nachinstallieren, mit</p>
<p><code>apt-get install build-essentials</code></p>
<p>zuerst alle benötigten Pakete installieren, damit man selbst Software kompilieren kann.</p>
<p>Weiterhin werden dann noch folgende Pakete benötigt:</p>
<p><code>apt-get install fuse-utils afuse libfuse-dev libmysqlclient15-dev libmysql++-dev glibc-dev mysql-server-5.0</code></p>
<p>Eine Liste aller installierten/benötigten Pakete gibt es <a href="http://www.netz-guru.de/downloads/mysqlfs-debian-pakete.txt" target="_blank">hier</a></p>
<p>Nachdem also unser Debian auf beiden Host-Systemen installiert ist, müssen wir noch unseren mySQL Server so konfigurieren, dass auf diesem NDB läuft. Dazu müssen auf beiden Host-Systemen Änderungen an der /etc/mysql/my.cnf vorgenommen werden:</p>
<ul>
<li>unter [mysqld] den Paramenter ndbcluster ohne Option hinzufügen</li>
<li>[MYSQL_CLUSTER] suchen und die Rauten entfernen</li>
<li>ndb-connectstring=127.0.0.1 kann beibehalten werden</li>
</ul>
<p>Dann die Datei speichern. mySQL noch nicht neu starten!</p>
<p>Dann wird in /etc/mysql/ die Datei ndb_mgmd.cnf angelegt, und folgender Inhalt eingefügt:</p>
<p><code><br />
[NDBD DEFAULT]<br />
NoOfReplicas=2</code></p>
<p>[MYSQLD DEFAULT]</p>
<p>[NDB_MGMD DEFAULT]</p>
<p>[TCP DEFAULT]</p>
<p># Section for the cluster management node<br />
[NDB_MGMD]<br />
# IP address of the management node (this system)<br />
HostName=192.168.200.40</p>
<p>#IP des ersten Nodes (mysqlfsdevelop01)</p>
<p>[NDB_MGMD]<br />
# IP address of the management node (this system)<br />
HostName=192.168.200.41</p>
<p>#IP des zweiten Nodes (mysqlfsdevelop02)</p>
<p># Section for the storage nodes<br />
[NDBD]<br />
# IP address of the first storage node<br />
HostName=192.168.200.40<br />
DataDir= /var/lib/mysql-cluster</p>
<p>[NDBD]<br />
# IP address of the second storage node<br />
HostName=192.168.200.41<br />
DataDir=/var/lib/mysql-cluster</p>
<p># one [MYSQLD] per storage node<br />
[MYSQLD]<br />
[MYSQLD]</p>
<p>Die Datei muss auf beiden Systemen angelegt werden, bei mysqlfsdevelop02 allerdings bei  [NDB_MGMD] die IP des zweiten Servers angeben, so dass auf beiden Systemen ein Management-Daemon läuft.</p>
<p>Nun starten wir zuerst den Management-Daemon, dann die NDB-Datenbank und zuletzt restarten wir mysql selbst (als API):<br />
<code><br />
/etc/init.d/mysql-ndb-mgm start</code></p>
<p>/etc/init.d/mysql-ndb start</p>
<p>/etc/init.d/mysql restart</p>
<p>Danach kann man mit ndb_mgm eine Konsole auf den NDB-Cluster öffnen. Ein &#8220;show&#8221; sollte folgenden Output erzeugen:</p>
<p><code>ndb_mgm&gt; show<br />
Connected to Management Server at: 127.0.0.1:1186<br />
Cluster Configuration<br />
---------------------<br />
[ndbd(NDB)] 2 node(s)<br />
id=3 (not connected, accepting connect from 192.168.200.40)<br />
id=4    @192.168.200.41  (Version: 5.0.32, Nodegroup: 0, Master)</code></p>
<p>[ndb_mgmd(MGM)] 2 node(s)<br />
id=1    @192.168.200.40  (Version: 5.0.32)<br />
id=2    @127.0.0.1  (Version: 5.0.32)</p>
<p>[mysqld(API)] 2 node(s)<br />
id=5    @192.168.200.40  (Version: 5.0.32)<br />
id=6    @192.168.200.41  (Version: 5.0.32)</p>
<p>Wenn dies soweit läuft, ist der erste Schritt getan.</p>
<p><!--more--><br />
Jetzt muss mysqlfs mit cvs heruntergeladen werden und übersetzt werden.</p>
<p>Dazu wechseln wir nach /usr/src und geben ein:<br />
<code><br />
cvs -d:pserver:anonymous@mysqlfs.cvs.sourceforge.net:/cvsroot/mysqlfs login<br />
</code><br />
und dann:<br />
<code><br />
cvs -z3 -d:pserver:anonymous@mysqlfs.cvs.sourceforge.net:/cvsroot/mysqlfs co -P mysqlfs<br />
</code><br />
sowie:<br />
<code><br />
./cvs-bootstrap<br />
./configure<br />
</code><br />
Falls es hier Fehler gibt, kann man mit autoreconf -i &#8211;force fehlende Teile automatisch erstellen lassen &#8211; spätestens jetzt sollte das configure ohne Probleme durchlaufen.</p>
<p>Jetzt musst allerdings noch das mysql-Schema gepatched werden &#8211; mit der Version vom CVS wird NDB-Cluster nicht unterstüzt:<br />
<code><br />
diff -Nuar mysqlfs/schema.sql mysqlfs-mrjack/schema.sql<br />
--- mysqlfs/schema.sql 2007-03-28 15:05:48.000000000 +0200<br />
+++ mysqlfs-mrjack/schema.sql   2008-03-31 22:59:06.000000000 +0200<br />
@@ -25,7 +25,7 @@<br />
`seq` int unsigned not null,<br />
`data` blob ,<br />
PRIMARY KEY  (`inode`, `seq`)<br />
-) ENGINE=MyISAM DEFAULT CHARSET=binary;<br />
+) ENGINE=NDBCLUSTER DEFAULT CHARSET=binary;</code></p>
<p>&#8211;<br />
&#8211; Table structure for table `inodes`<br />
@@ -45,7 +45,7 @@<br />
`size` bigint(20) NOT NULL default &#8216;0&#8242;,<br />
PRIMARY KEY  (`inode`),<br />
KEY `inode` (`inode`,`inuse`,`deleted`)<br />
-) ENGINE=MyISAM DEFAULT CHARSET=binary;<br />
+) ENGINE=NDBCLUSTER DEFAULT CHARSET=binary;</p>
<p>/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;<br />
DELIMITER ;;<br />
@@ -58,16 +58,16 @@<br />
&#8211;<br />
&#8211; Table structure for table `tree`<br />
&#8211;<br />
-<br />
+SET FOREIGN_KEY_CHECKS = 0;<br />
DROP TABLE IF EXISTS `tree`;<br />
CREATE TABLE `tree` (<br />
`inode` int(10) unsigned NOT NULL auto_increment,<br />
-  `parent` int(10) unsigned default NULL,<br />
+  `parent` int(10) unsigned,<br />
`name` varchar(255) NOT NULL,<br />
-  UNIQUE KEY `name` (`name`,`parent`),<br />
+  PRIMARY KEY `name` (`name`, `inode`),<br />
KEY `inode` (`inode`),<br />
KEY `parent` (`parent`)<br />
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;<br />
+) ENGINE=NDBCLUSTER DEFAULT CHARSET=utf8;<br />
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;</p>
<p>/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;</p>
<p>Nun kann man mysqlfs mit make compilieren.</p>
<p>Anschliessend muss man das Schema in die mysql-Datenbank importieren.</p>
<p>Dazu zuerst die Datenbank &#8220;mysqlfs&#8221; auf beiden Servern anlegen:<br />
<code><br />
mysql&gt; CREATE DATABASE mysqlfs;<br />
mysql&gt; GRANT SELECT, INSERT, UPDATE, DELETE ON mysqlfs.* TO mysqlfs@"%" IDENTIFIED BY 'password';<br />
mysql&gt; FLUSH PRIVILEGES;<br />
</code><br />
Sowie anschliessend das Schema importieren:<br />
<code><br />
$ mysql -uroot -p mysqlfs &lt; schema.sql<br />
</code><br />
Dann einen Mountpoint anlegen, z.B. /mysqlfs mittels mkdir /mysqlfs</p>
<p>und das File-System mounten mit:</p>
<p><code> ./mysqlfs -ohost=localhost -ouser=mysqlfs -opassword=password -odatabase=mysqlfs /mysqlfs<br />
</code></p>
<p>Man kann auch in der /etc/mysql/my.cnf einen Abschnitt [mysqlfs] erzeugen und diese Daten dort hinterlegen:<br />
<code><br />
[mysqlfs]<br />
host=localhost<br />
user=mysqlfs<br />
password=password<br />
database=mysqlfs<br />
</code><br />
Nun kann man das Filesystem einfach mit ./mysqlfs /mysqlfs mounten.</p>
<p>Ein &#8220;mount&#8221; gibt nun folgende Ausgabe:<br />
<code><br />
mysqlfs on /mysqlfs type fuse (rw,nosuid,nodev)<br />
</code><br />
Man muss mysqlfs natürlich auch auf dem zweiten, bzw. jedem weiteren Server installieren!</p>
<p>Wenn man nun Dateien in /mysqlfs erzeugt werden diese instantan auch bei dem zweiten Server verfügbar.</p>
<p>Ein Nachteil von mySQL-Fs ist jedoch, dass es relativ langsam ist, da durch mysql-ndb und fuse viel Overhead erzeugt wird. Es sei noch erwähnt, dass mysqlfs kein Locking unterstützt, weshalb man davon absehen sollte, Files mehrfach von unterschiedlichen Hosts gleichzeitig zu öffnen. Insbesondere Session-Daten etc. sind in einer mySQL-DB besser aufgehoben als ein mittels mysqlfs verteiltes /tmp/.</p>
<p>Es reicht allerdings aus, um z.B. PHP-Seiten zentral abzulegen und diese auf vielen verschiedenen Servern verfügbar zu machen, um z.B. ein Loadbalancing mittels DNS-Round-Robin zu realisieren.</p>
<p>mysqlfs ist Opensource und ist bei Sourceforge gehostet:<br />
<a title="mysql fs - fuse filesystem using mysql as storage" href="http://sourceforge.net/projects/mysqlfs/">http://sourceforge.net/projects/mysqlfs/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.netz-guru.de/2008/04/03/mysqlfs-mit-mysql-ndb-cluster-als-verteiltes-dateisystem/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>apache2, mod_mysql_auth, debian etch</title>
		<link>http://www.netz-guru.de/2008/01/30/apache2-mod_mysql_auth-debian-etch/</link>
		<comments>http://www.netz-guru.de/2008/01/30/apache2-mod_mysql_auth-debian-etch/#comments</comments>
		<pubDate>Wed, 30 Jan 2008 02:03:34 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Hosting]]></category>
		<category><![CDATA[Webtechniken]]></category>
		<category><![CDATA[apache2]]></category>
		<category><![CDATA[auth]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[etch]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://www.netz-guru.de/2008/01/30/apache2-mod_mysql_auth-debian-etch/</guid>
		<description><![CDATA[Wer ebenfalls verzweifelt mod_mysql_auth für Apache2 unter Debian Etch sucht, dem sei gesagt, dass es aus lizenztechnischen Gründen in Debian Etch nicht mehr enthalten ist.
Man kann jedoch das Module relativ einfach nachinstallieren:

mkdir /root/src
aptitude install apache2-prefork-dev libmysqlclient15-dev
cd /root/src/
mkdir auth_mysql
cd auth_mysql
wget http://download.nuxwin.com/apache2.2-modules/auth_mysql/mod_auth_mysql-3.0.0.tar.gz
wget http://download.nuxwin.com/apache2.2-modules/auth_mysql/patch/apache2.2.diff
tar xzf mod_auth_mysql-3.0.0.tar.gz
mv apache2.2.diff mod_auth_mysql-3.0.0/
cd mod_auth_mysql-3.0.0
patch -p0 &#60; apache2.2.diff mod_auth_mysql.c
apxs2 -c -L/usr/lib/mysql -I/usr/include/mysql -lmysqlclient -lm [...]]]></description>
			<content:encoded><![CDATA[<p>Wer ebenfalls verzweifelt mod_mysql_auth für Apache2 unter Debian Etch sucht, dem sei gesagt, dass es aus lizenztechnischen Gründen in Debian Etch nicht mehr enthalten ist.</p>
<p>Man kann jedoch das Module relativ einfach nachinstallieren:<br />
<span id="more-14"></span><br />
mkdir /root/src<br />
aptitude install apache2-prefork-dev libmysqlclient15-dev<br />
cd /root/src/<br />
mkdir auth_mysql<br />
cd auth_mysql<br />
wget http://download.nuxwin.com/apache2.2-modules/auth_mysql/mod_auth_mysql-3.0.0.tar.gz<br />
wget http://download.nuxwin.com/apache2.2-modules/auth_mysql/patch/apache2.2.diff<br />
tar xzf mod_auth_mysql-3.0.0.tar.gz<br />
mv apache2.2.diff mod_auth_mysql-3.0.0/<br />
cd mod_auth_mysql-3.0.0<br />
patch -p0 &lt; apache2.2.diff mod_auth_mysql.c<br />
apxs2 -c -L/usr/lib/mysql -I/usr/include/mysql -lmysqlclient -lm -lz mod_auth_mysql.c<br />
apxs2 -i mod_auth_mysql.la<br />
echo &#8220;LoadModule mysql_auth_module /usr/lib/apache2/modules/mod_auth_mysql.so&#8221; &gt; /etc/apache2/mods-available/auth_mysql.load<br />
a2enmod auth_mysql<br />
/etc/init.d/apache2 force-reload</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netz-guru.de/2008/01/30/apache2-mod_mysql_auth-debian-etch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
