Select Page

NETWAYS Blog

Analyse der Konfigration bei Galera-MySQL-Cluster

Ich möchte in diesem Blog-Beitrag noch Ergänzungen zum Galera-Blog von Marius zum Thema Konfiguration-Check machen.
Zum Beispiel kann man bestimmte Statis abfragen, ob der Cluster synchronisiert ist oder wie viele Nodes der Cluster besitzt und noch einiges mehr.
Kurz zum Verständnis bei MySQL ist das Prozentzeichen(%) das Wildcard wie bei der Bash das Sternchen(*).
Das werde ich Anhand nachfolgender Beispiele erklären.
Die Anzahl der Nodes im Cluster:
mariaDB [(none)]> show status like 'wsrep_cluster_size%';
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| wsrep_cluster_size | 3 |
+--------------------+-------+

Wie man sehen kann sind hier 3 Nodes im Cluster.
Den aktuellen Sync-Status im Cluster wird so ermittelt:
MariaDB [(none)]> show status like 'wsrep_local_state_comment%';
+---------------------------+--------+
| Variable_name | Value |
+---------------------------+--------+
| wsrep_local_state_comment | Synced |
+---------------------------+--------+

Die Ausgabe sollte hier selbsterklärend sein.
Um alle Statis von dem Cluster abzurufen kann man dieses Kommando benutzen:
show status like 'wsrep_%';
| wsrep_provider_name | Galera |
| wsrep_provider_vendor | Codership Oy <info@codership.com> |
| wsrep_provider_version | 25.3.19(r3667) |
| wsrep_ready | ON |
| wsrep_received | 56804 |
| wsrep_received_bytes | 2506329647 |
| wsrep_repl_data_bytes | 352492270

Das ist nur ein kleiner Ausschnitt aus dem Ouput der hier herauskommt
Jetzt kommen wir zur eingestellten Konfiguration, die man hier auch auslesen kann, um spätere Anpassungen vorzunehmen kann.
Die Werte dafür sind in Variablen bei MySQL gespeichert und können wie folgt abgerufen werden:
Die max_allow Variablen kann man so ermitteln:
MariaDB [(none)]> show variables like '%max_allow%';
+--------------------------+------------+
| Variable_name | Value |
+--------------------------+------------+
| max_allowed_packet | 536870912 |
| slave_max_allowed_packet | 1073741824 |
+--------------------------+------------+

Wenn man hier etwas herumspielt mit den Werten, kann man erstaunliches und informatives herausfinden.
So als kleiner Einstieg sollte dieser Beitrag ausreichen damit man die wichtigsten Einstellungen beim Galera-Cluster ausgegeben bekommt.
Lesenswert Link:
Galera Dokumtentation
Empfehlenswert sind natürlich unsere Schulungen im Bereich, die auf jeden Fall einen Blick wert sind.

Johannes Carraro
Johannes Carraro
Senior Systems Engineer

Bevor Johannes bei NETWAYS anheuerte war er knapp drei Jahre als Systemadministrator in Ansbach tätig. Seit Februar 2016 verstärkt er nun unser Team Operations als Senior Systems Engineer. In seiner Freizeit spielt Johannes E-Gitarre, bastelt an Linux Systemen zuhause herum und ertüchtigt sich beim Tischtennisspielen im Verein, bzw. Mountainbiken, Inlinern und nicht zuletzt Skifahren.

Icinga 2 – Monitoring automatisiert mit Puppet Teil 8: Integration von Icinga Web 2

This entry is part 8 of 14 in the series Icinga 2 Monitoring automatisiert mit Puppet

Zum Ausklang des Jahres 2017 gibt es nochmals einen Post zum Thema Puppet und Icinga. Es geht heute um das Ziel, einen Icinga-Server inklusive Icinga Web 2 mittels Puppet zu managen. Die Icinga IDO sowie eine Datenbank zur Authentifizierung am Icinga Web 2 sind beide als MySQL-Datenbanken realisiert. Kommandos von Icinga Web 2 werden zum Icinga-Core via Icinga-2-API übertragen.
Als Plattform kommt ein CentOS 7 zum Einsatz. Damit muss für die aktuellen Pakete zum Icinga Web 2 ab Version 2.5.0 der verwendete Apache den PHP-Code mittels FastCGI ausführen.
Voraussetzung ist, dass die erforderlichen Puppet-Module icinga-icinga2, icinga-icingaweb2, puppetlabs-mysql und deren jeweilige Abhängigkeiten installiert sein müssen.
Beginnen wir zuerst mit einigen Variablen, die wir setzen, um im nachfolgenden Code keine Redundanzen zu haben. Wir setzen hier wie die Datenbanken für die IDO und fürs Icinga Web 2 heißen sollen und mit welchem Account jeweils darauf zugegriffen werden soll. Zusätzlich kommt noch der Name und das Passwort des Benutzers für die Icinga-2-API hinzu.

$ido_db_name = 'icinga'
$ido_db_user = 'icinga'
$ido_db_pass = 'icinga'
$api_user    = 'icingaweb2'
$api_pass    = '12e2ef553068b519'
$web_db_name = 'icingaweb2'
$web_db_user = 'icingaweb2'
$web_db_pass = 'icingaweb2'

Der nun folgende Code ist für Puppet 4 und neuer gedacht, da das Feature bzgl. Reihenfolge der Deklarationen in der Datei vorausgesetzt wird.
Für CentOS werden im Vorfeld zusätzliche Repositories benötigt, EPEL für die Plugins und SCL für das FastCGI PHP in der Version 7. Die Klasse icinga2 kümmert sich nicht nur um die Grundkonfiguration, sondern außerdem auch um die Einbindung des Icinga-Repos.

package { ['centos-release-scl', 'epel-release']:
  ensure => installed,
}
class { '::icinga2':
  manage_repo => true,
}

Als nächstes kümmern wir uns um den MySQL-Server und die von uns benötigten Datenbanken für die IDO und das Icinga Web 2. Beide laufen auf dem selben Host wie Icinga 2 und Icinga Web 2.

include ::mysql::server
mysql::db { $ido_db_name:
  user     => $ido_db_user,
  password => $ido_db_pass,
  host     => 'localhost',
  grant    => ['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'DROP', 'CREATE VIEW', 'CREATE', 'ALTER', 'INDEX', 'EXECUTE'],
}
mysql::db { $web_db_name:
  user     => $web_db_user,
  password => $web_db_pass,
  host     => 'localhost',
  grant    => ['ALL'],
}

Nun können wir das IDO-Feature von Icinga 2 konfigurieren und aktivieren. Da es im Zusammenhang der Defined Resources für die Datenbank und das Feature zu einer Abhängigkeit kommt, die nicht via Top-Down-Dependency gelöst werden kann, muss hier mit require gearbeitet werden, damit die Datenbank vorher erzeugt wird.

class { '::icinga2::feature::idomysql':
  database      => $ido_db_name,
  user          => $ido_db_user,
  password      => $ido_db_pass,
  import_schema => true,
  require       => Mysql::Db[$ido_db_name],
}

Da Icinga Web 2 Kommandos mittels API an Icinga 2 senden soll, benötigen wir eine CA sowie die Aktivierung der Features API selbst. Die Certificate Authority soll eine von Icinga verwaltete CA sein. Das erfordert die Deklaration der Klasse icinga2::Pki::ca, die sich um genau dieses kümmert. Das Feature muss dann mit none für den Parameter pki werden, da sonst mit dem Default, die Puppet-Zertifikate verwendet werden und damit nicht mehr zur CA passen würden.
Zusätzlich erzeugen wir in einer Konfigurationsdatei noch einen API-User, der entsprechend eingeschränkte Rechte hat, um dann von Icinga Web 2 verwendet zu werden Kommandos zu übertragen.

class { '::icinga2::feature::api':
  pki => 'none',
}
include ::icinga2::pki::ca
::icinga2::object::apiuser { $api_user:
  ensure      => present,
  password    => $api_pass,
  permissions => [ 'status/query', 'actions/*', 'objects/modify/*', 'objects/query/*' ],
  target      => "/etc/icinga2/conf.d/api-users.conf",
}

Das Icinga-Repository ist schon aktiviert und wir ziehen die Installation der Pakete für Icinga Web 2 aus der Klasse icingaweb2 heraus. Damit profitieren wir davon, dass die abhängigen Pakete für PHP mit FastCGI zu diesem Zeitpunkt schon installiert werden und wir den Dienst rh-php71-php-fpm schon vor der Installation von icinga Web 2 mit allen benötigten PHP-Modulen starten können. Anders herum müsste dafür Sorge getragen werden die Dienst nach icingaweb2 nochmals für einen Neustart zu triggern.
Zusätzlich kommen noch die Standard-Plugins und der Apache aufs System. Bevor der Apache-Service deklariert wird, soll noch die erforderliche Apache-Konfiguration fürs Icinga Web 2 ins Konfigurationsverzeichnis des Webservers abgelegt werden. Dieses Beispiel für FastCGI ist erst im Module ab Version 2.0.1 von puppet-icingaweb2 enthalten.
TIPP: Die hier verwendete File-Resource mit der Quelle auf das Example aus dem offiziellen Modul sollte in Produktion nicht verwendet werden, sondern nur als Beispielvorlage für eine eigene Source dienen.

package { ['icingaweb2', 'icingacli', 'httpd', 'nagios-plugins-all']:
  ensure => installed,
}
file { '/etc/httpd/conf.d/icingaweb2.conf':
  ensure => file,
  source => 'puppet:///modules/icingaweb2/examples/apache2/for-mod_proxy_fcgi.conf',
  notify => Service['httpd'],
}
service { 'httpd':
  ensure => running,
  enable => true,
}

Das in Abhängigkeit vom Paket icingaweb2 installierte PHP mit dem FastCGI-Dienst kann nun konfiguriert und gestartet werden. Die hier verwendete file_line Resource kann bei bedarf durch eine mit Augeas gemanagte ersetzt werden.

file_line { 'php_date_time':
  path  => '/etc/opt/rh/rh-php71/php.ini',
  line  => 'date.timezone = Europe/Berlin',
  match => '^;*date.timezone',
}
~> service { 'rh-php71-php-fpm':
  ensure => running,
  enable => true,
}

Nachdem nun alle Voraussetzungen gegeben sind, kümmern wir uns abschließend um Icinga Web 2. Dies unterteilt sich in zwei Schritte. Icinga Web 2 ist als aller erstes ein Framework für Weboberflächen, die spezifischen Sachen fürs Monitoring ist in einem Modul implementiert. Da es viele weitere zusätzliche Module gibt, folgt auch das Puppet-Modul diesem Schema.

class { 'icingaweb2':
  manage_package => false,
  import_schema  => true,
  db_name        => $web_db_name,
  db_username    => $web_db_user,
  db_password    => $web_db_pass,
  require        => Mysql::Db[$web_db_name],
}

Zuerst wird das Framework mit dem zur Authentifizierung nötigen Datenbankzugriff konfiguriert und erst dann das Monitoring-Modul. Für dieses ist der IDO-Zugriff zwingend erforderlich und der Transportweg für die zusendenden Kommandos wird mittels API konfiguriert.

class { 'icingaweb2::module::monitoring':
  ido_host        => 'localhost',
  ido_db_name     => $ido_db_name,
  ido_db_username => $ido_db_user,
  ido_db_password => $ido_db_pass,
  commandtransports => {
    icinga2 => {
      transport => 'api',
      username  => $api_user,
      password  => $api_pass,
    }
  }
}

Bleibt als letzten allen unseren Bloglesern ein Frohes Neues Jahr zu wünschen!

Lennart Betz
Lennart Betz
Senior Consultant

Der diplomierte Mathematiker arbeitet bei NETWAYS im Bereich Consulting und bereichert seine Kunden mit seinem Wissen zu Icinga, Nagios und anderen Open Source Administrationstools. Im Büro erleuchtet Lennart seine Kollegen mit fundierten geschichtlichen Vorträgen die seinesgleichen suchen.

Revisited – Graphite-Web installation unter Debian 9

Erstmal wieso Revisited ?

Dies ist ein update meines älteren Blog Posts Blogpost 2016 welcher darauf einging das unter Debian 8.4 graphite-web wegen eines Fehlenden Eintrages in der Apache 2.4 Konfiguration nicht korrekt gestartet/aufgerufen werden konnte.
Es ist schon einige Zeit ins Land gegangen und ich habe weniger ein Auge darauf geworfen ob das weiterhin so Funktioniert.
Deshalb Revisited.

Here we Go again !

Ich gehe in diesem Fall von einer Debian Version der Nummer 9 aus und werde wie bei dem alten Blogpost. In der Grundannahme mal davon ausgehen das alles Funktioniert wie es soll:
Also hier die folgenden installationschritte:
#> apt-get install apache2 libapache2-mod-wsgi python-django python-django-tagging fontconfig python-tz python-pip python-dev python-twisted python-cairo
#> pip install carbon whisper graphite-web
#> pip install --upgrade twisted
#> cp /opt/graphite/conf/carbon.conf.example /opt/graphite/conf/carbon.conf
#> cp /opt/graphite/conf/storage-schemas.conf.example /opt/graphite/conf/storage-schemas.conf
#> /opt/graphite/bin/carbon-cache.py start
#> /opt/graphite/bin/carbon-cache.py status
#> cp /opt/graphite/examples/example-graphite-vhost.conf /etc/apache2/sites-available/graphite.conf
#> cp /opt/graphite/conf/graphite.wsgi.example /opt/graphite/conf/graphite.wsgi
#> cp /opt/graphite/webapp/graphite/local_settings.py.example \ /opt/graphite/webapp/graphite/local_settings.py
#> python /opt/graphite/webapp/graphite/manage.py syncdb
#> chown www-data. -R /opt/graphite/storage
#> a2dissite 000-default
#> a2ensite graphite
#> a2enmod wsgi
#> service apache2 restart
#> chmod +x /etc/init.d/carbon-cache // Damit 'carbon-cache.py start' mit Systemstart erfolgt

Ergebnis davon ist -> Nichts funktioniert.

Back to the Roots

Ab hier kommt der Weg graphite-web auf einem Debian 9 (Stretch) in Betrieb zu nehmen.
Ausgangspunkt ist ein frisch installiertes Debian 9.
#> apt-get install vim -y
#> vim /etc/apt/sources.list

Wir müssen die Sources auf die Jessie Repositories setzen da zum Zeitpunkt dieses Blogposts die graphite-web Pakete nicht abrufbar sind.
Daher fügen wir folgendes hinzu in der sources.list
deb http://httpredir.debian.org/debian jessie main
Gefolgt von einem frischem #> apt-get update -y .
Nun installieren wir den großteil der Pakete welche wir benötigen.
#> apt-get install graphite-web graphite-carbon mysql-server python-mysqldb python-pymysql apache2 libapache2-mod-wsgi apt-transport-https ssl-cert python-pip -y
Es folgen ca. 300MB an Daten.
Daraufhin stürzen wir uns direkt auf die Konfig.
Wir fangen an folgende Datei zu editieren.
#> vim /etc/graphite/local_settings.py
Darin ändern wir folgende Settings Sinnvoll in etwas was wir für unsere Installation benötigen.
Also SECRET_KEY, TIME_ZONE & ALLOWED_HOSTS setzen.
Danach muss in der folgenden Datei ein “true” gesetzt werden damit graphite & carbon gemeinsam starten.
#> vim /etc/default/graphite-carbon
Nun kommt der trickreichste Part wir sind leider dazu genötigt eine alte django Version zu installieren.
#> pip install "django==1.4"
Damit haben wir die Grundlage womit wir das folgende Kommando erfolgreich absetzen können.
#> graphite-manage syncdb
#> Kundenverbesserung: Danke an bbtronic!
#> graphite-manage migrate --run-syncdb
#> chown _graphite. /var/lib/graphite/graphite.db
HINWEIS ! Dies setzt erst mal die voreingestellte sqlitedb in Gang.
Wenn eine andere DB verwendet werden soll dann sollte dies bitte in der “local_settings.py” vorgenommen werden.
Wir sind fast am Ziel ein funktionierendes graphite-web zu haben.
Es fehlt nur etwas Apache2 Magie.
#>a2dissite 000-default.conf
#>cp /usr/share/graphite-web/apache2-graphite.conf /etc/apache2/sites-available/
#> a2ensite apache2-graphite.conf
#> systemctl restart apache2

Voilà !

Es sollte nun auf dem Host System das graphite-web aufrufbar sein.

Danke für die Aufmerksamkeit !

Addenum nicht Sichtbare Kommentare von Kunden:
# Oliver: Ich bekam leider den Fehler:
twisted.python.usage.UsageError: Unknown command: carbon-cache

Hier hat dies geholfen:
mv /usr/local/lib/python2.7/dist-packages/twisted /usr/local/lib/python2.7/dist-packages/twisted2

Hier half mir ein downgrade:
python -m pip install ‘django-tagging<0.4' Das hatte ich auch, habe es mit upgrade auf django 1.5 beseitigen können: python -m pip install django==1.5 Vinc: hallo David nach dem ich die Installation bei back to the roots gestartet habe, klappte es. Wobei ein paar Infos unter Also SECRET_KEY, TIME_ZONE & ALLOWED_HOSTS wäre wohl noch nützlich. Aber trotzdem – klappt es nicht – die “bilder” erscheinen nicht wie wenn der Pfad falsch ist. gruss vinc

David Okon
David Okon
Senior Systems Engineer

Weltenbummler David hat aus Berlin fast den direkten Weg zu uns nach Nürnberg genommen. Bevor er hier anheuerte, gab es einen kleinen Schlenker nach Irland, England, Frankreich und in die Niederlande. Alles nur, damit er sein Know How als IHK Geprüfter DOSenöffner so sehr vertiefen konnte, dass er vom Apple Consultant den Sprung in unser Professional Services-Team wagen konnte. Er ist stolzer Papa eines Sohnemanns und bei uns mit der Mission unterwegs, unsere Kunden zu glücklichen Menschen zu machen.

Galera Cluster – Tips für die Praxis

Galera Cluster für MySQL ist mal ein “einfacher” Cluster für MySQL und seit MariaDB Version 10.1 standardmäßig mit an Board. Dadurch erhält man mit ein paar Zeilen Konfiguration einen produktionsfähigen Cluster, um den man sich wenig kümmern muss. In der Praxis allerdings, bieten sich genügend Fallstricke, die es zu meistern gilt.

Die Terminologie

  • Joiner: Neues Member welches dem Cluster hinzugefügt wird
  • Donor: Meldet sich ein Joiner stellt der Cluster einen Lieferanten bereit welcher die Daten auf den Joiner überträgt
  • SST: Snapshot State Transfer – Ist Lücke zum aktuellen Stand zu groß, werden der komplette Stand übertragen
  • IST: Incremental State Transfer – Im laufenden Betrieb werden Änderungen direkt übertragen. Die Änderung ist am Cluster erst verfügbar wenn alle Mitglieder diesen Stand empfangen haben

Tipps

1. SST Vermeiden

Einen kompletten Stand der Daten zu übertragen ist keine gute Idee. Ein Cluster, welcher 1 TB Nutzdaten verwaltet, ist auch nach drei Tagen nicht fertig. Dadurch können stabile Member ihre Integrität verlieren und der Cluster wird instabil. Hat man eine solche Situation erreicht empfiehlt es sich, den kompletten Cluster manuell zu syncen (MySQL Daten löschen und per rsync kopieren – Aber bitte keine Binlogs!).

2. SST Method

Galera bietet verschiedene Methoden um einen SST durchzuführen. Laut Statistik ist SSH die schnellste Methode – D’Accord – Aber der dadurch entstehende Donor ist für Anfragen gelockt und fällt aus dem Cluster. Dadurch wären wir bei Punkt 1 angelangt. Der beste trade-off ist hier xtrabackup-v2. Dadurch wird ein Donor am wenigsten blockiert. Bitte dabei den Benutzer zur MySQL Authentifizierung nicht vergessen – Sonst geht gar nichts!

3. SST Konfiguration

SST und das ausführen auf dem Joiner kann maßgeblich verbessert werden mit folgender MySQL Konfiguration:

[sst]
inno-apply-opts="--use-memory=20G"
compressor="pigz"
decompressor="pigz -d"

Dadurch geben wir dem innobackupex Script, welches auf dem Joiner ausgeführt mehr Speicher um Daten aus den Logs (–apply-log) auszuführen. Weiterhin parallelisieren wir den Vorgang um Daten auf dem Donor zu komprimieren und – guess what – auf dem Joiner zu dekomprimieren.
Um die Transaktionen weiter zu parallelisieren erhöhen wir die Einstellung wsrep_slave_threads auf eine dem System angepasste Anzahl (Anzahl Cores und Auslastung).

4. Dedizierten Donor

Bei großen Datenmengen empfiehlt es sich einen eigenständigen Donor bereitzustellen welcher keine Anfragen entgegen nimmt.

[mysqld]
 wsrep_sst_donor = node-donor

Eventuell sollte man auch Queries mit der Einstellung wsrep_sst_donor_rejects_queries verbieten

5. Locking Queries

Galera ist maximal transparent für Applikationen. Einzig, LOCKING wird nicht akzeptiert. Falls es von der Applikation benötigt wird könnte man mit der Einstellung wsrep_convert_LOCK_to_trx die Queries in Transaktionen kapseln.

6. Provider Cache

Standardmäßig auf 128M eingestellt, enthält dieser Ringpuffer die zu Verfügung stehen write-sets für einen IST. Die Größe sollte man entsprechend hoch wählen. So kann auch bei größeren Lücken immer noch ein IST durchgeführt werden:

[mysqld]
wsrep_provider_options="gcache.size=1G"

Bei entsprechend Arbeitsspeicher oder SSD Storage ist es durchaus eine gute Idee die Datei auf das schnellste Storage zu legen oder eine Lastaufteilung vorzunehmen:

[mysqld]
wsrep_provider_options="gcache.size = 8G; gcache.name = /var/cache/ssd/galera.cache"
7. HAProxy verwenden

Der stabilste Cluster bringt einem gar nichts wenn man nur einen Knoten abfragt. Eine der Stärken von Galera ist es, von allen Knoten zu lesen. Hier sollte man sich Gedanken zur Aufteilung machen:

  • Die schnellsten Knoten zum lesen und in den HAProxy
  • Donor exkludieren
  • Backup members bereitstellen (hot-standby)

Eine Konfiguration können z.B. folgendermaßen aussehen:

backend mysql_pool   mode tcp
  balance roundrobin   option mysql-check user haproxy   option tcpka # keep-alive!   server galera-donor1   192.168.17.20:3306 check inter 12000 disabled   server galera-standby1 192.168.17.21:3306 check inter 12000 disabled   server galera-node3    192.168.17.22:3306 check inter 12000
  server galera-node4    192.168.17.23:3306 check inter 12000
  server galera-node5    192.168.17.24:3306 check inter 12000

Dadurch erhalten wir einen Donor, einen hot-standby und drei read-heads. Durch die HAProxy API kann man das auch je nach Zustand des Cluster zu oder abschalten. Auch wäre eine standortübergreifende Verteilung möglich. Man stelle sich verschiedene Pools in verschiedenen Ländern vor. Je nach Ursprung und Applikation können dann die Anfragen zu den schnellsten read-heads weitergeleitet werden. Dann sollte man sich aber überlegen, z.B.  wsrep_dirty_reads an den Standorten zu verwenden.

8. Bin Logs

Ein richtiger Klassiker der Cluster Pitfalls, die Binary Logs von MySQL. Man würde sie für Galera nicht unbedingt benötigen aber sie bieten Sicherheit beim Crash und helfen einen SST im Falle zu vermeiden. In großen Umgebungen muss man folgendes bedenken:

  • Speicherplatz begrenzen
  • Vorhaltezeit verkürzen
  • An das verfügbare Storage anpassen

Ansonsten dauert ein FLUSH LOGS gerne auch mal 3 Tage und blockiert einen unseren Knoten – Beim Donor besonders schlecht!

Fazit

Für mich ein fantastisches Cluster System für MySQL! Es gibt noch viele gute Tips da draussen und noch viel mehr Möglichkeiten (und auch schmerzen) mit InnoDB / MySQL Konfiguration. Es funktioniert auch leider beim Galera Cluster nichts ohne vorher die eigene Rübe einzuschalten 😉

Links

 

Marius Hein
Marius Hein
Head of IT Service Management

Marius Hein ist schon seit 2003 bei NETWAYS. Er hat hier seine Ausbildung zum Fachinformatiker absolviert und viele Jahre in der Softwareentwicklung gearbeitet. Mittlerweile ist er Herr über die interne IT und als Leiter von ITSM zuständig für die technische Schnittmenge der Abteilungen der NETWAYS Gruppe. Wenn er nicht gerade IPv6 IPSec Tunnel bohrt, sitzt er daheim am Schlagzeug und treibt seine Nachbarn in den Wahnsinn.

if exists for Column and Index Migrations in MySQL

Unfortunately MySQL does not provide an SQL statement for conditionally creating a column if it does not already exist. There also does not appear to be an easy way for dropping a column without causing an error if the column doesn’t exist. The same problem also applies to indices. This functionality however is commonly used for idempotent schema updates. Without stored procedures which take care of the changes you are lost. I would like to share a Gist on GitHub which helps for the following schema migrations:

  • Drop index if exists
  • Create index if not exists
  • Create unique index if not exists
  • Drop column if exists
  • Add column if not exists

I am using the INFORMATION_SCHEMA tables for testing for the existence of columns and indices. No special grant is necessary to query from those tables. The stored procedures have the following signature:
Drop index if exists
m_drop_index(table_name, index_name)
Create index if not exists
m_create_index(table_name, index_name, index_columns)
Create unique index if not exists
m_create_unique_index(table_name, index_name, index_columns)
Drop column if exists
m_drop_column(table_name, column_name)
Add column if not exists
m_add_column(table_name, column_name, column_definition)
After importing, you can use them instead of MySQL’s ALTER statements. Here is an example for adding the name column to the table person:

mysql> CALL m_add_column('person', 'name', 'varchar(255)');
Eric Lippmann
Eric Lippmann
CTO

Eric kam während seines ersten Lehrjahres zu NETWAYS und hat seine Ausbildung bereits 2011 sehr erfolgreich abgeschlossen. Seit Beginn arbeitet er in der Softwareentwicklung und dort an den unterschiedlichen NETWAYS Open Source Lösungen, insbesondere inGraph und im Icinga Team an Icinga Web. Darüber hinaus zeichnet er für viele Kundenentwicklungen in der Finanz- und Automobilbranche verantwortlich.