<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Юникс и другие &#187; MySQL articles</title>
	<atom:link href="http://boombick.org/blog/posts/category/mysql-articles/feed" rel="self" type="application/rss+xml" />
	<link>http://boombick.org/blog</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Wed, 26 May 2010 14:33:09 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>База данных MySQL с IP-адресами и их привязками к географическим объектам</title>
		<link>http://boombick.org/blog/posts/55</link>
		<comments>http://boombick.org/blog/posts/55#comments</comments>
		<pubDate>Tue, 10 Feb 2009 12:12:44 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[*NIX]]></category>
		<category><![CDATA[MySQL articles]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/55</guid>
		<description><![CDATA[В этой базе находятся соответствия IP-адресов и географических объектов с указанием города, страны, штата или региона, почтовый индекс и даже широта и долгота! В дампе базы есть следующие таблицы: cities : Города мира (страна, регион, широта, долгота, класс IP-адреса) fips_countries : Страны мира (код, имя) fips_regions : Регионы ip_group_city : Местонахождение IP-адресов (по стране, региону, [...]]]></description>
			<content:encoded><![CDATA[<p>В этой базе находятся соответствия IP-адресов и географических объектов с указанием города, страны, штата или региона, почтовый индекс и даже широта и долгота!<br />
<span id="more-55"></span><br />
В дампе базы есть следующие таблицы:</p>
<ul>
<li>cities : Города мира (страна, регион, широта, долгота, класс IP-адреса)</li>
<li>fips_countries : Страны мира (код, имя)</li>
<li>fips_regions : Регионы</li>
<li>ip_group_city : Местонахождение IP-адресов (по стране, региону, городу, почтовому индексу, широте и долготе)</li>
</ul>
<p><strong>Как пользоваться?</strong><br />
IP-адреса находятся в таблицах <em>ip_group_city</em> и <em>ip_group_country</em> и вычисляются по формуле (например для IP A.B.C.D):</p>
<blockquote>
<pre>
ip = (A*256+B)*256+C</pre>
</blockquote>
<p>Точность до последнего октета на так важна :)<br />
Например, у нас есть IP <em>74.125.45.100</em> (google)<br />
Приводим его к виду, сохраненному в БД</p>
<blockquote><p>ip = (74*256+125)*256+45 = 4881709</p></blockquote>
<p>И делаем запрос:</p>
<blockquote><pre>
SELECT * FROM `ip_group_city` where `ip_start` <= 4881709 order by ip_start desc limit 1;
</pre>
</blockquote>
<p>Результат:</p>
<blockquote><pre>
ip_start|country_code|region_code|city|zipcode|latitude|longitude
4881664|US|CA|Mountain View|94043|37.4192|-122.057
</pre>
</blockquote>
<p><strong>Почему в базе данных лишь 1,2 миллионов записей,  в то время как в действительности IP-адресов больше чуть ли не в 10 раз???</strong><br />
Пусть IP с 74.125.0.XXX по 74.125.32.XXX расположены близко друг к другу (принадлежат Google, например) Если бы в базе 32 раза была бы сохранена одна и таже информация, то размер базы был бы огромным! Поэтому в базе лежит лишь 74.125.0.XXX. Следующая строка начнется с 74.125.33.XXX</p>
<p><noindex><b>Оригинал:</b> <a href="http://blogama.org/node/58">http://blogama.org/node/58</a><br />
<b>Скачать базу:</b> <a href="http://www.blogama.org/ipinfodb.sql.bz2">http://www.blogama.org/ipinfodb.sql.bz2</a> (10 Mb)<br />
</noindex><br />
<b>Зеркало:</b> <a href="http://www.boombick.org/ipinfodb.sql.bz2">http://www.boombick.org/ipinfodb.sql.bz2</a></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/55/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>MySQL Proxy: tutorial</title>
		<link>http://boombick.org/blog/posts/34</link>
		<comments>http://boombick.org/blog/posts/34#comments</comments>
		<pubDate>Tue, 23 Sep 2008 13:55:35 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[MySQL articles]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/34</guid>
		<description><![CDATA[В продолжение прошлого поста про основы работы с MySQL Proxy по многочисленным просьбам аудитории публикуем продолжение :) На этот раз &#8211; более подробный разбор настройки и использования MySQL Proxy Краткий обзор MySQL Proxy &#8211; это небольшое приложение, расположенное между сервером баз данных и одним или несколькими клиентами. Вместо подключения напрямую к серверу, клиенты подключаются к [...]]]></description>
			<content:encoded><![CDATA[<p>В продолжение прошлого поста про <a href="http://boombick.org/blog/posts/31">основы работы с MySQL Proxy</a> по многочисленным просьбам аудитории публикуем продолжение :) На этот раз &#8211; более подробный разбор настройки и использования MySQL Proxy<br />
<span id="more-34"></span><br />
<strong>Краткий обзор</strong><br />
MySQL Proxy &#8211; это небольшое приложение, расположенное между сервером баз данных и одним или несколькими клиентами. Вместо подключения напрямую к серверу, клиенты подключаются к прокси (этот процесс прозрачен для клиента), MySQL Proxy выступает посредником между клиентом (-ами) и сервером.</p>
<p>Но использование MySQL Proxy лишь в качестве посредника (принял запрос -&gt; передал серверу -&gt; получил ответ -&gt; передал клиенту) было бы весьма нецелесообразным. И действительно, эта небольшая программа умеет немало всего. В MySQL Proxy есть встроенный интерпретатор языка <noindex><a href="http://www.lua.org">lua</a></noindex>, с его помощью мы можем выполнять немало полезных действий над данными, проходящими через прокси.<br />
<a href="http://boombick.org/blog/wp-content/uploads/2008/09/proxy-overview.png" title="proxy-overview.png"><img src="http://boombick.org/blog/wp-content/uploads/2008/09/proxy-overview.png" alt="proxy-overview.png" /></a><br />
Вся мощь прокси &#8211; в его гибкости, которая достигается за счет использования lua-движка. Вы перехватываете запрос и можете сделать с ним все, что угодно:</p>
<ul>
<li>Передать его дальше неизмененным (по умолчанию)</li>
<li>Исправить грамматические ошибки (<code>CRATE DATAABSE</code>, знакомо, не правда ли?)</li>
<li>Отфильтровать запрос по неким правилам (или совсем отклонить его)</li>
<li>Исправить запрос (например добавить более стойкий пароль или заполнить пустые значения)</li>
<li>Добавить &#8220;забытые&#8221; значения (автокоммит включен, а пользователь послал запрос <code>BEGIN WORK</code>? Вы можете поместить перед ним <code>SET AUTOCOMMIT = 0</code>)</li>
<li>И это далеко не все, полный список возможностей ограничен лишь вашей фантазией!</li>
</ul>
<p>Также вы можете выполнять операции над результатами запросов:</p>
<ul>
<li>Добавлять, удалять и модифицировать записи в результате запроса. Хотите замаскировать пароль или скрыть конфиденциальные данные от неавтоизованного пользователя?</li>
<li>Строить свои собственные result set&#8217;ы, включая имена столбцов. Например, если вы позволяете пользователю вводить его собственные SQL-команды, то вы можете показать предварительный результат</li>
<li>Игнорировать результат, то есть ничего не отсылать клиенту</li>
<li>Хотите большего? Ничего невозможного: смотрите примеры и экспериментируйте!</li>
</ul>
<p><strong>Ключевые понятия</strong><br />
MySQL Proxy построен на базе объектно-ориентированной архитектуры. Основной класс имеет три публичных метода и вы можете переопределить их в своих lua-сценариях.</p>
<ul>
<li><em>connect_server():</em> &#8211; вызывается при соединении, при помощи этого метода вы можете оперировать параметрами соединения. Именно этот метод используется при построении <em>распределения нагрузки (load balancing)</em></li>
<li><em>read_query(packet):</em> &#8211; этот метод вызывается перед отправкой запроса на сервер. Вы можете изменить оригинальный запрос, добавить свои подзапросы или запросы или решить вообще ничего не отправлять на сервер, а отдать клиенту собственный result set (Например в ответ на <code>SELECT * FROM big_table</code> вы можете вернуть <code>Таблица big_table содержит более 20 миллионов записей. Вы не забыли условие WHERE?</code>)</li>
<li><em>read_query_result(injection_packet)</em> &#8211; эта функция выполняется перед отправкой результата запроса клиенту. Вы можете проигнорировать result set, изменить его или отправить клиенту неизмененным</li>
</ul>
<p>Комбинация этих трех методов обеспечит вам прекрасную маневренность при управлении сервером (или серверами) MySQL</p>
<p><strong>Установка</strong><br />
Установки Proxy предельно проста. Дистрибутив содержит в себе один бинарный файл (с версии 0.5.1 также несколько lua-скриптов для примера). Вы можете распаковать его и поместить туда, куда вам больше нравится. Или воспользоваться пакетным менеджером вашего дистрибутива (например, RPM или apt-get).<br />
Если ваш дистрибутив не содержит готового пакета с Proxy или вы хотите поэксперементировать с опциями сборки, то вы можете получить исходные тексты из <noindex><a href="http://forge.mysql.com/wiki/MySQL_Proxy#Development_source_tree">репозитория Subversion</a></noindex> и собрать Proxy самостоятельно. Для этого необходимо выполнить несколько простых действий:</p>
<blockquote><p>  ./autogen.sh<br />
./configure &amp;&amp; make<br />
sudo make install<br />
# will copy the executable to /usr/local/sbin</p></blockquote>
<p><strong>Простой перехват запроса</strong><br />
В качестве нашего первого примера давайте просто сделаем преобразование запроса с добавлением метки типа &#8220;Я здесь был&#8221; :)</p>
<ol>
<li>Создайте lua-сценарий с листингом, приведенным ниже и сохраните его под именем <em>first_example.lua</em></li>
<li>Предположим, что ваш сервер находится на той же физической машине, что и клиент</li>
<li>С другой консоли присоединитесь к вашему прокси-серверу и выполните какой-нибудь запрос (используйте порт 4040 вместо порта сервера 3306)</li>
</ol>
<blockquote>
<pre>
 -- first_example.lua
 function read_query(packet)
   if string.byte(packet) == proxy.COM_QUERY then
     print("Hello world! Seen the query: " .. string.sub(packet, 2))
   end
 end</pre>
</blockquote>
<blockquote><p># starting the proxy<br />
$ mysql-proxy &#8211;proxy-lua-script=first_example.lua -D<br />
# from another console, accessing the proxy<br />
$ mysql -u USERNAME -pPASSWORD -h 127.0.0.1 -P 4040 -e &#8216;SHOW TABLES FROM test&#8217;</p></blockquote>
<p>Если мы вернемся к предыдущей консоли, то увидим, что прокси успешно перехватил запросы:</p>
<blockquote><p>Hello world! Seen the query: select @@version_comment limit 1<br />
Hello world! Seen the query: SHOW TABLES FROM test</p></blockquote>
<p>Первый запрос был послан клиентом MySQL при соединении, вторый выполнен нами. Как видите, мы находимся точно посередине между клиентом и сервером и даже уже можем кое-что сделать.. Пока это крайне мало, но в следующих главах будет интереснее.</p>
<p><em>Комментарий</em><br />
До версии 0.5.0 для использования lua-сценариев, вы должны были запускать прокси с параметром <em>&#8211;proxy-profiling</em>, иначе функции <em>read_query</em> и <em>read_query_result</em> просто не работали. Начиная с версии 0.5.1 этот параметр не обязателен. Теперь эти опции включены по умолчанию. Напротив, если вы используете MySQL Proxy только для балансировки нагрузки, то рекомендуется стартовать прокси-сервер с опцией <em>&#8211;proxy-skip-profiling</em></p>
<p><strong>Изменение запросов</strong><br />
Более интересные возможности открываются при взгляде на возможности прокси по изменению запросов. Для демонстрации давайте возьмем реальный пример. Мы хотим перехватывать запросы с типичными орфографическими ошибками и заменять их на корректные. Для примера используем часто встречающиеся <code>SLECT</code> и <code>CRATE</code></p>
<p><em>second_example.lua</em></p>
<blockquote>
<pre>
 function read_query( packet )
   if string.byte(packet) == proxy.COM_QUERY then
     local query = string.sub(packet, 2)
     print ("received " .. query)
     local replacing = false
     -- matches "CRATE" as first word of the query
     if string.match(string.upper(query), '^%s*CRATE') then
         query = string.gsub(query,'^%s*%w+', 'CREATE')
         replacing = true
     -- matches "SLECT" as first word of the query
     elseif string.match(string.upper(query), '^%s*SLECT') then
         query = string.gsub(query,'^%s*%w+', 'SELECT')
         replacing = true
     end
     if (replacing) then
         print("replaced with " .. query )
         proxy.queries:append(1, string.char(proxy.COM_QUERY) .. query )
         return proxy.PROXY_SEND_QUERY
     end
   end
 end</pre>
</blockquote>
<p>Не забываем запустить прокси с параметром <em>&#8211;proxy-lua-script=second_example.lua</em> и присоединиться к нему из mysql-клиента:</p>
<blockquote>
<pre>$ mysql -u USERNAME -pPASSWORD -h 127.0.0.1 -P 4040
 Welcome to the MySQL monitor.  Commands end with ; or \g.
 Your MySQL connection id is 48
 Server version: 5.0.37-log MySQL Community Server (GPL)

 Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

 mysql&gt; use test
 Database changed
 mysql&gt; CRATE TABLE t1 (id int);         # Notice: TYPO!
 Query OK, 0 rows affected (0.04 sec)

 mysql&gt; INSERT INTO t1 VALUES (1), (2);
 Query OK, 2 rows affected (0.01 sec)
 Records: 2  Duplicates: 0  Warnings: 0

 mysql&gt; SLECT * FROM t1;                 # Notice: TYPO!
 +------+
 | id   |
 +------+
 |    1 |
 |    2 |
 +------+
 2 rows in set (0.00 sec)</pre>
</blockquote>
<p>Великолепно! Я сделал свои типичные ошибки, но, тем не менее, запросы прекрасно выполнились.. Давайте посмотрим отчет</p>
<blockquote><p> received select @@version_comment limit 1<br />
received SELECT DATABASE()<br />
received CRATE TABLE t1 (id int)<br />
replaced with CREATE TABLE t1 (id int)<br />
received INSERT INTO t1 VALUES (1), (2)<br />
received SLECT * FROM t1<br />
replaced with SELECT * FROM t1</p></blockquote>
<p>Первые два запроса выполнил клиент.. А затем запросы с типичными ошибками были переписаны: <code>CRATE</code> был успешно изменен на <code>CREATE</code>, а <code>SLECT</code> превратился в <code>SELECT</code><br />
Это достаточно простой скрипт, но он демонстрирует большие возможности и безграничный простор для экспериментов!</p>
<p><strong>&#8220;Инъекции&#8221; в запросы</strong><br />
Далее мы рассмотрим уникальный механизм внедрения данных в запросы: query-инъекции. По мере надобности proxy может создавать очереди запросов, и после присвоения уникального ID каждому запросу, отсылать их на сервер.<br />
<a href="http://boombick.org/blog/wp-content/uploads/2008/09/proxy-injection1.png" title="proxy-injection1.png"><img src="http://boombick.org/blog/wp-content/uploads/2008/09/proxy-injection1.png" alt="proxy-injection1.png" /></a><br />
На картинке сервер получает три запроса и, конечно же, возвращает три result set&#8217;а. Когда мы используем механизм инъекций, обработку результатов берет на себя функция прокси: <em>read_query_result</em>, в которой вы можете сопоставить наборы данных с идентификаторами. Например, для ID 2 и 3 вы только извлекаете из значения и определяете влияние основного запроса на сервер. Посколько вы используете эти значения только для внутренних вычислений, вы не отсылаете их клиенту, и это, собственно, правильно, так как клиент их и не ожидает.</p>
<p><a href="http://boombick.org/blog/wp-content/uploads/2008/09/proxy-injection2.png" title="proxy-injection2.png"><img src="http://boombick.org/blog/wp-content/uploads/2008/09/proxy-injection2.png" alt="proxy-injection2.png" /></a><br />
Возвращенный результирующий набор данных в точности соответствует запросу клиента, но, абсолютно прозрачно для него, нам удалось собрать кое-какие статистические данные, которые и отображаются на консоли прокси. Более полное руководство по инъекциям вы можете найти в <noindex><a href="http://forge.mysql.com/snippets/view.php?id=77">Injection Tutorial</a></noindex></p>
<p><strong>Макросы</strong><br />
Макросы &#8211; это лишь один из способов применения &#8220;переписывания запроса&#8221;, но они являются одним из самых ярких примеров использования proxy. Вы можете изменить язык SQL или адаптировать его &#8220;под свой вкус&#8221;. Например, многие предпочитают использовать в командной строке <code>cd</code> и <code>ls</code>, вместо <code>USE db;</code> и <code>SHOW TABLES;</code>. Используя MySQL Proxy это возможно! Давайте попробуем написать свой первый макрос.</p>
<p><strong>Создание Result set&#8217;a: команды shell из mysql-клиента</strong><br />
Proxy получает запрос от клиента и возвращает набор данных, в большинстве случаев так и происходит. Передача запроса на сервер, получение набора данных, возврат результатов клиенту. Но что если мы должны вернуть данные, которые сервер <em>не может</em> нам предоставить? Мы должны самостоятельно построить результирующий набор данных, состоящий из имен столбцов и двумерного массива с данными.</p>
<p><strong><em>Основы создания result set&#8217;а</em></strong><br />
Например, если вы хотите вернуть предупреждение об устаревшей команде, вы можете использовать result set наподобие нижеследующего:</p>
<blockquote>
<pre>
 proxy.response.resultset = {
     fields = {
         {
            type = proxy.MYSQL_TYPE_STRING,
            name = "deprecated feature",
         },
         {
            type = proxy.MYSQL_TYPE_STRING,
            name = "suggested replacement",
         },
     },
     rows = {
          {
             "SHOW DATABASES",
             "SHOW SCHEMAS"
          }
     }
 }
 -- and then, send it to the client
 return proxy.PROXY_SEND_RESULT</pre>
</blockquote>
<p>В результате клиент получит следующий result set:</p>
<blockquote><pre>
+---------------------+-----------------------+
| deprecated feature  | suggested replacement |
+---------------------+-----------------------+
| SHOW DATABASES      | SHOW SCHEMAS          |
+---------------------+-----------------------+</pre>
</blockquote>
<p>Как видите, мы можем построить любой, необходимый нам, результирующий набор данных. За примерами обращайтесь к <a href="http://forge.mysql.com/snippets/view.php?id=78">Jan Kneschke</a></p>
<p><b>Системый командный интерпретатор в mysql-клиенте</b><br />
А теперь <noindex><a href="http://ru.wikipedia.org/wiki/%D0%90_%D1%82%D0%B5%D0%BF%D0%B5%D1%80%D1%8C_%D0%BD%D0%B5%D1%87%D1%82%D0%BE_%D1%81%D0%BE%D0%B2%D1%81%D0%B5%D0%BC_%D0%B4%D1%80%D1%83%D0%B3%D0%BE%D0%B5">нечто совсем другое</a></noindex>! Давайте посмотрим, как можно использовать только что полученные нами знания для выполнения команд оболочки через прокси. Как говорилось выше (и как вы уже могли заметить :)) поведение прокси-сервера может быть изменено при помощи lua-скриптов. LUA является полноценным языком программирования, поэтому вы можете делать на нем все, что угодно. В том числе и исполнять shell-команды. Связав этот факт с возможностью построения собственных result set&#8217;ов мы пришли к тому, что неплохо было бы обращаться к оболочке напрямую из командной строки mysql-клиента, возвращая данные в виде классического result set&#8217;а</p>
<p><a href='http://boombick.org/blog/wp-content/uploads/2008/09/proxy-shell.png' title='proxy-shell.png'><img src='http://boombick.org/blog/wp-content/uploads/2008/09/proxy-shell.png' alt='proxy-shell.png' /></a></p>
<p>Наш сценарий будет использовать следующий синтаксис для выполнения команд оболочки:</p>
<blockquote><p> SHELL command</p></blockquote>
<p>Например:<br />
SHELL ls -lh /usr/local/mysql/data</p></blockquote>
<ol>
<li>Загрузите <noindex><a href="http://forge.mysql.com/snippets/view.php?id=79">учебный сценарий</a></noindex></li>
<li>Запустите прокси</li>
<li>Соединитесь с прокси</li>
</ol>
<blockquote><p>$ /usr/local/sbin/mysql-proxy &#8211;proxy-lua-script=shell.lua -D</p>
<p># from a different console<br />
$ mysql -U USERNAME -pPASSWORD -h 127.0.0.1 -P 4040</p></blockquote>
<p>Убедитесь, что все работает нормально</p>
<blockquote><pre>
 Welcome to the MySQL monitor.  Commands end with ; or \g.
 Your MySQL connection id is 49
 Server version: 5.0.37-log MySQL Community Server (GPL)

 Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

 mysql> use test
 Database changed
 mysql> show tables;
 +----------------+
 | Tables_in_test |
 +----------------+
 | t1             |
 +----------------+
 1 row in set (0.00 sec)

 mysql> select * from t1;
 +------+
 | id   |
 +------+
 |    1 |
 |    2 |
 +------+
 2 rows in set (0.00 sec)</pre>
</blockquote>
<p>Отлично, обычные операции работают нормально. Теперь протестируем наши расширенные возможности:</p>
<blockquote><pre>
 mysql> shell df -h;
 +--------------------------------------------------------+
 | df -h                                                  |
 +--------------------------------------------------------+
 | Filesystem            Size  Used Avail Use% Mounted on |
 | /dev/md1               15G  3.9G  9.7G  29% /          |
 | /dev/md4              452G  116G  313G  27% /app       |
 | tmpfs                 1.7G     0  1.7G   0% /dev/shm   |
 | /dev/md3              253G  159G   82G  67% /home      |
 | /dev/md0               15G  710M   13G   6% /var       |
 +--------------------------------------------------------+
 6 rows in set (0.00 sec)</pre>
</blockquote>
<p>Привет, шелл! :) Теперь вы можете работать намного эффективнее&#8230;</p>
<blockquote><pre>
 mysql> shell grep key_buffer /usr/local/mysql/my.cnf;
 +-----------------------------------------+
 | grep key_buffer /usr/local/mysql/my.cnf |
 +-----------------------------------------+
 | key_buffer=2000M                        |
 +-----------------------------------------+
 1 row in set (0.00 sec)</pre>
</blockquote>
<p>Конечно, тот же результат можно было бы получить из запроса <code>SHOW VARIABLES;</code>, но наша задача &#8211; показать, что в клиенте mysql мы имеем полноценный shell!</p>
<blockquote><pre>
 mysql> shell free -m;
 +---------------------------------------------------------------------------+
 | free -m                                                                   |
 +---------------------------------------------------------------------------+
 |              total       used       free     shared    buffers     cached |
 | Mem:          3280       1720       1560          0          9       1006 |
 | -/+ buffers/cache:        704       2575                                  |
 | Swap:         8189          2       8186                                  |
 +---------------------------------------------------------------------------+
 4 rows in set (0.08 sec)</pre>
</blockquote>
<p>Неплохо. Но все это лежит на нашем же сервере.. А как насчет работы с сетью? Для примера мы посмотрим последние 20 записей на <noindex><a href="http://www.planetmysql.org/">Планете MySQL</a></noindex></p>
<blockquote><pre>
   wget -q -O - http://www.planetmysql.org/rss20.xml  \
      | perl -nle 'print $1 if m{}' \
      |head -n 21 | tail -n 20;</pre>
</blockquote>
<p>Да, длинновато немного, но это реально работает!</p>
<blockquote><pre>
 mysql> shell last_planet.sh;
 +-------------------------------------------------------------------------------------+
 | last_planet.sh                                                                      |
 +-------------------------------------------------------------------------------------+
 | Top 5 Wishes for MySQL                                                              |
 | Open Source ETL tools.                                                              |
 | MySQL Congratulates FSF on GPLv3                                                    |
 | Query cache is slow to the point of being unusable - what is being done about that. |
 | About 'semi-unicode' And 'quasi Moon Stone'                                         |
 | My top 5 MySQL wishes                                                               |
 | Four more open source startups to watch                                             |
 | More on queue... Possible Solution...                                               |
 | MySQL as universal server                                                           |
 | MySQL Proxy. Playing with the tutorials                                             |
 | Open source @ Oracle: Mike Olson speaks                                             |
 | Quick musing on the &quot;Queue&quot; engine.                                       |
 | Distributed business organization                                                   |
 | Ideas for a MySQL queuing storage engine                                            |
 | MySQL Test Creation Tool Design Change                                              |
 | Queue Engine, and why this won' likely happen...                                    |
 | What?s your disk I/O thoughtput?                                                    |
 | My 5+ Wish List?                                                                    |
 | Top 5 best MySql practices                                                          |
 | Packaging and Installing the MySQL Proxy with RPM                                   |
 +-------------------------------------------------------------------------------------+
 20 rows in set (1.48 sec)</pre>
</blockquote>
<p>Доступ к командной строке и Internet из mysql-клиента&#8230; Впечатляет :)</p>
<p><i>Пару слов об осторожности</i><br />
Разрешая доступ к командной строке вы можете получить кучу неприятностей. Тщательно следите за разделением доступа и контролируйте выполнение потенциально опасных shell-команд. Иначе вы можете в одночасье лишиться результатов долгой кропотливой работы&#8230;</p>
<p>Например:</p>
<blockquote><pre> mysql> shell ls *.lua*;
 +---------------------+
 | ls *.lua*           |
 +---------------------+
 | first_example.lua   |
 | first_example.lua~  |
 | second_example.lua  |
 | second_example.lua~ |
 +---------------------+
 4 rows in set (0.03 sec)

 mysql> shell rm *~;
 Empty set (0.00 sec)

 mysql> shell ls *.lua*;
 +--------------------+
 | ls *.lua*          |
 +--------------------+
 | first_example.lua  |
 | second_example.lua |
 +--------------------+
 2 rows in set (0.01 sec)</pre>
</blockquote>
<p>Будьте осторожны!!!<br />
Помните, что таким способом вы получаете доступ к командному интерпретатору хоста на котором запущен proxy, а не сервер баз данных. Это очень частая ошибка!!!</p>
<p><b>Выборочное логирование</b><br />
Я оставил этот пример напоследок, поскольку (судя по моему опыту) он является наиболее интересным и даже имеет практическое применение! В MySQL 5.1 у вас есть возможность <noindex><a href="http://datacharmer.blogspot.com/2007/04/logs-on-demand-dbas-prayer-come-true.html">вести такие логи</a></noindex> средствами самой СУБД, а если у вас версия 5.0, то proxy поможет вам :)<br />
Для помещения запросов в общий лог-файл просто поместите следующий код в файл <em>simple_logs.lua</em> или <noindex><a href="http://forge.mysql.com/snippets/view.php?id=80">скачайте его</a></noindex> с MySQL Forge.</p>
<blockquote><pre>
 local log_file = 'mysql.log'
 local fh = io.open(log_file, "a+")

 function read_query( packet )
   if string.byte(packet) == proxy.COM_QUERY then
     local query = string.sub(packet, 2)
     fh:write( string.format("%s %6d -- %s \n",
         os.date('%Y-%m-%d %H:%M:%S'),
         proxy.connection["thread_id"],
         query))
     fh:flush()
   end
 end</pre>
</blockquote>
<p>Запустите прокси и соединитесь с ним из нескольких различных клиентов. Сценарий будет записывать запросы в файл с именем <em>mysql.log</em> После завершения всех сессий файл будет выглядеть примерно так:</p>
<blockquote><pre>
 2007-06-29 11:04:28     50 -- select @@version_comment limit 1
 2007-06-29 11:04:31     50 -- SELECT DATABASE()
 2007-06-29 11:04:35     51 -- select @@version_comment limit 1
 2007-06-29 11:04:42     51 -- select USER()
 2007-06-29 11:05:03     51 -- SELECT DATABASE()
 2007-06-29 11:05:08     50 -- show tables
 2007-06-29 11:05:22     50 -- select * from t1
 2007-06-29 11:05:30     51 -- show databases
 2007-06-29 11:05:30     51 -- show tables
 2007-06-29 11:05:33     52 -- select count(*) from user
 2007-06-29 11:05:39     51 -- select count(*) from columns</pre>
</blockquote>
<p>Лог содержит дату, время, ID соединения и сам запрос. Просто и эффективно для короткого сценария. Надо заметить, что есть три сессии и запросы из них не отсортированы по ID, но расположены по времени выполнения.</p>
<p>Приятно, что вам не надо перезагружать сервер для включения логирования&#8230; Все, что необходимо, это перенаправить все запросы с порта 3306 (стандартного порта mysql-сервера) на порт 4040 (стандартный порт MySQL Proxy). И вам не нужно трогать сервер или какие-то приложения.. Одно просто правило для iptables поможет вам:</p>
<blockquote><p>sudo iptables -t nat -I PREROUTING \<br />
   -s ! 127.0.0.1 -p tcp \<br />
   &#8211;dport 3306 -j \<br />
   REDIRECT &#8211;to-ports 4040</p></blockquote>
<p><a href='http://boombick.org/blog/wp-content/uploads/2008/09/proxy-redirection.png' title='proxy-redirection.png'><img src='http://boombick.org/blog/wp-content/uploads/2008/09/proxy-redirection.png' alt='proxy-redirection.png' /></a></p>
<p>Теперь у вас включено логирование, а приложения-клиенты и сервер даже не заметили этого!! После того, как потребность в логировании отпадет просто удалите правило при помощи ключа <i>-D</i> и остановите прокси</p>
<blockquote><p>sudo iptables -t nat -D PREROUTING \<br />
   -s ! 127.0.0.1 -p tcp \<br />
   &#8211;dport 3306 -j \<br />
   REDIRECT &#8211;to-ports 4040</p></blockquote>
<p><b>Еще больше возможностей для логирования</b><br />
Предыдущий пример с ведением журналов прост и нагляден но, к сожалению, действительно слишком прост. Мы могли бы иметь гораздо более подробную информацию в логах: количество успешных и неуспешных запросов, количество запросов с синтаксическими ошибками, количество переданных или затронутых строк.</p>
<p>Попробуем это реализовать. Это сценарий уже побольше предыдущего</p>
<blockquote><pre>
 -- logs.lua
 assert(proxy.PROXY_VERSION >= 0x00600,
  "you need at least mysql-proxy 0.6.0 to run this module")

 local log_file = os.getenv("PROXY_LOG_FILE")
 if (log_file == nil) then
   log_file = "mysql.log"

 end

 local fh = io.open(log_file, "a+")
 local query = "";</pre>
</blockquote>
<p>Сначала мы проверяем версию прокси (так как мы используем возможности, которых нет  в 0.5.0) и устанавливаем имя файла (забирая его из переменной окружения или присваивая значение по умолчанию)</p>
<blockquote><pre>
 function read_query( packet )
   if string.byte(packet) == proxy.COM_QUERY then
     query = string.sub(packet, 2)
     proxy.queries:append(1, packet )
     return proxy.PROXY_SEND_QUERY
   else
       query = ""

   end
 end</pre>
</blockquote>
<p>Первая функция совсем проста &#8211; она добавляет запрос к очереди, чтобы следующая функция сработала, когда поступит результат.</p>
<blockquote><pre>
 function read_query_result (inj)
   local row_count = 0
   local res = assert(inj.resultset)
   local num_cols = string.byte(res.raw, 1)
   if num_cols > 0 and num_cols < 255 then
     for row in inj.resultset.rows do
       row_count = row_count + 1
     end
   end
   local error_status =""
   if res.query_status and (res.query_status < 0 ) then
       error_status = "[ERR]"

   end
   if (res.affected_rows) then
       row_count = res.affected_rows
   end
   --
   -- write the query, adding the number of retrieved rows
   --
   fh:write( string.format("%s %6d -- %s {%d} %s\n",
     os.date('%Y-%m-%d %H:%M:%S'),
     proxy.connection["thread_id"],
     query,
     row_count,
     error_status))
   fh:flush()
 end</pre>
</blockquote>
<p>В этой функции мы проверяем, имеем мы дело с запросом на выборку или же изменяются какие-то данные. В лог-файл записывается количество возвращенных строк. Если есть измененные строки, их количество также будет отображено в логе, и, наконец, все данные о произошедших ошибках тоже не останутся без внимания. Вот пример лога:</p>
<blockquote><pre>
 2007-06-29 16:41:10     33 -- show databases {5}
 2007-06-29 16:41:10     33 -- show tables {2}
 2007-06-29 16:41:12     33 -- Xhow tables {0} [ERR]
 2007-06-29 16:44:27     34 -- select * from t1 {6}
 2007-06-29 16:44:50     34 -- update t1 set id = id * 100 where c = 'a' {2}
 2007-06-29 16:45:53     34 -- insert into t1 values (10,'aa') {1}
 2007-06-29 16:46:07     34 -- insert into t1 values (20,'aa'),(30,'bb') {2}
 2007-06-29 16:46:22     34 -- delete from t1 {9}</pre>
</blockquote>
<p>Первая, вторая и четвертая строчки описывают, что сервер вернул, соотвественно, пять, две и шесть строк в ответ. Третья говорит об ошибке. В пятой строки мы видим, что команда <code>UPDATE</code> затронула две строки. Остальные строки описывают "последствия" команд <code>INSERT</code> и <code>DELETE</code></p>
<p><b>Оригинал: </b> <noindex><a href="http://www.oreillynet.com/pub/a/databases/2007/07/12/getting-started-with-mysql-proxy.html">http://www.oreillynet.com/pub/a/databases/2007/07/12/getting-started-with-mysql-proxy.html</a></noindex></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/34/feed</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>MySQL Proxy</title>
		<link>http://boombick.org/blog/posts/31</link>
		<comments>http://boombick.org/blog/posts/31#comments</comments>
		<pubDate>Wed, 27 Aug 2008 11:04:41 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[MySQL articles]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/31</guid>
		<description><![CDATA[MySQL proxy &#8211; это небольшая программа, которая располагается между клиентом и сервером (серверами) MySQL и может наблюдать или вмешиваться в процесс коммуникации между ними. Ее гибкость и настраиваемость позволяют делать многие удобные вещи: простое наблюдение за соединением, балансировку нагрузки, реализацию механизма failover, анализ запросов, фильтрацию и модификацию запросов, а также много другое Получение На официальной [...]]]></description>
			<content:encoded><![CDATA[<p>MySQL proxy &#8211; это небольшая программа, которая располагается между клиентом и сервером (серверами) MySQL и может наблюдать или вмешиваться в процесс коммуникации между ними. Ее гибкость и настраиваемость позволяют делать многие удобные вещи: простое наблюдение за соединением, балансировку нагрузки, реализацию механизма failover, анализ запросов, фильтрацию и модификацию запросов, а также много другое<br />
<span id="more-31"></span><br />
<strong>Получение</strong><br />
На <noindex><a href="http://dev.mysql.com/downloads/mysql-proxy/">официальной странице загрузки</a></noindex> вы найдете бинарную версию для всех поддерживаемых MySQL Enterprise платформ, исходный код для самостоятельной компиляции, RPM-пакеты (включая экспериментальные версии из SVN) для различных дистрибутивов Linux. deb-пакет доступен в официальном репозитории Debian.</p>
<p>MySQL Proxy распросраняется под лицензией GPL</p>
<p><strong>Синтаксис командной строки</strong></p>
<blockquote>
<pre>
$ mysql-proxy --help-all

Использование:

  mysql-proxy [OPTION...] - MySQL Proxy
Опции справки:

  -?, --help                                          Показать краткую справку
  --help-all                                          Показать все пункты справки
  --help-admin                                        Показать ключи для модуля admin
  --help-proxy                                        Показать ключи для модуля proxy

Модуль admin

  --admin-address=&lt;host:port&gt;                         Слушать заданный адрес:порт для внутреннего модуля администрирования (по умолчанию: :4041)

Модуль proxy

  --proxy-address=&lt;host:port&gt;                         Адрес:порт прокси-сервера (по умолчанию: :4040)
  --proxy-read-only-backend-addresses=&lt;host:port&gt;     Адрес:порт удаленного дополнительного сервера (по умолчанию: не задан)
  --proxy-backend-addresses=&lt;host:port&gt;               Адрес:порт удаленных backend-серверов (по умолчанию: 127.0.0.1:3306)
  --proxy-skip-profiling                              отключить профилирование запросов (по умолчанию: включено)
  --proxy-fix-bug-25371                               исправить ошибку #25371 (mysqld &gt; 5.1.12) для старых версий libmysql
  --proxy-lua-script=&lt;file&gt;                           имя lua-скрипта (по умолчанию: не задано)
  --no-proxy                                          Не стартовать прокси-сервер

Опции приложения:

  -V, --version                                       Показать версию
  --daemon                                            Запускаться в режиме демона
  --pid-file=&lt;file&gt;                                   PID-файл (в случае запуска в режиме демона)</pre>
</blockquote>
<p><strong>Соединение</strong><br />
В качестве простого примера запустите mysql-proxy и попробуйте присоединиться к ней с помощью клиента:</p>
<blockquote><p>  $ mysql-proxy &amp;<br />
$ mysql &#8211;host=127.0.0.1 &#8211;port=4040 &#8211;user=&#8230; &#8211;password</p></blockquote>
<p>Подключение будет проксировано на адрес 127.0.0.1 и порт 3306<br />
<em>ВАЖНО:</em> сервер MySQL должен иметь версию 5.0.x и выше. Работа с версиями 4.1 официально не поддерживается, но если вы решите использовать эту связку, то не забудьте отослать репорты об ошибках</p>
<p><strong>Модуль Proxy</strong><br />
Модуль Proxy состоит из двух частей:</p>
<ul>
<li>Ядро, написанное на C</li>
<li>Интерфейс на lua</li>
</ul>
<p>Ядро обрабатывает пересылку пакетов на низком уровне и пытается работать настолько быстро, насколько это возможно, оно обрабатывает более тысячи параллельных соединений одновременно. Ядро состоит из:</p>
<ul>
<li>обработчика конфиг-файла</li>
<li>шифровщика протокола mysql</li>
<li>обработчика сокетов</li>
<li>балансировщика нагрузки</li>
<li>реализации механизма failover</li>
</ul>
<pre>
<blockquote>

 $ mysql-proxy --help-proxy
 Использование:
   mysql-proxy [OPTION...] - MySQL Proxy

 proxy-module
   --proxy-address=&lt;ip:port&gt;               слушать адрес:порт прокси-сервера (по умолчанию: :4040)
   --proxy-read-only-address=&lt;ip:port&gt;     Слушать адрес:порт для соединений только для чтения (по умолчанию: :4042)
   --proxy-backend-addresses=&lt;ip:port&gt;     Адрес:порт для удаленных backend-серверов (по умолчанию: не задан)
   --proxy-profiling                       включить профилирование запросов
   --proxy-fix-bug-25371                   исправить ошибку #25371 (mysqld &gt; 5.1.12) для старых версий libmysql
   --proxy-lua-script=&lt;file&gt;               расположение lua-скрипта (по умолчанию: не задан)</blockquote>
</pre>
<p>&#8211;proxy-address &#8211; это адрес и порт сервера, который транслирует запросы к одному из backend-серверов.<br />
Backend-сервер, объявленный при помощи &#8211;proxy-backend-addresses по умолчанию имеет значение 127.0.0.1:3306. Вы можете использовать эту опцию несколько раз и задать нужное количество серверов.</p>
<p><strong>Admin server</strong><br />
Сервер администрирования реализует основные возможности протокола mysql и может отвечать на некоторые базовые запросы. В нем реализованы:</p>
<ul>
<li>Обработка сокетов</li>
<li>Жизненный цикл соединения</li>
<li>mysql wire-протокол</li>
<li>len-encoding (?) некоторых полей</li>
<li>Типы полей</li>
<li>Результирующие наборы данных</li>
</ul>
<p>Дизайн основывается на идеях, заимствованных из lighttpd и использует неблокирующий сетевой ввод/вывод, сетевой протокол основан на информации, доступной во внутренних документах с dev.mysql.com<br />
В admin server реализованы 2 базовых запроса, которые доступны из командной строки mysql-клиента:</p>
<blockquote><p> select @@version_comment LIMIT 1;<br />
select USER();</p></blockquote>
<p>Используя admin server, вы можете реализовать необходимую функциональность, чтобы любой mysql-клиент (php, jdbc, odbc, perl, &#8230;) мог использовать его.<br />
Мы используем его для экспорта текущей конфигурации и отслеживания открытых соединений.</p>
<pre>
<blockquote>

&gt; select * from proxy_connections;
+------+--------+-------+-------+
| id   | type   | state | db    |
+------+--------+-------+-------+
|    2 | proxy  | 8     | world |
|    3 | server | 8     |       |
+------+--------+-------+-------+</blockquote>
</pre>
<pre>
<blockquote>

&gt; select * from proxy_config;
+---------------------------------+----------------+
| option                          | value          |
+---------------------------------+----------------+
| admin.address                   | :4041          |
| proxy.address                   | :4040          |
| proxy.backend_addresses[0]      | 127.0.0.1:3306 |
| proxy.backend_addresses[1]      | 127.0.0.1:3307 |
| proxy.fix_bug_25371             | 0              |
| repclient.master_address        |                |
+---------------------------------+----------------+</blockquote>
</pre>
<p><strong>Балансировка нагрузки и failover</strong></p>
<blockquote><p>  $ mysql-proxy \<br />
&#8211;proxy-backend-addresses=10.0.1.2:3306 \<br />
&#8211;proxy-backend-addresses=10.0.1.3:3306 &amp;</p></blockquote>
<p>Запустите тестовые соединения, остановите один из backend-серверов и вы увидите, как весь трафик будет передан второму, который продолжает работать.</p>
<p><strong>Расширение lua</strong><br />
MySQL Proxy поддерживает <noindex><a href="http://lua.org">язык lua</a></noindex>. Это маленький встраиваемый и очень удобный язык. На mysql.com есть <noindex><a href="http://forge.mysql.com/tools/search.php?t=tag&amp;k=mysqlproxy">репозиторий скриптов для MySQL Proxy</a></noindex></p>
<p>На рисунке изображены состояния работы сервера с клиентом<br />
<a href="http://boombick.org/blog/wp-content/uploads/2008/08/mysql-proto-state.png" title="mysql-proto-state.png"><img src="http://boombick.org/blog/wp-content/uploads/2008/08/mysql-proto-state.png" alt="mysql-proto-state.png" /></a></p>
<p>При помощи lua-скриптов вы можете &#8220;вклиниться&#8221; в три стадии:</p>
<ul>
<li>connect_server</li>
<li>read_query</li>
<li>read_query_result</li>
</ul>
<p>Если вы хотите написать балансировщик нагрузки, то вы можете &#8220;вклиниться&#8221; в connect_server, который вызывается перед соединением с backend-сервером. Балансировщик может выбрать backend из списка, который был задан при запуске прокси.</p>
<p>read_query &#8211; это стадия между передачей запроса от клиента серверу. На этой стадии вы можете решить что делать с запросом: передать клиенту &#8220;как есть&#8221;, изменить его, добавить еще запросов или напрямую ответить клиенту без передачи запроса на сервер.</p>
<p>Например, вы можете &#8220;дампить&#8221; все данные, передаваемые между клиентом и сервером (после авторизации):</p>
<pre>
<blockquote>

 (sqf) taking 127.0.0.1:3306, clients: 0
 .---  mysql result packet
 | query.len = 13
 | query.packet = 03 73 68 6f 77 20 65 6e 67 69 6e 65 73
 | .--- query
 | | command = COM_QUERY
 | | query = "show engines"
 | '---
 |
 | result.len = 1
 | result.packet = 06
 | .---
 | | command = COM_QUERY
 | | num-cols = 6
 | | field[0] = { type = 253, name = Engine }
 | | field[1] = { type = 253, name = Support }
 | | field[2] = { type = 253, name = Comment }
 | | field[3] = { type = 253, name = Transactions }
 | | field[4] = { type = 253, name = XA }
 | | field[5] = { type = 253, name = Savepoints }
 | | row[0] = { ndbcluster, DISABLED, Clustered, fault-tolerant tables, YES, NO, NO }
 | | row[1] = { MRG_MYISAM, YES, Collection of identical MyISAM tables, NO, NO, NO }
 | | row[2] = { BLACKHOLE, YES, /dev/null storage engine (anything you write to it disappears), NO, NO, NO }
 | | row[3] = { CSV, YES, CSV storage engine, NO, NO, NO }
 | | row[4] = { MEMORY, YES, Hash based, stored in memory, useful for temporary tables, NO, NO, NO }
 | | row[5] = { FEDERATED, YES, Federated MySQL storage engine, YES, NO, NO }
 | | row[6] = { ARCHIVE, YES, Archive storage engine, NO, NO, NO }
 | | row[7] = { InnoDB, YES, Supports transactions, row-level locking, and foreign keys, YES, YES, YES }
 | | row[8] = { MyISAM, DEFAULT, Default engine as of MySQL 3.23 with great performance, NO, NO, NO }
 | '---
 '---</blockquote>
</pre>
<p>Для более глубокого изучения работы MySQL Proxy мы рекомендуем статью <noindex><a href="http://www.oreillynet.com/pub/a/databases/2007/07/12/getting-started-with-mysql-proxy.html">Getting started with MySQL Proxy</a></noindex> (<a href="http://boombick.org/blog/posts/34">Перевод</a>)</p>
<p><strong><em>Оригинал:</em></strong> <noindex><a href="http://forge.mysql.com/wiki/MySQL_Proxy">http://forge.mysql.com/wiki/MySQL_Proxy</a></noindex></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/31/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>10+ способов обрушить mysql-сервер</title>
		<link>http://boombick.org/blog/posts/12</link>
		<comments>http://boombick.org/blog/posts/12#comments</comments>
		<pubDate>Wed, 21 Nov 2007 09:24:25 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[MySQL articles]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/12</guid>
		<description><![CDATA[Иногда у меня спрашивают об ошибках MySQL, (например таких), которые могут привести к падению mysql-сервера, вызванного пользователем с обычными привилегиями. Потом звучит вопрос: &#8220;Что же делать в таких случаях? Как защититься от подобных ситуаций?&#8221; Мой ответ &#8220;Сядьте и расслабьтесь :)&#8221; Действительно, существует очень много ситуаций, в которых сервер падает или не отвечает на запросы. Причем ситуации [...]]]></description>
			<content:encoded><![CDATA[<p>Иногда у меня спрашивают об ошибках MySQL, (например <noindex><a HREF="http://bugs.mysql.com/bug.php?id=32125">таких</a></noindex>), которые могут привести к  падению mysql-сервера, вызванного пользователем с обычными привилегиями. Потом звучит вопрос: &#8220;Что же делать в таких случаях? Как защититься от подобных ситуаций?&#8221;<br />
<span id="more-12"></span><br />
Мой ответ &#8220;Сядьте и расслабьтесь :)&#8221;</p>
<p>Действительно, существует очень много ситуаций, в которых сервер падает или не отвечает на запросы. Причем ситуации эти существуют для любых версий MySQL и их можно воспроизвести, обладая базовыми привилегиями для доступа к sql-серверу.</p>
<p>Мы часто помогаем людям исправлять ошибки в их приложениях, использующих MySQL (но положа руку на сердце можно сказать &#8211; в большинстве случаев они сами являются причиной некорректной работы сервера) и ошибки эти очевидны.</p>
<p>По-моему, девиз безопасности MySQL должна выглядеть так: если у вас полностью закрыт доступ к серверу, вы действительно защищены. Для некоторых видов атак не нужен валидный аккаунт, но такие ошибки довольно быстро исправляются. В тот момент, когда вы даете кому-то аккаунт вы перестаете полностью контролировать ситуацию. И значит, что защищенность сервера становится немного ниже.</p>
<p>Такое положение вещей будет сохраняться все время, пока MySQL использует <strong>Глобальное Управление Ресурсами</strong>, и вы реально не можете контролировать количество ресурсов, доступных вашим пользователям.</p>
<p>Вы можете возразить, что это, в принципе, не катастрофа. Конечно, но сервер можно еще перегрузить и сделать его недоступным. Или заставить MySQL использовать всю доступную память, в результате чего сервер будет просто убит операционной системой. На 32-битных системах провести подобные трюки гораздо легче.</p>
<p>Дам вам несколько советов:<br />
<strong>Временные таблицы</strong> вы можете использовать запросы с производными таблицами и создавать в памяти неограниченное количество временных таблиц с неограниченным размером.</p>
<p><strong>Таблицы в памяти</strong> Если вы можете создать в памяти одну таблицу, значит вы можете создать любое количество. Хотя размер таблицы ограничен директивой <strong>max_heap_table_size</strong>, общий размер таблиц не ограничен никак. Вы можете создавать таблицы как TEMPORARY и их не будет в файловой системе.</p>
<p><strong>MyISAM Sort Buffer</strong> &#8211; обычно его размер устанавливают довольно большим, но он может одновременно работать только с несколькими таблицами. А что будет, если пользователь использует все его дозволеные 100 подключений для инструкции ALTER для 100 разных таблиц? Можно искусственно ограничить его занижением значения параметра <strong>myisam_sort_buffer_size</strong>, но это отразится на производительности.</p>
<p><strong>Количество подготовленных инструкций (Prepared Statements)</strong> &#8211; к счастью теперь есть лимит на максимальное количество подготовленных инструкций (параметр <strong>max_stmt_count</strong>), который задается сервером. Это лучше, чем было раньше, когда можно было заставить сервер использовать всю доступную память, просто забыв закрыть подготовленные инструкции. Однако ограничения для пользователя отсутствуют и один пользователь может исчерпать весь лимит, заблокировав доступ к использованию подготовленных инструкций для остальных. Кроме того, не все инструкции занимают одинаковое количество памяти и подготовка сложных инструкций может отнять б<em>o</em>льшую часть ресурсов. Решить проблему можно, ограничив использование подготовленных инструкций и установив параметр <strong> max_prepared_stmt_count</strong> в очень низкое значение.</p>
<p><strong>Подготовленные инструкции и BLOB-данные</strong> &#8211; если вы хотите получить память, занятую одной подготовленной инструкцией, вы можете создать инструкцию с тысячей меток (placeholders) и посылать данные каждой из них, используя вызов <strong> mysql_stmt_send_long_data</strong>. Буферы сервера будут принимать данные до тех пор, пока инструкция не будет выполнена.</p>
<p><strong>Утечки кэша таблиц Innodb</strong> &#8211; InnoDB никогда не ограничивает размер внутренних таблиц в кеше (словарь данных). Так что открывая большие таблицы и работая с ними вы можете исчерпать всю доступную память. Обычно размер 4-8К на таблицу, но сложные таблицы могут занимать и больше. В основном это проблема небольших серверов.</p>
<p><strong>Кэш Слитых таблиц</strong> &#8211; кэш таблиц обычно распределен и каждая запись обычно соответствует не более, чем паре файловых дескрипторов. Но не в случае Слитых таблиц &#8211; создание и доступ к нескольким слитым таблицам с, например, тысячей подтаблиц не лучшим образом скажется на вашем сервере. Тоже самое относится и к Разделенным талицам из MySQL 5.1</p>
<p><strong>Место на диске</strong> &#8211; для MyISAM-таблиц хостинг-провайдеры обычно используют дисковые квоты. Вы можете использовать похожий подход при помощи <strong>innodb_file_per_table</strong>. Однако вы не можете контролировать рост системных таблиц InnoDB, которые используются для хранения данных об отменах и которые могут увеличиваться с каждой открытой транзакцией и делать множество обновлений. Или просто сохранять транзакцию открытой и позволять другим пользователям делать обновления &#8211; InnoDB может только очистить данные после старых транзакций, нуждающихся в мгновенном коммите. Вы можете решить этот вопрос путем уничтожения слишком старых транзакций, но более верным решением будет установление некоего лимита на объем хранимой информации о отменах. Еще один неплохой способ &#8211; это использовать запросы с большими временными таблицами или сортировкой файлов. Даже если временные таблицы будут храниться на другом разделе, при его переполнении другие пользователи не смогут нормально работать с сервером.</p>
<p><strong>Хранимые процедуры</strong> &#8211; сколько памяти можно выделить для хранимой процедуры? Можно создать 1000 переменных в хранимой процедуре и зарезервировать для каждой их них по 1М памяти. Я не проводил целенаправленных экспериментов, но думаю, что жесткой политики выделения памяти для хранимых процедур нет.</p>
<p><strong>Указатели в хранимых процедурах</strong> &#8211; указатели в хранимых процедурах реализованы в виде временных таблиц. Поэтому используя большое количество указателей можно заполнить доступный объем оперативной памяти.</p>
<p><strong>Рекурсия в хранимых процедурах</strong> &#8211; На самом деле отличается от &#8220;классического&#8221; представления рекурсии. Это всего лишь вызовы одной процедуры из другой. Которые так же требуют выделения памяти и, что важно, размещаются в стеке. Есть некоторые способы для защиты от переполнения стека, но они не могут гарантировать 100%-ного результата.</p>
<p><strong>Переменные на стороне сервера</strong> &#8211; каждый сервер имеет ограничение в виде директивы <strong>max_allowed_packet</strong> (1M по умолчанию). Но, по-видимому, нет никаких ограничений на количество создаваемых переменных.</p>
<p><strong>Разбор деревьев</strong> &#8211; внутренне представление запросов в MySQL выглядит как разбор дерева, которое зависит от размера запроса, который, в свою очередь, контролируется директивой <strong>max_allowed_packet</strong>. Но некоторые способы оптимизации MySQL (такие как equity propagation и range expansion) могут привести к критическим ошибкам при анализе дерева. Для нескольких тривиальных случаев такое поведение было <a HREF="http://bugs.mysql.com/bug.php?id=26625">исправлено</a>, но вызывает сомнения, что эти исправления актуальны для всех подобных ситуаций.</p>
<p><strong>Сессионные переменные</strong> &#8211; нет никаких ограничений на использование переменных непривилегированным пользователем, которому разрешено выполнять запросы без ограничения доступа к ресурсам.</p>
<p><strong>Блокировка хоста</strong> &#8211; сервер может заблокировать хост клиента из-за большого количества неудачных соединений. Этого можно избежать, выставив большое значение для параметра <strong>max_connect_errors</strong>, но будьте осторожны: это снизит устойчивость к брутфорсу.</p>
<p><strong>Взаимные исключения</strong> &#8211; как InnoDB, так и MyISAM имеют &#8220;хотспоты&#8221; с несколькими соединениями. Используя их можно существенно замедлить работу сервера.</p>
<p><strong>Перегрузка</strong> &#8211; у MySQL нет достаточного контроля за использованием ресурсов и вы можете &#8220;положить&#8221; сервер просто выполняя тяжелые запросы. <a HREF="http://dev.mysql.com/doc/refman/5.0/en/user-resources.html">Существующие ограничения</a> не могут полностью контролировать потребление ресурсов пользователем, поскольку не имеют механизма определения &#8220;тяжести&#8221; запроса. Тяжелые запросы могут сильно нагрузить систему ввода/вывода и заполнить кэш ОС, что заметно снизит скорость работы сервера и запросы других пользователей будут выполняться на порядок медленнее.</p>
<p>Некоторые из вышеизложенных способов были испробованы на реальных приложений, некоторые являются лишь предположением о возможном поведении сервера в случае критических ситуаций.</p>
<p>Как вы видите, MySQL-сервер отнюдь не выглядит &#8220;пуленепробиваемым&#8221;, если кто-то намеренно будет пытаться его обрушить. Дело в том, что большинство существующих ограничений (таких как <strong>max_heap_table_size<strong> </strong></strong>или<strong><strong> <strong>max_prepared_stmt_count</strong></strong></strong>) реализованы для защиты от типичных ошибок при разработке приложений, а отнюдь не от запланированной атаки</p>
<p><strong><strong><strong>Примечание:</strong> </strong></strong>я рассмотрел лишь некоторые из объектов сервера, т.е. снижение производительности при некорректной работе с каждым из них. Существует ряд глобальных квот, которые влияют на работу сервера в целом &#8211; вы не можете применить их для конкретного пользователя или соединения.</p>
<p><strong><strong><strong>P.S.:</strong> </strong></strong>вы можете подумать: &#8220;как же это все возможно, если существуют тысячи хостинг-провайдеров, предоставляющих доступ к своим серверам БД?&#8221; Да, некоторым везт и их пользователи не создают проблем для корректной работы MySQL, но большинству приходится &#8220;вручную&#8221; постоянно контролировать и ограничивать пользователей, мешающих нормальному функционированию. Не говоря о компаниях, предоставляющих вирутальный хостинг &#8211; там, как правило, используются старые версии ПО, имеющие куда больше проблем.</p>
<p><strong><strong><strong>P.P.S.:</strong> </strong></strong>ничего из вышеописанного не является &#8220;новостью&#8221; для команды разработчиков MySQL. Эта заметка &#8211; лишь попытка осветить некоторые аспекты безопасности и обеспечения корректной работы MySQL-сервера.</p>
<p><strong><strong><strong>Оригинал:</strong> </strong></strong><noindex><a HREF="http://www.mysqlperformanceblog.com/2007/11/13/10-ways-to-crash-or-overload-mysql/">http://www.mysqlperformanceblog.com/2007/11/13/10-ways-to-crash-or-overload-mysql/</a></noindex></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/12/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Мониторинг запросов MySQL при помощи bash-скрипта</title>
		<link>http://boombick.org/blog/posts/15</link>
		<comments>http://boombick.org/blog/posts/15#comments</comments>
		<pubDate>Tue, 20 Nov 2007 07:09:40 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[*NIX]]></category>
		<category><![CDATA[MySQL articles]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/15</guid>
		<description><![CDATA[Мониторинг запросов MySQL &#8211; это любимое времяпровождение администраторов, особенно в процессе тюнинга для увеличения производительности. Я хочу представить вам небольшой bash-скрипт для мониторинга запросов в релаьном времени. Скрипт использует команду &#8220;SHOW PROCESSLIST&#8221;. Вся прелесть этого сценария заключается в том, что с его помощью вы сможете логировать все запросы и провести анализ логов позже. #!/bin/bash while [...]]]></description>
			<content:encoded><![CDATA[<p>Мониторинг запросов MySQL &#8211; это любимое времяпровождение администраторов, особенно в процессе тюнинга для увеличения производительности. Я хочу представить вам небольшой bash-скрипт для мониторинга запросов в релаьном времени. Скрипт использует команду &#8220;SHOW PROCESSLIST&#8221;. Вся прелесть этого сценария заключается в том, что с его помощью вы сможете логировать все запросы и провести анализ логов позже.<br />
<span id="more-15"></span></p>
<blockquote><p> #!/bin/bash<br />
while [ 1 ]<br />
do<br />
mysql -N -u root -p password -e &#8216;show processlist&#8217; |grep -v &#8216;show processlist&#8217;<br />
sleep 2<br />
done</p></blockquote>
<p><strong>Примечание:</strong> Замените <em>password</em> на ваш пароль.<br />
<strong>Примечание:</strong> -N убирает заголовки полей</p>
<p>Скрипт не показывает сам вывод команды SHOW PROCESSLIST. Вы также можете исключить из вывода спящие процессы, модифицировав сценарий следующим образом:</p>
<blockquote><p> mysql -N -u root -ppassword -e ’show processlist’ |egrep -v ‘Sleep|show processlist’</p></blockquote>
<p>Этот скрипт далеко не идеален, и уж тем более, не &#8220;одинок&#8221;. Существует мощная утилита mtop, с бОльшей функциональностью. Но она написана на perl, а его не слишком люблю :) Вероятно, что именно у меня не получилось заставить ее работать так, как хотелось бы мне. Лично я предпочел ей простое решение на bash, потому что я отнюдь не матерый perl-хакер.</p>
<p>Вы также можете использовать лог медленных запросов, но предложенный мной способ лучше подходит для поиска узких мест. Лог медленных запросов не показывает причину &#8220;замедленности&#8221; запроса, запись попадет в него уже после завершения запроса.</p>
<p><strong>Оригинал</strong>: <noindex><a HREF="http://blog.taragana.com/index.php/archive/monitoring-mysql-queries-using-bash-script/">http://blog.taragana.com/index.php/archive/monitoring-mysql-queries-using-bash-script/</a></noindex></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/15/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Основы оптимизации производительности InnoDB</title>
		<link>http://boombick.org/blog/posts/11</link>
		<comments>http://boombick.org/blog/posts/11#comments</comments>
		<pubDate>Thu, 15 Nov 2007 08:45:44 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[MySQL articles]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/11</guid>
		<description><![CDATA[Проводя опрос среди посетителей раздела Job Opening я задавал им один простой вопрос: если бы у вас был сервер с 16GB RAM, который был бы предназначен для MySQL-сервера с очень большим объемом innodb-таблиц, работающий с стандартным веб-проектом, какие бы настройки вы скорректировали? И самое интересное, что большинство не смогло четко ответить. Поэтому и было принято [...]]]></description>
			<content:encoded><![CDATA[<p>Проводя опрос среди посетителей раздела <noindex><a href="http://www.mysqlperformanceblog.com/jobs/">Job Opening</a></noindex> я задавал им один простой вопрос: если бы у вас был сервер с 16GB RAM, который был бы предназначен для MySQL-сервера с очень большим объемом innodb-таблиц, работающий с стандартным веб-проектом, какие бы настройки вы скорректировали? И самое интересное, что большинство не смогло четко ответить. Поэтому и было принято решение опубликовать эту заметку, которая, возможно, расширит ваши знания об оптимизации программной и аппаратной частей сервера.<br />
<span id="more-11"></span><br />
Я назвал эту статью <strong>Основы оптимизации производительности InnoDB</strong>, желая подчеркнуть, что это именно основы. Это универсальные советы, работающие на большинстве систем. Но более точную настройку необходимо производить, исходя из конкретных поставленных задач.</p>
<p><strong>Hardware</strong><br />
Если у вас есть база данных innodb большого объема, и это действительно важные данные, то 16 &#8211; 32 GB оперативной памяти будут оптимальным решением. Процессоры &#8211; 2*DualCore подойдут для большой нагрузки, а два Quad Core помогут решить проблемы с дальнейшим масштабированием системы. Хотя имеется множество нюансов. Третий момент &#8211; это подсистема ввода/вывода. Напрямую подключенный DataStorage с большим количеством дисков и RAID с возможностью сохранения кэша будут отличным выбором. Обычно необходимо 6 &#8211; 8 жестких дисков в стандартный блок, но порой может понадобиться и больше. Также обратите внимание на новые 2.5” SAS диски. Они меньше, но часто работают гораздо быстрее, чем обычные HDD. RAID10 хорошо подходит как для хранения, так и для чтения данных, но в случае, если вы можете позволить некоторую избытычность. В противном случае можно сделать RAID5, но опасайтесь случайных записей.</p>
<p><strong>Операционная система</strong><br />
Дя начала: установите 64-битную операционную систему. Часто можно увидеть 32-битный linux, или запущенный в режиме совместимости с 64-bit. Не делайте так. Если вы используете LVM для хранения базы данных, вы сможете более эффективно работать с резервными копиями. Файловая система Ext3 будет оптимальным выбором в большинстве случаев, но если вы запускаете particular roadblocks, то попробуйте XFS. Вы можете использовать опции noatime и nodiratime, если вы используете innodb_file_per_table и большое количество таблиц, но это, в принципе, не столь важно. Также убедитесь, что OS резервирует достаточно большое количество памяти для MySQL.</p>
<p><strong>Опции MySQL InnoDB</strong><br />
Важнейшими опциями являются:<br />
<strong>innodb_buffer_pool_size</strong> &#8211; 70 &#8211; 80% оперативной памяти. Я ставлю это значение в 12G на системе с 16G RAM<br />
<strong>innodb_log_file_size</strong> &#8211; зависит от необходимого вам объема данных для восстановления, но 256МБ будут разумным компромиссом между производительностью и рамером лог-файла<br />
<strong>innodb_log_buffer_size=4M</strong> &#8211; 4 мегабайта &#8211; нормальное значение, если вы не используете подачу больших блоков данных в InnoDB через каналы (pipes). Если используете, это значение лучше увеличить.<br />
<strong>innodb_flush_logs_at_trx_commit=2</strong> &#8211; если вас не особо заботит ACID, и вы можете себе позволить потерять транзакции за последние секунду или две, в случае полного краха ОС, то установите это значение. Но это может повлечь печальные эффекты при коротких записях транзакций.<br />
<strong>innodb_thread_concurrency=8</strong> &#8211; даже при имеющихся InnoDB Scalability Fixes будет совсем не лишним иметь ограниченное количество потоков. Значение может быть больше или меньше в зависомости от ваших потребностей, но 8 будет оптимальным значением для начала.<br />
<strong>innodb_flush_method=O_DIRECT</strong> &#8211; избегайте двойной буферизации и уменьшите активность swap, в большинстве случаев это увеличивает производительность. Но будьте осторожны, если у вас нет RAID с возможностью сохранения данных, операции ввода-вывода могут проходить некорректно и данные могут быть повреждены.<br />
<strong>innodb_file_per_table</strong> &#8211; если у вас немного таблиц, используйте эту опцию и рост занимаемого таблицами места не будет бесконтрольным. Эта опция добавлена в MySQL 4.1 и сейчас достаточно стабильна для использования.</p>
<p>Проверьте также, могут ли ваши приложения запускаться в режиме изоляции READ-COMMITED. Если это так, то установите опцию transaction-isolation=READ-COMITTED. Этот вариант увеличит производительность.</p>
<p>Есть еще немало опций, значения которых можно поменять для достижения лучшей производительности. Об этом можно прочитать в заметке <noindex><a href="http://www.mysqlperformanceblog.com/2006/09/29/what-to-tune-in-mysql-server-after-installation/">Настройка опций mysql-server</a></noindex> (<a href="http://boombick.org/blog/posts/6">перевод</a>) или в одной из <noindex><a href="http://www.mysqlperformanceblog.com/mysql-performance-presentations/">наших презентаций</a></noindex>.</p>
<p><strong>Настройка приложений для работы с InnoDB</strong><br />
При переходе с типа MyISAM, вам конечно будет интересно, что изменилось и какие новые возможности вам теперь доступны. Во-первых: убедитесь, что вы используете транзакции при обновлениях. Это необходимо для повышения производительности. Во-вторых: готово ли ваше приложение обрабатывать проблемы, которые могут произойти? И в-третьих: возможно вы захотите пересмотреть структуру своих таблиц и посмотреть как вы можете использовать свойства InnoDB: распределение по первичному ключу, использование первичного ключа на всех индексах (это позволяет сократить первичеый ключ), быстрый просмотр по первичным ключам (попробуйте использовать это при запросах с JOIN) или большие несжаты индексы (облегчают индексирование).</p>
<p>При помощи этого краткого описания вы сможете провести первичную настройку InnoDB, которая повысит производительность на системах без battery backup, без изменения настроек ОС и не внося изменения в настройки приложений, до сих пор использующих MyISAM</p>
<p>Оригинал: <noindex><a href="http://www.mysqlperformanceblog.com/2007/11/01/innodb-performance-optimization-basics/">http://www.mysqlperformanceblog.com/2007/11/01/innodb-performance-optimization-basics/</a></noindex></p>
<p>P.S.: Буду благодарен за корректный перевод словосочетания particular roadblocks.<!--more--></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/11/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Выбор оптимального значения для innodb_buffer_pool_size</title>
		<link>http://boombick.org/blog/posts/8</link>
		<comments>http://boombick.org/blog/posts/8#comments</comments>
		<pubDate>Thu, 15 Nov 2007 07:23:29 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[MySQL articles]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/8</guid>
		<description><![CDATA[Мой предыдущий пост Основы оптимизации производительности InnoDB (Перевод) получил большое количество комментариев по поводу оптимального значения innodb_buffer_pool_size. Я действительно не слишком подробно описал проблему, посему исправляюсь. Пул буферов InnoDB &#8211; это очень важный параметр и для него должно быть выбрано правильное значение. Мне приходилось видеть множество людей, которые оставляли значение по умолчанию (8М) и получали [...]]]></description>
			<content:encoded><![CDATA[<p ALIGN="left">Мой предыдущий пост <noindex><a HREF="http://www.mysqlperformanceblog.com/2007/11/01/innodb-performance-optimization-basics/">Основы оптимизации производительности InnoDB</a></noindex> (<a HREF="http://boombick.org/blog/posts/11">Перевод</a>) получил большое количество комментариев по поводу оптимального значения innodb_buffer_pool_size. Я действительно не слишком подробно описал проблему, посему исправляюсь.</p>
<p><span id="more-8"></span><br />
Пул буферов InnoDB &#8211; это очень важный параметр и для него должно быть выбрано правильное значение. Мне приходилось видеть множество людей, которые оставляли значение по умолчанию (8М) и получали из-за этого проблемы. Если у вас есть выделенный сервер для MySQL и вы используете только innodb-таблицы, возможно вы захотите отдать всю неиспользуемую память для пула буферов InnoDB.</p>
<p>Конечно же предполагается, что размер ваших InnoDB-таблиц достаточно велик для большого размера пула. Если нет, то установите размер пула немного большим, чем размер ваших таблиц. Несомненно, стоит учесть дальнейшее увеличение объема ваших баз данных. Размер пула должен быть немного (скажем, на 10%) большим, чем размер ваших таблиц, потому что в нем содержатся не только сами таблицы, но также и индексы, вставленные буферы, блокировки, которым тоже необходимо некоторое количество памяти. Но это не очень критично. На большинстве задач размер пула, меньший чем 10% особо не отразится на производительности.</p>
<p>Также вы можете исходить из того, что объем базы данных уже больше, чем объем имеющейся памяти. Но не забывайте корректировать его. Так же это будет хорошим выбором в том случае, если у вас выделенный сервер для MySQL и нет иных задач, требующих оперативной памяти.</p>
<p>Необходимо помнить о том, что InnoDB выделяет немного больше памяти для хранения пула, чем задано в конфигурации &#8211; я только что проверил на наших серверах с размером буфера 12GB и очень маленьким дополнительным буфером и лог-буфером. InnoDB занимал там немного больше 13GB. Некоторое время назад <noindex><a HREF="http://www.percona.com/team/vadim-tkachenko.html">Вадим</a></noindex> <noindex><a HREF="http://www.mysqlperformanceblog.com/2006/05/30/innodb-memory-usage/">писал</a></noindex> об этом.</p>
<p>После того, как вы определились с размером баз данных, проверьте, нет ли каких-либо ограничений для размера пула, который вы хотите использовать. Обычно подобные ограничения возникают на 32-битных системах, но бывают и неожиданные сюрпризы, особенно в среде Windows. Обычно подобные ограничения распространяются на общий размер памяти, который может использовать процесс. При подборе оптимального значения убедитесь в том, что вы оставили некоторое количество памяти для остальных нужд MySQL.</p>
<p>Следующий шаг, который необходимо сделать &#8211; это <strong>рассчитать объем памяти, необходимый остальным приложениям</strong>. Это могут быть нужды операционной системы &#8211; системные процессы, буферы сокетов и так далее :) Всем нужна память. Я использую примерно такие интервалы: от 256MB (на маленьких системах) до 5% от всего объема (соответсвенно, на больших :)). Хотя реальные потребности могут быть и меньше. Помимо ОС самому серверу MySQL также необходима дополнительная память &#8211; это буферы MySQL, кэш запросов, key_buffer, нити, временные таблицы, буферы сортировки в нитях. На это тоже необъодимо выделить память. Также подумайте о доаолнительных буферах InnoDB (которые могут занимать бОльший объем памяти, чем вы установили для них. Особенно если у вас много таблиц).</p>
<p>Я мог бы начать приводить вам какие-то цифры. Например, сложите все ваши глобальные буферы и добавьте по 1 мегабайту на каждое планируемое соединение. Но в реальности эти числа могут сильно отличаться &#8211; все зависит от конкретных задач. К примеру неактивные соединения будут потреблять меньше памяти, чем работающие с временными таблицами. Или чем другие более сложные запросы к БД. Как правило, это гораздо проще и быстрее проверить на практике. Запустите mysql-server с буфером размером 10GB для начала и посмотрите, как увеличиваются RSS и VSZ (их значения можно увидеть в выводе команды `ps` на Unix-системах). Если буфер увеличился до 12GB, а вам необходимо 2GB под иные задачи, вы сможете немнго увеличить его размер, в соответствии с вашими потребностями.</p>
<p>Третий важный момент, о котором необходимо помнить &#8211; это <strong>кэш операционной системы</strong>. Даже если вы и исключили ваши InnoDB-таблицы из кэша ОС, есть и другие процессы, которым этот кэш необходим: таблицы MyISAM (собственные баз данных mysql, временные таблицы и так далее), frm-файлы, логи.. Логи транзакций InnoDB тоже неплохо кэшировать там. Ну и конечно же у вас есть системные процессы, которым тоже необходимо некоторое количество кэш-памяти. Значение этого параметра сильно варьируется в зависимости от системы и задач. Обычно значения этого параметра лежат в диапазоне от 200MB до 1GB.</p>
<p><strong>Отключите двойную буферизацию</strong> &#8211; это опять-таки очень важно для выбора размера пула. Вы же не хотите, чтобы операционная система кэшировала данные, уже находящиеся в кэше InnoDB. Собственный кэш более эффективен, чем кэш ОС, так как он не копирует данные, адаптирует хэш-индексы, позволяет писать в буферы.. Есть множество факторов, чтобы отказаться от использования двойной буферизации. Тем более, как уже говорилось выше, кэш ОС нужен не только для InnoDB, и если вы не отключите двойную буферизацию, InnoDB попросту затрет весь ваш кэш. На win-системах вам не нужно ничего менять. На Linux, FreeBSD, Solaris вам нужно задать параметр <strong>innodb_flush_method=O_DIRECT</strong>. На других системах вы сможете блокировать двойную буфферизацию на уровне ОС, но будьте уверены в своих действиях.<br />
Но бывают ситуации, когда отключение двойной буфферизации не очень полезно. Например, если у вас нет RAID с BBU, а для вашей системы характерна интенсивная запись. Но даже в этом случае бывают исключения.</p>
<p><strong>Облегчите работу вашей ОС</strong> &#8211; хорошей идеей будет запретить MySQL и другим важным процессам использовать файловую систему для кэша. Но ОС может решить, что это &#8220;неправильно&#8221; &#8211; MySQL занимает 95% памяти и лишь несколько процентов кэша на диске. Некоторые администраторы пытаются решить эту пролему, вообще отключая своппинг. Но тут есть подводный камень: ОС может убить процесс MySQL, который вышел за допустимые пределы (или ОС &#8220;думает&#8221;, что вышел). Такое сожет случиться, например, из-за неожиданно высокой нагрузки с большим числом соединений. Вдобавок не все ядра хорошо работают с отключенным своппингом. Да есть еще масса причин, чтобы так не делать. Люди, которые все-таки отключают использование файла подкачки, обычно подстраховывают себя, обеспечивая достаточное количество свободной памяти для кэша и буферов. Кевин Бартон (Kevin Burton) написал <noindex><a HREF="http://feedblog.org/2007/09/29/using-o_direct-on-linux-and-innodb-to-fix-swap-insanity/">хорошую заметку о его экспериментах</a></noindex></p>
<p>В зависимости от ОС вы можете использовать различные методы стабилизации виртуальной памяти. Например, можно &#8220;заставить&#8221; MySQL использовать LargePages (большие страницы) памяти для размещение пула буферов InnoDB и использовать другие буферы, что хорошо скажется на производительности системы. Можно подкорректировать работу вирутальной памяти, выполнив <strong>echo 0 &gt; /proc/sys/vm/swappiness</strong>, но не факт, что это спасет вас от своппинга. Некоторые ядра имеют другие собственные опции для оптимизации работы VM. Наконец, вы можете попробовать &#8220;закрепить&#8221; процессы MySQL в памяти, используя опцию -memlock, но будьте осторожны &#8211; ОС может уничтожить процессы, потребляющие слишком много памяти.</p>
<p>Два момента в использовании вирутальной памяти. Первый: мониторинг swap по показателям &#8220;swap used&#8221; &#8211; не самая удачная идея, так как вы не можете точно сказать, кто пишет в своп &#8211; MySQL или другие процессы. Чтобы убедиться в отстутствии активного своппинга, следите за значениями &#8220;si/so&#8221; в выводе <em>vmstat</em> на linux-системах. Пока там 0 &#8211; все в порядке :) Нет ничего страшного в нескольктх обращениях к swap-файлу в минуту. Но если за 60 секунд пишется 100+ страниц, то это уже проблема.</p>
<p>Второй момент: администраторы, которые заботятся о том, чтобы вирутальная памяьт не использовалась для буферов, часто думают так: если у меня маленький размер буфера, то получится одна операция ввода/вывода на запись его в своп и одна на извлечение. Малое количество операций &#8211; это не страшно. Это заблуждение. Во-первых ОС должна синхронизировать страницы в реальной и виртуальной памяти, а InnoDB может просто игнорировать выбор ОС. Но что более важно, алгоритмы InnoDB уже оптимизированы для более эффесктивного размещения страниц в реальной и вирутальной памяти. Например,  InnoDB старается избегать блокирования данных в момент выполнения операции ввода/вывода, но данные могут оказаться заблокированными, пока осуществляется доступ к пулу буферов. Если одна из страниц окажется в своп-файле, в то время, как имеются связанные с ней страницы в памяти, то придется ожидать выполнения всех операций ввода/вывода для получения полных данных, необходимых для выполнения операции.</p>
<p>Эти рекомендации подходят для 70-80% систем, и, конечно же, не стоит слишком сильно привязываться к цифрам. Если у вас 50GB RAM, то для вас вполне будут приемлемы настройки, описаные для 64GB систем.</p>
<p><strong>P.S.</strong> В заметке описаны рекомендации только для InnoDB. Если вы используете иной тип хранения данных (например MyISAM, Falcon, PBXT или Archive), то вы должны оптимизировать работу сервера в соответствии с рекомендациями именно к используемому вами Storage Engine.</p>
<p>Оригинал: <noindex><a HREF="http://www.mysqlperformanceblog.com/2007/11/03/choosing-innodb_buffer_pool_size/">http://www.mysqlperformanceblog.com/2007/11/03/choosing-innodb_buffer_pool_size/</a></noindex></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/8/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Первоначальная настройка mysql-server</title>
		<link>http://boombick.org/blog/posts/6</link>
		<comments>http://boombick.org/blog/posts/6#comments</comments>
		<pubDate>Fri, 02 Nov 2007 19:27:47 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[MySQL articles]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/6</guid>
		<description><![CDATA[Мой любимый вопрос, задаваемый DBA, которые хотят увеличить производительность MySQL: &#8220;какие параметры надо настраивать в первую очередь, сразу после установки сервера?&#8221; Я удивлен количеством людей, которые не могут дать ответа на этот вопрос. И еще более удивлен количеством серверов, которые работают с настройками по умолчанию Для настройки доступно довольно большое количество параметров, но лишь некоторые [...]]]></description>
			<content:encoded><![CDATA[<p>Мой любимый вопрос, задаваемый DBA, которые хотят увеличить производительность MySQL: &#8220;какие параметры надо настраивать в первую очередь, сразу после установки сервера?&#8221;<br />
Я удивлен количеством людей, которые не могут дать ответа на этот вопрос. И еще более удивлен количеством серверов, которые работают с настройками по умолчанию</p>
<p>Для настройки доступно довольно большое количество параметров, но лишь некоторые из них действительно влияют на производительность сервера. После установки этих параметров в правильные для вашего проекта значения, остальные настройки будут лишь незначительно влиять на поведение сервера.<br />
<span id="more-6"></span><br />
<strong>key_buffer_size</strong> &#8211; очень важный параметр, если вы используете MyISAM-таблицы. Установите его равным 30-40% от имеющейся оперативной памяти, если вы используете только MyISAM. Актуальное для вашей системы значение зависит от индексов, размера данных и рабочего процесса. Помните, MyISAM использует кэш операционной системы для хранения данных и вам необходимо позаботиться о достаточных размерах выделяемой памяти. Во многих случаях, объем данных может быть значительно больше. Проверьте, не используется ли завышенное значение key_buffer. Нередко параметр установлен в значение 4GB при суммарном объеме .MYI-файлов в один гигабайт. Это напрасная трата ресурсов. Если вы используете несколько таблиц MyISAM &#8211; понизьте значение этого параметра. Но не опускайте его ниже 16-23 MB &#8211; этого будет достаточно для размещения индексов временных таблиц, которые создаются на диске.</p>
<p><strong>innodb_buffer_pool_size</strong> &#8211; это очень важный параметр для настройки InnoDB. Таблицы этого типа гораздо более чувствительны к размеру буфера, нежели MyISAM. MyISAM может нормально работать даже при дефолтном значении buffer_size, в отличии от InnoDB, производительность которых будет заметно ниже при значении innodb_buffer_pool_size по умолчанию и больших объемах данных. Также пул буферов InnoDB самостоятельно кэширует индексы и данные, так что не нужно оставлять место для кэша ОС. Обычно предполагается выделение 70 &#8211; 80% памяти для серверов, на которых ничего не запущено, кроме InnoDB. Некоторые правила key_buffer применимы и в этом параметре: если у вас небольшие объемы данных и они не собираются стремительно увеличиваться, не завышайте значение innodb_buffer_pool_size, вы сможете найти свободной оперативной памяти лучшее применение.</p>
<p><strong>innodb_additional_mem_pool_size</strong> &#8211; этот параметр не имеет сильного влияния на производительность. По крайней мере в операционных системах с грамотным распределением памяти. Но вы можете установить значение этого параметра раным 20MB (иногда больше) и вы можете видетm сколько памяти выделяет InnoDB для различных нужд.</p>
<p><strong>innodb_log_file_size</strong> &#8211; очень важный параметр для систем с интенсивной записью, особенно больших объемов данных. Увелечение значения этого параметра обычно дает прирост производительности, но будьте осторожны. Обычно я использую значения 64M &#8211; 512 MB в зависимости от сервера.</p>
<p><strong>innodb_log_buffer_size</strong> &#8211; значение по умолчанию вполне подойдет для большинства проектов со средней интенсивностью записи и короткими транзакциями. Однако если у вас бывают пики активности или работа с большим объемом данных, вы, вероятно, захотите увеличить значение этого параметра. Не делайте его слишком большим, это повлечет лишний расход памяти. Буфер сбрасывается каждую секунду и вам не нужен бОльший объем памяти. Обычно вполне хватает 8 &#8211; 16МB. Чем меньше система &#8211; тем меньше должно быть значение.</p>
<p><strong>innodb_flush_logs_at_trx_commit</strong> &#8211; Вам кажется, что InnoDB в сто раз медленнее MyISAM? Вероятно, вы забыли изменить значение этого параметра. Значение по умолчанию <em>1</em> означает, что после каждой завершенной транзакции (или после изменения состояния транзакции) лог должен быть сброшен на диск. Это достаточно дорогая операция, особенно если у вас нет Battery backed up cache. Многие приложения, особенно те, в которых раньше использовался MyISAM будут хорошо работать при значении <em>2</em>, который означает, что не надо сбрасывать буфер на диск, а следует отправить его в кэш операционной системы. Лог по-прежнему будет сбрасываться на диск каждую секунду и максимум, что вы можете потерять &#8211; это 1-2 секунды записей. Значение <em>0</em> обеспечивает более высокую скорость, но и более низкую надежность. Есть вероятность потерять транзакции даже при падении mysql-сервера. При значении равном 2 единственная возможность потерять данные &#8211; это фатальный сбой операционной системы.</p>
<p><strong>table_cache</strong> &#8211; открытые таблицы могут разрастаться. Например, таблицы MyISAM помечают MYI-заголовок, как используемый. Вы, конечно же, не хотите, чтобы это происходило слишком часто и это, как правило, хорошее решение. Лучше увеличить размер кэша, чтобы он мог вместить большинство открытых таблиц. Кэш использует некоторое количество памяти и ресурсов ОС, но для современной техники это, как правило, не проблема. Значение <em>1024</em> будет оптимальным решением для нескольких сотен открытых таблиц (помните, каждое соединение нуждается в собственной копии). Если у вас много соединений или большое количество открытых таблиц &#8211; увеличьте это значение. Я видел системы со значением этого параметра &gt; 100.000</p>
<p><strong>thread_cache</strong> &#8211; Создание/уничтожение нитей (threads) может ухудшать производительность, особенно если они создаются/уничтожаются при каждом соединении/разъединении. Обычно я устанавилваю значение этого параметра равным <em>16</em>. Если приложение делает большие прыжки в параллельных соединениях, то можно увидеть, как быстро растет переменная <strong>Threads_Created</strong>. Параметр предназначен для того, чтобы не создавать новых нитей в нормальных операциях.</p>
<p><strong>query_cache_size</strong> &#8211; если ваше приложение читает много данных и у вас нет кэша на уровне приложения, этот параметр может неплохо помочь. Но не устанавливайте слишком большого значения &#8211; это может замедлить работу и содержание такого кэша может обойтись довольно дорого. Оптимальные значения &#8211; от 32MB до 512MB. Тем не менее, проверьте эффективность работы кэша через некоторое время. Вполне возможно, что текущее значение слишком велико.</p>
<p><strong>Примечание:</strong> как вы заметили, все эти переменные являются глобальными и зависят от аппаратного обеспечения и устройств хранения данных. Сессионные переменные зависят от специфики конкретного проекта. Если у вас простые запросы, вам совершенно не нужно увеличивать параметр <strong>sort_buffer_size</strong>, даже если в вашем распоряжении 64GB оперативной памяти. Кроме того, это может снизить производительность. Обычно я оставляю настройку сессионных переменных на второй шаг, уже после оценки фронта работ.</p>
<p>P.S.: в дистрибутиве MySQL есть отличные примеры файла <code>my.cnf</code> для систем различных размеров. Они могут использоваться в качестве базы для ваших собственных файлов конфигурации, главное правильно выбрать шаблон.</p>
<p>Оригинал: <noindex><a HREF="http://www.mysqlperformanceblog.com/2006/09/29/what-to-tune-in-mysql-server-after-installation/">http://www.mysqlperformanceblog.com/2006/09/29/what-to-tune-in-mysql-server-after-installation/</a></noindex></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/6/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Какое значение оптимально для read_buffer_size?</title>
		<link>http://boombick.org/blog/posts/3</link>
		<comments>http://boombick.org/blog/posts/3#comments</comments>
		<pubDate>Wed, 31 Oct 2007 06:27:55 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[MySQL articles]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/?p=3</guid>
		<description><![CDATA[Чем больше я работаю над оптимизацией и повышением эффективности работы MySQL, тем меньше я доверяю здравому смыслу авторов документации и стараюсь больше полагаться на собственные исследования и опыт. Совсем недавно я писал о неожиданных результатах в повышении эффективности сортировки, а сегодня обнаружил, что и выбор значения для read_buffer_size может быть не столь тривиальной проблемой. Что [...]]]></description>
			<content:encoded><![CDATA[<p>Чем больше я работаю над оптимизацией и повышением эффективности работы MySQL, тем меньше я доверяю здравому смыслу авторов документации и стараюсь больше полагаться на собственные исследования и опыт. Совсем недавно я писал о неожиданных результатах в <noindex><a HREF="http://www.mysqlperformanceblog.com/2007/08/18/how-fast-can-you-sort-data-with-mysql/">повышении эффективности сортировки</a></noindex>, а сегодня обнаружил, что и выбор значения для <strong>read_buffer_size</strong> может быть не столь тривиальной проблемой.</p>
<p><span id="more-3"></span><br />
Что обычно говорят про настройку этого параметра: если вы хотите ускорить поиск в больших таблицах, увеличьте значение этого параметра. В стандартном <code>my.cnf</code> для систем с большим количеством памяти это значение установлено в 1М, дефолтное значение &#8211; 128К. Некоторые администраторы, имея большое количество оперативной памяти и несколько соединений устанавливают это значение в 32М, надеясь повысить производительность. Давайте посмотрим, оправдано ли это?</p>
<p>Чтобы проверить это, я создал таблицу с простой структурой:</p>
<pre>
<code>
SQL:
mysql&gt; SHOW CREATE TABLE dt2 \G
*************************** 1. row ***************************
TABLE: dt2
CREATE TABLE: CREATE TABLE `dt2` (
`grp` int(10) UNSIGNED NOT NULL,
`slack` varchar(50) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row IN SET (0.00 sec)
</code></pre>
<p>Таблица заполнена 75М строк и занимает 4GB. Система запущена на Fedora Core i686. Характеристики: 2 процессора Xeon, 2 GB RAM и два жестких диска в RAID0.</p>
<p>Я использовал следующие запросы для проверки поиска в таблице:</p>
<pre>
<code>
SQL:
mysql&gt; SELECT count(*) FROM dt2 WHERE slack LIKE "a%";
+----------+
| count(*) |
+----------+
|  4705992 |
+----------+
1 row IN SET (51.77 sec)
</code></pre>
<p>Вот результаты, которые я получил:<br />
<em>read_buffer_size и эффективность поиска:</em></p>
<table BORDER="1" CELLSPACING="1" CELLPADDING="1">
<tr>
<td><strong>read_buffer_size</strong></td>
<td><strong>Time (sec)</strong></td>
</tr>
<tr>
<td>8200</td>
<td>45.2</td>
</tr>
<tr>
<td>16K</td>
<td>44.8</td>
</tr>
<tr>
<td>32K</td>
<td>45.6</td>
</tr>
<tr>
<td>64K</td>
<td>43.4</td>
</tr>
<tr>
<td>128K</td>
<td>43.0</td>
</tr>
<tr>
<td>256K</td>
<td>51.9</td>
</tr>
<tr>
<td>512K</td>
<td>60.8</td>
</tr>
<tr>
<td>2M</td>
<td>65.2</td>
</tr>
<tr>
<td>8M</td>
<td>66.8</td>
<td></td>
</tr>
<tr>
<td>32M</td>
<td>67.2</td>
</tr>
</table>
<p>8200 байт &#8211; минимальное значение для read_buffer_size, поэтому мы начали с него.<br />
Как вы можете видеть, результаты двольно неожиданные. Производительность действительно увеличивается на несколько процентов при увеличении значения вплоть до 128К. Но при последующем увеличении она резко падает. И продолжает снижаться по мере увеличения значения параметра до 32М.</p>
<p>Почему это происходит? У меня не было достаточного количества времени, для выяснения точных причин подобного поведения. Быть может, операционная система разбивает большие запросы на несколько маленьких и их обрабатывает более медленное устройство, быть может причина в чем-то другом. Но факт остается фактом &#8211; слишком большое значение параметра read_buffer_size способно снизить эффективность запросов. (Не так давно я уже <noindex><a HREF="http://www.mysqlperformanceblog.com/2006/06/06/are-larger-buffers-always-better/">писал</a></noindex> об этом)</p>
<p>Давайте проведем еще один тест для небольших таблиц (умещающихся в кеше ОС):<br />
<em>read_buffer_size и кэш в памяти:</em></p>
<table BORDER="1" CELLSPACING="1" CELLPADDING="1">
<tr>
<td><strong>read_buffer_size</strong></td>
<td><strong>Time (sec)</strong></td>
</tr>
<tr>
<td>8200</td>
<td>4.15</td>
</tr>
<tr>
<td>16K</td>
<td>4.15</td>
</tr>
<tr>
<td>32K</td>
<td>4.12</td>
</tr>
<tr>
<td>64K</td>
<td>4.11</td>
</tr>
<tr>
<td>128K</td>
<td>4.11</td>
</tr>
<tr>
<td>256K</td>
<td>4.12</td>
</tr>
<tr>
<td>512K</td>
<td>4.25</td>
</tr>
<tr>
<td>2M</td>
<td>4.49</td>
</tr>
<tr>
<td>8M</td>
<td>4.54</td>
<td></td>
</tr>
<tr>
<td>32M</td>
<td>4.58</td>
</tr>
</table>
<p>Как вы видите, разница в процентах уменьшилась. Теперь она составляет всего 10% между наилучшим и наихудшим значениями. Но пиковые пороги остаются теми же: 128К и 32М. Значит дело не в разбивке запроса, по крайней мере не только в этом.</p>
<p><strong>Примечание:</strong> в данном случае любопытно было бы узнать результаты тестов на различных платформах, с разным аппаратным обеспечением и операционными системами. Различные структуры и размер таблиц, не говоря уж о таблицах с разрозненными строками также могут влиять на результаты.</p>
<p>В этом тестировании не учитывается степень распараллеливания &#8211; маленькие буферы, возможно, были бы более эффективными. Все необходимо испытывать на реальном тестировании.</p>
<p>В целом это подтверждает старую истину: универсальное решение не может быть идеальным для вашей системы. Я рекомендую вам тестировать различные значения на вашей системе и сравнивать ваши собственные результаты, если вы хотите добиться лучшей производительности.</p>
<p>Оригинал: <noindex><a HREF="http://www.mysqlperformanceblog.com/2007/09/17/mysql-what-read_buffer_size-value-is-optimal/">http://www.mysqlperformanceblog.com/2007/09/17/mysql-what-read_buffer_size-value-is-optimal/</a></noindex></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/3/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
