Das Backend von ComputerBase Steffen Weber / @Steffen185 01.09.2014 / Webentwickler Paderborn
Gliederung 1. Einleitung 2. Datenbank 3. Webserver 4. Website
ComputerBase
Reichweite 2,5 Mio Unique User ( AGOF Juni 2014) CHIP.de / computerbild.de: ~ 13 Mio Golem.de / pcgameshardware.de: ~ 1,3 Mio 1 Mio Seitenaufrufe pro Tag
Die Köpfe hinter CB 3 Geschäftsführer 3 Festangestellte Redakteure Freie Redakteure Freie Moderatoren
Datenbank 27 GB Größte Tabelle: 13 GB
Dateien 220 GB Bilder 620 GB Videos 130 GB Downloads
Server-Setup Stromverbrauch: je ~ 100 Watt, Anbindung: 500 MBit/s Verantwortung: CB (Software) und Host Europe (Hardware)
Datenbank
MySQL-Setup Basics Percona Server (MySQL + Patches) kein Cluster Master-Slave-Setup DB-Server 1: Master DB-Server 2: Slave
MySQL-Performance 27 GB 64 GB InnoDB > MyISAM RAID-Controller mit 1 GB Cache + BBU Alternative SSD? Tuning-Tipps: MySQL Performance Blog InnoDB performance optimization basics (redux)
Schema-Änderung großer Tabellen Problem: ALTER TABLE Lock Downtime :-( Lösung: pt-online-schema-change $ pt-online-schema-change --alter="add logoid INT" D=cb,t=cb_news Altering `cb`.`cb_news`... Creating new table... Created new table cb._cb_news_new OK. Altering new table... Altered `cb`.`_cb_news_new` OK. Creating triggers... Created triggers OK. Copying approximately 1119 rows... Copied rows OK. Swapping tables... Swapped original and new tables OK. Dropping old table... Dropped old table `cb`.`_cb_news_old` OK. Dropping triggers... Dropped triggers OK. Successfully altered `cb`.`cb_news`.
MySQL-Backups Problem: mysqldump Lock Downtime :-( Lösung: Percona XtraBackup Achtung: Ausgabe ist kein SQL-Dump! XtraBackup GnuPG Amazon S3
Aufwärmen nach Neustart Einfache Lösung: cat /data/mysql/computerbase/* > /dev/null Neue Lösung (InnoDB-only): Percona Server 5.5: Buffer Pool Dump/Restore MySQL 5.6+: Buffer Pool Preloading
Live -Daten in Entwicklungsumgebung Server: db-dev-copy.php 1. Struktur der Datenbank klonen 2. Selektiv Daten in geklonte DB kopieren 3. mysqldumpder geklonten DB an stdoutsenden Entwicklungsumgebung: mysql-sync-dev.sh #!/bin/sh ssh -C db2.computerbase.de 'db-dev-copy.php' \ mysql -u computerbase computerbase $ time mysql-sync-dev.sh real 0m57.651s
Sicherheit: phpmyadmin-zugriff Standard-Lösung: HTTP Auth Separate Benutzer-Datenbank Rate Limiting? Ergänzung: SSH-Tunnel Server: phpmyadmin erreichbar auf Port 1443, der in nginx und iptables nur für 127.0.0.1 / ::1 freigegeben ist Client-Terminal: ssh -N -L 1443:localhost:1443 <server> Client-Browser: https://localhost:1443/
Vollständige UTF-8-Unterstützung UTF-8 kodiert Zeichen mit 1 4 Byte utf8in MySQL: maximal 3 Byte je Zeichen Lösung ab MySQL 5.5: utf8mb4
Webserver
PHP-Einbindung Steinzeit: PHP-Modul läuft in jedem Apache-Prozess Heute: FastCGI, PHP als separater Daemon Umstellung auf nginx um 9 Uhr (22. Juli 2008)
Mehrere PHP-Prozess-Pools (1) Beispiel Preisvergleich: Proxy auf PHP-Ebene
Mehrere PHP-Prozess-Pools (2) [www] listen = 127.0.0.1:9000 pm = static pm.max_children = 16 [preisvergleich] listen = 127.0.0.1:9001 pm = static pm.max_children = 2 location /preisvergleich { fastcgi_pass 127.0.0.1:9001;... } php-fpm.conf nginx.conf
PHP-Performance PHP selten das Bottleneck, aber... PHP 5.6 > PHP 5.5 > PHP 5.4 > PHP 5.3 APC / OpCache
DoS-Schutz in iptables 1. Beschränken der Anzahl neuer Verbindungen iptables-modul hashlimit 2. Beschränken der Anzahl gleichzeitiger Verbindungen iptables-modul connlimit 3. Connection-Tracking-Timeouts herabsetzen Datei /etc/sysctl.conf net.netfilter.nf_conntrack_tcp_timeout_close_wait = 10 net.netfilter.nf_conntrack_tcp_timeout_established = 3600...
DoS-Schutz in nginx Motivation: HTTP-Requests nach dynamischen Seiten sind sehr viel teurer als HTTP-Requests nach statischen Dateien http {... limit_req_zone $binary_remote_addr zone=flood:10m rate=2r/s; server {... } } location ~ \.php$ { limit_req zone=flood burst=8;... }
Bonus: gzip_static + Zopfli 1. nginx-modul gzip_static : auf Requests nach main.css antwortet nginx mit main.css.gz 2. Deployment: Erstellen der.gz-dateien mit Zopfli Größe [Byte] Zeit [ms] main.css 72.865 - gzip 14.471 10 gzip -9 14.366 13 zopfli 13.618 355
Website
Website: Grundlagen BaseCMS Content Management System (für Redakteure) Eigenentwicklung, 50k SLOCs (PHP) vbulletin Forum-Software Off the Shelf
Website: Performance Erfahrung: PHP ist (fast) nie das Bottleneck, daher Konzentration auf die Datenbank! 1. Während der Entwicklung: jede neue SQL-Query mit EXPLAIN SELECT...analysieren 2. Im Live-Betrieb: Einen Blick werfen in MySQL Slow Query Log PHP-FPM Slow Log 3. Caching: nächste Folie
Website: Caching Memcached: Speichern von HTML-Fragmenten Startseiten-Aufruf $code = $this->memcache->get('index-news', function() { $html =...; // Generate HTML return $html; }); Speichern einer News $this->memcache->delete('index-news');
Website: Message Queue Gearman: Aufgaben an andere Server verteilen Bei News-Veröffentlichung $this->gearman->dobackground('feed-update', 'news'); Hintergrund-Prozess $worker = new Lib\GearmanWorker();... $worker->addfunction('feed-update', [Lib\Feeds::class, 'updatefeed']);... while ($worker->work()); Weitere Beispiele: Bild-Upload, Twitter-Status,
HTTPS Drei Vorteile Sicherheit: Vertraulichkeit, Authentizität, Integrität Performance: SPDY / HTTP 2.0 SEO: Besseres Google-Ranking (angeblich) Warum (noch) nicht auf CB? HTTPS-inkompatible Anzeigen Ausnahmen: Login-Seite, Passwort ändern,
Deployment mehrmals täglich, möglichst atomar 1. git pullin temporärem Verzeichnis 2. CSS und JS komprimieren (wenn geändert) 3. Kopieren der Dateien ins Ziel-Verzeichnis via rsyncmit dem Parameter --delay-updates
Fragen? Steffen Weber / @Steffen185