<?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>JL&#039;s blog &#187; oProxy</title>
	<atom:link href="http://john.5070.info/category/oproxy/feed/" rel="self" type="application/rss+xml" />
	<link>http://john.5070.info</link>
	<description>:-)</description>
	<lastBuildDate>Sun, 06 Dec 2009 17:11:56 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>oProxy release</title>
		<link>http://john.5070.info/2009/05/oproxy-release/</link>
		<comments>http://john.5070.info/2009/05/oproxy-release/#comments</comments>
		<pubDate>Wed, 20 May 2009 13:31:28 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[oProxy]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[cluster]]></category>
		<category><![CDATA[LWT]]></category>
		<category><![CDATA[Ocaml]]></category>
		<category><![CDATA[хостинг]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=106</guid>
		<description><![CDATA[Не прошло и полгода, как я решил разродиться на релиз прокси. Назовём его &#8220;1.1&#8243;.
Самой большой моей ошибкой в проектировании была идея использовать POSIX треды. Всё замечательно, но только до тех пор, пока активных соединений не становится больше сотни. Дело в том, что такие треды, по сути, являются почти что отдельными процессами: у них свой стек, [...]]]></description>
			<content:encoded><![CDATA[<p>Не прошло и полгода, как я решил разродиться на релиз прокси. Назовём его &#8220;1.1&#8243;.</p>
<p><span id="more-106"></span>Самой большой моей ошибкой в проектировании была идея использовать POSIX треды. Всё замечательно, но только до тех пор, пока активных соединений не становится больше сотни. Дело в том, что такие треды, по сути, являются почти что отдельными процессами: у них свой стек, их обрабатывает шедулер ядра и т.д. Единственное отличие — у них в пределах одного процесса единое адресное пространство. Так вот, всё это вызывало такие проблемы, как переполнение стека, нелинейность масштабирования и пр. В качестве альтернатиы рассматривалось два варианта:</p>
<ol>
<li>Библиотека Equeue. Знаменита тем, что предоставляет низкий уровень к управлению очередями обработки дескрипторов. Это и минус — работать с ней не слишком комфортно: &#8220;есть только очередь и события, всё остальное на ваше усмотрение&#8221;.</li>
<li>Библиотека Lwt. По сути, то же самое, но выполнено совсем, совсем с другого бока. В интерфейсе предоставляется модель монад и псевдопотоков (отсюда название: LightWeight Threads). Быдлокодеру, навроде меня, достаточно лишь описать зависимости между состояниями: что делать, когда я получу данные из вон того сокета, и куда их записать потом.</li>
</ol>
<p>Выбор пал на Lwt. А вот тут следует сказать несколько восторженных слов о типизации Хиндли — Милнера, используемой, в том числе, в Ocaml. Как я уже сказал, потоки POSIX при разработке выглядят практически как отдельные процессы. Создал поток, и забыл о нём, а он варится сам по себе. В Lwt же надо отдельно позаботиться о последствиях каждой операции IO. Прежде всего, я заменил все вызовы Unix.socket (создание сокета) — благо в коде почти все они были в моей обёртке и реально вызов встречался только в 2-3 местах — на Lwt_unix.socket. И понеслось. Типовычислялка компилятора сразу указала мне, где я, дурень, пытаюсь подсунуть в нормальную сокетную функцию параметр с каким-то странным типом Lwt_unix.file_descr. Следующая неделя прошла за чрезвычайно интеллектуальной работой. Компилятор говорил мне, что нужно сделать чтобы впасть в нирвану, а я всячески пытался её достичь. Таким образом, буквально через несколько дней негритянской работы, передо мной предстал код, который мало того, что не содержал ни одного вызова к стандартным функциям IO, так ещё и компилился.</p>
<p>Каково же было моё удивление, когда с первым запуском оно ещё и заработало! После недели тупой работы, перехода с философии &#8220;одно соединение == один самостоятельный псевдопроцесс&#8221; на &#8220;одно соединение == один конечный автомат&#8221;, после исправления тучи кода <em>исключительно</em> по указаниям компилятора! Кривенько, но заработало, результат я увидел. Последующая неделя ушла на исправление совсем новых багов, багов ещё со старой версии и дописывания новых приятных мелочей.</p>
<p>Итого, имеем. Кластер с определённым количеством клиентов (пока меньше, чем на одной машине в среднем, но уже существенно). Прокся заведует как балансировкой нагрузки между HTTP-узлами, так и между MySQL. Т.е. гоняются вполне реальные данные настоящих сайтов. На одно <strong>соединение</strong> (не запрос) HTTP в среднем уходит чуть меньше миллисекунды CPU (это и проксирование динамики, и отдача статики с помощью системного sendfile). На соединение MySQL уходит несколько больше — около 5 миллисекунд, хотя алгоритм там наоборот в целом проще. Связываю это с</p>
<ul>
<li>sendfile() там не применишь, все проксируемые данные копируются в userspace</li>
<li> Имею богатый опыт разглядывания скриптов клиентов. А это совсем другая, удивительная, не поддающаяся научному изучению культура. У них принято сказать SELECT * на большую табличку, затем сложным алгоритмом с циклами тройной вложенности вычленить из многомегабайтного результата 2 строки, затем их отправить обратно в мускуль с целью join&#8217;а в непристойной позе с другой табличкой.</li>
</ul>
<p>Памяти жрёт в рабочем режиме при текущих нагрузках стабильно 12-15MB (один мастер, 4 рабочих).</p>
<p>Планы (или мечты?) на будущее:</p>
<ul>
<li>Пропатчить Lwt на предмет использования epoll() вместо select(). Чтобы в будущем не было мучительно больно обрабатывать 10000 одновременных соединений. Если, конечно, до этого дойдёт.</li>
<li>Написать некую глюкалу, которая сильно поможет в поиске причин высоких нагрузок как на сайтах, так и в БД. Пока мне это видится чем-то вроде: oproxyreport &#8220;select response_time-start_time, uri from http where host=&#8217;ispsystem.com&#8217; and uri begins with &#8216;/ru/&#8217; save to &#8216;/tmp/load.log&#8217;&#8221;. Если будет реализовано — сразу можно будет написать интерфейсик в ISPmanager, чтобы клиенты могли сами это делать.</li>
</ul>
<p>Я всё сказал.</p>
<p>p.s. Нет, не всё :) С переходом на Lwt, обнаружилась ещё одна приятная особенность: портабельность. Например, во FreeBSD 7.1. поломали те самые POSIX треды, из-за чего мне пришлось отказаться от альфа-тестирования прокси на ней в своё время. Lwt же ни от чего не зависит. Select() есть везде, а не блокирующие сокеты криво реализованы разве что в винде.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/05/oproxy-release/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Nginx против oProxy: друг другу сливаем :)</title>
		<link>http://john.5070.info/2009/02/nginx-%d0%bf%d1%80%d0%be%d1%82%d0%b8%d0%b2-oproxy-%d0%b4%d1%80%d1%83%d0%b3-%d0%b4%d1%80%d1%83%d0%b3%d1%83-%d1%81%d0%bb%d0%b8%d0%b2%d0%b0%d0%b5%d0%bc/</link>
		<comments>http://john.5070.info/2009/02/nginx-%d0%bf%d1%80%d0%be%d1%82%d0%b8%d0%b2-oproxy-%d0%b4%d1%80%d1%83%d0%b3-%d0%b4%d1%80%d1%83%d0%b3%d1%83-%d1%81%d0%bb%d0%b8%d0%b2%d0%b0%d0%b5%d0%bc/#comments</comments>
		<pubDate>Sun, 01 Feb 2009 15:19:55 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[Ocaml]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[oProxy]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[profiling]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=69</guid>
		<description><![CDATA[Потестировал производительность проксирования HTTP трафика. Результаты местами получились весьма неожиданными.
Повторю, тестировалось именно проксирование. Известно, что при прямой отдаче и Apache, и Nginx использует ядрёный вызов sendfile(), который отдаёт содержимое файлика в сокет без лишних копирований. Это неинтересно. А вот проксирование — это совсем другое дело. В ядре пока что ещё нет прямых путей для копирования [...]]]></description>
			<content:encoded><![CDATA[<p>Потестировал производительность проксирования HTTP трафика. Результаты местами получились весьма неожиданными.</p>
<p>Повторю, тестировалось именно проксирование. Известно, что при прямой отдаче и Apache, и Nginx использует ядрёный вызов sendfile(), который отдаёт содержимое файлика в сокет без лишних копирований. Это неинтересно. А вот проксирование — это совсем другое дело. В ядре пока что ещё нет прямых путей для копирования из сокета в сокет (есть полупрямой вариант splice() + pipe(), но как выяснилось он даже не на всех современных ядрах работает).</p>
<p>Итак…</p>
<p><span id="more-69"></span>На порту 8080 живёт Apache 2 ITK. У него в VirtualHost лежит bigfile размером ровно 20MB.</p>
<p>На порту 8081 живёт Nginx, который проксирует в Apache. Его конфиг:</p>
<p>worker_processes  16;</p>
<p>error_log  /var/log/nginx/error.log;<br />
pid        /var/run/nginx.pid;</p>
<p>events {<br />
worker_connections  1024;<br />
}</p>
<p>http {<br />
sendfile        on;<br />
tcp_nodelay        on;<br />
gzip  off;</p>
<p>server {<br />
listen 12.34.56.78:8081;<br />
server_name test1.com www.test1.com;<br />
location / {<br />
proxy_pass http://12.34.56.78:8080;<br />
proxy_redirect http://test1.com:8080/ /;<br />
proxy_set_header Host $host;<br />
}<br />
}<br />
}</p>
<p>Результаты siege для Nginx:</p>
<p>debian2:~# siege -t30s -b -c 10 http://test1.com:8081/bigfile &gt;/dev/null<br />
** SIEGE 2.66<br />
** Preparing 10 concurrent users for battle.<br />
The server is now under siege&#8230;</p>
<p>Lifting the server siege&#8230;      done.<br />
Transactions:                 372 hits<br />
Availability:              100.00 %<br />
Elapsed time:               29.66 secs<br />
Data transferred:         6773.34 MB<br />
Response time:                0.78 secs<br />
Transaction rate:           12.54 trans/sec<br />
Throughput:              228.37 MB/sec<br />
Concurrency:                9.82<br />
Successful transactions:         372<br />
Failed transactions:               0<br />
Longest transaction:            4.09<br />
Shortest transaction:            0.07</p>
<p>228MB в секунду. Конкурентность 9.82. Доступность 100%. Самый медленный ответ: через 4 секунды.</p>
<p>Результаты oProxy (тоже 16 рабочих, чтобы было абсолютно честно):</p>
<p>debian2:~# siege -t30s -b -c 10 http://test1.com/bigfile &gt;/dev/null<br />
** SIEGE 2.66<br />
** Preparing 10 concurrent users for battle.<br />
The server is now under siege&#8230;</p>
<p>Lifting the server siege&#8230;      done.<br />
Transactions:                 691 hits<br />
Availability:              100.00 %<br />
Elapsed time:               29.71 secs<br />
Data transferred:        13820.00 MB<br />
Response time:                0.38 secs<br />
Transaction rate:           23.26 trans/sec<br />
Throughput:              465.16 MB/sec<br />
Concurrency:                8.94<br />
Successful transactions:         691<br />
Failed transactions:               0<br />
Longest transaction:            9.18<br />
Shortest transaction:            0.05</p>
<p>465MB в секунду (лучше более, чем в 2 раза). Конкурентность 9.18. Доступность 100%. Самый медленный ответ: через 9 секунд (хуже более, чем в 2 раза). Почувствуйте разницу ©</p>
<p>Мерим на маленьком файле. smallfile имеет размер 5 байт. Эмулируем атаку яростных 10 пользователей. Прочая конфигурация такая же. Результаты в Nginx:</p>
<p>debian2:~# siege -t30s -b -c 10 http://test1.com:8081/smallfile &gt;/dev/null<br />
** SIEGE 2.66<br />
** Preparing 10 concurrent users for battle.<br />
The server is now under siege&#8230;</p>
<p>Lifting the server siege&#8230;      done.<br />
Transactions:               16952 hits<br />
Availability:              100.00 %<br />
Elapsed time:               30.47 secs<br />
Data transferred:            0.08 MB<br />
Response time:                0.02 secs<br />
Transaction rate:          556.35 trans/sec<br />
Throughput:                0.00 MB/sec<br />
Concurrency:                9.97<br />
Successful transactions:       16952<br />
Failed transactions:               0<br />
Longest transaction:            0.20<br />
Shortest transaction:            0.00</p>
<p>Результаты в oProxy:</p>
<p>debian2:~# siege -t30s -b -c 10 http://test1.com/smallfile &gt;/dev/null<br />
** SIEGE 2.66<br />
** Preparing 10 concurrent users for battle.<br />
The server is now under siege&#8230;</p>
<p>Lifting the server siege&#8230;      done.<br />
Transactions:                8718 hits<br />
Availability:              100.00 %<br />
Elapsed time:               29.57 secs<br />
Data transferred:            0.04 MB<br />
Response time:                0.03 secs<br />
Transaction rate:          294.83 trans/sec<br />
Throughput:                0.00 MB/sec<br />
Concurrency:                9.27<br />
Successful transactions:        8718<br />
Failed transactions:               0<br />
Longest transaction:            9.00<br />
Shortest transaction:            0.00</p>
<p>А вот тут сливаем, почти в 2 раза. Аналогичная картина при увеличении конкурентных запросов. Но прокся при этом начинает показывать ещё более худшие результаты в Longext transaction. Буду над этим работать.</p>
<p>Update: нашёл в чём причина. В <span style="text-decoration: line-through;">генах</span> архитектуре. Завтра найду время, и перееду с socket passing на shared accept() и, возможно, epoll. Правда, при этом не совсем понятно, что делать с шедулингом нагрузки по рабочим. Рычаг теряю. Судя по логам, accept() на каждое соединение в среднем 3 миллисекунды тратит. Отсюда и цифра — 300 транзакций в секунду.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/02/nginx-%d0%bf%d1%80%d0%be%d1%82%d0%b8%d0%b2-oproxy-%d0%b4%d1%80%d1%83%d0%b3-%d0%b4%d1%80%d1%83%d0%b3%d1%83-%d1%81%d0%bb%d0%b8%d0%b2%d0%b0%d0%b5%d0%bc/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Пора в production? Скоро узнаем.</title>
		<link>http://john.5070.info/2009/01/%d0%bf%d0%be%d1%80%d0%b0-%d0%b2-production-%d1%81%d0%ba%d0%be%d1%80%d0%be-%d1%83%d0%b7%d0%bd%d0%b0%d0%b5%d0%bc/</link>
		<comments>http://john.5070.info/2009/01/%d0%bf%d0%be%d1%80%d0%b0-%d0%b2-production-%d1%81%d0%ba%d0%be%d1%80%d0%be-%d1%83%d0%b7%d0%bd%d0%b0%d0%b5%d0%bc/#comments</comments>
		<pubDate>Thu, 29 Jan 2009 18:46:40 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[Ocaml]]></category>
		<category><![CDATA[oProxy]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[cluster]]></category>
		<category><![CDATA[хостинг]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=67</guid>
		<description><![CDATA[Готовимся к продакшен тестированию. Надеюсь, завтра запустить всё воедино на тестовых машинах.
Из нового:

Балансировка нагрузки. Универсальный модуль для любых видов соединений. Написано кривовато, но работает. Заведует всеми узлами мастер-процесс. Это несколько замедляет процесс (рабочим приходится больше общаться с мастером), зато позволяет контролировать балансировку в одном месте.
Файлик: список сайтов. Пока каждый сайт можно только включить/выключить и прописать [...]]]></description>
			<content:encoded><![CDATA[<p>Готовимся к продакшен тестированию. Надеюсь, завтра запустить всё воедино на тестовых машинах.</p>
<p>Из нового:</p>
<ul>
<li>Балансировка нагрузки. Универсальный модуль для любых видов соединений. Написано кривовато, но работает. Заведует всеми узлами мастер-процесс. Это несколько замедляет процесс (рабочим приходится больше общаться с мастером), зато позволяет контролировать балансировку в одном месте.</li>
<li>Файлик: список сайтов. Пока каждый сайт можно только включить/выключить и прописать алиасы. Кроме того, на будущее есть поле &#8220;домашняя директория сайта&#8221;. В ближайшее время есть планы проксёй отдавать статичные файлы. Не понятно, что делать с .htaccess. Не хочется забивать, как это нынче делается в Nginx.</li>
<li>Файлик: список узлов. Представляет из себя IP, мастер-пароль, список ролей.</li>
<li>Роли. Что каждая машина умеет/должна делать. От этого зависит поведение балансировщика и некоторых скриптов. Предопределённые роли: worker_http (узел умеет обрабатывать HTTP-запросы), master (узел будет точкой входа, где висит балансировщик) и другие. Всё рассказывать раньше времени не буду :)</li>
<li>Мониторинг. Наконец нашёл, где заюзать функционалы. На основе этого функционала (functional) написан мониторинг файлов. Как результат, прокся умеет автоматически подгружать изменённый список сайтов или узлов.</li>
<li>Новый параметр у oproxyctl: show_nodes. Показывает известные узлы. Кто в дауне, сколько у каждого активных запросов, сколько всего обработано. Может оказаться полезным для выяснения проблемных узлов.</li>
<li>Поддерживаем новый протокол, который я сам выдумал :) Служит для различных сервисных запросов к узлу. Поскольку позволяет совершать совершенно небезопасные вещи, авторизация происходит без передачи открытого пароля по сети.</li>
<li>Новая утилита: clusterctl. Умеет 1) запустить на узлах с указанной ролью (или на всех, или на определённом IP) определённую команду и вернуть в STDOUT/STDERR что в итоге получилось 2) рассказывать список ролей текущей ноды 3) рассказывать список узлов, поддерживающих указанную роль. Служит для сервисных скриптов.</li>
<li>Прокся умеет выставлять X-Forwarded-For, чтобы в конечном итоге в логи попадал нужный IP.</li>
<li>Сервисные скрипты: apachectl (рестарт Апача на всех узлах), repquota и другие.</li>
<li>Оптимизация, стабильность.</li>
</ul>
<p>Допил коньяк. Опять потянуло на философию…</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/01/%d0%bf%d0%be%d1%80%d0%b0-%d0%b2-production-%d1%81%d0%ba%d0%be%d1%80%d0%be-%d1%83%d0%b7%d0%bd%d0%b0%d0%b5%d0%bc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Торжественно заборот(заборон?) последний крупный баг</title>
		<link>http://john.5070.info/2008/12/%d1%82%d0%be%d1%80%d0%b6%d0%b5%d1%81%d1%82%d0%b2%d0%b5%d0%bd%d0%bd%d0%be-%d0%b7%d0%b0%d0%b1%d0%be%d1%80%d0%be%d1%82%d0%b7%d0%b0%d0%b1%d0%be%d1%80%d0%be%d0%bd-%d0%bf%d0%be%d1%81%d0%bb%d0%b5%d0%b4/</link>
		<comments>http://john.5070.info/2008/12/%d1%82%d0%be%d1%80%d0%b6%d0%b5%d1%81%d1%82%d0%b2%d0%b5%d0%bd%d0%bd%d0%be-%d0%b7%d0%b0%d0%b1%d0%be%d1%80%d0%be%d1%82%d0%b7%d0%b0%d0%b1%d0%be%d1%80%d0%be%d0%bd-%d0%bf%d0%be%d1%81%d0%bb%d0%b5%d0%b4/#comments</comments>
		<pubDate>Sun, 28 Dec 2008 21:58:51 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[oProxy]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[статистика]]></category>
		<category><![CDATA[хостинг]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=51</guid>
		<description><![CDATA[… В результате которого рабочий иногда падал, валя за собой всю проксю. Как и предполагал, дело оказалось в рекурсии, которая не могла быть развёрнута в tail из-за не пойманных исключений внутри. Это можно назвать минусом смешивания чистой функциональщины с чем-то ещё. Но, увы и ах, ловить все исключения внутри нельзя.
Заменил рекурсивный вызов на цикл, и [...]]]></description>
			<content:encoded><![CDATA[<p>… В результате которого рабочий иногда падал, валя за собой всю проксю. Как и предполагал, дело оказалось в рекурсии, которая не могла быть развёрнута в tail из-за не пойманных исключений внутри. Это можно назвать минусом смешивания чистой функциональщины с чем-то ещё. Но, увы и ах, ловить все исключения внутри нельзя.</p>
<p>Заменил рекурсивный вызов на цикл, и уже двое суток работаем ровно и без падений; обработано около 2000000 реальных соединений к MySQL.</p>
<p>Кстати…</p>
<p><span id="more-51"></span> Уже можно подвести итог, насколько в условиях хостинга с абстрактным набором сайтов (как правило, кривых :), нагружен мускуль. Статистика за сутки. Машина средней мощи, набито правильное количество клиентов.</p>
<p>Активных пользователей в MySQL: 453</p>
<p>Из них, имеющих соединие каждые 5 минут за сутки (т.е. работающих круглосуточно): 46</p>
<p>Принято данных от пользователя (байты голого протокола):  9015309900</p>
<p>Передано байт:  121983229037</p>
<p>В сумме потрачено времени внутри MySQL: 138884 секунды (не забываем, что мускуль умеет жрать несколько процессоров)</p>
<p>Обработано запросов (в т.ч. авторизация и протокольная команда QUIT считаются запросами):  61044220</p>
<p>Это данные за сутки назад, включая бэкапный трафик (прибавляет ~15% ко всем циферкам).</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2008/12/%d1%82%d0%be%d1%80%d0%b6%d0%b5%d1%81%d1%82%d0%b2%d0%b5%d0%bd%d0%bd%d0%be-%d0%b7%d0%b0%d0%b1%d0%be%d1%80%d0%be%d1%82%d0%b7%d0%b0%d0%b1%d0%be%d1%80%d0%be%d0%bd-%d0%bf%d0%be%d1%81%d0%bb%d0%b5%d0%b4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>релиз</title>
		<link>http://john.5070.info/2008/12/%d1%80%d0%b5%d0%bb%d0%b8%d0%b7/</link>
		<comments>http://john.5070.info/2008/12/%d1%80%d0%b5%d0%bb%d0%b8%d0%b7/#comments</comments>
		<pubDate>Fri, 19 Dec 2008 12:33:05 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[oProxy]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=49</guid>
		<description><![CDATA[Первый релиз.
  1. Забил на сложный ЯП-подобный конфиг. Нет на это времени, а не разворачивать идею до конца я не умею. In spirit of ispmgr.conf:
Param workers_count &#8220;4&#8243;
Param socket_reuseaddr &#8220;0&#8243;
Param log_statistics_period &#8220;300&#8243;
Listen mysql &#8220;0.0.0.0:3306&#8243;
Listen mysql &#8220;/tmp/mysql.sock&#8221;
MySQLBackend &#8220;/tmp/mysql-real.sock&#8221;
MySQLBackend &#8220;0.0.0.0:3307&#8243;
/*
Listen mysql &#8220;0.0.0.0:3307&#8243;
Listen mysql &#8220;/tmp/mysql-my.sock&#8221;
MySQLBackend &#8220;/tmp/mysql.sock&#8221;
*/
2. MySQL backend failover. По умолчанию, все соединения идут на 1-й бэкенд. Если к [...]]]></description>
			<content:encoded><![CDATA[<p>Первый релиз.</p>
<p><span id="more-49"></span>  1. Забил на сложный ЯП-подобный конфиг. Нет на это времени, а не разворачивать идею до конца я не умею. In spirit of ispmgr.conf:</p>
<p>Param workers_count &#8220;4&#8243;<br />
Param socket_reuseaddr &#8220;0&#8243;<br />
Param log_statistics_period &#8220;300&#8243;</p>
<p>Listen mysql &#8220;0.0.0.0:3306&#8243;<br />
Listen mysql &#8220;/tmp/mysql.sock&#8221;</p>
<p>MySQLBackend &#8220;/tmp/mysql-real.sock&#8221;<br />
MySQLBackend &#8220;0.0.0.0:3307&#8243;</p>
<p>/*<br />
Listen mysql &#8220;0.0.0.0:3307&#8243;<br />
Listen mysql &#8220;/tmp/mysql-my.sock&#8221;</p>
<p>MySQLBackend &#8220;/tmp/mysql.sock&#8221;<br />
*/</p>
<p>2. MySQL backend failover. По умолчанию, все соединения идут на 1-й бэкенд. Если к нему подсоединиться не удалось, прозрачно пробуем следующие. Балансировку делать пока не стал т.к. в репликации master-master она только больше проблем создаст. Возможно, её имеет смысл сделать только для балансировки select-запросов. Но это будет позже, с тестированием под нагрузкой.</p>
<p>3.  Если log_statistics_period в конфиге больше нуля — раз в это количество секунд сбрасывать статистику в /usr/local/ispmgr/var/oproxy-stats.log</p>
<p>4. Залечил совершенно замечательную ошибку, из-за которой потенциально, через несколько дней работы мог случиться stack overflow. Но на данный момент, выражалась только в memory leak.</p>
<p>5. Запустил в тест на рабочей хостинг-машине. Несколько часов полёт нормальный.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2008/12/%d1%80%d0%b5%d0%bb%d0%b8%d0%b7/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>чуть-чуть обновлений</title>
		<link>http://john.5070.info/2008/11/%d1%87%d1%83%d1%82%d1%8c-%d1%87%d1%83%d1%82%d1%8c-%d0%be%d0%b1%d0%bd%d0%be%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b9/</link>
		<comments>http://john.5070.info/2008/11/%d1%87%d1%83%d1%82%d1%8c-%d1%87%d1%83%d1%82%d1%8c-%d0%be%d0%b1%d0%bd%d0%be%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b9/#comments</comments>
		<pubDate>Fri, 28 Nov 2008 16:40:59 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[oProxy]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=48</guid>
		<description><![CDATA[1. oproxyctl — утилита управления проксёй. Пока умеет корректно останавливать, показывать/сбрасывать статистику.
2. Порт под FreeBSD. Это удивительно, но под фрюхой прокся вываливалась с исключениями о deadlock&#8217;ах в мутексах. И это правильно, там алгоритмически иначе быть не может. Почему этого не происходило под Linux — фиг знает. А ведь и там вываливалась иногда с этим, но [...]]]></description>
			<content:encoded><![CDATA[<p>1. oproxyctl — утилита управления проксёй. Пока умеет корректно останавливать, показывать/сбрасывать статистику.</p>
<p>2. Порт под FreeBSD. Это удивительно, но под фрюхой прокся вываливалась с исключениями о deadlock&#8217;ах в мутексах. И это правильно, там алгоритмически иначе быть не может. Почему этого не происходило под Linux — фиг знает. А ведь и там вываливалась иногда с этим, но не в этих местах кода&#8230;</p>
<p>3. Полная поддержка KeepAlive. Сводится к тому, что прокси теперь не жалуется в логи, если в процессе ожидания команды от клиента случился таймаут. И вообще, логи оставлены практически только для ошибок.</p>
<p>4.  Исправлено несколько разного рода ошибок.</p>
<p>В общем, ничего интересного. Дальше в планах написание балансировщика для mysql_proxy и конфиг. Конфиг — это большая тема. Там должен быть элемент ЯП. И что этот язык должен уметь, ещё надо подумать.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2008/11/%d1%87%d1%83%d1%82%d1%8c-%d1%87%d1%83%d1%82%d1%8c-%d0%be%d0%b1%d0%bd%d0%be%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b9/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>oProxy: производительность mysql_proxy</title>
		<link>http://john.5070.info/2008/11/oproxy-%d0%bf%d1%80%d0%be%d0%b8%d0%b7%d0%b2%d0%be%d0%b4%d0%b8%d1%82%d0%b5%d0%bb%d1%8c%d0%bd%d0%be%d1%81%d1%82%d1%8c-mysql_proxy/</link>
		<comments>http://john.5070.info/2008/11/oproxy-%d0%bf%d1%80%d0%be%d0%b8%d0%b7%d0%b2%d0%be%d0%b4%d0%b8%d1%82%d0%b5%d0%bb%d1%8c%d0%bd%d0%be%d1%81%d1%82%d1%8c-mysql_proxy/#comments</comments>
		<pubDate>Tue, 25 Nov 2008 19:57:08 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[oProxy]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=47</guid>
		<description><![CDATA[Сократил оверхед до 56 МИКРОсекунд на запрос (т.е. запрос отдаётся в среднем медленнее на это время, чем если бы подсоединялись напрямую). Для сравнения, у Mysql Proxy это значение заявлено в 400 МИКРОсекунд, т.е. 7 раз больше. Но у меня практически никакого анализа пакетов не делается, только выясняю подсоединившегося пользователя и собираю статистику. Считал скриптом:
time perl [...]]]></description>
			<content:encoded><![CDATA[<p>Сократил оверхед до 56 МИКРОсекунд на запрос (т.е. запрос отдаётся в среднем медленнее на это время, чем если бы подсоединялись напрямую). Для сравнения, у Mysql Proxy это значение заявлено в 400 МИКРОсекунд, т.е. 7 раз больше. Но у меня практически никакого анализа пакетов не делается, только выясняю подсоединившегося пользователя и собираю статистику. Считал скриптом:</p>
<p>time perl -MDBI -e &#8216;$dsn = &#8220;DBI:mysql:database=mysql;host=127.0.0.1;port=5501&#8243;;$dbh = DBI-&gt;connect($dsn, &#8220;user&#8221;, &#8220;анунеподглядывай&#8221;);for(0..100000){$s = $dbh-&gt;selectall_arrayref(&#8221;select repeat(100000000000000000, 10)&#8221;);}&#8217;</p>
<p>Во время выполнения, oProxy ел около 31% CPU, MySQL 25% Perl 50%. Ещё есть куда расти.</p>
<p><span id="more-47"></span>Как этого добился:</p>
<p>1. Прежде всего выяснил, что очень большие задержки происходят при чтении из сокета. Исследование показало, что я всегда перед этим делаю двойную запись в сокет (отдельно заголовок пакета, и отдельно содержимое), как следствие включается дополнительное ожидание данных ядром от программы, а удалённая сторона некоторое время ничего не получает и не отвечает. Слил всё в один write, ситуация улучилась раза в 4. Но всё равно плохо.</p>
<p>2.  Далее обнаружил, что иногда из-за особенностей протокола MySQL, данные опять отправляются несколькими исходящими пакетами подряд (пакет-заголовок датасета, описание поля, описание поля &#8230;, пакет конец описаний, данные, данные, &#8230;, конец данных). Всё-таки поставил Ocaml 3.11 и включил для сокета опцию Unix.TCP_NODELAY. Стало ещё лучше, но всё равно не то.</p>
<p>2.5. (в этом месте выясняется, что 80% времени программа проводит в обработке той кучи дебага, что есть в коде. Логи были стремительно сокращены :)</p>
<p>3.  Часовое разглядывание вывода tcpdump&#8217;а привело к интересному результату: оказывается, последовательности своих пакетов, MySQL склеивает в одно целое и отправляет одним TCP пакетом. Только сейчас в описании протокола вижу ключевую фразу: The description is of <strong>logical</strong> packets. Не стал мудрствовать лукаво, тоже начал склеивать последовательности, сократив таким образом количество write&#8217;ов в сокет до возможного минимума. С этим пунктом, TCP_NODELAY начинает иметь смысл только при отправке больших массивов данных, поэтому временно упразднён и всё возвращено обратно на Ocaml 3.10.2.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2008/11/oproxy-%d0%bf%d1%80%d0%be%d0%b8%d0%b7%d0%b2%d0%be%d0%b4%d0%b8%d1%82%d0%b5%d0%bb%d1%8c%d0%bd%d0%be%d1%81%d1%82%d1%8c-mysql_proxy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>oProxy: mysql_proxy</title>
		<link>http://john.5070.info/2008/11/oproxy-mysql_proxy/</link>
		<comments>http://john.5070.info/2008/11/oproxy-mysql_proxy/#comments</comments>
		<pubDate>Sun, 23 Nov 2008 15:07:04 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[oProxy]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=45</guid>
		<description><![CDATA[Сел вечерком в воскресенье, и практически написал проксю для MySQL. Затраченное время: 2:56.
Что умеет: собственно, проксировать (80% готово, см. ниже). Считать трафик, затраченное время и количество запросов. Поддерживает протоколы MySQL &#62;= 4.1 (версия протокола 10?). Теоретически поддерживает и более младшие версии, но не тестировал.
Чего пока не умеет: проксировать наборы данных в ответах клиенту. На реализацию [...]]]></description>
			<content:encoded><![CDATA[<p>Сел вечерком в воскресенье, и практически написал проксю для MySQL. Затраченное время: 2:56.</p>
<p>Что умеет: собственно, проксировать (80% готово, см. ниже). Считать трафик, затраченное время и количество запросов. Поддерживает протоколы MySQL &gt;= 4.1 (версия протокола 10?). Теоретически поддерживает и более младшие версии, но не тестировал.</p>
<p>Чего <strong>пока</strong> не умеет: проксировать наборы данных в ответах клиенту. На реализацию потребуется не более полутора часов.</p>
<p>Чего <strong>не будет</strong> уметь: балансировать нагрузку. Изначально планировал часть select&#8217;ов направлять на реплицирующий сервер. Увы, из-за особенностей протокола MySQL и авторизации в частности, это не представляется реализуемым. Во всяком случае, идея меня пока так и не посетила. Возможно, что-то даст изучение исходников существующих балансеров, если конечно есть с открытым кодом.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2008/11/oproxy-mysql_proxy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>oProxy: еще больше статистики, поймано последнее исключение, которое оказалось совсем и не исключением.</title>
		<link>http://john.5070.info/2008/11/oproxy-%d0%b5%d1%89%d0%b5-%d0%b1%d0%be%d0%bb%d1%8c%d1%88%d0%b5-%d1%81%d1%82%d0%b0%d1%82%d0%b8%d1%81%d1%82%d0%b8%d0%ba%d0%b8-%d0%bf%d0%be%d0%b9%d0%bc%d0%b0%d0%bd%d0%be-%d0%bf%d0%be%d1%81%d0%bb%d0%b5/</link>
		<comments>http://john.5070.info/2008/11/oproxy-%d0%b5%d1%89%d0%b5-%d0%b1%d0%be%d0%bb%d1%8c%d1%88%d0%b5-%d1%81%d1%82%d0%b0%d1%82%d0%b8%d1%81%d1%82%d0%b8%d0%ba%d0%b8-%d0%bf%d0%be%d0%b9%d0%bc%d0%b0%d0%bd%d0%be-%d0%bf%d0%be%d1%81%d0%bb%d0%b5/#comments</comments>
		<pubDate>Thu, 20 Nov 2008 18:09:37 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[oProxy]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=44</guid>
		<description><![CDATA[3 дня охотился за мифической ошибкой, которая намертво обрушивала рабочих. Дело осложнялось тем, что происходило это только через магические 180/210 секунд и только после серии прерванных запросов. Следы привели к Unix.write. Долго расставлял ловушки для исключений, но улова не было. Заменил Unix.write на Unix.single_write. И — о чудо! Похоже, что больше не падает.
UPDATE: Дело оказалось [...]]]></description>
			<content:encoded><![CDATA[<p>3 дня охотился за мифической ошибкой, которая намертво обрушивала рабочих. Дело осложнялось тем, что происходило это только через магические 180/210 секунд и только после серии прерванных запросов. Следы привели к Unix.write. Долго расставлял ловушки для исключений, но улова не было. Заменил Unix.write на Unix.single_write. И — о чудо! Похоже, что больше не падает.</p>
<p>UPDATE: Дело оказалось в другом. Когда далёкая сторона рвёт пайп, процесс ловит не исключение, а сигнал SIGPIPE. Который, соответственно, и надо было отловить. Но это уже исключительно моя глупость. Достаточно было воспользоваться gdb. Теперь уже точно всё чудесно:</p>
<p>2008-11-21 15:04:49 [21685] Worker: Exception: Exception got while putstring(): Failure(&#8221;Broken pipe&#8221;)<br />
2008-11-21 15:04:49 [21685] Worker: Exception: Exception in protocol_http: End_of_file<br />
<span id="more-44"></span></p>
<p>Добавил подсчёт времени ответа. Считается от момента начала отправки запроса серверу и до появления первого токена (версии протокола) . Пригодится для оценки нагрузки. (циферки: принято/отправлено/суммарное время ответа/количество запросов, среднее время ответа):</p>
<p>2008-11-21 01:15:53 [9458] Master: www-128.ibm.com: 1492/2231/1.151/4 avg response time: 0.288<br />
2008-11-21 01:15:53 [9458] Master: www.google.com: 1529/7240/1.275/4 avg response time: 0.319<br />
2008-11-21 01:15:53 [9458] Master: tldp.org: 2183/32055/2.462/10 avg response time: 0.246<br />
2008-11-21 01:15:53 [9458] Master: do.davebsd.com: 892/61312/3.156/16 avg response time: 0.197<br />
2008-11-21 01:15:53 [9458] Master: 62.105.135.103: 492/4796/0.488/2 avg response time: 0.244<br />
2008-11-21 01:15:53 [9458] Master: john.5070.info: 48972/56860/29.940/25 avg response time: 1.198<br />
2008-11-21 01:15:53 [9458] Master: angara.net: 17093/783047/21.354/64 avg response time: 0.334<br />
2008-11-21 01:15:53 [9458] Master: opennet.ru: 404/18673/3.246/2 avg response time: 1.623<br />
2008-11-21 01:15:53 [9458] Master: weather.noaa.gov: 432/41257/11.670/12 avg response time: 0.973<br />
2008-11-21 01:15:53 [9458] Master: linux.org.ru: 406/359/0.271/2 avg response time: 0.135<br />
2008-11-21 01:15:53 [9458] Master: www.opennet.ru: 827/838/0.091/4 avg response time: 0.023<br />
2008-11-21 01:15:53 [9458] Master: www.linux.org.ru: 3414/21411/1.079/12 avg response time: 0.090</p>
<p>Думаю, на этом можно с HTTP заканчивать и начинать MySQL. Будет продолжать активно тестироваться — я через это дело в интернет хожу.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2008/11/oproxy-%d0%b5%d1%89%d0%b5-%d0%b1%d0%be%d0%bb%d1%8c%d1%88%d0%b5-%d1%81%d1%82%d0%b0%d1%82%d0%b8%d1%81%d1%82%d0%b8%d0%ba%d0%b8-%d0%bf%d0%be%d0%b9%d0%bc%d0%b0%d0%bd%d0%be-%d0%bf%d0%be%d1%81%d0%bb%d0%b5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>oProxy: поддержка постоянных соединений, охота на исключения и http benchmark</title>
		<link>http://john.5070.info/2008/11/oproxy-%d0%bf%d0%be%d0%b4%d0%b4%d0%b5%d1%80%d0%b6%d0%ba%d0%b0-%d0%bf%d0%be%d1%81%d1%82%d0%be%d1%8f%d0%bd%d0%bd%d1%8b%d1%85-%d1%81%d0%be%d0%b5%d0%b4%d0%b8%d0%bd%d0%b5%d0%bd%d0%b8%d0%b9-%d0%be%d1%85/</link>
		<comments>http://john.5070.info/2008/11/oproxy-%d0%bf%d0%be%d0%b4%d0%b4%d0%b5%d1%80%d0%b6%d0%ba%d0%b0-%d0%bf%d0%be%d1%81%d1%82%d0%be%d1%8f%d0%bd%d0%bd%d1%8b%d1%85-%d1%81%d0%be%d0%b5%d0%b4%d0%b8%d0%bd%d0%b5%d0%bd%d0%b8%d0%b9-%d0%be%d1%85/#comments</comments>
		<pubDate>Wed, 19 Nov 2008 15:57:29 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[oProxy]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=43</guid>
		<description><![CDATA[Дописал поддержку keepalive, ловлю в ключевых местах все исключения. Но этот момент можно улучшать ещё долго. Стабильность кода значительно увеличилась.
Померил более достоверными средствами производительность. Окружение: запросы на http://ya.ru, контент которого закэширован моей домашней прокси (Squid). Запросы идут через wlan. Флуд-атака 40-а конкурентными пользователями. Организовал с помощью siege. Строчка запуска: siege -t 30s -b -c 40 [...]]]></description>
			<content:encoded><![CDATA[<p>Дописал поддержку keepalive, ловлю в ключевых местах все исключения. Но этот момент можно улучшать ещё долго. Стабильность кода значительно увеличилась.</p>
<p>Померил более достоверными средствами производительность. Окружение: запросы на http://ya.ru, контент которого закэширован моей домашней прокси (Squid). Запросы идут через wlan. Флуд-атака 40-а конкурентными пользователями. Организовал с помощью siege. Строчка запуска: siege -t 30s -b -c 40 http://ya.ru &gt;/dev/null</p>
<p><span id="more-43"></span>Результаты 30-секундной атаки:</p>
<p>Через oProxy:</p>
<p>Transactions:                1767 hits<br />
Availability:              100.00 %<br />
Elapsed time:               30.08 secs<br />
Data transferred:            6.24 MB<br />
Response time:                0.67 secs<br />
Transaction rate:           58.74 trans/sec<br />
Throughput:                0.21 MB/sec<br />
Concurrency:               39.27<br />
Successful transactions:        1767<br />
Failed transactions:               0<br />
Longest transaction:            4.14<br />
Shortest transaction:            0.21</p>
<p>Напрямую:</p>
<p>Transactions:                1390 hits<br />
Availability:              100.00 %<br />
Elapsed time:               29.83 secs<br />
Data transferred:            4.91 MB<br />
Response time:                0.83 secs<br />
Transaction rate:           46.60 trans/sec<br />
Throughput:                0.16 MB/sec<br />
Concurrency:               38.78<br />
Successful transactions:        1390<br />
Failed transactions:               0<br />
Longest transaction:            3.65<br />
Shortest transaction:            0.10</p>
<p>Внимательный читатель заметит, что напрямую эффективность даже хуже как по конкурентности, так и по общей производительности (лучше по минимальному и максимальному времени ответа). По общей производительности хуже получилось аж на четверть. Причины сего явления ещё предстоит выяснить. Грешу на буферизацию.</p>
<p>Кстати, заняло это проксирование 0.22 секунды процессорного времени (в предыдущем измерении допустил ошибку). Т.е. около 0.00012 секунды на запрос.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2008/11/oproxy-%d0%bf%d0%be%d0%b4%d0%b4%d0%b5%d1%80%d0%b6%d0%ba%d0%b0-%d0%bf%d0%be%d1%81%d1%82%d0%be%d1%8f%d0%bd%d0%bd%d1%8b%d1%85-%d1%81%d0%be%d0%b5%d0%b4%d0%b8%d0%bd%d0%b5%d0%bd%d0%b8%d0%b9-%d0%be%d1%85/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
