dhcp-perf-guide.xml 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926
  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) and Dynamic Host Configuration Protocol (DHCP)
  39. software 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 the early stages of development. It is
  61. expected to grow significantly in the near future. It will
  62. cover topics like database backend perfomance measurements,
  63. tools, and the pros an cons of various optimization techniques.
  64. </para>
  65. </chapter>
  66. <chapter id="dhcp4">
  67. <title>ISC DHCP 4.x</title>
  68. <para>
  69. TODO: Write something about ISC DHCP4 here.
  70. </para>
  71. </chapter>
  72. <chapter id="kea">
  73. <title>Kea</title>
  74. <para>
  75. </para>
  76. <section>
  77. <title>Backend performance evaluation</title>
  78. <para>
  79. Kea will support several different database backends, using
  80. both popular databases (like MySQL or SQLite) and
  81. custom-developed solutions (such as an in-memory database).
  82. To aid in the choice of backend, the BIND 10
  83. source code features a set of performance microbenchmarks.
  84. Written in C/C++, these are small tools that simulate expected
  85. DHCP server behaviour and evaluate the performance of
  86. considered databases. As implemented, the benchmarks are not really
  87. simulating DHCP operation, but rather use set of primitives
  88. that can be used by a real server. For this reason, 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 the information held for IPv4
  94. and IPv6 leases differs slightly, it is expected that the performance
  95. differences will be minimal between IPv4 and IPv6 lease operations.
  96. Therefore each test uses the lease4 table (in which IPv4 leases are stored)
  97. for performance measurements.
  98. </para>
  99. <para>All benchmarks are implemented as single threaded applications
  100. that take advantage of a single database connection.</para>
  101. <para>
  102. Those benchmarks are stored in tests/tools/dhcp-ubench
  103. directory of the BIND 10 source tree. This directory contains simplified prototypes for
  104. the various database back-ends that are planned or considered as a
  105. possibly for BIND10 DHCP. Athough trivial now, the benchmarks are
  106. expected to evolve into useful tools that will allow users to
  107. measure performance in their specific environment.
  108. </para>
  109. <para>
  110. Currently the following benchmarks are implemented:
  111. <itemizedlist>
  112. <listitem><para>In memory + flat file</para></listitem>
  113. <listitem><para>SQLite</para></listitem>
  114. <listitem><para>MySQL</para></listitem>
  115. </itemizedlist>
  116. </para>
  117. <para>
  118. As the benchmarks require additional (sometimes heavy) dependencies, they are not
  119. built by default. Actually, their build system is completely separate from that
  120. of the rest of BIND 10.
  121. It is anticipated that they will be eventually merged into the rest of BIND 10, but
  122. that is a low priority for now.
  123. </para>
  124. <para>
  125. All benchmarks will follow the same pattern:
  126. <orderedlist>
  127. <listitem><para>Prepare operation (connect to a database, create a file etc.)</para></listitem>
  128. <listitem><para>Measure timestamp 0</para></listitem>
  129. <listitem><para>Commit new lease4 record (repeated N times)</para></listitem>
  130. <listitem><para>Measure timestamp 1</para></listitem>
  131. <listitem><para>Search for random lease4 record (repeated N times)</para></listitem>
  132. <listitem><para>Measure timestamp 2</para></listitem>
  133. <listitem><para>Update existing lease4 record (repeated N times)</para></listitem>
  134. <listitem><para>Measure timestamp 3</para></listitem>
  135. <listitem><para>Delete existing lease4 record (repeated N times)</para></listitem>
  136. <listitem><para>Measure timestamp 4</para></listitem>
  137. <listitem><para>Print out statistics, based on N and measured timestamps.</para></listitem>
  138. </orderedlist>
  139. Although this approach does not attempt to simulate actual DHCP server
  140. operation that has mix of all steps, it answers the
  141. questions about basic database strengths and weak points. In particular
  142. it can show what is the impact of specific database optimizations, such as
  143. changing engine, optimizing for writes/reads etc.
  144. </para>
  145. <para>
  146. The framework attempts to do the same amount of work for every
  147. backend thus allowing fair complarison between them.
  148. </para>
  149. </section>
  150. <section id="mysql-backend">
  151. <title>MySQL backend</title>
  152. <para>The MySQL backend requires the MySQL client development libraries. It uses
  153. the mysql_config tool (similar to pkg-config) to discover required
  154. compilation and linking options. To install required packages on Ubuntu,
  155. use the following command:
  156. <screen>$ <userinput>sudo apt-get install mysql-client mysql-server libmysqlclient-dev</userinput></screen>
  157. Make sure that MySQL server is running. Make sure that you have your setup
  158. configured so there is a user that is able to modify used database.</para>
  159. <para>Before running tests, you need to initialize your database. You can
  160. use mysql.schema script for that purpose.</para>
  161. <para><emphasis>WARNING: It will drop existing
  162. Kea database. Do not run this on your production server. </emphasis></para>
  163. <para>Assuming your
  164. MySQL user is "kea", you can initialize your test database by:
  165. <screen>$ <userinput>mysql -u kea -p &lt; mysql.schema</userinput></screen>
  166. </para>
  167. <para>After the database is initialized, you are ready to run the test:
  168. <screen>$ <userinput>./mysql_ubench</userinput></screen>
  169. or
  170. <screen>$ <userinput>./mysql_ubench &gt; results-mysql.txt</userinput></screen>
  171. Redirecting output to a file is important, because for each operation
  172. there is a single character printed to show progress. If you have a slow
  173. terminal, this may considerably affect test performance. On the other hand,
  174. printing something after each operation is required as poor database settings
  175. may slow down operations to around 20 per second. (The observant user is expected
  176. to note that the initial dots are printed too slowly and abort the test.)</para>
  177. <para>Currently all default parameters are hardcoded. Default values can be
  178. overridden using command line switches. Although all benchmarks take
  179. the same list of parameters, some of them are specific to a given backend.
  180. To get a list of supported parameters, run the benchmark with the "-h" option:
  181. <screen>$ <userinput>./mysql_ubench -h</userinput>
  182. This is a benchmark designed to measure expected performance
  183. of several backends. This particular version identifies itself
  184. as following:
  185. MySQL client version is 5.5.24
  186. Possible command-line parameters:
  187. -h - help (you are reading this)
  188. -m hostname - specifies MySQL server to connect (MySQL backend only)
  189. -u username - specifies MySQL user name (MySQL backend only)
  190. -p password - specifies MySQL passwod (MySQL backend only)
  191. -f name - database or filename (MySQL, SQLite and memfile)
  192. -n integer - number of test repetitions (MySQL, SQLite and memfile)
  193. -s yes|no - synchronous/asynchronous operation (MySQL, SQLite and memfile)
  194. -v yes|no - verbose mode (MySQL, SQLite and memfile)
  195. -c yes|no - should compiled statements be used (MySQL only)
  196. </screen>
  197. </para>
  198. <section>
  199. <title>MySQL tweaks</title>
  200. <para>One parameter that has huge impact on performance is the choice of backend engine.
  201. You can get a list of engines of your MySQL implementation by using
  202. <screen>&gt; <userinput>show engines;</userinput></screen>
  203. in your mysql client. Two notable engines are MyISAM and InnoDB. mysql_ubench uses
  204. use MyISAM for synchronous mode and InnoDB for asynchronous. Please use
  205. '-s yes|no' to choose whether you want synchronous or asynchronous operations.</para>
  206. <para>Another parameter that affects performance are precompiled statements.
  207. In a basic approach, the actual SQL query is passed as a text string that is
  208. then parsed by the database engine. Alternative is a so called precompiled
  209. statement. In this approach the SQL query is compiled an specific values are being
  210. bound to it. In the next iteration the query remains the same, only bound values
  211. are changing (e.g. searching for a different address). Usage of basic or precompiled
  212. statements is controlled with '-c no|yes'.</para>
  213. </section>
  214. </section>
  215. <section id="sqlite-ubench">
  216. <title>SQLite-ubench</title>
  217. <para>The SQLite backend requires both the sqlite3 development and run-time packages. Their
  218. names may vary from system to system, but on Ubuntu 12.04 they are called
  219. sqlite3 libsqlite3-dev. To install them, use the following command:
  220. <screen>&gt; <userinput>sudo apt-get install sqlite3 libsqlite3-dev</userinput></screen>
  221. Before running the test the database has to be created. Use the following command for that:
  222. <screen>&gt; <userinput>cat sqlite.schema | sqlite3 sqlite.db</userinput></screen>
  223. A new database called sqlite.db will be created. That is the default name used
  224. by sqlite_ubench test. If you prefer other name, make sure you update
  225. sqlite_ubench.cc accordingly.</para>
  226. <para>Once the database is created, you can run tests:
  227. <screen>&gt; <userinput>./sqlite_ubench</userinput></screen>
  228. or
  229. <screen>&gt; <userinput>./sqlite_ubench > results-sqlite.txt</userinput></screen>
  230. </para>
  231. <section id="sqlite-tweaks">
  232. <title>SQLite tweaks</title>
  233. <para>To modify default sqlite_ubench parameters, command line
  234. switches can be used. The currently supported switches are
  235. (default values specified in brackets):
  236. <orderedlist>
  237. <listitem><para>-f filename - name of the database file ("sqlite.db")</para></listitem>
  238. <listitem><para>-n num - number of iterations (100)</para></listitem>
  239. <listitem><para>-s yes|no - should the operations be performed in a synchronous (yes)
  240. or asynchronous (no) manner (yes)</para></listitem>
  241. <listitem><para>-v yes|no - verbose mode. Should the test print out progress? (yes)</para></listitem>
  242. <listitem><para>-c yes|no - precompiled statements. Should the SQL statements be precompiled?</para></listitem>
  243. </orderedlist>
  244. </para>
  245. <para>SQLite can run in asynchronous or synchronous mode. This
  246. mode can be controlled by using "synchronous" parameter. It is set
  247. using the SQLite command:</para>
  248. <para><command>PRAGMA synchronous = ON|OFF</command></para>
  249. <para>Another tweakable feature is journal mode. It can be
  250. turned to several modes of operation. Its value can be
  251. modified in SQLite_uBenchmark::connect(). See
  252. http://www.sqlite.org/pragma.html#pragma_journal_mode for
  253. detailed explanantion.</para>
  254. <para>sqlite_bench supports precompiled statements. Please use
  255. '-c no|yes' to define which should be used: basic SQL query (no) or
  256. precompiled statement (yes).</para>
  257. </section>
  258. </section>
  259. <section id="memfile-ubench">
  260. <title>memfile-ubench</title>
  261. <para>The memfile backend is a custom backend that
  262. somewhat mimics operation of ISC DHCP4. It implements in-memory
  263. storage using standard C++ and boost mechanisms (std::map and
  264. boost::shared_ptr&lt;&gt;). All database changes are also
  265. written to a lease file, which is strictly write-only. This
  266. approach takes advantage of the fact that simple append is faster
  267. than edition with potential whole file relocation.</para>
  268. <section id="memfile-tweaks">
  269. <title>memfile tweaks</title>
  270. <para>To modify default memfile_ubench parameters, command line
  271. switches can be used. Currently supported switches are
  272. (default values specified in brackets):
  273. <orderedlist>
  274. <listitem><para>-f filename - name of the database file ("dhcpd.leases")</para></listitem>
  275. <listitem><para>-n num - number of iterations (100)</para></listitem>
  276. <listitem><para>-s yes|no - should the operations be performend in a synchronous (yes)
  277. or asynchronous (no) manner (yes)</para></listitem>
  278. <listitem><para>-v yes|no - verbose mode. Should the test print out progress? (yes)</para></listitem>
  279. </orderedlist>
  280. </para>
  281. <para>memfile can run in asynchronous or synchronous mode. This
  282. mode can be controlled by using sync parameter. It uses
  283. fflush() and fsync() in synchronous mode to make sure that
  284. data is not buffered and physically stored on disk.</para>
  285. </section>
  286. </section>
  287. <section>
  288. <title>Basic performance measurements</title>
  289. <para>This section contains sample results for backend performance measurements,
  290. taken using microbenchmarks. Tests were conducted on reasonably powerful machine:
  291. <screen>
  292. CPU: Quad-core Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 logical cores)
  293. HDD: 1,5TB Seagate Barracuda ST31500341AS 7200rpm, ext4 partition
  294. OS: Ubuntu 12.04, running kernel 3.2.0-26-generic SMP x86_64
  295. compiler: g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
  296. MySQL version: 5.5.24
  297. SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e</screen>
  298. </para>
  299. <para>The benchmarks were run without using precompiled statements.
  300. The code was compiled with the -O0 flag (no code optimizations).
  301. Each run was executed once.</para>
  302. <para>Two series of measures were made, synchronous and
  303. asynchronous. As those modes offer radically different
  304. performances, synchronous mode was conducted for one
  305. thousand repetitions and asynchronous mode was conducted for
  306. one hundred thousand repetitions.</para>
  307. <!-- raw results sync -->
  308. <table><title>Synchronous results (basic)</title>
  309. <tgroup cols='6' align='center' colsep='1' rowsep='1'>
  310. <colspec colname='Backend'/>
  311. <colspec colname='Num' />
  312. <colspec colname='Create'/>
  313. <colspec colname='Search'/>
  314. <colspec colname='Update'/>
  315. <colspec colname='Delete'/>
  316. <colspec colname='Average'/>
  317. <thead>
  318. <row>
  319. <entry>Backend</entry>
  320. <entry>Operations</entry>
  321. <entry>Create [s]</entry>
  322. <entry>Search [s]</entry>
  323. <entry>Update [s]</entry>
  324. <entry>Delete [s]</entry>
  325. <entry>Average [s]</entry>
  326. </row>
  327. </thead>
  328. <tbody>
  329. <row>
  330. <entry>MySQL</entry>
  331. <entry>1,000</entry>
  332. <entry>31.603978</entry>
  333. <entry> 0.116612</entry>
  334. <entry>27.964191</entry>
  335. <entry>27.695209</entry>
  336. <entry>21.844998</entry>
  337. </row>
  338. <row>
  339. <entry>SQLite</entry>
  340. <entry>1,000</entry>
  341. <entry>61.421356</entry>
  342. <entry> 0.033283</entry>
  343. <entry>59.476638</entry>
  344. <entry>56.034150</entry>
  345. <entry>44.241357</entry>
  346. </row>
  347. <row>
  348. <entry>memfile</entry>
  349. <entry>1,000</entry>
  350. <entry>38.223757</entry>
  351. <entry> 0.000817</entry>
  352. <entry>38.041153</entry>
  353. <entry>38.017293</entry>
  354. <entry>28.570755</entry>
  355. </row>
  356. </tbody>
  357. </tgroup>
  358. </table>
  359. <para>The following parameters were measured for asynchronous mode.
  360. MySQL and SQLite were run with one hundred thousand repetitions. Memfile
  361. was run for one million repetitions due to its much higher performance.</para>
  362. <!-- raw results async -->
  363. <table><title>Asynchronous results (basic)</title>
  364. <tgroup cols='6' align='center' colsep='1' rowsep='1'>
  365. <colspec colname='Backend'/>
  366. <colspec colname='Num' />
  367. <colspec colname='Create'/>
  368. <colspec colname='Search'/>
  369. <colspec colname='Update'/>
  370. <colspec colname='Delete'/>
  371. <colspec colname='Average'/>
  372. <thead>
  373. <row>
  374. <entry>Backend</entry>
  375. <entry>Operations</entry>
  376. <entry>Create [s]</entry>
  377. <entry>Search [s]</entry>
  378. <entry>Update [s]</entry>
  379. <entry>Delete [s]</entry>
  380. <entry>Average [s]</entry>
  381. </row>
  382. </thead>
  383. <tbody>
  384. <row>
  385. <entry>MySQL</entry>
  386. <entry>100,000</entry>
  387. <entry>10.584842</entry>
  388. <entry>10.386402</entry>
  389. <entry>10.062384</entry>
  390. <entry> 8.890197</entry>
  391. <entry> 9.980956</entry>
  392. </row>
  393. <row>
  394. <entry>SQLite</entry>
  395. <entry>100,000</entry>
  396. <entry> 3.710356</entry>
  397. <entry> 3.159129</entry>
  398. <entry> 2.865354</entry>
  399. <entry> 2.439406</entry>
  400. <entry> 3.043561</entry>
  401. </row>
  402. <row>
  403. <entry>memfile</entry>
  404. <entry>1,000,000</entry>
  405. <entry> 1.299642</entry>
  406. <entry> 0.039330</entry>
  407. <entry> 1.307112</entry>
  408. <entry> 1.277641</entry>
  409. <entry> 0.980931</entry>
  410. </row>
  411. </tbody>
  412. </tgroup>
  413. </table>
  414. <para>The presented performance results can be converted into operations per second metrics.
  415. It should be noted that due to large differences between various operations (sometimes
  416. over three orders of magnitude), it is difficult to create a simple, readable chart with
  417. that data.</para>
  418. <table id="tbl-basic-perf-results"><title>Estimated basic performance</title>
  419. <tgroup cols='6' align='center' colsep='1' rowsep='1'>
  420. <colspec colname='Backend'/>
  421. <colspec colname='Create'/>
  422. <colspec colname='Search'/>
  423. <colspec colname='Update'/>
  424. <colspec colname='Delete'/>
  425. <colspec colname='Average'/>
  426. <thead>
  427. <row>
  428. <entry>Backend</entry>
  429. <entry>Create [oper/s]</entry>
  430. <entry>Search [oper/s]</entry>
  431. <entry>Update [oper/s]</entry>
  432. <entry>Delete [oper/s]</entry>
  433. <entry>Average [oper/s]</entry>
  434. </row>
  435. </thead>
  436. <tbody>
  437. <row>
  438. <entry>MySQL (async)</entry>
  439. <entry>9447.47</entry>
  440. <entry>9627.97</entry>
  441. <entry>9938.00</entry>
  442. <entry>11248.34</entry>
  443. <entry>10065.45</entry>
  444. </row>
  445. <row>
  446. <entry>SQLite (async)</entry>
  447. <entry>26951.59</entry>
  448. <entry>31654.29</entry>
  449. <entry>34899.70</entry>
  450. <entry>40993.59</entry>
  451. <entry>33624.79</entry>
  452. </row>
  453. <row>
  454. <entry>memfile (async)</entry>
  455. <entry>76944.27</entry>
  456. <entry>2542588.35</entry>
  457. <entry>76504.54</entry>
  458. <entry>78269.25</entry>
  459. <entry>693576.60</entry>
  460. </row>
  461. <row>
  462. <entry>MySQL (sync)</entry>
  463. <entry>31.64</entry>
  464. <entry>8575.45</entry>
  465. <entry>35.76</entry>
  466. <entry>36.11</entry>
  467. <entry>2169.74</entry>
  468. </row>
  469. <row>
  470. <entry>SQLite (sync)</entry>
  471. <entry>16.28</entry>
  472. <entry>20045.37</entry>
  473. <entry>16.81</entry>
  474. <entry>17.85</entry>
  475. <entry>7524.08</entry>
  476. </row>
  477. <row>
  478. <entry>memfile (sync)</entry>
  479. <entry>26.16</entry>
  480. <entry>1223990.21</entry>
  481. <entry>26.29</entry>
  482. <entry>26.30</entry>
  483. <entry>306017.24</entry>
  484. </row>
  485. </tbody>
  486. </tgroup>
  487. </table>
  488. <mediaobject>
  489. <imageobject>
  490. <imagedata fileref="performance-results-graph1.png" format="PNG"/>
  491. </imageobject>
  492. <textobject>
  493. <phrase>Basic performance measurements</phrase>
  494. </textobject>
  495. <caption>
  496. <para>Graphical representation of the basic performance results
  497. presented in table <xref linkend="tbl-basic-perf-results" />.</para>
  498. </caption>
  499. </mediaobject>
  500. </section>
  501. <section>
  502. <title>Optimized performance measurements</title>
  503. <para>This section contains sample results for backend performance measurements,
  504. taken using microbenchmarks. Tests were conducted on reasonably powerful machine:
  505. <screen>
  506. CPU: Quad-core Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 logical cores)
  507. HDD: 1,5TB Seagate Barracuda ST31500341AS 7200rpm, ext4 partition
  508. OS: Ubuntu 12.04, running kernel 3.2.0-26-generic SMP x86_64
  509. compiler: g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
  510. MySQL version: 5.5.24
  511. SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e</screen>
  512. </para>
  513. <para>The benchmarks were run with precompiled statements enabled.
  514. The code was compiled with the -Ofast flag (optimize compilation for speed).
  515. Each run was repeated three times and measured values were averaged.</para>
  516. <para>Again the benchmarks were run in two series, synchronous and
  517. asynchronous. As those modes offer radically different
  518. performances, synchronous mode was conducted for one
  519. thousand repetitions and asynchronous mode was conducted for
  520. one hundred thousand repetitions.</para>
  521. <!-- raw results sync -->
  522. <table><title>Synchronous results (optimized)</title>
  523. <tgroup cols='6' align='center' colsep='1' rowsep='1'>
  524. <colspec colname='Backend'/>
  525. <colspec colname='Num' />
  526. <colspec colname='Create'/>
  527. <colspec colname='Search'/>
  528. <colspec colname='Update'/>
  529. <colspec colname='Delete'/>
  530. <colspec colname='Average'/>
  531. <thead>
  532. <row>
  533. <entry>Backend</entry>
  534. <entry>Operations</entry>
  535. <entry>Create [s]</entry>
  536. <entry>Search [s]</entry>
  537. <entry>Update [s]</entry>
  538. <entry>Delete [s]</entry>
  539. <entry>Average [s]</entry>
  540. </row>
  541. </thead>
  542. <tbody>
  543. <row>
  544. <entry>MySQL</entry>
  545. <entry>1,000</entry>
  546. <entry>27.887</entry>
  547. <entry> 0.106</entry>
  548. <entry>28.223</entry>
  549. <entry>27.696</entry>
  550. <entry>20.978</entry>
  551. </row>
  552. <row>
  553. <entry>SQLite</entry>
  554. <entry>1,000</entry>
  555. <entry>61.299</entry>
  556. <entry> 0.015</entry>
  557. <entry>59.648</entry>
  558. <entry>61.098</entry>
  559. <entry>45.626</entry>
  560. </row>
  561. <row>
  562. <entry>memfile</entry>
  563. <entry>1,000</entry>
  564. <entry>39.564</entry>
  565. <entry> 0.000724</entry>
  566. <entry>39.543</entry>
  567. <entry>39.326</entry>
  568. <entry>29.608</entry>
  569. </row>
  570. </tbody>
  571. </tgroup>
  572. </table>
  573. <para>The following parameters were measured for asynchronous mode.
  574. MySQL and SQLite were run with one hundred thousand repetitions. Memfile
  575. was run for one million repetitions due to its much higher performance.</para>
  576. <!-- raw results async -->
  577. <table><title>Asynchronous results (optimized)</title>
  578. <tgroup cols='6' align='center' colsep='1' rowsep='1'>
  579. <colspec colname='Backend'/>
  580. <colspec colname='Num' />
  581. <colspec colname='Create'/>
  582. <colspec colname='Search'/>
  583. <colspec colname='Update'/>
  584. <colspec colname='Delete'/>
  585. <colspec colname='Average'/>
  586. <thead>
  587. <row>
  588. <entry>Backend</entry>
  589. <entry>Operations</entry>
  590. <entry>Create [s]</entry>
  591. <entry>Search [s]</entry>
  592. <entry>Update [s]</entry>
  593. <entry>Delete [s]</entry>
  594. <entry>Average [s]</entry>
  595. </row>
  596. </thead>
  597. <tbody>
  598. <row>
  599. <entry>MySQL</entry>
  600. <entry>100,000</entry>
  601. <entry>8.507</entry>
  602. <entry>9.698</entry>
  603. <entry>7.785</entry>
  604. <entry>8.326</entry>
  605. <entry>8.579</entry>
  606. </row>
  607. <row>
  608. <entry>SQLite</entry>
  609. <entry>100,000</entry>
  610. <entry> 1.562</entry>
  611. <entry> 0.949</entry>
  612. <entry> 1.513</entry>
  613. <entry> 1.502</entry>
  614. <entry> 1.382</entry>
  615. </row>
  616. <row>
  617. <entry>memfile</entry>
  618. <entry>1,000,000</entry>
  619. <entry>1.302</entry>
  620. <entry>0.038</entry>
  621. <entry>1.306</entry>
  622. <entry>1.263</entry>
  623. <entry>0.977</entry>
  624. </row>
  625. </tbody>
  626. </tgroup>
  627. </table>
  628. <para>The presented performance results can be converted into operations per second metrics.
  629. It should be noted that due to large differences between various operations (sometime
  630. over three orders of magnitude), it is difficult to create a simple, readable chart with
  631. the data.</para>
  632. <table id="tbl-optim-perf-results"><title>Estimated optimized performance</title>
  633. <tgroup cols='6' align='center' colsep='1' rowsep='1'>
  634. <colspec colname='Backend'/>
  635. <colspec colname='Create'/>
  636. <colspec colname='Search'/>
  637. <colspec colname='Update'/>
  638. <colspec colname='Delete'/>
  639. <colspec colname='Average'/>
  640. <thead>
  641. <row>
  642. <entry>Backend</entry>
  643. <entry>Create [oper/s]</entry>
  644. <entry>Search [oper/s]</entry>
  645. <entry>Update [oper/s]</entry>
  646. <entry>Delete [oper/s]</entry>
  647. <entry>Average [oper/s]</entry>
  648. </row>
  649. </thead>
  650. <tbody>
  651. <row>
  652. <entry>MySQL (async)</entry>
  653. <entry>11754.84</entry>
  654. <entry>10311.34</entry>
  655. <entry>12845.35</entry>
  656. <entry>12010.24</entry>
  657. <entry>11730.44</entry>
  658. </row>
  659. <row>
  660. <entry>SQLite (async)</entry>
  661. <entry>64005.90</entry>
  662. <entry>105391.29</entry>
  663. <entry>66075.51</entry>
  664. <entry>66566.43</entry>
  665. <entry>75509.78</entry>
  666. </row>
  667. <row>
  668. <entry>memfile (async)</entry>
  669. <entry>76832.16</entry>
  670. <entry>2636018.56</entry>
  671. <entry>76542.50</entry>
  672. <entry>79188.81</entry>
  673. <entry>717145.51</entry>
  674. </row>
  675. <row>
  676. <entry>MySQL (sync)</entry>
  677. <entry>35.86</entry>
  678. <entry>9461.10</entry>
  679. <entry>35.43</entry>
  680. <entry>36.11</entry>
  681. <entry>2392.12</entry>
  682. </row>
  683. <row>
  684. <entry>SQLite (sync)</entry>
  685. <entry>16.31</entry>
  686. <entry>67036.11</entry>
  687. <entry>16.76</entry>
  688. <entry>16.37</entry>
  689. <entry>16771.39</entry>
  690. </row>
  691. <row>
  692. <entry>memfile (sync)</entry>
  693. <entry>25.28</entry>
  694. <entry>3460207.61</entry>
  695. <entry>25.29</entry>
  696. <entry>25.43</entry>
  697. <entry>865070.90</entry>
  698. </row>
  699. </tbody>
  700. </tgroup>
  701. </table>
  702. <mediaobject>
  703. <imageobject>
  704. <imagedata fileref="performance-results-graph2.png" format="PNG"/>
  705. </imageobject>
  706. <textobject>
  707. <phrase>Optimized performance measurements</phrase>
  708. </textobject>
  709. <caption>
  710. <para>Graphical representation of the optimized performance
  711. results presented in table <xref linkend="tbl-optim-perf-results"
  712. />.</para>
  713. </caption>
  714. </mediaobject>
  715. </section>
  716. <section>
  717. <title>Conclusions</title>
  718. <para>
  719. Improvements gained by introducing support for precompiled
  720. statements in MySQL is somewhat disappointing - between 6 and
  721. 29%. On the other hand, the improvement in SQLite is
  722. surprisingly high - the efficiency is more than doubled.
  723. </para>
  724. <para>
  725. Compiled statements do not have any measureable impact on
  726. synchronous operations. That is as expected, because the major
  727. bottleneck is the disk performance.
  728. </para>
  729. <para>
  730. Compilation flags yield surprisingly high improvements for C++
  731. STL code. The memfile backend is in some operations is almost
  732. twice as fast.
  733. </para>
  734. <para>
  735. If synchronous operation is required, the current performance
  736. results are likely to be deemed inadequate. The limiting
  737. factor here is a disk access time. Even migrating to high
  738. performance 15,000 rpm disk is expected to only roughly double
  739. number of leases per second, compared to the current results.
  740. The reason is that to write a file to disk, at least two writes
  741. are required: the new content and i-node modification of the
  742. file. The easiest way to boost synchronous performance is to
  743. switch to SSD disks. Memory-backed RAM disks are also a viable
  744. solution. However, care should be taken to properly engineer
  745. backup strategy for RAM disks.
  746. </para>
  747. <para>
  748. While the custom made backend (memfile) provides the best
  749. perfomance, it carries over all the limitations existing in
  750. the ISC DHCP4 code: there are no external tools to query or
  751. change database, the maintenance requires deep knowledge etc.
  752. Those flaws are not shared by usage of a proper database
  753. backend, like MySQL and SQLite. They both offer third party
  754. tools for administrative tasks, they are well documented and
  755. maintained. However, SQLite support for concurrent access is
  756. limiting in certain cases. Since all three investigated
  757. backends more than meet expected performance results, it is
  758. recommended to use MySQL as a first concrete database backend.
  759. Should this choice be rejected for any reason, the second
  760. recommended choice is SQLite.
  761. </para>
  762. <para>
  763. It should be emphaisized that obtained measurements indicate
  764. only database performance and they cannot be directly
  765. translated to expected leases per second or queries per second
  766. performance by an actual server. The DHCP server must do much
  767. more than just query the database to properly process client's
  768. message. The provided results should be considered as only rough
  769. estimates. They can also be used for relative comparisons
  770. between backends.
  771. </para>
  772. </section>
  773. <section>
  774. <title>Possible further optimizations</title>
  775. <para>
  776. For basic measurements the code was compiled with -g -O0
  777. flags. For optimized measurements the benchmarking code was
  778. compiled with -Ofast (optimize for speed). In both cases, the
  779. same backend (MySQL or SQLite) library was used. It may be
  780. useful to recompile the libraries (or the whole server in case
  781. of MySQL) with -Ofast.
  782. </para>
  783. <para>
  784. There are many MySQL parameters that various sources recommend
  785. to improve performance. They were not investigated further.
  786. </para>
  787. <para>
  788. Currently all operations are conducted on one by one
  789. basis. Each operation is treated as a separate
  790. transaction. Grouping N operations together will potentially
  791. bring almost N fold increase in synchronous operations. Such a
  792. feature is present in ISC DHCP4 and is called cache-threshold.
  793. Extension for this benchmark in this regard should be
  794. considered. That affects only write operations (insert,
  795. update and delete). Read operations (search) are expected to
  796. be barely affected.
  797. </para>
  798. <para>
  799. Multi-threaded or multi-process benchmark may be considered in
  800. the future. It may be somewhat difficult as only some backends
  801. support concurrent access.
  802. </para>
  803. </section>
  804. </chapter>
  805. <chapter id="perfdhcp">
  806. <title>perfdhcp</title>
  807. <para>
  808. TODO: Write something about perfdhcp here.
  809. </para>
  810. </chapter>
  811. </book>