<?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; Performance</title>
	<atom:link href="http://john.5070.info/category/profiling-%d0%be%d0%bf%d1%82%d0%b8%d0%bc%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d1%8f-%d1%8d%d1%84%d1%84%d0%b5%d0%ba%d1%82%d0%b8%d0%b2%d0%bd%d0%be%d1%81%d1%82%d1%8c/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>сумасшедший алгоритм</title>
		<link>http://john.5070.info/2009/11/%d1%81%d1%83%d0%bc%d0%b0%d1%81%d1%88%d0%b5%d0%b4%d1%88%d0%b8%d0%b9-%d0%b0%d0%bb%d0%b3%d0%be%d1%80%d0%b8%d1%82%d0%bc/</link>
		<comments>http://john.5070.info/2009/11/%d1%81%d1%83%d0%bc%d0%b0%d1%81%d1%88%d0%b5%d0%b4%d1%88%d0%b8%d0%b9-%d0%b0%d0%bb%d0%b3%d0%be%d1%80%d0%b8%d1%82%d0%bc/#comments</comments>
		<pubDate>Mon, 16 Nov 2009 16:37:40 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[cluster]]></category>
		<category><![CDATA[алгоритмы]]></category>
		<category><![CDATA[хостинг]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=220</guid>
		<description><![CDATA[Уже 3-й день размышляю над алгоритмом следующей задачки.
Дано:

Есть кластер. В кластере живёт несколько узлов. В узле живёт несколько веб-серверов. В веб-сервере живёт несколько аккаунтов. В аккаунте живёт несколько сайтов.
Для каждого сайта известна текущая нагрузка. Соответственно, известна нагрузка для каждого из аккаунтов.
Известно количество сайтов в каждом из аккаунтов.
Для каждого аккаунта сказано, на скольких минимум узлах (не [...]]]></description>
			<content:encoded><![CDATA[<p>Уже 3-й день размышляю над алгоритмом следующей задачки.</p>
<p>Дано:</p>
<ol>
<li>Есть кластер. В кластере живёт несколько узлов. В узле живёт несколько веб-серверов. В веб-сервере живёт несколько аккаунтов. В аккаунте живёт несколько сайтов.</li>
<li>Для каждого сайта известна текущая нагрузка. Соответственно, известна нагрузка для каждого из аккаунтов.</li>
<li>Известно количество сайтов в каждом из аккаунтов.</li>
<li>Для каждого аккаунта сказано, на скольких <em>минимум</em> узлах (не веб-серверах) он должен присутствовать. Пусть это будет <strong>μ</strong>.</li>
<li>Для каждого аккаунта известно, какие веб-серверы обрабатывают его в данный момент.</li>
</ol>
<p>Задача состоит в том, чтобы перераспределить аккаунты по веб-серверам так, чтобы</p>
<ol>
<li>Аккаунты с максимальной нагрузкой присутствовали на максимальном числе узлов. Ну и соразмерно все остальные.</li>
<li>Каждый аккаунт представлен минимум на <strong>μ</strong> узлах.</li>
<li>В пределах одного узла каждый аккаунт представлен лишь один раз.</li>
<li>Текущая нагрузка наиболее равномерно распределена между всеми узлами (или с каким-то коэффициентом — не суть).</li>
<li>Сайты максимально равномерно распределены между всеми веб-серверами, чтобы минимизировать объём памяти каждого из процессов веб-серверов.</li>
<li>Сделать это всё так, чтобы изменения коснулись по возможности минимального количества веб-серверов, чтобы затем минимум их пришлось заставить перечитывать конфиг.</li>
<li>Делать это каким-то хитрым алгоритмом т.к. простой перебор на потенциальные десятки тысяч сайтов может отожрать немало проца и памяти&#8230;</li>
</ol>
<p>Понятно, что идеально соблюсти все условия не получится. Соответственно, надо либо расставить приоритеты условиям, либо ввести коэффициент максимальной допустимой погрешности решения. Решение вырастает весьма объёмным даже для простого перебора. Мне страшно представить о часе, когда надо будет искать более изящные решения.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/11/%d1%81%d1%83%d0%bc%d0%b0%d1%81%d1%88%d0%b5%d0%b4%d1%88%d0%b8%d0%b9-%d0%b0%d0%bb%d0%b3%d0%be%d1%80%d0%b8%d1%82%d0%bc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Решение для решателя Sudoku</title>
		<link>http://john.5070.info/2009/06/%d1%80%d0%b5%d1%88%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b4%d0%bb%d1%8f-%d1%80%d0%b5%d1%88%d0%b0%d1%82%d0%b5%d0%bb%d1%8f-sudoku/</link>
		<comments>http://john.5070.info/2009/06/%d1%80%d0%b5%d1%88%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b4%d0%bb%d1%8f-%d1%80%d0%b5%d1%88%d0%b0%d1%82%d0%b5%d0%bb%d1%8f-sudoku/#comments</comments>
		<pubDate>Wed, 10 Jun 2009 14:54:30 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[Blogroll]]></category>
		<category><![CDATA[Ocaml]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Sudoku]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=126</guid>
		<description><![CDATA[Хотел вечерком размять мозг — набросать какой-нибудь особенно красивый решатель Sudoku на Ocaml. Но возникла мысль изучить вражеские аналоги. Итак, решатель Sudoku размером 800 с небольшим байт:

include Set.Make&#40;struct type t = &#40;int * int&#41; * int let compare = compare end&#41;
&#160;
let &#40;@&#41; g f x = g &#40;f x&#41; and id x = x and [...]]]></description>
			<content:encoded><![CDATA[<p>Хотел вечерком размять мозг — набросать какой-нибудь особенно красивый решатель Sudoku на Ocaml. Но возникла мысль изучить вражеские аналоги. Итак, решатель Sudoku размером 800 с небольшим байт:</p>

<div class="wp_syntax"><div class="code"><pre class="ocaml" style="font-family:monospace;"><span style="color: #06c; font-weight: bold;">include</span> <span style="color: #06c; font-weight: bold;">Set</span><span style="color: #a52a2a;">.</span><span style="color: #060;">Make</span><span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">struct</span> <span style="color: #06c; font-weight: bold;">type</span> t <span style="color: #a52a2a;">=</span> <span style="color: #6c6;">&#40;</span>int <span style="color: #a52a2a;">*</span> int<span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">*</span> int <span style="color: #06c; font-weight: bold;">let</span> <span style="color: #06c; font-weight: bold;">compare</span> <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">compare</span> <span style="color: #06c; font-weight: bold;">end</span><span style="color: #6c6;">&#41;</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> <span style="color: #6c6;">&#40;</span>@<span style="color: #6c6;">&#41;</span> g f x <span style="color: #a52a2a;">=</span> g <span style="color: #6c6;">&#40;</span>f x<span style="color: #6c6;">&#41;</span> <span style="color: #06c; font-weight: bold;">and</span> id x <span style="color: #a52a2a;">=</span> x <span style="color: #06c; font-weight: bold;">and</span> sw f x y <span style="color: #a52a2a;">=</span> f y x <span style="color: #06c; font-weight: bold;">and</span> zip x y <span style="color: #a52a2a;">=</span> <span style="color: #6c6;">&#40;</span>x, y<span style="color: #6c6;">&#41;</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> fold9 f <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">let</span> <span style="color: #06c; font-weight: bold;">rec</span> loop i <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">if</span> i<span style="color: #a52a2a;">&gt;</span><span style="color: #c6c;">8</span> <span style="color: #06c; font-weight: bold;">then</span> id <span style="color: #06c; font-weight: bold;">else</span> loop <span style="color: #6c6;">&#40;</span>i<span style="color: #a52a2a;">+</span><span style="color: #c6c;">1</span><span style="color: #6c6;">&#41;</span> @ f i <span style="color: #06c; font-weight: bold;">in</span> loop <span style="color: #c6c;">0</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> fold81 f <span style="color: #a52a2a;">=</span> fold9 <span style="color: #6c6;">&#40;</span>fold9 @ <span style="color: #6c6;">&#40;</span>@<span style="color: #6c6;">&#41;</span> f @ zip<span style="color: #6c6;">&#41;</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> mark <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span>i,j<span style="color: #6c6;">&#41;</span>,x <span style="color: #06c; font-weight: bold;">as</span> e<span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">:</span> t <span style="color: #a52a2a;">-&gt;</span> t <span style="color: #a52a2a;">=</span>
  add e @ fold9 <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">fun</span> k <span style="color: #a52a2a;">-&gt;</span> remove <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span>i<span style="color: #a52a2a;">/</span><span style="color: #c6c;">3</span><span style="color: #a52a2a;">*</span><span style="color: #c6c;">3</span> <span style="color: #a52a2a;">+</span> k<span style="color: #a52a2a;">/</span><span style="color: #c6c;">3</span>, j<span style="color: #a52a2a;">/</span><span style="color: #c6c;">3</span><span style="color: #a52a2a;">*</span><span style="color: #c6c;">3</span> <span style="color: #a52a2a;">+</span> k <span style="color: #06c; font-weight: bold;">mod</span> <span style="color: #c6c;">3</span><span style="color: #6c6;">&#41;</span>, x<span style="color: #6c6;">&#41;</span> @
    remove <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span>i,j<span style="color: #6c6;">&#41;</span>,k<span style="color: #6c6;">&#41;</span> @ remove <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span>i,k<span style="color: #6c6;">&#41;</span>,x<span style="color: #6c6;">&#41;</span> @ remove <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span>k,j<span style="color: #6c6;">&#41;</span>,x<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> search <span style="color: #a52a2a;">=</span>
  <span style="color: #06c; font-weight: bold;">let</span> g p f s <span style="color: #a52a2a;">=</span> fold <span style="color: #6c6;">&#40;</span>f @ sw mark s<span style="color: #6c6;">&#41;</span> <span style="color: #6c6;">&#40;</span>filter <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span><span style="color: #a52a2a;">=</span><span style="color: #6c6;">&#41;</span> p @ <span style="color: #06c; font-weight: bold;">fst</span><span style="color: #6c6;">&#41;</span> s<span style="color: #6c6;">&#41;</span> <span style="color: #06c; font-weight: bold;">in</span>
  fold81 g
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> read <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">=</span>
  <span style="color: #06c; font-weight: bold;">let</span> f p <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">Scanf</span><span style="color: #a52a2a;">.</span><span style="color: #060;">scanf</span> <span style="color: #3cb371;">&quot;%d &quot;</span> <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">fun</span> x <span style="color: #a52a2a;">-&gt;</span> <span style="color: #06c; font-weight: bold;">if</span> x<span style="color: #a52a2a;">&gt;</span><span style="color: #c6c;">0</span> <span style="color: #06c; font-weight: bold;">then</span> mark <span style="color: #6c6;">&#40;</span>p,x<span style="color: #a52a2a;">-</span><span style="color: #c6c;">1</span><span style="color: #6c6;">&#41;</span> <span style="color: #06c; font-weight: bold;">else</span> id<span style="color: #6c6;">&#41;</span> <span style="color: #06c; font-weight: bold;">in</span>
  fold81 f <span style="color: #6c6;">&#40;</span>fold81 <span style="color: #6c6;">&#40;</span>fold9 @ <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span>@<span style="color: #6c6;">&#41;</span> add @ zip<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> empty<span style="color: #6c6;">&#41;</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> print s <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">=</span>
  <span style="color: #06c; font-weight: bold;">let</span> pr <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span>i,j<span style="color: #6c6;">&#41;</span>,x<span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">Printf</span><span style="color: #a52a2a;">.</span><span style="color: #060;">printf</span> <span style="color: #3cb371;">&quot;%d%c&quot;</span> <span style="color: #6c6;">&#40;</span>x<span style="color: #a52a2a;">+</span><span style="color: #c6c;">1</span><span style="color: #6c6;">&#41;</span> <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">if</span> j<span style="color: #a52a2a;">=</span><span style="color: #c6c;">8</span> <span style="color: #06c; font-weight: bold;">then</span> <span style="color: #a52a2a;">'</span>\n<span style="color: #a52a2a;">'</span> <span style="color: #06c; font-weight: bold;">else</span> <span style="color: #a52a2a;">'</span> <span style="color: #a52a2a;">'</span><span style="color: #6c6;">&#41;</span> <span style="color: #06c; font-weight: bold;">in</span>
  iter pr s<span style="color: #a52a2a;">;</span> <span style="color: #06c; font-weight: bold;">print_newline</span> <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span><span style="color: #a52a2a;">;;</span>
&nbsp;
search print <span style="color: #6c6;">&#40;</span>read <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span></pre></div></div>

<p>Вы посмотрите эту красоту, это же [почти] совершенство! А если учесть, что 272 байта — это чтение задачи с STDIN и вывод результата, размер кода сокращается до менее чем 600 байт.</p>
<p><span id="more-126"></span>Впрочем, Perl традиционно отличился своей минималистической магической мешаниной:</p>

<div class="wp_syntax"><div class="code"><pre class="perl" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">use</span> integer<span style="color: #339933;">;</span><span style="color: #0000ff;">@A</span><span style="color: #339933;">=</span><span style="color: #000066;">split</span><span style="color: #339933;">//,&lt;&gt;;</span>sub R<span style="color: #009900;">&#123;</span><span style="color: #b1b100;">for</span><span style="color: #0000ff;">$i</span><span style="color: #009900;">&#40;</span>0<span style="color: #339933;">..</span>80<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><span style="color: #b1b100;">next</span> <span style="color: #b1b100;">if</span><span style="color: #0000ff;">$A</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>my<span style="color: #0000ff;">%t</span><span style="color: #339933;">=</span><span style="color: #000066;">map</span><span style="color: #009900;">&#123;</span><span style="color: #0000ff;">$_</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">9</span>
<span style="color: #339933;">==</span><span style="color: #0000ff;">$i</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">9</span><span style="color: #339933;">||</span><span style="color: #0000ff;">$_</span><span style="color: #339933;">%</span>9<span style="color: #339933;">==</span><span style="color: #0000ff;">$i</span><span style="color: #339933;">%</span>9<span style="color: #339933;">||</span><span style="color: #0000ff;">$_</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">27</span><span style="color: #339933;">==</span><span style="color: #0000ff;">$i</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">27</span><span style="color: #339933;">&amp;&amp;</span><span style="color: #0000ff;">$_</span><span style="color: #339933;">%</span>9<span style="color: #339933;">/</span><span style="color: #cc66cc;">3</span><span style="color: #339933;">==</span><span style="color: #0000ff;">$i</span><span style="color: #339933;">%</span>9<span style="color: #339933;">/</span><span style="color: #cc66cc;">3</span><span style="color: #339933;">?</span><span style="color: #0000ff;">$A</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$_</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">:</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">=&gt;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#125;</span>0<span style="color: #339933;">..</span>80<span style="color: #339933;">;</span>R<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$A</span><span style="color: #009900;">&#91;</span>
<span style="color: #0000ff;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #0000ff;">$_</span><span style="color: #009900;">&#41;</span><span style="color: #b1b100;">for</span> <span style="color: #000066;">grep</span><span style="color: #009900;">&#123;</span><span style="color: #339933;">!</span><span style="color: #0000ff;">$t</span><span style="color: #009900;">&#123;</span><span style="color: #0000ff;">$_</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#125;</span>1<span style="color: #339933;">..</span>9<span style="color: #339933;">;</span>return<span style="color: #0000ff;">$A</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#125;</span><span style="color: #000066;">die</span><span style="color: #0000ff;">@A</span><span style="color: #009900;">&#125;</span>R</pre></div></div>

<p>Ну и специалисты по PHP тоже выразились: <a href="http://www.weberdev.com/get_example-4243.html">http://www.weberdev.com/get_example-4243.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/06/%d1%80%d0%b5%d1%88%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b4%d0%bb%d1%8f-%d1%80%d0%b5%d1%88%d0%b0%d1%82%d0%b5%d0%bb%d1%8f-sudoku/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ocaml-epoll</title>
		<link>http://john.5070.info/2009/05/ocaml-epoll/</link>
		<comments>http://john.5070.info/2009/05/ocaml-epoll/#comments</comments>
		<pubDate>Fri, 29 May 2009 06:49:27 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[Ocaml]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[epoll]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=112</guid>
		<description><![CDATA[Написал биндинг для работы с epoll(7). Пока бета, но на ней уже ради эксперимента написал успешно работающий маленький веб-сервер :) Скачать можно со страницы Software. epoll является аналогом select() и poll(), но с увеличением количества обрабатываемых сокетов сложность остаётся O(1), что позволяет без особых задержек обрабатывать тысячи параллельных соединений.
]]></description>
			<content:encoded><![CDATA[<p>Написал биндинг для работы с epoll(7). Пока бета, но на ней уже ради эксперимента написал успешно работающий маленький веб-сервер :) Скачать можно со страницы <a title="Мой софт" href="http://john.5070.info/software/">Software</a>. epoll является аналогом select() и poll(), но с увеличением количества обрабатываемых сокетов сложность остаётся O(1), что позволяет без особых задержек обрабатывать тысячи параллельных соединений.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/05/ocaml-epoll/feed/</wfw:commentRss>
		<slash:comments>2</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>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 (о прокси, about proxy)</title>
		<link>http://john.5070.info/2008/11/oproxy/</link>
		<comments>http://john.5070.info/2008/11/oproxy/#comments</comments>
		<pubDate>Fri, 14 Nov 2008 17:51:04 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[Ocaml]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[программирование]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=38</guid>
		<description><![CDATA[Настроение: подшофе. Первый эксбиционисткий пост, как и положено в б-сферах. Прости меня, г-поди!
Написал версию 0.02 проекта с рабочим названием oProxy. В этой версии всё переписано с нуля + умеет считать трафик и прочую статистику :) На моём ноуте умеет обрабатывать ~2500 соединений в секунду. Соединения обрабатываются рабочими. При этом, 80% тормозов происходит на принятии соединения [...]]]></description>
			<content:encoded><![CDATA[<p>Настроение: подшофе. Первый эксбиционисткий пост, как и положено в б-сферах. Прости меня, г-поди!</p>
<p><span id="more-38"></span>Написал версию 0.02 проекта с рабочим названием oProxy. В этой версии всё переписано с нуля + умеет считать трафик и прочую статистику :) На моём ноуте умеет обрабатывать ~2500 соединений в секунду. Соединения обрабатываются рабочими. При этом, 80% тормозов происходит на принятии соединения мастером, около 10% в мутексах для сбора статистики внутри рабочих, и около 10% уходит непосредственно на саму обработку (парсинг заголовков HTTP-запроса, обработка ошибок протокола и т.д.). Рабочие CPU почти не едят, в отличие от атакующего siege&#8217;а (~0.4% против 35%). То есть, запас роста есть. Памяти жрёт 1.7Mb на одного рабочего.</p>
<p>За пятничный вечер сделал дома больше, чем за всю рабочую неделю в офисе. Там становится невозможно работать. И причины не совсем ясны. Даже старое средство — наушники с музыкой — уже не помогает. Надо что-то придумывать. Послушать Шурика, и приходить на работу к 07:00?.. [не канает: ответственнен за некоторые машины, которые почему-то любят падать в период 23:00..03:00].</p>
<p>Полтора года тащился от Ocaml. Полтора года прищуренным глазом посматривал на вакансии. С вакансиями ситуация такая: за полтора года в России их было 2 штуки, обе уровня &#8220;мы тут пишем крутую фигню, но зарплата фиг знает когда будет&#8221;. За рубежом ситуация чуть лучше, но Ocaml-программистов хотят там всякие университеты и на соответствующие должности. И тут получил официальное одобрение разрабатывать заданный проект на чём сам пожелаю. Если так пойдёт и дальше — через полгодика я сам смогу торговать окамлевыми вакансиями! А ведь ещё не прошло и года с момента увольнения Стаса, который буквально позавчера должен уехать в СПб на вакансию Lisp-программиста.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2008/11/oproxy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Сравнение ЯП</title>
		<link>http://john.5070.info/2007/08/%d1%81%d1%80%d0%b0%d0%b2%d0%bd%d0%b5%d0%bd%d0%b8%d0%b5-%d1%8f%d0%bf/</link>
		<comments>http://john.5070.info/2007/08/%d1%81%d1%80%d0%b0%d0%b2%d0%bd%d0%b5%d0%bd%d0%b8%d0%b5-%d1%8f%d0%bf/#comments</comments>
		<pubDate>Thu, 09 Aug 2007 08:20:20 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=4</guid>
		<description><![CDATA[Любопытный сайт, сравнивающий пару десятков языков по производительности и ресурсоемкости на реальных алгоритмических задачах. Любители священных войн могут обратить внимание на производительность PHP по сравнению, например, с Perl:

&#8220;Ocaml&#8221;, судя по всему, тестировался в скомпилированном в нативный код виде. В режиме интерпретатора варианта тестирования нет. Кстати, похожие языки &#8211; Ocaml и Haskell &#8211; оказались близкими и [...]]]></description>
			<content:encoded><![CDATA[<p>Любопытный <a href="http://shootout.alioth.debian.org/gp4/benchmark.php?test=all&amp;lang=php&amp;lang2=perl">сайт</a>, сравнивающий пару десятков языков по производительности и ресурсоемкости на реальных алгоритмических задачах. Любители священных войн могут обратить внимание на производительность PHP по сравнению, например, с Perl:</p>
<p><span id="more-4"></span><img src="http://shootout.alioth.debian.org/gp4/chartvs.php?test=all&amp;lang=php&amp;lang2=perl" width="300" height="300" /></p>
<p>&#8220;Ocaml&#8221;, судя по всему, тестировался в скомпилированном в нативный код виде. В режиме интерпретатора варианта тестирования нет. Кстати, похожие языки &#8211; Ocaml и Haskell &#8211; оказались близкими и по производительности:</p>
<p><img src="http://shootout.alioth.debian.org/gp4/chartvs.php?test=all&amp;lang=ocaml&amp;lang2=ghc" width="300" height="300" /></p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2007/08/%d1%81%d1%80%d0%b0%d0%b2%d0%bd%d0%b5%d0%bd%d0%b8%d0%b5-%d1%8f%d0%bf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
