<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>erkules</title>
    <link rel="alternate" type="text/html" href="http://linsenraum.de/erkules/" />
    <link rel="self" type="application/atom+xml" href="http://linsenraum.de/erkules/atom.xml" />
    <id>tag:linsenraum.de,2010-01-29:/erkules//2</id>
    <updated>2011-05-08T23:55:17Z</updated>
    <subtitle>bloggiwoggi</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.23-en</generator>

<entry>
    <title>Power to the Backend</title>
    <link rel="alternate" type="text/html" href="http://linsenraum.de/erkules/2011/05/power-to-the-backend.html" />
    <id>tag:linsenraum.de,2011:/erkules//2.171</id>

    <published>2011-05-08T23:17:45Z</published>
    <updated>2011-05-08T23:55:17Z</updated>

    <summary> Ich selbst nutze unter anderem PowerDNS als DNS-Server. Im letzten Monat betrachtete ich mir dessen MySQL-Backend, da ich über zwei Kanäle darüber informiert wurde, dass PowerDNS mit dem Backend nicht skaliert. Die DNS-Records werden in PowerDNS in zwei Tabellen...</summary>
    <author>
        <name>erkan</name>
        
    </author>
    
        <category term="PowerDNS" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="mysql" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="mysql" label="mysql" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="de" xml:base="http://linsenraum.de/erkules/">
        <![CDATA[ Ich selbst nutze unter anderem PowerDNS als DNS-Server. Im letzten
Monat betrachtete ich mir dessen MySQL-Backend, da ich über zwei
Kanäle darüber informiert wurde, dass PowerDNS mit dem
Backend nicht skaliert. <br />
<br />
Die DNS-Records werden in PowerDNS in zwei Tabellen abgelegt. Eine
für die Domains:<br /><br />
<p style="font-family: Courier New,Courier,monospace; background-color: rgb(240, 192, 172); margin-left: 40px; margin-right: 40px;"><span style="font-family: monospace;">create table domains (</span><br style="font-family: monospace;" />
<span style="font-family: monospace;"> id INT auto_increment,</span><br style="font-family: monospace;" />
<span style="font-family: monospace;"> name VARCHAR(255) NOT NULL,</span><br style="font-family: monospace;" />
<span style="font-family: monospace;"> master VARCHAR(128) DEFAULT NULL,</span><br style="font-family: monospace;" />
<span style="font-family: monospace;"> last_check INT DEFAULT NULL,</span><br style="font-family: monospace;" />
<span style="font-family: monospace;"> type VARCHAR(6) NOT NULL,</span><br style="font-family: monospace;" />
<span style="font-family: monospace;"> notified_serial INT DEFAULT
NULL, </span><br style="font-family: monospace;" />
<span style="font-family: monospace;"> account VARCHAR(40) DEFAULT NULL,</span><br style="font-family: monospace;" />
<span style="font-family: monospace;"> primary key (id)</span><br style="font-family: monospace;" />
<span style="font-family: monospace;">) Engine=InnoDB;</span><br />
</p>
Und eine weitere für die Records:<br /><br />
<p style="font-family: monospace; background-color: rgb(240, 192, 172); margin-left: 40px; margin-right: 40px;">CREATE
TABLE records (<br />
id int(11) NOT NULL auto_increment,<br />
domain_id int(11) NOT NULL,<br />
name varchar(255) NOT NULL,<br />
type varchar(10) NOT NULL,<br />
content varchar(255) NOT NULL,<br />
ttl int(11) NOT NULL,<br />
prio int(11) default NULL,<br />
change_date int(11) default NULL,<br />
PRIMARY KEY (id),<br />
KEY name_index(name),<br />
KEY nametype_index(name,type),<br />
KEY domainid_index(domain_id)<br />
);</p>
Zudem existiert noch ein FK-Constraint, aber auch der tut hier nichts
zur Sache.<br />
Die Tabelle domains wurde mit 6.000.000 Datensätzen bestückt.
Die Tabelle records wurde mit 46.195.356 Datensätzen
bestückt. Ich denke damit wird schon ein größerer DNS-Server simuliert :D<br /><br />
Zwar schien es, als sollte man sich mal Gedanken über die
Normalisierung ansich machen, doch das war nicht
mein Skope. Es galt mit etwas Mikrotuning schon Erfolge zu erzielen. PowerDNS pdns-3.0-rc2 und folgende MySQL-Version kam zum Einsatz:<br /><br />
<p style="font-family: Courier New,Courier,monospace; background-color: rgb(240, 192, 172); margin-left: 40px; margin-right: 40px;"><code>[pdns]&gt;
SELECT VERSION();<br />
+-------------------+<br />
| VERSION()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />
+-------------------+<br />
| 5.2.5-MariaDB-log |<br />
+-------------------+<br />
1 row in set (0.00 sec)<br />
</code></p>
<code><span style="font-family: serif;">Die Datenbank meinte die
Tabellen würden folgenden Platzverbrauch haben.</span><br /><br />
</code>
<p style="font-family: Courier New,Courier,monospace; background-color: rgb(240, 192, 172); margin-left: 40px; margin-right: 40px;"><code>&gt;
SELECT TABLE_NAME,INDEX_LENGTH,DATA_LENGTH from
information_schema.TABLES where TABLE_NAME IN('records','domains');<br />
+------------+--------------+-------------+<br />
| TABLE_NAME | INDEX_LENGTH | DATA_LENGTH |<br />
+------------+--------------+-------------+<br />
| domains&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; 475004928 |&nbsp;&nbsp;
431898624 |<br />
| records&nbsp;&nbsp;&nbsp; |&nbsp; 11372855296 |&nbsp; 5813305344 |<br />
+------------+--------------+-------------+<br />
<br />
</code></p>
<code><span style="font-family: serif;">Bei PowerDNS wurden alle Caches
abgeschaltet (es galt die Datenbank zu testen!) und 494969 disjunkte
DNS-Abfragen gestellt. Diese waren in 48.9 Sekunden durchgelaufen, was
ca. 10114 qps entspricht. (Für jeden Test wurde die Datenbank
restartet und der zweite Lauf genommen.)<br /><br />Da Abfragen gegen die Tabelle records gehen,&nbsp; nur diese Tabelle "optimiert"- Einige Änderungen sind analog in der Tabelle domains möglich.<br />
<br />
Als erste Optimierung wurde ein redundanter Index entfernt. <br />
<br />
</span></code>
<p style="font-family: Courier New,Courier,monospace; background-color: rgb(240, 192, 172); margin-left: 40px; margin-right: 40px;"><code>drop&nbsp;
index `rec_name_index`&nbsp; on records;<br />
</code></p>
<code><span style="font-family: serif;"><br />
Hiernach wurden 10822 qps gemessen. Dies ist wohl nicht die Welt. Beim
Platzverbrauch sieht es schon besser aus:</span><br />
</code><br />
<p style="font-family: Courier New,Courier,monospace; background-color: rgb(240, 192, 172); margin-left: 40px; margin-right: 40px;"><code>+------------+--------------+-------------+<br />
| TABLE_NAME | INDEX_LENGTH | DATA_LENGTH |<br />
+------------+--------------+-------------+<br />
| domains&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; 475004928 |&nbsp;&nbsp;
431898624 |<br />
| records&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; 6116343808 |&nbsp; 5813305344
|<br />
+------------+--------------+-------------+<br />
</code></p>
<span style="font-family: serif;">Die Spalte type speichert die
Recordtypen</span>. Aus dem VARCHAR wird im Index ein CHAR. Da die
Menge der Werte begrenzt ist bietet sich hier ein ENUM an. Welches den
Vorteil hat ein INT zu sein und zum anderen sicherstellt, dass nicht
andere als die definierten Werte in die Tabelle kommen.<br /><br />
<code></code>
<p style="font-family: Courier New,Courier,monospace; background-color: rgb(240, 192, 172); margin-left: 40px; margin-right: 40px;"><code>ALTER
TABLE records&nbsp;&nbsp; MODIFY&nbsp; `type`
enum('A','AAAA','SOA','NS','MX','CNAME','PTR','TXT');<br />
</code></p>
<code><span style="font-family: serif;">Zugegeben, dies ist nur ein
Subset der nötigen Recordtypen. Am Ergebnis wird dies nichts
ändern. Nach dieser Änderung haben wir nun 10918 qps.
Angenehmer ist die weitere Reduktion der Datengröße. Diesmal
auch nicht nur bei den Indexdaten.</span><br /><br />
</code>
<p style="font-family: Courier New,Courier,monospace; background-color: rgb(240, 192, 172); margin-left: 40px; margin-right: 40px;"><code><br />
+------------+--------------+-------------+<br />
| TABLE_NAME | INDEX_LENGTH | DATA_LENGTH |<br />
+------------+--------------+-------------+<br />
| domains&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; 475004928 |&nbsp;&nbsp;
431898624 |<br />
| records&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; 5816451072 |&nbsp; 5696913408
|<br />
+------------+--------------+-------------+<br />
<br />
</code></p>
<code><span style="font-family: serif;">All diese Tests liefen
mit&nbsp; distributor-threads=32. Das ist eine
Konfigurationseinstellung (im PowerDNS) für die Anzahl der
Verbindungen, die PowerDNS zur Datenbank öffnet. Der Default liegt
bei 3. Mit </span></code><code><span style="font-family: serif;">distributor-threads=3
erreichte ich lediglich<span style="font-family: serif;"> 5656 qps.<br />
Zu guter Letzt ändern wir noch den Index nametype_index. Die
wenigsten FQDN nutzen die im RFC ermöglichten 255 Zeichen aus.
Sprich hier lohnt sich ein prefix-Index. (Der alte wurde gedropt)<br /><br />
</span></span></code><code></code>
<p style="font-family: Courier New,Courier,monospace; background-color: rgb(240, 192, 172); margin-left: 40px; margin-right: 40px;"><code>CREATE
INDEX `nametype_index` on records(name(100),type);<br />
</code></p>
<small><big><span style="font-family: serif;">Nun waren wir bei 10923
qps angelangt und was sagt der Platzverbrauch?</span><br /><br />
</big></small>
<p style="font-family: Courier New,Courier,monospace; background-color: rgb(240, 192, 172); margin-left: 40px; margin-right: 40px;"><small><big><span style="font-family: monospace;">+------------+--------------+-------------+</span><br style="font-family: monospace;" />
<span style="font-family: monospace;">| TABLE_NAME | INDEX_LENGTH |
DATA_LENGTH |</span><br style="font-family: monospace;" />
<span style="font-family: monospace;">+------------+--------------+-------------+</span><br style="font-family: monospace;" />
<span style="font-family: monospace;">| domains&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp; 475004928 |&nbsp;&nbsp; 431898624 |</span><br style="font-family: monospace;" />
<span style="font-family: monospace;">| records&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp; 3547332608 |&nbsp; 5696913408 |</span><br style="font-family: monospace;" />
<span style="font-family: monospace;">+------------+--------------+-------------+<br />
</span></big></small></p>
<br />
Sweet! Halten wir fest die Index_legth ist von <code style="font-family: serif;">11372855296 Bytes auf </code><small style="font-family: serif;"><big>3547332608 Bytes reduziert worden.</big></small>
Damit wurden hier etwas über 7GB gespart \o/<br />
An diesem Punkt angelangt wurden die records noch in PBXT
geändert. Hierbei wurden 12375 qps erreicht:) Wobei der
Platzverbrauch immens anstieg:<br /><br />
<p style="font-family: Courier New,Courier,monospace; background-color: rgb(240, 192, 172); margin-left: 40px; margin-right: 40px;"><small><big><span style="font-family: monospace;">| records&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp; 5684629504 | 12380356432 |<br />
</span></big>
</small></p>
<br />
Später wurde ich in #powerdns darauf hingewiesen, dass das
verwendete Benchmarktool (dnsperf) auch mit einer längeren Queue
ausgeführt werden kann. So wurden mit <span style="font-family: Courier New,Courier,monospace;">./dnsperf -d
/var/tmp/pdns.list -q 2000 -s localhost</span> schnell 22994 qps
erreicht.<br />
Das ist selbstredend nur ein Anfang. Aber zeigt es doch, dass in vielen
Projekten noch Steigerungspotential steckt. Von nicht skalieren kann aber nicht gesprochen werden. :) <br />
<br />
<br />
Viel Spaß<br />
Erkan<br />]]>
        
    </content>
</entry>

</feed>
