<?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"
	>

<channel>
	<title>Записки программиста</title>
	<atom:link href="http://www.saterenko.ru/feed/" rel="self" type="application/rss+xml" />
	<link>http://saterenko.ru</link>
	<description></description>
	<pubDate>Sat, 14 May 2011 12:51:54 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.2</generator>
	<language>en</language>
			<item>
		<title>Распределённая рекламная сеть</title>
		<link>http://saterenko.ru/2011/05/14/%d1%80%d0%b0%d1%81%d0%bf%d1%80%d0%b5%d0%b4%d0%b5%d0%bb%d1%91%d0%bd%d0%bd%d0%b0%d1%8f-%d1%80%d0%b5%d0%ba%d0%bb%d0%b0%d0%bc%d0%bd%d0%b0%d1%8f-%d1%81%d0%b5%d1%82%d1%8c/</link>
		<comments>http://saterenko.ru/2011/05/14/%d1%80%d0%b0%d1%81%d0%bf%d1%80%d0%b5%d0%b4%d0%b5%d0%bb%d1%91%d0%bd%d0%bd%d0%b0%d1%8f-%d1%80%d0%b5%d0%ba%d0%bb%d0%b0%d0%bc%d0%bd%d0%b0%d1%8f-%d1%81%d0%b5%d1%82%d1%8c/#comments</comments>
		<pubDate>Sat, 14 May 2011 12:51:22 +0000</pubDate>
		<dc:creator>Андрей Сатеренко</dc:creator>
		
		<category><![CDATA[крутилка]]></category>

		<category><![CDATA[мысли вслух]]></category>

		<category><![CDATA[программирование]]></category>

		<category><![CDATA[система управления рекламой]]></category>

		<guid isPermaLink="false">http://saterenko.ru/?p=135</guid>
		<description><![CDATA[Чтобы осуществлять качественный показ рекламы (повышать её эффективность), необходим индивидуальный подход к каждому пользователю. Сбор всей доступной информации по пользователю, её анализ и использование при выборе рекламной кампании. Если делать маленькую сеть, рассчитанную на несколько десятков миллионов показов в сутки, то всё можно реализовать в рамках одного, среднего по мощности сервера. Если же планируется строить [...]]]></description>
			<content:encoded><![CDATA[<p>Чтобы осуществлять качественный показ рекламы (повышать её эффективность), необходим индивидуальный подход к каждому пользователю. Сбор всей доступной информации по пользователю, её анализ и использование при выборе рекламной кампании. Если делать маленькую сеть, рассчитанную на несколько десятков миллионов показов в сутки, то всё можно реализовать в рамках одного, среднего по мощности сервера. Если же планируется строить сеть, способную обрабатывать сотни и тысячи миллионов показов в сутки, одним сервером не обойтись. Тогда возникает вопрос, как эффективно разделить данные по множеству серверов так, чтобы нагрузка на них распределялась более-менее равномерно, без перекосов и без узких мест.<span id="more-135"></span></p>
<p>Логично сделать систему модульной, когда есть ядро системы, отвечающее за формирование ответа на запрос пользователя (выбор рекламных кампаний, обработка событий, переходов и т.п.) и множество модулей, отвечающих за хранение и обработку той или иной информации, которой будет пользоваться ядро при обработке запросов (модуль контекста (хранение информации о категории страницы, индексы слов и т.п.), модуль пользователей (частотные настройки, поведенческая информация и т.п.) и т.п.).</p>
<p>А теперь появляются вопросы: если у нас много рекламных кампаний, как их распределять между серверами? Каждый сервер хранит все кампании или у каждого сервера свой уникальный список кампаний? Как синхронизировать счётчики между серверами? Как работать с модулями? Получать всю информацию по объекту и обрабатывать её в ядре? Отсылать список кампаний в модуль и получать обратно модифицированный список? И т.д. и т.п.</p>
<h3>Распределённое ядро</h3>
<p>В чём вообще проблема? Проблема в синхронизации счётчиком между серверами. Если одна и та же кампания отдаётся с нескольких серверов, может возникнуть такая ситуация, когда будет осуществлено большее количество показов/переходов/действий, чем надо. Как синхронизировать счётчики таким образом, чтобы перекрутов не происходило?</p>
<p>Самый простой способ &#8212; это распределить кампании между серверами таким образом, чтобы ни одна кампания не была одновременно на двух (и более) серверах. Например, кампании можно разделить по формату, как правило, на один запрос отдаётся список кампаний определённого формата, а не нескольких. Это хороший вариант в том случае, если количество запросов по одному формату не превышает количества запросов, которое способен обработать сервер. А если у нас один формат и миллиард запросов в сутки? Такой вариан не подойдёт.</p>
<p>Простых вариантов в голову не пришло. То, что мне более-менее понравилось, выглядит следующим образом. Есть множество &#8220;алгоритмов&#8221; (демон, отвечающий на запрос), есть &#8220;менеджер&#8221; (демон, распределяющий кампании между алгоритмами). Алгоритмы ни чего не знают о количестве показов/переходов/действий, они оперируют только ограниченими (показал, уменьшил ограничение по показам и так до нуля). Менеджер делит ограничения для каждой кампании между алгоритмами. В самом простом случае, ограничения делятся поровну. В таком случае, перекрутов не будет. Минусом такого варианта является централизованное управление, чего хотелось бы избежать. Но, пока других варинатов в голову не пришло, считаю его оптимальным.</p>
<h3>Добавляем модуль</h3>
<p>Допустим, у нас всё замечательно работает и тут мы решили, что надо улучшать качество показов, а давайте сделаем поведенческий таргетинг. Всю информацию мы хотим хранить и анализировать на серверах. Можно конечно что-то хранить в куках, но это не наш вариант. </p>
<p>Теперь нам надо получать информацию о пользователе, модифицировать её. Если модификация будет требовать отправки, как правило, малого количества данных, то количество требуемых данных о пользователе, при выборе кампании, может быть большим. В этом случае видится несколько вариантов: расширять каналы между серверами, максимально упаковывать данные, передаваемые между серверами либо перенести функционал алгоритма поближе к пользовательским данным.</p>
<p>Первый вариант хорош в том случае, если передаваемые данные между алгоритмом и модулем можно хорошо упаковать, когда данные модуля позволяют некоторую латентность, т.е. не важно, когда обновлённые данные появятся в других алгоритмах: мгновенно или через минуту. Помимо этого, это будет единственный возможный варинат в случае, когда модулей будет несколько и все они будут требовать передачи большого количества данных, функционал алгоритма можно будет &#8220;приблизить&#8221; только к одному модулю, а не всем сразу.</p>
<p>Второй варинат позволит сократить количество передаваемых данных по сети и ускорить общение с модулем, но не подойдёт в случае, если таких модулей несколько. В таком случае наиболее трафико-генерирующий или наименее латентный (требующий минимальные задержки при обновлении данных) модуль распологается рядом с алгоритмом, а остальные модули работают по первому варианту.</p>
<h3>Итого</h3>
<p>Резюмируя. Я бы совместил функционал алгоритма и модуля пользователей в рамках одного демона (чтобы алгоритм мог напрямую работать с данными пользователей, без необходимости их куда-то пересылать), а модуль контекста вынес бы в отдельный демон/демона с кешированием на стороне клиента. Контекст меняется достаточно редко, а потому его можно кешировать на длительное время на стороне клиента с периодической проверкой на изменения.</p>
]]></content:encoded>
			<wfw:commentRss>http://saterenko.ru/2011/05/14/%d1%80%d0%b0%d1%81%d0%bf%d1%80%d0%b5%d0%b4%d0%b5%d0%bb%d1%91%d0%bd%d0%bd%d0%b0%d1%8f-%d1%80%d0%b5%d0%ba%d0%bb%d0%b0%d0%bc%d0%bd%d0%b0%d1%8f-%d1%81%d0%b5%d1%82%d1%8c/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Удаление объекта flash под IE8</title>
		<link>http://saterenko.ru/2011/04/10/%d1%83%d0%b4%d0%b0%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%be%d0%b1%d1%8a%d0%b5%d0%ba%d1%82%d0%b0-flash-%d0%bf%d0%be%d0%b4-ie8/</link>
		<comments>http://saterenko.ru/2011/04/10/%d1%83%d0%b4%d0%b0%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%be%d0%b1%d1%8a%d0%b5%d0%ba%d1%82%d0%b0-flash-%d0%bf%d0%be%d0%b4-ie8/#comments</comments>
		<pubDate>Sun, 10 Apr 2011 11:10:26 +0000</pubDate>
		<dc:creator>Андрей Сатеренко</dc:creator>
		
		<category><![CDATA[программирование]]></category>

		<category><![CDATA[flash]]></category>

		<category><![CDATA[ie8]]></category>

		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://saterenko.ru/?p=130</guid>
		<description><![CDATA[Недавно, в одном из форматов рекламы, была обнаружена ошибка, появляющаяся в IE7 и IE8. После закрытия баннера появлялась JS-ошибка &#8216;null&#8217; is null or is not an object. После дебага удалось обнаружить место, в котором возникала ошибка, это происходило в коде:
try { document.getElementById("_banner_").SetReturnValue( __flash__toXML(window.location.href.toString()) ); } catch (e) { document.getElementById("_banner_").SetReturnValue("&#8220;); }
Но это не код показа баннера, [...]]]></description>
			<content:encoded><![CDATA[<p>Недавно, в одном из форматов рекламы, была обнаружена ошибка, появляющаяся в IE7 и IE8. После закрытия баннера появлялась JS-ошибка <b>&#8216;null&#8217; is null or is not an object</b>. После дебага удалось обнаружить место, в котором возникала ошибка, это происходило в коде:</p>
<p><code>try { document.getElementById("_banner_").SetReturnValue( __flash__toXML(window.location.href.toString()) ); } catch (e) { document.getElementById("_banner_").SetReturnValue("<undefined></undefined>&#8220;); }</code></p>
<p>Но это не код показа баннера, это код взаимодействия flash с JS. Дальнейшее изучение проблемы показало, что document.getElementById(&#8221;_banner_&#8221;) возвращает null.</p>
<p>Проблема, как оказалось, была в том, что объект flash не удалялся после удаления div-а, служащего контейнером для flash-баннера. Т.е. div вместе с object удалялся из DOM, но оставался в памяти браузера и продолжал отсылать сообщения, но, так как элемента document.getElementById(&#8221;_banner_&#8221;) больше не существовало, появлялась ошибка.</p>
<p>Решилась проблема небыстро, но решение оказалось простым. Надо было просто удалить object. Т.е. перед удалением контейнера надо удалить object и это решает проблему.</p>
]]></content:encoded>
			<wfw:commentRss>http://saterenko.ru/2011/04/10/%d1%83%d0%b4%d0%b0%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%be%d0%b1%d1%8a%d0%b5%d0%ba%d1%82%d0%b0-flash-%d0%bf%d0%be%d0%b4-ie8/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Система управления рекламой Videoclick: уроки</title>
		<link>http://saterenko.ru/2011/03/21/%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d0%b0-%d1%83%d0%bf%d1%80%d0%b0%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d1%8f-%d1%80%d0%b5%d0%ba%d0%bb%d0%b0%d0%bc%d0%be%d0%b9-videoclick-%d1%83%d1%80%d0%be%d0%ba%d0%b8/</link>
		<comments>http://saterenko.ru/2011/03/21/%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d0%b0-%d1%83%d0%bf%d1%80%d0%b0%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d1%8f-%d1%80%d0%b5%d0%ba%d0%bb%d0%b0%d0%bc%d0%be%d0%b9-videoclick-%d1%83%d1%80%d0%be%d0%ba%d0%b8/#comments</comments>
		<pubDate>Mon, 21 Mar 2011 12:19:15 +0000</pubDate>
		<dc:creator>Андрей Сатеренко</dc:creator>
		
		<category><![CDATA[крутилка]]></category>

		<category><![CDATA[программирование]]></category>

		<category><![CDATA[система управления рекламой]]></category>

		<category><![CDATA[уроки]]></category>

		<guid isPermaLink="false">http://saterenko.ru/?p=126</guid>
		<description><![CDATA[Каждый раз, начиная разработку нового проекта, придумываешь новые алгоритмы, новые способы решения задач, новые подходы. Так произошло и с новой версией системы управления рекламой для Videoclick.
Потоки вместо процессов
В старой системе использовались процессы, по одному процессу на каждый воркер (воркер занимается разбором запроса и формированием ответа). Плюс такого подхода в том, что при падении одного из [...]]]></description>
			<content:encoded><![CDATA[<p>Каждый раз, начиная разработку нового проекта, придумываешь новые алгоритмы, новые способы решения задач, новые подходы. Так произошло и с новой версией системы управления рекламой для Videoclick.</p>
<p><strong>Потоки вместо процессов</strong></p>
<p>В старой системе использовались процессы, по одному процессу на каждый воркер (воркер занимается разбором запроса и формированием ответа). Плюс такого подхода в том, что при падении одного из процессов, всегда есть ещё процесс/процессы, которые обработают запросы пока мастер (процесс, контролирующий работу воркеров, собирающий статистику и т.п.) не поднимет новый процесс взамен упавшему, т.е. мы потеряем только один запрос, на котором процесс упал. Минус в том, что для шаринга данных между процессами приходится пользоваться shared memory, а работа с ней не самое приятное занятие.</p>
<p>В новой системе используются потоки. При падении потока весь процесс валиться и, пока не будет поднят новый процесс, мы теряем все запросы. Плохо конечно, но, как показала практика, не критично. Падал демон всего несколько раз при тестировании, пока не были исправлены ошибки, приводящие к падению (а это критичные ошибки). Т.е., в реальной работе, плюс процессов не такой уж и плюс.</p>
<p>Зато как легко работать с общими данными. Достаточно легко удалось избежать использования всякого рода блокировок. Всё работает быстро и без головной боли.</p>
<p><span id="more-126"></span></p>
<p><strong>Обновляем только обновлённые данные</strong></p>
<p>В старой системе, по аналогии с прототипом (http://valuead.com/), функционал которого необходимо было повторить на 100%, данные из базы загружались с заданной периодичностью сразу все. Загружать ежеминутно по 5-10Мб данных &#8212; это норма.</p>
<p>В новой системе, в каждой из таблиц, данные из которой загружает демон, есть поле modified, в котором содержится дата последнего обновления объекта. При этом данное поле обновляется только в том случае, если изменённое значение/значения влияют на работу движка. Так как данные меняются достаточно редко, это позволяет, без особых нагрузок, проверять базу данных на обновления ежесекундно, что положительно сказывается на времени отклика системы.</p>
<p><strong>Новая схема логирования/отчётности</strong></p>
<p>В старой системе ежечасно собирались логи за текущие сутки, аггрегировались и формировалось несколько десятков всевозможных отчётов. В таком подходе я видел два минуса. Во-первых, обрабатывались логи не за последний час, а за всё время с полуночи, до текущего час. Т.е. каждый час повторно обрабатывались предыдущие часы, а это очень много лишней работы. Во-вторых, формировались десятки огромных отчётов, которыми либо вообще не пользовались, либо пользовались крайне редко (например, отчёт по баннерам-сайтам-городам, десятки баннеров помноженные на сотни сайтов и тысячи городов &#8212; это очень много).</p>
<p>В новой системе логи обрабатываются за предыдущий час один раз. По результатам обработки формируется одна таблица (баннер-сайт-час со счётчиками) из которой формируются другие таблицы с аггрегированием по тому или иному полю средствами базы данных (типа insert into &#8230; select from &#8230;). Так же формируются логи с аггрегацией по баннерам, по сайтам и по системе вцелом. В случае, если нам нужен произвольный отчёт, в интерфейсах формируется запрос на отчёт, система обрабатывает логи, аггрегирует данные и сохраняет результат в базу данных.</p>
<p>Плюса в новой схеме три. Во-первых, формируя отчёты из одной таблицы, мы исключаем возможность появления расхождений между разными отчётами, которая могла появиться в старой системе. Во-вторых, в базе данных не хранится куча ненужных отчётов. В-третьих, в любой момент мы можем придумать новый отчёт и получить его по прошедшим кампаниям, потому как все данные есть. Но есть и маленький минус. За 9 месяцев работы системы, с учётом архивирования прошедших кампаний, логи занимают порядка 140Гб. Но, с учётом того, какого размера современные винчестеры и сколько они стоят, это не такой уж и минус. Зато есть полная информация по каждому показу/клику/событию баннера.</p>
<p><strong>Межпроцессное взаимодействие</strong></p>
<p>В старой системе процессы общались через pipe. В новой системе потоки общаются через socketpair. Новый вариат мне показался более удобным, но есть один минус. Тестирование показало, что на моём ноутбуке, может быть выполнено не более 80 тыс. циклов запрос/ответ. Учитывая то, что каждый запрос сначала отправляется в воркер, потом в storage (сохранение данных в лог), это даёт не более 40 тыс. запрсов в секунду, и это без какой-либо другой работы, только обмен сообщениями. Для реальной системы нормально, но для перфекциониста, жевущему во мне, &#8220;Маловато будет&#8221; (с) Падал прошлогодний снег. В будущем придётся либо изобретать собственный велосипед (lock-free очереди для межпотокового взаимодействия), либо воспользоваться <a href="http://www.zeromq.org/">www.zeromq.org</a>, что я быстрее всего и сделаю.</p>
]]></content:encoded>
			<wfw:commentRss>http://saterenko.ru/2011/03/21/%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d0%b0-%d1%83%d0%bf%d1%80%d0%b0%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d1%8f-%d1%80%d0%b5%d0%ba%d0%bb%d0%b0%d0%bc%d0%be%d0%b9-videoclick-%d1%83%d1%80%d0%be%d0%ba%d0%b8/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Апгрейд ноута</title>
		<link>http://saterenko.ru/2010/02/15/%d0%b0%d0%bf%d0%b3%d1%80%d0%b5%d0%b9%d0%b4-%d0%bd%d0%be%d1%83%d1%82%d0%b0/</link>
		<comments>http://saterenko.ru/2010/02/15/%d0%b0%d0%bf%d0%b3%d1%80%d0%b5%d0%b9%d0%b4-%d0%bd%d0%be%d1%83%d1%82%d0%b0/#comments</comments>
		<pubDate>Mon, 15 Feb 2010 06:12:11 +0000</pubDate>
		<dc:creator>Андрей Сатеренко</dc:creator>
		
		<category><![CDATA[разное]]></category>

		<category><![CDATA[macbook]]></category>

		<guid isPermaLink="false">http://saterenko.ru/?p=122</guid>
		<description><![CDATA[Проапгрейдил свой макбук&#8230; Достало что на Tiger новый софт стал глючить либо вообще отказывается ставиться. Купил Snow Leopard. Но это не самое главное, самое главное, что купил SSD Transcend на 128Gb. Хотел взять Intel X25-E 80Gb, но его найти не удалось, а вернее задолбался искать, а потому взял Transcend, тем более что он по тестам [...]]]></description>
			<content:encoded><![CDATA[<p>Проапгрейдил свой макбук&#8230; Достало что на Tiger новый софт стал глючить либо вообще отказывается ставиться. Купил Snow Leopard. Но это не самое главное, самое главное, что купил SSD Transcend на 128Gb. Хотел взять Intel X25-E 80Gb, но его найти не удалось, а вернее задолбался искать, а потому взял Transcend, тем более что он по тестам не сильно отстаёт от Intel в посведневных задачах&#8230;</p>
<p>По новой системе пока никаких особых впечатлений кроме возможости поставить Google Chrom и другой нужный софт&#8230; А вот винт радует&#8230; Явное увеличение скорости загрузки приложений&#8230; В общем, я доволен <img src='http://saterenko.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p>
]]></content:encoded>
			<wfw:commentRss>http://saterenko.ru/2010/02/15/%d0%b0%d0%bf%d0%b3%d1%80%d0%b5%d0%b9%d0%b4-%d0%bd%d0%be%d1%83%d1%82%d0%b0/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Были получены исходники 3300 глобальных интернет-проектов</title>
		<link>http://saterenko.ru/2009/09/23/%d0%b1%d1%8b%d0%bb%d0%b8-%d0%bf%d0%be%d0%bb%d1%83%d1%87%d0%b5%d0%bd%d1%8b-%d0%b8%d1%81%d1%85%d0%be%d0%b4%d0%bd%d0%b8%d0%ba%d0%b8-3300-%d0%b3%d0%bb%d0%be%d0%b1%d0%b0%d0%bb%d1%8c%d0%bd%d1%8b%d1%85/</link>
		<comments>http://saterenko.ru/2009/09/23/%d0%b1%d1%8b%d0%bb%d0%b8-%d0%bf%d0%be%d0%bb%d1%83%d1%87%d0%b5%d0%bd%d1%8b-%d0%b8%d1%81%d1%85%d0%be%d0%b4%d0%bd%d0%b8%d0%ba%d0%b8-3300-%d0%b3%d0%bb%d0%be%d0%b1%d0%b0%d0%bb%d1%8c%d0%bd%d1%8b%d1%85/#comments</comments>
		<pubDate>Wed, 23 Sep 2009 09:38:02 +0000</pubDate>
		<dc:creator>Андрей Сатеренко</dc:creator>
		
		<category><![CDATA[программирование]]></category>

		<category><![CDATA[разное]]></category>

		<category><![CDATA[безопасность]]></category>

		<guid isPermaLink="false">http://saterenko.ru/?p=119</guid>
		<description><![CDATA[Про сабж можно почитать на хабре: http://habrahabr.ru/blogs/infosecurity/70330/.
]]></description>
			<content:encoded><![CDATA[<p>Про сабж можно почитать на хабре: <a href="http://habrahabr.ru/blogs/infosecurity/70330/">http://habrahabr.ru/blogs/infosecurity/70330/</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://saterenko.ru/2009/09/23/%d0%b1%d1%8b%d0%bb%d0%b8-%d0%bf%d0%be%d0%bb%d1%83%d1%87%d0%b5%d0%bd%d1%8b-%d0%b8%d1%81%d1%85%d0%be%d0%b4%d0%bd%d0%b8%d0%ba%d0%b8-3300-%d0%b3%d0%bb%d0%be%d0%b1%d0%b0%d0%bb%d1%8c%d0%bd%d1%8b%d1%85/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Диван лучше табуретки</title>
		<link>http://saterenko.ru/2009/08/21/%d0%b4%d0%b8%d0%b2%d0%b0%d0%bd-%d0%bb%d1%83%d1%87%d1%88%d0%b5-%d1%82%d0%b0%d0%b1%d1%83%d1%80%d0%b5%d1%82%d0%ba%d0%b8/</link>
		<comments>http://saterenko.ru/2009/08/21/%d0%b4%d0%b8%d0%b2%d0%b0%d0%bd-%d0%bb%d1%83%d1%87%d1%88%d0%b5-%d1%82%d0%b0%d0%b1%d1%83%d1%80%d0%b5%d1%82%d0%ba%d0%b8/#comments</comments>
		<pubDate>Fri, 21 Aug 2009 12:45:34 +0000</pubDate>
		<dc:creator>Андрей Сатеренко</dc:creator>
		
		<category><![CDATA[разное]]></category>

		<category><![CDATA[машина]]></category>

		<guid isPermaLink="false">http://saterenko.ru/?p=117</guid>
		<description><![CDATA[Старенький пассат месяц стоял во дворе, ждал пока хозяин накопит на ремонт. Это был долгий месяц. Непогода покрыла его слоем пыли, хотя нет, в Москве это не пыль, непогода покрыла его слоем грязи. Пока он спал, кто-то подмял ему заднюю дверь. Потом приказал долго жить аккумулятор, но хозяин вовремя поменял его на новый. Пока пассат [...]]]></description>
			<content:encoded><![CDATA[<p>Старенький пассат месяц стоял во дворе, ждал пока хозяин накопит на ремонт. Это был долгий месяц. Непогода покрыла его слоем пыли, хотя нет, в Москве это не пыль, непогода покрыла его слоем грязи. Пока он спал, кто-то подмял ему заднюю дверь. Потом приказал долго жить аккумулятор, но хозяин вовремя поменял его на новый. Пока пассат ждал ремонта, хозяин катался на микре хозяйки, с механикой. Сначала ругался, потом привык и даже стал думать, что маленькая машинка на механике &#8212; это очень даже хорошо.</p>
<p>Во вторник его отвезли в больничку. Не смотря на то, что дорога была близкая, ехал он долго. Четырежды хозяин останавливался, остужал двигатель и доливал холодной воды в радиатор. А сегодня его забрали, здорового и бодренького. Заправили полный бак бензина и поехали кататься. Кататься просто так, а не по делам. Видимо хозяин соскучился, ведь старый диван всегда лучше новой табуретки <img src='http://saterenko.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p>
]]></content:encoded>
			<wfw:commentRss>http://saterenko.ru/2009/08/21/%d0%b4%d0%b8%d0%b2%d0%b0%d0%bd-%d0%bb%d1%83%d1%87%d1%88%d0%b5-%d1%82%d0%b0%d0%b1%d1%83%d1%80%d0%b5%d1%82%d0%ba%d0%b8/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Так ли страшен серый волк?</title>
		<link>http://saterenko.ru/2009/07/28/%d1%82%d0%b0%d0%ba-%d0%bb%d0%b8-%d1%81%d1%82%d1%80%d0%b0%d1%88%d0%b5%d0%bd-%d1%81%d0%b5%d1%80%d1%8b%d0%b9-%d0%b2%d0%be%d0%bb%d0%ba/</link>
		<comments>http://saterenko.ru/2009/07/28/%d1%82%d0%b0%d0%ba-%d0%bb%d0%b8-%d1%81%d1%82%d1%80%d0%b0%d1%88%d0%b5%d0%bd-%d1%81%d0%b5%d1%80%d1%8b%d0%b9-%d0%b2%d0%be%d0%bb%d0%ba/#comments</comments>
		<pubDate>Tue, 28 Jul 2009 07:16:30 +0000</pubDate>
		<dc:creator>Андрей Сатеренко</dc:creator>
		
		<category><![CDATA[программирование]]></category>

		<category><![CDATA[latency]]></category>

		<category><![CDATA[сеть]]></category>

		<category><![CDATA[хранилища]]></category>

		<guid isPermaLink="false">http://saterenko.ru/?p=114</guid>
		<description><![CDATA[Исследовал тему хранилищ типа ключ/значение и обратил внимание, что все тесты на производительность сетевых хранилищ производились в однопоточном режиме. Типа &#8220;Tokyo Cabinet крутая бибилиотека, выдаёт порядка 17К запросов в секунду на дисковой базе данных, но через сеть (Tokyo Tyrant) всего 1.6К запросов в секунду&#8221;, а потом &#8220;latency &#8212; это зло&#8221;. Но почему-то не видел многопоточных [...]]]></description>
			<content:encoded><![CDATA[<p>Исследовал тему хранилищ типа ключ/значение и обратил внимание, что все тесты на производительность сетевых хранилищ производились в однопоточном режиме. Типа &#8220;Tokyo Cabinet крутая бибилиотека, выдаёт порядка 17К запросов в секунду на дисковой базе данных, но через сеть (Tokyo Tyrant) всего 1.6К запросов в секунду&#8221;, а потом &#8220;latency &#8212; это зло&#8221;. Но почему-то не видел многопоточных тестов, как это бывает в реальных web-приложениях со множеством фронтендов. И не видел клиентских библиотек, работающих по событийной схеме, а не по схеме &#8220;послал запрос, жду ответа, ненавижу latency&#8221;. Ведь в этих случаях latency будет не так страшна, или я где-то не прав?</p>
]]></content:encoded>
			<wfw:commentRss>http://saterenko.ru/2009/07/28/%d1%82%d0%b0%d0%ba-%d0%bb%d0%b8-%d1%81%d1%82%d1%80%d0%b0%d1%88%d0%b5%d0%bd-%d1%81%d0%b5%d1%80%d1%8b%d0%b9-%d0%b2%d0%be%d0%bb%d0%ba/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Российская география</title>
		<link>http://saterenko.ru/2009/03/27/%d1%80%d0%be%d1%81%d1%81%d0%b8%d0%b9%d1%81%d0%ba%d0%b0%d1%8f-%d0%b3%d0%b5%d0%be%d0%b3%d1%80%d0%b0%d1%84%d0%b8%d1%8f/</link>
		<comments>http://saterenko.ru/2009/03/27/%d1%80%d0%be%d1%81%d1%81%d0%b8%d0%b9%d1%81%d0%ba%d0%b0%d1%8f-%d0%b3%d0%b5%d0%be%d0%b3%d1%80%d0%b0%d1%84%d0%b8%d1%8f/#comments</comments>
		<pubDate>Fri, 27 Mar 2009 08:12:55 +0000</pubDate>
		<dc:creator>Андрей Сатеренко</dc:creator>
		
		<category><![CDATA[программирование]]></category>

		<category><![CDATA[ipgeobase]]></category>

		<category><![CDATA[maxmind]]></category>

		<category><![CDATA[география]]></category>

		<guid isPermaLink="false">http://saterenko.ru/?p=99</guid>
		<description><![CDATA[Гео-база maxmind окончательно задолбала своими приколами, когда треть Москвы определяется как область в Великобритании. Могу себе представить как она определяет географию для других городов России. В поисках нормальной базы ip-адресов России нашёл ipgeobase.ru. Бесплатная, поддерживаемая, актуальная база для России. Но когда дело дошло до парсинга, меня её формат взбесил. Вместо того, чтобы сделать так, как [...]]]></description>
			<content:encoded><![CDATA[<p>Гео-база maxmind окончательно задолбала своими приколами, когда треть Москвы определяется как область в Великобритании. Могу себе представить как она определяет географию для других городов России. В поисках нормальной базы ip-адресов России нашёл <a href="http://ipgeobase.ru/">ipgeobase.ru</a>. Бесплатная, поддерживаемая, актуальная база для России. Но когда дело дошло до парсинга, меня её формат взбесил. Вместо того, чтобы сделать так, как делают те же maxmind, где последовательно располагаются блоки адресов, они реализовали структуру со множественными вложениями, парсер для которой, без поллитра не напишешь.</p>
<p>Поломав голову над парсером, я его родил и решил выложить доработанный скрипт для тех, кому не хочется мучаться самому <img src='http://saterenko.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Скачать скрипт можно тут: <a href="http://saterenko.ru/files/ipgeobase.php.gz">ipgeobase.php.gz</a>.</p>
<p>Для работы скрипта нужен файл cidr_ru_block.txt из архива <a href="http://ipgeobase.ru/files/db/Main/db_files.tar.gz">db_files.tar.gz</a>. Запускаться скрипт должен в том же каталоге, что и cidr_ru_block.txt. После работы скрипта появляются 3 файла: ipgeobase-states.dat, ipgeobase-cities.dat, ipgeobase-ips.dat. </p>
<p>В ipgeobase-states.dat храняться области в формате [идентификатор области]\t[название области].<br />
В ipgeobase-cities.dat храняться города в формате [идентификатор города]\t[идентификатор области]\t[название города].<br />
В ipgeobase-ips.dat храняться диапазоны ip-адресов в формате [IP от]\t[IP до]\t[идентификатор области]\t[идентификатор города].</p>
<p>При повторном запуске скрипт начитывает данные из ipgeobase-states.dat и ipgeobase-cities.dat (если они есть). Таким образом, при появлении новых городов или областей, идентификаторы &#8220;старых&#8221; записей не изменятся. IP храняться в виде беззнакового 32-битного числа.</p>
<p>Как-то так, надеюсь кому-то мой труд облегчит жизнь <img src='http://saterenko.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>P.S. Исправлена ошибка в скрипте, приводящая к появлению &#8220;левых&#8221; диапазонов, типа 774930432	774930431	92	658, спасибо Виталию (werzer) за наводку.</p>
]]></content:encoded>
			<wfw:commentRss>http://saterenko.ru/2009/03/27/%d1%80%d0%be%d1%81%d1%81%d0%b8%d0%b9%d1%81%d0%ba%d0%b0%d1%8f-%d0%b3%d0%b5%d0%be%d0%b3%d1%80%d0%b0%d1%84%d0%b8%d1%8f/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Такси в День Святого Валентина</title>
		<link>http://saterenko.ru/2009/02/15/%d1%82%d0%b0%d0%ba%d1%81%d0%b8-%d0%b2-%d0%b4%d0%b5%d0%bd%d1%8c-%d1%81%d0%b2%d1%8f%d1%82%d0%be%d0%b3%d0%be-%d0%b2%d0%b0%d0%bb%d0%b5%d0%bd%d1%82%d0%b8%d0%bd%d0%b0/</link>
		<comments>http://saterenko.ru/2009/02/15/%d1%82%d0%b0%d0%ba%d1%81%d0%b8-%d0%b2-%d0%b4%d0%b5%d0%bd%d1%8c-%d1%81%d0%b2%d1%8f%d1%82%d0%be%d0%b3%d0%be-%d0%b2%d0%b0%d0%bb%d0%b5%d0%bd%d1%82%d0%b8%d0%bd%d0%b0/#comments</comments>
		<pubDate>Sun, 15 Feb 2009 09:52:12 +0000</pubDate>
		<dc:creator>Андрей Сатеренко</dc:creator>
		
		<category><![CDATA[разное]]></category>

		<category><![CDATA[такси]]></category>

		<guid isPermaLink="false">http://saterenko.ru/?p=96</guid>
		<description><![CDATA[Вчера возникла необходимость воспользоваться такси для поездки от дома до The Real McCoy на Баррикадной. Google запросу &#8220;такси москва&#8221; выдал кучу предложений. 
В одном месте на звонок не ответили, но перезвонили через 20 минут и, не представившись, спросили зачем звонили. Это было неожиданным, потому что на сайте был указан &#8220;многоканальный телефон&#8221;, а на деле оказался [...]]]></description>
			<content:encoded><![CDATA[<p>Вчера возникла необходимость воспользоваться такси для поездки от дома до <a href="http://www.mccoy.ru/">The Real McCoy</a> на Баррикадной. Google запросу &#8220;такси москва&#8221; выдал кучу предложений. </p>
<p>В одном месте на звонок не ответили, но перезвонили через 20 минут и, не представившись, спросили зачем звонили. Это было неожиданным, потому что на сайте был указан &#8220;многоканальный телефон&#8221;, а на деле оказался мобильный частного таксиста.</p>
<p>Вторым сайтом был <a href="http://www.500-50-50.ru/">www.500-50-50.ru</a>. Вот эти ребята натурально удивили и порадовали. Приятная девушка приняла заказ. Секунд через 10 пришла SMS-ка о том, что заказ принят, с указанием куда и в какое время подать такси. Такси было заказано на 18:30. В районе 16:30 часов пришла SMS-ка с указанием модели машины, госномером, именем водителя и его мобильным телефоном. В 18:25 пришла SMS-ка о том, что такси ждёт у подъезда. Доехали без приключений. Через минуту после приезда пришла SMS-ка со &#8220;спасибками&#8221;, указанием стоимости поездки (290 рублей) и указанием что на накопительный счёт капнуло 14 рублей. В общем, молодцы, порадовали.</p>
]]></content:encoded>
			<wfw:commentRss>http://saterenko.ru/2009/02/15/%d1%82%d0%b0%d0%ba%d1%81%d0%b8-%d0%b2-%d0%b4%d0%b5%d0%bd%d1%8c-%d1%81%d0%b2%d1%8f%d1%82%d0%be%d0%b3%d0%be-%d0%b2%d0%b0%d0%bb%d0%b5%d0%bd%d1%82%d0%b8%d0%bd%d0%b0/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Пулированный связный список</title>
		<link>http://saterenko.ru/2009/02/04/%d0%bf%d1%83%d0%bb%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%bd%d1%8b%d0%b9-%d1%81%d0%b2%d1%8f%d0%b7%d0%bd%d1%8b%d0%b9-%d1%81%d0%bf%d0%b8%d1%81%d0%be%d0%ba/</link>
		<comments>http://saterenko.ru/2009/02/04/%d0%bf%d1%83%d0%bb%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%bd%d1%8b%d0%b9-%d1%81%d0%b2%d1%8f%d0%b7%d0%bd%d1%8b%d0%b9-%d1%81%d0%bf%d0%b8%d1%81%d0%be%d0%ba/#comments</comments>
		<pubDate>Wed, 04 Feb 2009 08:01:45 +0000</pubDate>
		<dc:creator>Андрей Сатеренко</dc:creator>
		
		<category><![CDATA[программирование]]></category>

		<category><![CDATA[c]]></category>

		<category><![CDATA[оптимизация]]></category>

		<category><![CDATA[связные списки]]></category>

		<category><![CDATA[структуры данных]]></category>

		<guid isPermaLink="false">http://saterenko.ru/?p=84</guid>
		<description><![CDATA[Решил поделиться недавно написанной библиотекой для организации связного списка. Реализация должна была производить минимум операций по выделению и освобождению памяти при частых операциях по добавлению, удалению и перемещению элементов внутри списка.
Основная идея, заложенная в реализацию &#8212; это использование пула выделенной памяти. Моя библиотека, реализующая пул памяти, не подразумевает повторное использование памяти, которая была освобождена всвязи [...]]]></description>
			<content:encoded><![CDATA[<p>Решил поделиться недавно написанной библиотекой для организации связного списка. Реализация должна была производить минимум операций по выделению и освобождению памяти при частых операциях по добавлению, удалению и перемещению элементов внутри списка.</p>
<p>Основная идея, заложенная в реализацию &#8212; это использование пула выделенной памяти. Моя библиотека, реализующая пул памяти, не подразумевает повторное использование памяти, которая была освобождена всвязи с удалением элемента. Писать универсальную библиотеку, которая позволяла бы использовать память повторно, не посчитал целесообразным, потому как под разные данные выделяется память разного размера и контроль за свободными кусками снизит производительность пула. В случае со связными списками, мы имеем дело с кусками памяти одного размера, а потому проблем с контролем освобождённых кусков памяти нет.<span id="more-84"></span></p>
<p>В результате получилась библиотека со следующим набором функций:</p>
<p>cor_list_t    *cor_list_init(int size);<br />
int             cor_list_pool_expand(cor_list_t *l);<br />
void           cor_list_destroy(cor_list_t *l);</p>
<p>cor_list_init &#8212; инициализация списка заданного размера (минимальный размер установлен в 16 элементов). Каждый раз, при добавлении нового элемента, когда не останеться свободных, пул будет расширятся на заданный размер. Размер стоит подобрать так, чтобы операции расширения были как можно более редкими.</p>
<p>cor_list_pool_expand &#8212; расширение списка. Эта функция вызывается при вставке новых элементов, если свободных нет. Принудительно вызывать эту функцию не требуется.</p>
<p>cor_list_destroy &#8212; освобождение памяти, занятой списком. </p>
<p>Остальные функции работы со списком написаны в виде макросов, для увеличения скорости работы:</p>
<p>#define cor_list_insert_head(_pv, _l)<br />
#define cor_list_insert_tail(_pv, _l)<br />
#define cor_list_insert_after(_pv1, _pv2, _l)<br />
#define cor_list_insert_before(_pv1, _pv2, _l)<br />
#define cor_list_delete(_pv, _l)<br />
#define cor_list_move_head(_pv, _l)<br />
#define cor_list_move_tail(_pv, _l)<br />
#define cor_list_first(_pv, _l)<br />
#define cor_list_last(_pv, _l)<br />
#define cor_list_next(_pv)<br />
#define cor_list_prev(_pv)<br />
#define cor_list_value(_pv)</p>
<p>cor_list_insert_head &#8212; вставка новго элемента (_pv) в начало списка (_l). _pv &#8212; это указатель, который указывает на встравленный элемент.</p>
<p>cor_list_insert_tail &#8212; вставка нового элемента (_pv) в конец списка (_l).</p>
<p>cor_list_insert_after &#8212; вставка нового элемента (_pv1) после элемента (_pv2) в списке (_l). </p>
<p>cor_list_insert_before &#8212; вставка нового элемента (_pv1) перед элементом (_pv2) в списке (_l).</p>
<p>cor_list_delete &#8212; удаление элемента (_pv) из списка (_l).</p>
<p>cor_list_move_head &#8212; перемещение элемента (_pv) в начало списка (_l).</p>
<p>cor_list_move_tail &#8212; перемещение элемента (_pv) в конец списка (_l).</p>
<p>cor_list_first &#8212; получение в _pv первого элемента в списке (_l).</p>
<p>cor_list_last &#8212; получение в _pv последнего элемента в списке (_l).</p>
<p>cor_list_next &#8212; получение в _pv элемента, следующего за элементом _pv. Т.е. в _pv передаётся текущий элемент, и в него же сохраняется следующий. Если достигнут конец списка, возвращается NULL.</p>
<p>cor_list_prev &#8212; получение в _pv элемента, предыдущего, по отношению к элементу _pv.</p>
<p>cor_list_value &#8212; получение значения элемента _pv.</p>
<p>Исходники: <a href="http://saterenko.ru/files/cor_list.h">cor_list.h</a>, <a href="http://saterenko.ru/files/cor_list.c">cor_list.c</a>.</p>
<p>Если кому-то пригодится, буду рад <img src='http://saterenko.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://saterenko.ru/2009/02/04/%d0%bf%d1%83%d0%bb%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%bd%d1%8b%d0%b9-%d1%81%d0%b2%d1%8f%d0%b7%d0%bd%d1%8b%d0%b9-%d1%81%d0%bf%d0%b8%d1%81%d0%be%d0%ba/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>

