dhcp-perf-guide.xml 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
  3. "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
  4. <!ENTITY mdash "&#x2014;" >
  5. <!ENTITY % version SYSTEM "version.ent">
  6. %version;
  7. ]>
  8. <!--
  9. - Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  10. -
  11. - Permission to use, copy, modify, and/or distribute this software for any
  12. - purpose with or without fee is hereby granted, provided that the above
  13. - copyright notice and this permission notice appear in all copies.
  14. -
  15. - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  16. - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  17. - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  18. - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  19. - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  20. - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  21. - PERFORMANCE OF THIS SOFTWARE.
  22. -->
  23. <book>
  24. <?xml-stylesheet href="bind10-guide.css" type="text/css"?>
  25. <bookinfo>
  26. <title>DHCP Performance Guide</title>
  27. <!-- <subtitle>Various aspects of DHCP Performance in BIND 10</subtitle> -->
  28. <copyright>
  29. <year>2012</year>
  30. <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
  31. </copyright>
  32. <author>
  33. <firstname>Tomasz</firstname>
  34. <surname>Mrugalski</surname>
  35. </author>
  36. <abstract>
  37. <para>BIND 10 is a framework that features Domain Name System
  38. (DNS) suite and Dynamic Host Configuration Protocol (DHCP)
  39. servers with development managed by Internet Systems Consortium (ISC).
  40. This document describes various aspects of DHCP performance,
  41. measurements and tuning. It covers BIND 10 DHCP (codename Kea),
  42. existing ISC DHCP4 software, perfdhcp (a DHCP performance
  43. measurement tool) and other related topics.</para>
  44. </abstract>
  45. <releaseinfo>This is a companion document for BIND 10 version
  46. &__VERSION__;.</releaseinfo>
  47. </bookinfo>
  48. <preface>
  49. <title>Preface</title>
  50. <section id="acknowledgements">
  51. <title>Acknowledgements</title>
  52. <para>ISC would like to acknowledge generous support for
  53. BIND 10 development of DHCPv4 and DHCPv6 components provided
  54. by <ulink url="http://www.comcast.com/">Comcast</ulink>.</para>
  55. </section>
  56. </preface>
  57. <chapter id="intro">
  58. <title>Introduction</title>
  59. <para>
  60. This document is in its early stages of development. It is
  61. expected to grow significantly in a near future. It will
  62. cover topics like database backend perfomance measurements,
  63. pros an cons of various optimization techniques and
  64. tools.
  65. </para>
  66. </chapter>
  67. <chapter id="dhcp4">
  68. <title>ISC DHCP 4.x</title>
  69. <para>
  70. TODO: Write something about ISC DHCP4 here.
  71. </para>
  72. </chapter>
  73. <chapter id="kea">
  74. <title>Kea</title>
  75. <para>
  76. </para>
  77. <section>
  78. <title>Backend performance evaluation</title>
  79. <para>
  80. Kea will support several different database backends, using
  81. both popular databases (like MySQL or SQLite) and
  82. custom-developed solutions (like in-memory database). BIND 10
  83. source code features set of performance microbenchmarks.
  84. These are small tools written in C/C++ that simulate expected
  85. DHCP server behaviour and evaluate the performance of
  86. considered databases. As implemented benchmarks are not really
  87. simulating DHCP operation, but rather use set of primitives
  88. that can be used by a real server, they are called
  89. micro-benchmarks.
  90. </para>
  91. <para>Although there are many operations and data types that
  92. server could store in a database, the most frequently used data
  93. type is lease information. Although lease information for IPv4
  94. and IPv6 differs slightly, it is expected that the performance
  95. differences will be minimal between IPv4 and IPv6 lease operations.
  96. Therefore each test uses lease4 table for performance measurements.
  97. </para>
  98. <para>All benchmarks are implemented as single threaded applications
  99. that take advantage of a single database connection.</para>
  100. <para>
  101. Those benchmarks are stored in tests/tools/dhcp-ubench
  102. directory. This directory contains simplified prototypes for
  103. various DB back-ends that are planned or considered as a
  104. backend engine for BIND10 DHCP. Athough trivial now, they are
  105. expected to evolve into useful tools that will allow users to
  106. measure performance in their specific environment.
  107. </para>
  108. <para>
  109. Currently the following benchmarks are implemented:
  110. <itemizedlist>
  111. <listitem><para>in memory+flat file</para></listitem>
  112. <listitem><para>SQLite</para></listitem>
  113. <listitem><para>MySQL</para></listitem>
  114. </itemizedlist>
  115. </para>
  116. <para>
  117. As they require additional (sometimes heavy) dependencies, they are not
  118. built by default. Actually, their build system is completely separated.
  119. It will be eventually merged with the main BIND10 makefile system, but
  120. that is a low priority for now.
  121. </para>
  122. <para>
  123. All benchmarks will follow the same pattern:
  124. <orderedlist>
  125. <listitem><para>prepare operation (connect to a database, create a file etc.)</para></listitem>
  126. <listitem><para>Measure timestamp 0</para></listitem>
  127. <listitem><para>Commit new lease4 (repeated X times)</para></listitem>
  128. <listitem><para>Measure timestamp 1</para></listitem>
  129. <listitem><para>Search for random lease4 (repeated X times)</para></listitem>
  130. <listitem><para>Measure timestamp 2</para></listitem>
  131. <listitem><para>Update existing lease4 (repeated X times)</para></listitem>
  132. <listitem><para>Measure timestamp 3</para></listitem>
  133. <listitem><para>Delete existing lease4 (repeated X times)</para></listitem>
  134. <listitem><para>Measure timestamp 4</para></listitem>
  135. <listitem><para>Print out statistics, based on X and measured timestamps.</para></listitem>
  136. </orderedlist>
  137. Although this approach does not attempt to simulate actual DHCP server
  138. operation that has mix of all steps intervening, it answers the
  139. questions about basic database strenghts and weak points. In particular
  140. it can show what is the impact of specific DB optimizations, like
  141. changing engine, optimizing for writes/reads etc.
  142. </para>
  143. <para>
  144. The framework attempts to do the same amount of operations for every
  145. backend thus allowing fair complarison between them.
  146. </para>
  147. </section>
  148. <section id="mysql-backend">
  149. <title>MySQL backend</title>
  150. <para>MySQL backend requires MySQL client development libraries. It uses
  151. mysql_config tool (that works similar to pkg-config) to discover required
  152. compilation and linking options. To install required packages on Ubuntu,
  153. use the following command:
  154. <screen>$ <userinput>sudo apt-get install mysql-client mysql-server libmysqlclient-dev</userinput></screen>
  155. Make sure that MySQL server is running. Make sure that you have your setup
  156. configured so there is a user that is able to modify used database.</para>
  157. <para>Before running tests, you need to initialize your database. You can
  158. use mysql.schema script for that purpose. WARNING: It will drop existing
  159. Kea database. Do not run this on your production server. Assuming your
  160. MySQL user is kea, you can initialize your test database by:
  161. <screen>$ <userinput>mysql -u kea -p &lt; mysql.schema</userinput></screen>
  162. </para>
  163. <para>After database is initialized, you are ready to run the test:
  164. <screen>$ <userinput>./mysql_ubench</userinput></screen>
  165. or
  166. <screen>$ <userinput>./mysql_ubench &gt; results->mysql.txt</userinput></screen>
  167. Redirecting output to a file is important, because for each operation
  168. there is a single character printed to show progress. If you have a slow
  169. terminal, this may considerably affect test perfromance. On the other hand,
  170. printing something after each operation is required, as poor DB setting
  171. may slow down operations to around 20 per second. Observant user is expected
  172. to note that initial dots are printed too slowly and abort the test.</para>
  173. <para>Currently all default parameters are hardcoded. Default values can be
  174. overwritten using command line switches. Although all benchmarks take
  175. the same list of parameters, some of them are specific to a given backend
  176. type. To get a list of supported parameters, run your benchmark with -h option:
  177. <screen>$ <userinput>./mysql_ubench -h</userinput>
  178. This is a benchmark designed to measure expected performance
  179. of several backends. This particular version identifies itself
  180. as following:
  181. MySQL client version is 5.5.24
  182. Possible command-line parameters:
  183. -h - help (you are reading this)
  184. -m hostname - specifies MySQL server to connect (MySQL backend only)
  185. -u username - specifies MySQL user name (MySQL backend only)
  186. -p password - specifies MySQL passwod (MySQL backend only)
  187. -f name - database or filename (MySQL, SQLite and memfile)
  188. -n integer - number of test repetitions (MySQL, SQLite and memfile)
  189. -s yes|no - synchronous/asynchronous operation (MySQL, SQLite and memfile)
  190. -v yes|no - verbose mode (MySQL, SQLite and memfile)
  191. -c yes|no - should compiled statements be used (MySQL only)
  192. </screen>
  193. </para>
  194. <section>
  195. <title>MySQL tweaks</title>
  196. <para>One parameter that has huge impact on performance is a a backend engine.
  197. You can get a list of engines of your MySQL implementation by using
  198. <screen>&gt; <userinput>show engines;</userinput></screen>
  199. in your mysql client. Two notable engines are MyISAM and InnoDB. mysql_ubench will
  200. use MyISAM for synchronous mode and InnoDB for asynchronous.</para>
  201. </section>
  202. </section>
  203. <section id="sqlite-ubench">
  204. <title>SQLite-ubench</title>
  205. <para>SQLite backend requires both sqlite3 development and run-time package. Their
  206. names may vary from system to system, but on Ubuntu 12.04 they are called
  207. sqlite3 libsqlite3-dev. To install them, use the following command:
  208. <screen>&gt; <userinput>sudo apt-get install sqlite3 libsqlite3-dev</userinput></screen>
  209. Before running the test the database has to be created. Use the following command for that:
  210. <screen>&gt; <userinput>cat sqlite.schema | sqlite3 sqlite.db</userinput></screen>
  211. A new database called sqlite.db will be created. That is the default name used
  212. by sqlite_ubench test. If you prefer other name, make sure you update
  213. sqlite_ubench.cc accordingly.</para>
  214. <para>Once the database is created, you can run tests:
  215. <screen>&gt; <userinput>./sqlite_ubench</userinput></screen>
  216. or
  217. <screen>&gt; <userinput>./sqlite_ubench > results-sqlite.txt</userinput></screen>
  218. </para>
  219. <section id="sqlite-tweaks">
  220. <title>SQLite tweaks</title>
  221. <para>To modify default sqlite_ubench parameters, command line
  222. switches can be used. Currently supported parameters are
  223. (default values specified in brackets):
  224. <orderedlist>
  225. <listitem><para>-f filename - name of the database file ("sqlite.db")</para></listitem>
  226. <listitem><para>-n num - number of iterations (100)</para></listitem>
  227. <listitem><para>-s yes|no - should the operations be performend in synchronous (yes)
  228. or asynchronous (no) manner (yes)</para></listitem>
  229. <listitem><para>-v yes|no - verbose mode. Should the test print out progress? (yes)</para></listitem>
  230. <listitem><para>-c yes|no - compiled statements. Should the SQL statements be precompiled?</para></listitem>
  231. </orderedlist>
  232. </para>
  233. <para>SQLite can run in asynchronous or synchronous mode. This
  234. mode can be controlled by using sync parameter. It is set
  235. using (PRAGMA synchronous = ON or OFF).</para>
  236. <para>Another tweakable feature is journal mode. It can be
  237. turned to several modes of operation. Its value can be
  238. modified in SQLite_uBenchmark::connect(). See
  239. http://www.sqlite.org/pragma.html#pragma_journal_mode for
  240. detailed explanantion.</para>
  241. </section>
  242. </section>
  243. <section id="memfile-ubench">
  244. <title>memfile-ubench</title>
  245. <para>Memfile backend is custom developed prototype backend that
  246. somewhat mimics operation of ISC DHCP4. It uses in-memory
  247. storage using standard C++ and boost mechanisms (std::map and
  248. boost::shared_ptr&lt;&gt;). All database changes are also
  249. written to a lease file. That file is strictly write-only. This
  250. approach takes advantage of the fact that simple append is faster
  251. than edition with potential whole file relocation.</para>
  252. <section id="memfile-tweaks">
  253. <title>memfile tweaks</title>
  254. <para>To modify default memfile_ubench parameters, command line
  255. switches can be used. Currently supported parameters are
  256. (default values specified in brackets):
  257. <orderedlist>
  258. <listitem><para>-f filename - name of the database file ("dhcpd.leases")</para></listitem>
  259. <listitem><para>-n num - number of iterations (100)</para></listitem>
  260. <listitem><para>-s yes|no - should the operations be performend in synchronous (yes)
  261. or asynchronous (no) manner (yes)</para></listitem>
  262. <listitem><para>-v yes|no - verbose mode. Should the test print out progress? (yes)</para></listitem>
  263. </orderedlist>
  264. </para>
  265. <para>memfile can run in asynchronous or synchronous mode. This
  266. mode can be controlled by using sync parameter. It uses
  267. fflush() and fsync() in synchronous mode to make sure that
  268. data is not buffered and physically stored on disk.</para>
  269. </section>
  270. </section>
  271. <section>
  272. <title>Performance measurements</title>
  273. <para>This section contains sample results for backend performance measurements,
  274. taken using microbenchmarks. Tests were conducted on reasonably powerful machine:
  275. <screen>
  276. CPU: Quad-core Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 logical cores)
  277. HDD: 1,5TB Seagate Barracuda ST31500341AS 7200rpm (used only one of them), ext4 partition
  278. OS: Ubuntu 12.04, running kernel 3.2.0-26-generic SMP x86_64
  279. compiler: g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
  280. MySQL version: 5.5.24
  281. SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e</screen>
  282. </para>
  283. <para>Benchmarks were run in two series: synchronous and
  284. asynchronous. As those modes offer radically different
  285. performances, synchronous mode was conducted for 1000 (one
  286. thousand) repetitions and asynchronous mode was conducted for
  287. 100000 (hundred thousand) repetitions.</para>
  288. <!-- raw results sync -->
  289. <table><title>Synchronous results</title>
  290. <tgroup cols='6' align='center' colsep='1' rowsep='1'>
  291. <colspec colname='Backend'/>
  292. <colspec colname='Num' />
  293. <colspec colname='Create'/>
  294. <colspec colname='Search'/>
  295. <colspec colname='Update'/>
  296. <colspec colname='Delete'/>
  297. <colspec colname='Average'/>
  298. <thead>
  299. <row>
  300. <entry>Backend</entry>
  301. <entry>Operations</entry>
  302. <entry>Create</entry>
  303. <entry>Search</entry>
  304. <entry>Update</entry>
  305. <entry>Delete</entry>
  306. <entry>Average</entry>
  307. </row>
  308. </thead>
  309. <tbody>
  310. <row>
  311. <entry>MySQL</entry>
  312. <entry>1000</entry>
  313. <entry>31.603978s</entry>
  314. <entry> 0.116612s</entry>
  315. <entry>27.964191s</entry>
  316. <entry>27.695209s</entry>
  317. <entry>21.844998s</entry>
  318. </row>
  319. <row>
  320. <entry>SQLite</entry>
  321. <entry>1000</entry>
  322. <entry>61.421356s</entry>
  323. <entry> 0.033283s</entry>
  324. <entry>59.476638s</entry>
  325. <entry>56.034150s</entry>
  326. <entry>44.241357s</entry>
  327. </row>
  328. <row>
  329. <entry>memfile</entry>
  330. <entry>1000</entry>
  331. <entry>41.711886s</entry>
  332. <entry> 0.000724s</entry>
  333. <entry>42.267578s</entry>
  334. <entry>42.169679s</entry>
  335. <entry>31.537467s</entry>
  336. </row>
  337. </tbody>
  338. </tgroup>
  339. </table>
  340. <para>Following parameters were measured for asynchronous mode.
  341. MySQL and SQLite were run with 100 thousand repetitions. Memfile
  342. was run for 1 million repetitions due to much larger performance.</para>
  343. <!-- raw results async -->
  344. <table><title>Asynchronous results</title>
  345. <tgroup cols='6' align='center' colsep='1' rowsep='1'>
  346. <colspec colname='Backend'/>
  347. <colspec colname='Num' />
  348. <colspec colname='Create'/>
  349. <colspec colname='Search'/>
  350. <colspec colname='Update'/>
  351. <colspec colname='Delete'/>
  352. <colspec colname='Average'/>
  353. <thead>
  354. <row>
  355. <entry>Backend</entry>
  356. <entry>Operations</entry>
  357. <entry>Create [s]</entry>
  358. <entry>Search [s]</entry>
  359. <entry>Update [s]</entry>
  360. <entry>Delete [s]</entry>
  361. <entry>Average [s]</entry>
  362. </row>
  363. </thead>
  364. <tbody>
  365. <row>
  366. <entry>MySQL</entry>
  367. <entry>100000</entry>
  368. <entry>10.584842s</entry>
  369. <entry>10.386402s</entry>
  370. <entry>10.062384s</entry>
  371. <entry> 8.890197s</entry>
  372. <entry> 9.980956s</entry>
  373. </row>
  374. <row>
  375. <entry>SQLite</entry>
  376. <entry>100000</entry>
  377. <entry> 3.710356s</entry>
  378. <entry> 3.159129s</entry>
  379. <entry> 2.865354s</entry>
  380. <entry> 2.439406s</entry>
  381. <entry> 3.043561s</entry>
  382. </row>
  383. <row>
  384. <entry>memfile</entry>
  385. <entry>1000000 (sic!)</entry>
  386. <entry> 6.084131s</entry>
  387. <entry> 0.862667s</entry>
  388. <entry> 6.018585s</entry>
  389. <entry> 5.146704s</entry>
  390. <entry> 4.528022s</entry>
  391. </row>
  392. </tbody>
  393. </tgroup>
  394. </table>
  395. <para>Presented performance results can be computed into operations per second metrics.
  396. It should be noted that due to large differences between various operations (sometime
  397. over 3 orders of magnitude), it is difficult to create a simple, readable chart with
  398. that data.</para>
  399. <table id="tbl-perf-results"><title>Estimated performance</title>
  400. <tgroup cols='6' align='center' colsep='1' rowsep='1'>
  401. <colspec colname='Backend'/>
  402. <colspec colname='Create'/>
  403. <colspec colname='Search'/>
  404. <colspec colname='Update'/>
  405. <colspec colname='Delete'/>
  406. <colspec colname='Average'/>
  407. <thead>
  408. <row>
  409. <entry>Backend</entry>
  410. <entry>Create [oper/s]</entry>
  411. <entry>Search [oper/s]</entry>
  412. <entry>Update [oper/s]</entry>
  413. <entry>Delete [oper/s]</entry>
  414. <entry>Average [oper/s]</entry>
  415. </row>
  416. </thead>
  417. <tbody>
  418. <row>
  419. <entry>MySQL (async)</entry>
  420. <entry>9447.47</entry>
  421. <entry>9627.97</entry>
  422. <entry>9938.00</entry>
  423. <entry>11248.34</entry>
  424. <entry>10065.45</entry>
  425. </row>
  426. <row>
  427. <entry>SQLite (async)</entry>
  428. <entry>26951.59</entry>
  429. <entry>31654.29</entry>
  430. <entry>34899.70</entry>
  431. <entry>40993.59</entry>
  432. <entry>33624.79</entry>
  433. </row>
  434. <row>
  435. <entry>memfile (async)</entry>
  436. <entry>164362.01</entry>
  437. <entry>1159195.84</entry>
  438. <entry>166152.01</entry>
  439. <entry>194299.11</entry>
  440. <entry>421002.24</entry>
  441. </row>
  442. <row>
  443. <entry>MySQL (sync)</entry>
  444. <entry>31.64</entry>
  445. <entry>8575.45</entry>
  446. <entry>35.76</entry>
  447. <entry>36.11</entry>
  448. <entry>2169.74</entry>
  449. </row>
  450. <row>
  451. <entry>SQLite (sync)</entry>
  452. <entry>16.28</entry>
  453. <entry>20045.37</entry>
  454. <entry>16.81</entry>
  455. <entry>17.85</entry>
  456. <entry>7524.08</entry>
  457. </row>
  458. <row>
  459. <entry>memfile (sync)</entry>
  460. <entry>23.97</entry>
  461. <entry>1381215.47</entry>
  462. <entry>23.66</entry>
  463. <entry>23.71</entry>
  464. <entry>345321.70</entry>
  465. </row>
  466. </tbody>
  467. </tgroup>
  468. </table>
  469. <mediaobject>
  470. <imageobject>
  471. <imagedata fileref="performance-results-graph1.png" format="PNG"/>
  472. </imageobject>
  473. <textobject>
  474. <phrase>Performance measurements</phrase>
  475. </textobject>
  476. <caption>
  477. <para>Graphical representation of the performance results
  478. presented in table <xref linkend="tbl-perf-results" />.</para>
  479. </caption>
  480. </mediaobject>
  481. </section>
  482. <section>
  483. <title>Possible further optimizations</title>
  484. <para>
  485. For debugging purposes the code was compiled with -g -O0
  486. flags. While majority of the time was spent in backend
  487. functions (that was probably compiled with -O2 flags), the
  488. benchmark code could perform faster, when compiled with -O2,
  489. rather than -O0. That is expected to affect memfile benchmark.
  490. </para>
  491. <para>
  492. Currently all operations were conducted on one by one
  493. basis. Each operation was treated as a separate
  494. transaction. Grouping X operations together will potentially
  495. bring almost X fold increase in synchronous operations.
  496. Extension for this benchmark in this regard should be considered.
  497. That affects only write operations (insert, update and delete). Read
  498. operations (search) are expected to be barely affected.
  499. </para>
  500. <para>
  501. Multi-threaded or multi-process benchmark may be considered in
  502. the future. It may be somewhat difficult as only some backends
  503. support concurrent access.
  504. </para>
  505. </section>
  506. </chapter>
  507. <chapter id="perfdhcp">
  508. <title>perfdhcp</title>
  509. <para>
  510. TODO: Write something about perfdhcp here.
  511. </para>
  512. </chapter>
  513. </book>