tag:blogger.com,1999:blog-39005140354705744802024-03-12T17:17:29.642-07:00valmat личный блогvalmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.comBlogger31125tag:blogger.com,1999:blog-3900514035470574480.post-55553473578423387732016-02-21T07:35:00.001-08:002016-02-21T07:35:51.624-08:00Мой первый Arduino проектПару лет назад подарили отцу на день рождения лодочный электро мотор и литиевый тяговый аккумулятор к нему. Хорошая вещь. Сплошные положительные эмоции от использования. Но, как оказалось, мотор не рассчитан на работу с этим аккумулятором. В том смысле, что индикация уровня заряда на корпусе мотора оказалось совершенно не адекватной.
<br />
Решил попробовать сделать необходимый девайс на Ардуино.
<br />
<br />
До этого с микроконтроллерами дела не имел. Оказалось это совсем не сложно и даже интересно.
<br />
Исходники выложил на Гитхаб: <a href="https://github.com/valmat/BatterySensor">https://github.com/valmat/BatterySensor</a>
<br />
<br />
Документация там же.
Прибор умеет отображать уровень заряда батареи в процентах, с помощью значка, а также тремя RGB светодиодами. Которые постепенно меняют свои цвета с зеленого на желтый потом на красный. В зависимости от уровня заряда.
<br />
<br />
На корпусе расположил выключатель и кнопку. Кнопка выключает светодиоды, а долгое нажатие кнопки отключает подсветку экрана. Для экономии батареи в солнечный день и что бы не слепило ночью.
<br />
<br />
Кроме того, подключил датчик BMP180. Устройство показывает температуру и давление. Давление на рыбалке знать необходимо.
<br />
Корпус сделал герметичным. Все проклеил резиновым клеем, а сверху заклеил алюминиевым скотчем.
<br />
Работает надежно. Показания точные.
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQwsjbYMhtcJHgqreMoXZOruvmB8kaP9HGfLYTFxK_XPGxmKfbq7hoOs4NWYIdfMADTJnQdMWr6sokxlKgRlXtSE4dOpPJyvhQCSg2zw5wUUh65jOEVgH8bLGuOgZwKfENc1omegtiKZ0/s1600/3.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQwsjbYMhtcJHgqreMoXZOruvmB8kaP9HGfLYTFxK_XPGxmKfbq7hoOs4NWYIdfMADTJnQdMWr6sokxlKgRlXtSE4dOpPJyvhQCSg2zw5wUUh65jOEVgH8bLGuOgZwKfENc1omegtiKZ0/s320/3.JPG" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghOWYrFYXq7oQiC7rOtP1H9-qa6UBCMokgqLXwlfvG_UEnbgK80p-T6j3q1ocinlLLyeadrkcpGMDWlTfj-98wYdmHCKomhN8Dhzlm68SbnekD9ckC36506zD4jRPWrWwVonCWxwFkpM8/s1600/4.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghOWYrFYXq7oQiC7rOtP1H9-qa6UBCMokgqLXwlfvG_UEnbgK80p-T6j3q1ocinlLLyeadrkcpGMDWlTfj-98wYdmHCKomhN8Dhzlm68SbnekD9ckC36506zD4jRPWrWwVonCWxwFkpM8/s320/4.JPG" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwiT3zHXbJ2KNsxbolidcGPX8Yz3F_FQJTrx5MrZ7pPwaZIwnMdLsW0sW2u4_h1mXqpnzRzwyQGJFdSHwRnQFIIxTJTEWL2WjWSBAR6FObIox6EVRvZyz7r-8tRkT1xUljzJfhb-kHL78/s1600/5.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwiT3zHXbJ2KNsxbolidcGPX8Yz3F_FQJTrx5MrZ7pPwaZIwnMdLsW0sW2u4_h1mXqpnzRzwyQGJFdSHwRnQFIIxTJTEWL2WjWSBAR6FObIox6EVRvZyz7r-8tRkT1xUljzJfhb-kHL78/s320/5.JPG" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGj3Wc_xOXx6e7rc9B_CrRcl2eyNGilrvQjoJ3SMLXah1l8Nc0x_X33swJG31771JGyjhRZnFwMUVSWtcy8pw8HNzVHMZNAVCkpqAXTiCJmdno3Bd5Ex_JD-_Vnh0pYWuOv3HfubvWMhQ/s1600/10.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGj3Wc_xOXx6e7rc9B_CrRcl2eyNGilrvQjoJ3SMLXah1l8Nc0x_X33swJG31771JGyjhRZnFwMUVSWtcy8pw8HNzVHMZNAVCkpqAXTiCJmdno3Bd5Ex_JD-_Vnh0pYWuOv3HfubvWMhQ/s320/10.jpg" /></a></div>
valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-47565080945269078412014-11-18T08:38:00.001-08:002014-11-20T08:51:56.072-08:00Определение по списку в C++В php есть возможность присвоить переменным значения используя массив.
<br />
<blockquote>
<span style="color: #990000;">list</span><span style="color: #009900;">(</span><span style="color: #000088;">$a</span><span style="color: #339933;">,</span> <span style="color: #000088;">$b</span><span style="color: #009900;">)</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">(</span><span style="color: blue;">'str1'</span><span style="color: #339933;">,</span> <span style="color: blue;">'str2'</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></blockquote>
В pyton, вроде есть что то вроде этого:
<br />
<blockquote>
a<span style="color: #339933;">,</span> b <span style="color: #339933;">=</span> <span style="color: #009900;">[</span><span style="color: blue;">'str1'</span><span style="color: #339933;">,</span> <span style="color: blue;">'str2'</span><span style="color: #009900;">]</span><span style="color: #339933;">;</span></blockquote>
А вот в C++ такой языковой конструкции нет. Но это совершенно не проблема, потому что ее можно сделать самому.
Вот что у меня получилось<br />
<br />
<blockquote><font color="#ff0000">/**<br/>
* This is a helper class.<br/>
* It can be used only inside the function ListInitializer tolist(Args&& ...args)<br/>
* ListInitializer list(Args&& ...args)<br/>
* In all other cases, use it not possible<br/>
* size is the number of arguments with which the constructor was called<br/>
*/</font> <br/>
<font color="#0000ff">template</font><font color="#000080"><</font><font color="#0000ff">typename</font> DataType, <font color="#0000ff">unsigned</font> size<font color="#000080">></font><br/>
<font color="#0000ff">class</font> ListInitializer<br/>
<font color="#008000">{</font><br/>
<font color="#0000ff">public</font><font color="#008080">:</font><br/>
<br/>
<font color="#ff0000">/**<br/>
* Assignment operator<br/>
* Ref-qualified forbids such things:<br/>
* ListInitializer c(a,b);<br/>
* c = arr;<br/>
* You can only use this form:<br/>
* ListInitializer(a,b) = arr;<br/>
* VecType must be convertable to DataType<br/>
*/</font><br/>
<font color="#0000ff">template</font><font color="#000080"><</font><font color="#0000ff">typename</font> ContainerType<font color="#000080">></font><br/>
ListInitializer <font color="#000040">&</font>operator<font color="#000080">=</font><font color="#008000">(</font>ContainerType <font color="#000040">&&</font>arr<font color="#008000">)</font> <font color="#000040">&&</font> <font color="#666666">// <-- Ref-qualified</font><br/>
<font color="#008000">{</font><br/>
<font color="#0000ff">auto</font> it <font color="#000080">=</font> arr.<font color="#007788">begin</font><font color="#008000">(</font><font color="#008000">)</font>, itend <font color="#000080">=</font> arr.<font color="#007788">end</font><font color="#008000">(</font><font color="#008000">)</font><font color="#008080">;</font><br/>
<font color="#0000ff">unsigned</font> i <font color="#000080">=</font> <font color="#0000dd">0</font><font color="#008080">;</font><br/>
<font color="#0000ff">while</font><font color="#008000">(</font>it <font color="#000040">!</font><font color="#000080">=</font> itend <font color="#000040">&&</font> i <font color="#000080"><</font> size<font color="#008000">)</font> <font color="#008000">{</font><br/>
<font color="#000040">*</font>parr<font color="#008000">[</font>i<font color="#008000">]</font> <font color="#000080">=</font> <font color="#000040">*</font>it<font color="#008080">;</font><br/>
<font color="#000040">++</font>it<font color="#008080">;</font><br/>
<font color="#000040">++</font>i<font color="#008080">;</font><br/>
<font color="#008000">}</font><br/>
<font color="#0000ff">return</font> <font color="#000040">*</font><font color="#0000dd">this</font><font color="#008080">;</font><br/>
<font color="#008000">}</font><br/>
<br/>
<font color="#ff0000">/**<br/>
* Deleted constructors. Forbids such things:<br/>
* tolist q(a,b,c,d,e),w(a,b,c,d,e);<br/>
* w = q;<br/>
* You can only use this form:<br/>
* tolist(a,b,c,d,e) = arr;<br/>
*/</font><br/>
ListInitializer<font color="#008000">(</font><font color="#0000ff">const</font> ListInitializer <font color="#000040">&</font>that<font color="#008000">)</font> <font color="#000080">=</font> <font color="#0000dd">delete</font><font color="#008080">;</font><br/>
ListInitializer<font color="#008000">(</font><font color="#008000">)</font> <font color="#000080">=</font> <font color="#0000dd">delete</font><font color="#008080">;</font><br/>
<br/>
<br/>
<font color="#0000ff">private</font><font color="#008080">:</font><br/>
<font color="#ff0000">/**<br/>
* Constructor with one argument<br/>
*/</font><br/>
<font color="#0000ff">explicit</font> ListInitializer<font color="#008000">(</font>DataType<font color="#000040">&</font> arg<font color="#008000">)</font> <font color="#666666">//: size(1)</font><br/>
<font color="#008000">{</font><br/>
helper<font color="#008000">(</font><font color="#0000dd">0</font>, arg<font color="#008000">)</font><font color="#008080">;</font><br/>
<font color="#008000">}</font><br/>
<br/>
<font color="#ff0000">/**<br/>
* Constructor with a variable (>1) number of arguments<br/>
* You can use any number of arguments of type DataType in the constructor.<br/>
* tolist(a,b,c,d) = arr;<br/>
* tolist(a,b) = arr;<br/>
*/</font><br/>
<font color="#0000ff">template</font> <font color="#000080"><</font><font color="#0000ff">typename</font> ...<font color="#007788">Args</font><font color="#000080">></font><br/>
ListInitializer<font color="#008000">(</font>DataType<font color="#000040">&</font> arg0, Args<font color="#000040">&</font>... <font color="#007788">args</font><font color="#008000">)</font> <font color="#666666">//: size(sizeof...(Args)+1)</font><br/>
<font color="#008000">{</font><br/>
helper<font color="#008000">(</font><font color="#0000dd">0</font>, arg0, args...<font color="#008000">)</font><font color="#008080">;</font><br/>
<font color="#008000">}</font><br/>
<br/>
<font color="#ff0000">/**<br/>
* Move constructor<br/>
*/</font><br/>
ListInitializer<font color="#008000">(</font>ListInitializer <font color="#000040">&&</font>that<font color="#008000">)</font><br/>
<font color="#008000">{</font><br/>
<font color="#0000ff">for</font><font color="#008000">(</font><font color="#0000ff">unsigned</font> i <font color="#000080">=</font> <font color="#0000dd">0</font><font color="#008080">;</font> i <font color="#000080"><</font> size<font color="#008080">;</font> i<font color="#000040">++</font><font color="#008000">)</font> <font color="#008000">{</font><br/>
parr<font color="#008000">[</font>i<font color="#008000">]</font> <font color="#000080">=</font> that.<font color="#007788">parr</font><font color="#008000">[</font>i<font color="#008000">]</font><font color="#008080">;</font><br/>
that.<font color="#007788">parr</font><font color="#008000">[</font>i<font color="#008000">]</font> <font color="#000080">=</font> nullptr<font color="#008080">;</font><br/>
<font color="#008000">}</font><br/>
<font color="#008000">}</font><br/>
<br/>
<font color="#ff0000">/**<br/>
* Helper method.<br/>
* Allows to initialize the list of any number of arguments.<br/>
* Alternately, one by one makes pointers to the arguments into the internal array.<br/>
*/</font><br/>
<font color="#0000ff">template</font> <font color="#000080"><</font><font color="#0000ff">typename</font> ...<font color="#007788">Args</font><font color="#000080">></font><br/>
<font color="#0000ff">void</font> helper<font color="#008000">(</font><font color="#0000ff">int</font> ind, DataType<font color="#000040">&</font> arg0, Args<font color="#000040">&</font>... <font color="#007788">args</font><font color="#008000">)</font><br/>
<font color="#008000">{</font><br/>
helper<font color="#008000">(</font>ind, arg0<font color="#008000">)</font><font color="#008080">;</font><br/>
helper<font color="#008000">(</font><font color="#000040">++</font>ind, args...<font color="#008000">)</font><font color="#008080">;</font><br/>
<font color="#008000">}</font><br/>
<br/>
<font color="#ff0000">/**<br/>
* Helper method.<br/>
*/</font><br/>
<font color="#0000ff">void</font> helper<font color="#008000">(</font><font color="#0000ff">int</font> ind, DataType<font color="#000040">&</font> arg0<font color="#008000">)</font><br/>
<font color="#008000">{</font><br/>
parr<font color="#008000">[</font>ind<font color="#008000">]</font> <font color="#000080">=</font> <font color="#000040">&</font>arg0<font color="#008080">;</font><br/>
<font color="#008000">}</font><br/>
<br/>
<font color="#0000ff">template</font> <font color="#000080"><</font><font color="#0000ff">typename</font> T, <font color="#0000ff">typename</font> ...<font color="#007788">Args</font><font color="#000080">></font><br/>
<font color="#0000ff">friend</font> ListInitializer<font color="#000080"><</font>T, <font color="#0000dd">sizeof</font>...<font color="#008000">(</font>Args<font color="#008000">)</font><font color="#000040">+</font><font color="#0000dd">1</font><font color="#000080">></font> tolist<font color="#008000">(</font>T<font color="#000040">&</font> arg0, Args<font color="#000040">&</font>... <font color="#007788">args</font><font color="#008000">)</font><font color="#008080">;</font><br/>
<br/>
<font color="#666666">// Internal array of pointers to pointers to arguments</font><br/>
DataType<font color="#000040">*</font> parr<font color="#008000">[</font>size<font color="#008000">]</font><font color="#008080">;</font><br/>
<br/>
<font color="#008000">}</font><font color="#008080">;</font><br/>
<br/>
<br/>
<font color="#0000ff">template</font> <font color="#000080"><</font><font color="#0000ff">typename</font> DataType, <font color="#0000ff">typename</font> ...<font color="#007788">Args</font><font color="#000080">></font><br/>
ListInitializer<font color="#000080"><</font>DataType, <font color="#0000dd">sizeof</font>...<font color="#008000">(</font>Args<font color="#008000">)</font><font color="#000040">+</font><font color="#0000dd">1</font><font color="#000080">></font> tolist<font color="#008000">(</font>DataType<font color="#000040">&</font> arg0, Args<font color="#000040">&</font>... <font color="#007788">args</font><font color="#008000">)</font><br/>
<font color="#008000">{</font><br/>
<font color="#0000ff">return</font> ListInitializer<font color="#000080"><</font>DataType, <font color="#0000dd">sizeof</font>...<font color="#008000">(</font>Args<font color="#008000">)</font><font color="#000040">+</font><font color="#0000dd">1</font><font color="#000080">></font><font color="#008000">(</font>arg0, args...<font color="#008000">)</font><font color="#008080">;</font><br/>
<font color="#008000">}</font><br/>
<br/>
<br/>
<font color="#666666">// Check</font><br/>
<font color="#339900">#include <iostream></font><br/>
<font color="#339900">#include <vector></font><br/>
<font color="#0000ff">int</font> main<font color="#008000">(</font><font color="#008000">)</font><font color="#008000">{</font><br/>
<br/>
std<font color="#008080">::</font><font color="#007788">vector</font><font color="#000080"><</font>std<font color="#008080">::</font><font color="#007788">string</font><font color="#000080">></font> arr<font color="#008000">{</font><font color="#FF0000">"str1"</font>,<font color="#FF0000">"str2"</font>,<font color="#FF0000">"str3"</font>,<font color="#FF0000">"str4"</font>,<font color="#FF0000">"str5"</font>,<font color="#FF0000">"str6"</font><font color="#008000">}</font><font color="#008080">;</font><br/>
std<font color="#008080">::</font><font color="#007788">string</font> a,b,c,d,e<font color="#008080">;</font><br/>
<br/>
tolist<font color="#008000">(</font>b<font color="#008000">)</font> <font color="#000080">=</font> arr<font color="#008080">;</font><br/>
std<font color="#008080">::</font><font color="#0000dd">cout</font> <font color="#000080"><<</font> std<font color="#008080">::</font><font color="#007788">endl</font> <font color="#000080"><<</font> a <font color="#000080"><<</font> <font color="#FF0000">" "</font> <font color="#000080"><<</font> b <font color="#000080"><<</font> <font color="#FF0000">" "</font> <font color="#000080"><<</font> c <font color="#000080"><<</font> <font color="#FF0000">" "</font> <font color="#000080"><<</font> d <font color="#000080"><<</font> <font color="#FF0000">" "</font> <font color="#000080"><<</font> e <font color="#000080"><<</font> std<font color="#008080">::</font><font color="#007788">endl</font><font color="#008080">;</font><br/>
<br/>
tolist<font color="#008000">(</font>a,b,c,d,e<font color="#008000">)</font> <font color="#000080">=</font> arr<font color="#008080">;</font><br/>
std<font color="#008080">::</font><font color="#0000dd">cout</font> <font color="#000080"><<</font> std<font color="#008080">::</font><font color="#007788">endl</font> <font color="#000080"><<</font> a <font color="#000080"><<</font> <font color="#FF0000">" "</font> <font color="#000080"><<</font> b <font color="#000080"><<</font> <font color="#FF0000">" "</font> <font color="#000080"><<</font> c <font color="#000080"><<</font> <font color="#FF0000">" "</font> <font color="#000080"><<</font> d <font color="#000080"><<</font> <font color="#FF0000">" "</font> <font color="#000080"><<</font> e <font color="#000080"><<</font> std<font color="#008080">::</font><font color="#007788">endl</font><font color="#008080">;</font><br/>
<br/>
<font color="#0000ff">return</font> <font color="#0000dd">0</font><font color="#008080">;</font><br/>
<font color="#008000">}</font><font color="#008080">;</font><br/>
<br/>
<font color="#ff0000">/*<br/>
* g++ tolist.cpp -std=c++11 && ./a.out<br/>
* or <br/>
* clang++ tolist.cpp -std=c++11 && ./a.out<br/>
*<br/>
* |output:<br/>
* | str1 <br/>
* |<br/>
* |str1 str2 str3 str4 str5<br/>
*<br/>
*<br/>
*/</font></blockquote>
<br />
Нужен C++11 т.к. используется Ref-qualifiers
PS blogger.com как всегда портит код. Надо менять блогодвижок.valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com2tag:blogger.com,1999:blog-3900514035470574480.post-66475990203430187112014-08-20T23:00:00.001-07:002014-08-22T06:47:36.279-07:00Микро-бенчмарк RocksDB serverВ полноценном смысле то что я тут хочу написать, конечно бенчмарком не является. Но вполне способно дать понимание области применения RocksDB.<br />
<br />
RocksDB -- это довольно таки крутое хранилище, являющееся (на данный момент) встраиваемым решением.<br />
Главной фишкой RocksDB является то, что она рассчитана на использование на flash накопителях. Т.е. на SSD дисках.<br />
<br />
Лично я давно ждал появления таких решений. Поскольку память все еще дорагая, а жесткие диски медленные. Поэтому использование SSD для хранения данных -- очень логичный шаг.<br />
<br />
Как я уже говорил, RocksDB -- встраиваемое решение. И не является сервером. Я честно ждал почти год, когда кто нибудь напишет или хотя бы начнет писать серверную обертку над ней. Но то что появилось за это время по разным причинам категорически меня не устраивает.<br />
<div style="margin-bottom: 0cm;">
Поэтому я написал собственную серверную обертку:<span style="font-family: Arial, sans-serif;"><a href="https://github.com/valmat/RocksServer"> https://github.com/valmat/RocksServer</a>. В настоящее время вполне функционален, протестирован и готов к работе. Но есть еще моменты требующие улучшения. Эти моменты ни как не связаны с его пригодностью к использованию, поэтому ничто не мешает уже сейчас произвести замеры производительности.</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Arial, sans-serif;"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Arial, sans-serif;">Замеры я осуществлял с помощью идущего в комплекте с сервером драйвера для PHP. Во первых мне так было удобнее, а во вторых использовать я его в ближайшее время буду из PHP.</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Arial, sans-serif;"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Arial, sans-serif;">Итак, табличка.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Arial, sans-serif;">MultiGet со случайными ключами.<br /><br />Условия проведения эксперимента:<br />В бд 1000000 ключей. Выбирается набор случайных ключей в случайном порядке.<br />Кэш
не используется. Прямо перед экспериментом я перезагрузил компьютер что
бы полностью исключить возможность использования файлового кэша.<br />Хранимые значения имеют длину 50 +-5 байт</span></div>
<table border="1" cellpadding="5" cellspacing="0"><tbody>
<tr><td>Количество<br />
ключей в выборке</td><td>SDD</td><td>HDD</td></tr>
<tr><td>50</td><td>4.7 ms</td><td>131.3 ms</td></tr>
<tr><td>300</td><td>12.6 ms</td><td>2371.4 ms (~2s)</td></tr>
<tr><td>1000</td><td>29.5 ms</td><td>7918.4 ms (~8s)</td></tr>
<tr><td>10 000</td><td>124.6 ms</td><td>45229.5 ms (~45s)</td></tr>
<tr><td>100 000</td><td>2346.6 ms</td><td>51855.8 ms (~56s)</td></tr>
</tbody></table>
<br />
<div style="margin-bottom: 0cm;">
<br />
Следует отметить, что после попадания ключей в кэш скорость выборки на HDD возрастает и приближается к скорости выборки на SDD.</div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
Какие выводы можно сделать из таблички? RocksDB действительно очень быстрое хранилище и подходит для использования ее на SDD дисках.</div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
PS Сама RocksDB обладает очень богатыми возможностями. В настоящий момент я реализовал лишь базовый необходимый мне функционал. В дальнейшем, постепенно я планирую наращивать функциональные возможности RocksServer.</div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<br /></div>
valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-30193452891702095032014-05-31T14:18:00.000-07:002014-05-31T14:18:04.070-07:00Сlang vs gcc performanceСтало мне интересно и решил я провести такую глупую проверку: сравнить производительность программ откомпилированных Clang'ом и gcc<br />
<br />
Для эксперимента взял первую попавшуюся реализацию пузырьковой сортировки с GitHub'а<br />
<br />
Компилировал с опциями -g, -O1, -O2, -O3 и без опций<br />
<br />
Получилось интересно и неожиданно.<br />
<br />
Для запуска тестов использовал такой скрипт:<br />
<blockquote>
<span style="color: #666666;">#!/bin/bash</span><br />
<br />
<span style="color: #007800;">OPT</span>=<span style="color: red;">"-O3"</span><br />
<span style="color: #c20cb9;">g++</span> <span style="color: #007800;">$OPT</span> bubble.cpp <span style="color: #660033;">-o</span> bubble1<br />
clang++ <span style="color: #007800;">$OPT</span> bubble.cpp <span style="color: #660033;">-o</span> bubble2 <span style="color: #666666;">#-stdlib=libstdc++</span><br />
clang++ <span style="color: #007800;">$OPT</span> <span style="color: #660033;">-stdlib</span>=libc++ bubble.cpp <span style="color: #660033;">-o</span> bubble3 <span style="color: #666666;">#-stdlib=libc++</span><br />
<br />
<span style="color: #666666;">#ls -slh</span><br />
<span style="color: #666666;">#exit;</span><br />
<br />
<span style="color: #c20cb9;">sleep</span> <span style="color: black;">3</span><br />
<span style="color: black;">time</span> .<span style="color: black;">/</span>bubble1 ><span style="color: black;"></span> <span style="color: black;">/</span>dev<span style="color: black;">/</span>null<br />
<span style="color: #c20cb9;">sleep</span> <span style="color: black;">3</span><br />
<span style="color: black;">time</span> .<span style="color: black;">/</span>bubble2 ><span style="color: black;"></span> <span style="color: black;">/</span>dev<span style="color: black;">/</span>null<br />
<span style="color: #c20cb9;">sleep</span> <span style="color: black;">3</span><br />
<span style="color: black;">time</span> .<span style="color: black;">/</span>bubble3 ><span style="color: black;"></span> <span style="color: black;">/</span>dev<span style="color: black;">/</span>null</blockquote>
Меняя параметр <span style="color: #007800;">OPT</span>.<br />
Поясню, что здесь компилируется. <br />
<br />
<span style="color: #c20cb9;">g++</span> <span style="color: #007800;">$OPT</span> bubble.cpp <span style="color: #660033;">-o</span> bubble1 <br />
Используется <b>gcc </b><br />
<br />
clang++ <span style="color: #007800;">$OPT</span> bubble.cpp <span style="color: #660033;">-o</span> bubble2 <span style="color: #666666;">#-stdlib=libstdc++</span><br />
<br />
Используется <b>clang</b> со стандартной библиотекой <b>libstdc++</b> от gcc<br />
<br />
clang++ <span style="color: #007800;">$OPT</span> <span style="color: #660033;">-stdlib</span>=libc++ bubble.cpp <span style="color: #660033;">-o</span> bubble3 <span style="color: #666666;">#-stdlib=libc++</span><br />
Используется <b>clang</b> со своей собственной стандартной библиотекой <b>libc++</b><br />
<br />
<br />
<table align="center" border="1" cellpadding="5" cellspacing="0">
<tbody>
<tr>
<th valign="top">Опция</th>
<th valign="top">gcc</th>
<th valign="top">clang -stdlib=libstdc++ (gcc)</th>
<th valign="top">clang -stdlib=libc++</th>
</tr>
<tr>
</tr>
<tr>
<td valign="top">-g</td>
<td valign="top">real <b>0m3.337</b>s<br />
user 0m3.335s<br />
sys 0m0.004s</td>
<td valign="top">real <b>0m3.294</b>s<br />
user 0m3.296s<br />
sys 0m0.000s</td>
<td valign="top">real <b>0m3.323</b>s<br />
user 0m3.325s<br />
sys 0m0.000s</td>
</tr>
<tr>
</tr>
<tr>
<td valign="top">без опций</td>
<td valign="top">real <b>0m3.334</b>s<br />
user 0m3.336s<br />
sys 0m0.000s</td>
<td valign="top">real <b>0m3.293</b>s<br />
user 0m3.295s<br />
sys 0m0.000s</td>
<td valign="top">real <b>0m3.320</b>s<br />
user 0m3.318s<br />
sys 0m0.004s</td>
</tr>
<tr>
</tr>
<tr>
<td valign="top">-O1</td>
<td valign="top">real <b>0m1.735</b>s<br />
user 0m1.735s<br />
sys 0m0.000s</td>
<td valign="top">real <b>0m1.485</b>s<br />
user 0m1.486s<br />
sys 0m0.000s</td>
<td valign="top">real <b>0m1.493</b>s<br />
user 0m1.494s<br />
sys 0m0.000s</td>
</tr>
<tr>
</tr>
<tr>
<td valign="top">-O2</td>
<td valign="top">real <b>0m1.516</b>s<br />
user 0m1.517s<br />
sys 0m0.000s</td>
<td valign="top">real <b>0m1.522</b>s<br />
user 0m1.523s<br />
sys 0m0.000s</td>
<td valign="top">real <b> 0m1.495</b>s<br />
user 0m1.492s<br />
sys 0m0.004s</td>
</tr>
<tr>
</tr>
<tr>
<td valign="top">-O3</td>
<td valign="top">real <b>0m1.510</b>s<br />
user 0m1.506s<br />
sys 0m0.004s</td>
<td valign="top">real <b>0m1.534</b>s<br />
user 0m1.535s<br />
sys 0m0.000s</td>
<td valign="top">real <b>0m1.498</b>s<br />
user 0m1.499s<br />
sys 0m0.000s</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Размеры бинарников:<br />
<table align="center" border="1" cellpadding="5" cellspacing="0">
<tbody>
<tr>
<th valign="top">Опция</th>
<th valign="top">gcc</th>
<th valign="top">clang -stdlib=libstdc++ (gcc)</th>
<th valign="top">clang -stdlib=libc++</th>
</tr>
<tr>
</tr>
<tr>
<td valign="top">-g</td>
<td valign="top">22K</td>
<td valign="top">28K</td>
<td valign="top">65K</td>
</tr>
<tr>
</tr>
<tr>
<td valign="top">без опций</td>
<td valign="top">9,2K<br />
</td>
<td valign="top">8,3K</td>
<td valign="top">15K</td>
</tr>
<tr>
</tr>
<tr>
<td valign="top">-O1</td>
<td valign="top">8,9K</td>
<td valign="top">8,4K</td>
<td valign="top">12K</td>
</tr>
<tr>
</tr>
<tr>
<td valign="top">-O2</td>
<td valign="top">8,9K</td>
<td valign="top">8,1K</td>
<td valign="top">12K</td>
</tr>
<tr>
</tr>
<tr>
<td valign="top">-O3</td>
<td valign="top">8,9K</td>
<td valign="top">8,1K</td>
<td valign="top">12K</td>
</tr>
<tr>
</tr>
</tbody></table>
<br />
Понятно, что по такому примеру корректно сравнивать компиляторы нельзя, но для меня как для приверженца GNU компилятора результаты получились неожиданными.<br />
По сути clang превзошел gcc во всех направлениях.<br />
Для меня основной вывод такой:<br />
Clang заслуживает внимания и заслуживает того, что бы к нему присмотреться. Тем более сообщения об ошибках которые он выдает информативнее чем сообщения выдаваемые gcc.<br />
<br />
До этого я никогда не пользовался клэнгом (силангом). Сталкнулся с ним по необходимости. Думаю, что стоит попробовать использовать его в своей работе.<br />
<br />
Мои версии clang и gcc:<br />
<br />
<b>gcc version 4.8.1</b> (Ubuntu/Linaro 4.8.1-10ubuntu9)<br />
Debian <b>clang version 3.2</b>-7ubuntu1 (tags/RELEASE_32/final) (based on LLVM 3.2) valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com2tag:blogger.com,1999:blog-3900514035470574480.post-71644697839617244452014-03-20T03:43:00.003-07:002014-03-20T04:02:30.061-07:00отчетность в налоговую на LinuxКак я готовлю отчетность в налоговую.<br />
Выписки у меня достаются в таком формате:<br />
2014.01.20.rtf<br />
2014.01.20-1.rtf<br />
...<br />
В первую очередь, нужно упорядочить по дате, поэтому переименовываем:<br />
for i in `find . -type f -name "*.rtf*"`; do dst=`echo $i | sed -e :a -e 's/\(.*\)\([0-9]\{2\}\)\.\([0-9]\{2\}\)\.\([0-9]\{4\}\)\(.*\)/\1\4.\3.\2\5/;ta'`; echo mv $i $dst; done<br />
<br />
Потом конвертируем в pdf<br />
libreoffice --invisible --convert-to pdf *.rtf<br />
И соединяем все в один файл<br />
<br />
gs -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=toprint.pdf -dBATCH `find . -type f -name "*.pdf" | sort`<br />
<br />
Все.valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-57175314589436812722014-03-10T11:42:00.000-07:002014-06-30T11:58:40.418-07:00Документация PHP-CPPУ PHP-CPP появился раздел с <a href="http://www.php-cpp.com/documentation" target="_blank">документацией</a>.<br />
Вообще разработка библиотеки идет семимильными шагами и похоже не долго осталось ждать первого рабочего релиза. Когда будет готово, напишу подробнее про саму библиотеку и ее возможности.<br />
<br />
<br />
<hr />
<br />
PS вместо того, что бы что то писать здесь про библиотеку, я просто взял и начал переводить документацию на русский язык: <a href="http://phpcpp.ru/">http://phpcpp.ru/</a>
<br />
<br />
Основная цель этого перевода -- познакомить рускоязычное сообщество с библиотекой.<br />
Перевод вольный. Поскольку многие вещи в библиотеке так или иначе сделаны с моим участием (да и просто потому что я уже достаточно хорошо в ней разобрался) мой перевод во многих местах дополняет и расширяет оригинальный текст.valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-29773340380450293952014-01-12T07:11:00.003-08:002014-01-12T07:45:20.426-08:00Сравнение производительности C++ php-расширения php с нативным кодомДавно меня интересовал вопрос насколько добавляет производительности переписывание нативного кода в php-расширение.<br />
<br />
И вот я решил провести сравнение.<br />
В качестве платформы для написания расширения была выбрана библиотека <a href="https://github.com/CopernicaMarketingSoftware/PHP-CPP" target="_blank">PHP-CPP</a>.<br />
<br />
<b>Пару слов о самой библиотеке PHP-CPP.</b><br />
Довольно неплохая библиотека. Работать с ней приятно и удобно. Честно говоря, никогда еще не было так легко писать расширения для php.<br />
Из минусов могу отметить недостаток документации. Что бы разобраться с некоторыми вещами недостаточно даже примеров, которыми автор снабжает код - приходится смотреть исходники. В частности я так и не разобрался, как перенести статический метод класса из C++ в статический же метод в php.<br />
Основана она на C++11 т.е. на старых дистрибутивах может потребоваться обновить gcc.<br />
<br />
В качестве подопытного был выбран модуль постраничного разбиения.<br />
Исходники на Гитхабе: <a href="https://github.com/valmat/myscrnav">https://github.com/valmat/myscrnav</a><br />
Я написал два идентичных класса. Один на php, другой на C++ (в виде расширения к php).<br />
<br />
<b>Пару слов как пользоваться.</b><br />
Пример использования есть в исходниках: <a href="https://github.com/valmat/myscrnav/blob/master/screennav_test.php">https://github.com/valmat/myscrnav/blob/master/screennav_test.php</a><br />
<br />
Создаем pagination-объект из расширения:<br />
<span style="color: #000088;">$scr</span> <span style="color: #339933;">=</span> <span style="color: black;">new</span> myScrNav<span style="color: #009900;">(</span><span style="color: #000088;">$pageNom</span><span style="color: #339933;">,</span> <span style="color: #000088;">$Count</span><span style="color: #339933;">,</span> <span style="color: blue;">'/url/to/page/'</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span><br />
Или из php класса:<br />
<span style="color: #b1b100;">require</span> <span style="color: blue;">'php/class.screennav.php'</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$scr</span> <span style="color: #339933;">=</span> <span style="color: black;">new</span> ScreenNav<span style="color: #009900;">(</span><span style="color: #000088;">$pageNom</span><span style="color: #339933;">,</span> <span style="color: #000088;">$Count</span><span style="color: #339933;">,</span> <span style="color: blue;">'/url/to/page/'</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span><br />
<br />
Задаем необходимые параметры (если необходимо, можно не задавать):<br />
<blockquote>
<span style="color: #000088;">$scr</span><span style="color: #339933;">-></span><span style="color: #004000;">setInterval</span><span style="color: #009900;">(</span><span style="color: #cc66cc;">10</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #666666;">// Сколько объектов на странице</span><br />
<span style="color: #000088;">$scr</span><span style="color: #339933;">-></span><span style="color: #004000;">setPrefix</span><span style="color: #009900;">(</span><span style="color: blue;">'?qwe&part='</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #666666;">// URL prefix</span><br />
<span style="color: #000088;">$scr</span><span style="color: #339933;">-></span><span style="color: #004000;">setPostfix</span><span style="color: #009900;">(</span><span style="color: blue;">'&prm=132'</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #666666;">// URL prefix</span><br />
<span style="color: #000088;">$scr</span><span style="color: #339933;">-></span><span style="color: #004000;">setSpace</span><span style="color: #009900;">(</span><span style="color: blue;">'<space>...</space>'</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #666666;">// Разделитель блоков табов</span><br />
<span style="color: #000088;">$scr</span><span style="color: #339933;">-></span><span style="color: #004000;">setCssName</span><span style="color: #009900;">(</span><span style="color: blue;">'newClassName'</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #666666;">// Имя класса css блока управления постраничным выводом</span><br />
<span style="color: #000088;">$scr</span><span style="color: #339933;">-></span><span style="color: #004000;">setMidTab</span><span style="color: #009900;">(</span><span style="color: #cc66cc;">15</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #666666;">// см. info.png</span><br />
<span style="color: #000088;">$scr</span><span style="color: #339933;">-></span><span style="color: #004000;">setMaxTab</span><span style="color: #009900;">(</span><span style="color: #cc66cc;">5</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #666666;">// см. info.png</span><br />
<span style="color: #000088;">$scr</span><span style="color: #339933;">-></span><span style="color: #004000;">showCount</span><span style="color: #009900;">(</span><span style="color: #009900;">true</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #666666;">// Показывать ли общее количество элементов</span></blockquote>
<div class="separator" style="clear: both; text-align: center;">
<img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMvEMDFOIcs6fWcTlEWozYZbeXHo-05qW5xIosLvd6LIfRBTIyG0_Q1P7Nqx4uw41AmN0PVid0vj87gTPC6CClFAdFVzpM5FpXcS191RGKMtSxWB4weFL8bfY6MJkj36vuJRmGCHTRv1o/s1600/info.png" /></div>
<br />
Кроме того доступны следующие методы для получения вычисленных данных:<br />
<blockquote>
getStartPos<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #666666;">// Номер начального элемента на текущей странице (для выборки из БД)</span><br />
getLimitPos<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #666666;">// Длина списка элементов на странице на текущей странице (для выборки из БД)</span><br />
getPageCnt<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #666666;">// Количество страниц при разбивке на части</span><br />
getStartPos<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #666666;">// Номер (вычисленный) текущей страницы</span><br />
show<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #666666;">// Возвращает собственно сам элемент управления постраничной разбивкой (html)</span></blockquote>
Т.е. можно управлять постраничной разбивкой и делать запросы к БД на основе этой постраничной разбивки. Внешний вид, разумеется, полностью настраивается через css<br />
<br />
<b>Теперь сами результаты сравнения.</b><br />
PHP тестируется со включенным опкешером (apc). Без него смысла тестировать не вижу, ибо тестировать нужно так, как используется на рабочей системе.<br />
<b>1</b><br />
Во-первых сравним просто функции.<br />
На php будет<br />
<blockquote>
<span style="color: black;">function</span> ScreenNav_pageNo<span style="color: #009900;">(</span><span style="color: #000088;">$var</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span><span style="color: #b1b100;">return</span> <span style="color: #009900;">(</span><span style="color: #990000;">isset</span><span style="color: #009900;">(</span><span style="color: #000088;">$_GET</span><span style="color: #009900;">[</span><span style="color: #000088;">$var</span><span style="color: #009900;">]</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span>?<span style="color: #009900;">(</span><span style="color: #009900;">(</span>int<span style="color: #009900;">)</span><span style="color: #000088;">$_GET</span><span style="color: #009900;">[</span><span style="color: #000088;">$var</span><span style="color: #009900;">]</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">)</span><span style="color: #339933;">:</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span><span style="color: #009900;">}</span></blockquote>
На C++<br />
<blockquote>
Php<span style="color: teal;">::</span><span style="color: #007788;">Value</span> GETpageNom<span style="color: green;">(</span>Php<span style="color: teal;">::</span><span style="color: #007788;">Parameters</span> <span style="color: #000040;">&</span>params<span style="color: green;">)</span> <span style="color: green;">{</span><br />
<span style="color: blue;">if</span> <span style="color: green;">(</span>params.<span style="color: #007788;">size</span><span style="color: green;">(</span><span style="color: green;">)</span> <span style="color: navy;">==</span> <span style="color: #0000dd;">0</span><span style="color: green;">)</span> <span style="color: blue;">return</span> <span style="color: #0000dd;">0</span><span style="color: teal;">;</span><br />
string var <span style="color: navy;">=</span> <span style="color: green;">(</span><span style="color: #0000dd;">new</span> Php<span style="color: teal;">::</span><span style="color: #007788;">Value</span><span style="color: green;">(</span>params<span style="color: green;">[</span><span style="color: #0000dd;">0</span><span style="color: green;">]</span><span style="color: green;">)</span><span style="color: green;">)</span><span style="color: #000040;">-</span><span style="color: navy;">></span>stringValue<span style="color: green;">(</span><span style="color: green;">)</span><span style="color: teal;">;</span><br />
string get <span style="color: navy;">=</span> Php<span style="color: teal;">::</span><span style="color: #007788;">globals</span><span style="color: green;">[</span><span style="color: red;">"_GET"</span><span style="color: green;">]</span><span style="color: green;">[</span>var<span style="color: green;">]</span><span style="color: teal;">;</span><br />
<span style="color: blue;">long</span> <span style="color: blue;">int</span> rez <span style="color: navy;">=</span> <span style="color: green;">(</span><span style="color: #0000dd;">new</span> Php<span style="color: teal;">::</span><span style="color: #007788;">Value</span><span style="color: green;">(</span> get <span style="color: green;">)</span><span style="color: green;">)</span><span style="color: #000040;">-</span><span style="color: navy;">></span>numericValue<span style="color: green;">(</span><span style="color: green;">)</span><span style="color: teal;">;</span><br />
<span style="color: blue;">return</span> rez <span style="color: teal;">?</span> <span style="color: green;">(</span>rez<span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: green;">)</span> <span style="color: teal;">:</span> <span style="color: #0000dd;">0</span><span style="color: teal;">;</span><br />
<span style="color: green;">}</span></blockquote>
<div>
php</div>
<div>
memory usage: 0.56Kb</div>
<div>
memory peak_usage: 1.1Kb</div>
<div>
Вычесленное: time: 50•10<sup>-6</sup> sec</div>
<div>
ab -n 10000 ... : Time per request: 0.39 [ms] (mean)</div>
<div>
</div>
<div>
C++</div>
<div>
memory usage: 1.26Kb</div>
<div>
memory peak_usage: 1.8Kb</div>
<div>
Вычесленное: time: 60•10<sup>-6</sup> sec</div>
<div>
ab -n 10000 ... : Time per request: 0.4 [ms] (mean)</div>
<br />
Как видно, на таком простом примере расширение не выигрывает, а даже проигрывает нативному коду.<br />
<br />
<b>2</b><br />
Теперь сравним классы.<br />
<br />
<div>
php</div>
<div>
time: 215•10<sup>-6</sup> sec</div>
<div>
memory usage: 16.5Kb</div>
<div>
memory peak_usage: 22.7Kb</div>
<div>
ab -n 10000 ... : Time per request: 0.533 [ms] (mean)</div>
<div>
</div>
<div>
C++</div>
<div>
time: 170•10<sup>-6</sup> sec</div>
<div>
memory usage: 2.3Kb</div>
<div>
memory peak_usage: 4.6Kb</div>
<div>
ab -n 10000 ... : Time per request: 0.49 [ms] (mean)</div>
<br />
Выводы.<br />
Разница во времени порядка 10<sup>-5</sup> sec - не то ради чего нужно переписывать с php на C++.<br />
С другой стороны, само то, что она проявилась на такой незначительной задаче уже результат.<br />
Приведенный пример позволяет понять порядок выигрыша и оценить целесообразность переписывания нативного кода в C++ расширение.<br />
Обращает на себя внимание разница в потреблении памяти. Причем, если расширение выгрузить, то потребление памяти нативным кодом не уменьшается.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com1tag:blogger.com,1999:blog-3900514035470574480.post-73524630739308098382013-12-15T11:08:00.000-08:002013-12-15T11:08:04.190-08:00Сериализация в PHPБудут сравниваться 4-е способа сериализации:<br />
1) Стандартная сериализация serialize<br />
2) JSON<br />
3) msgpack<br />
4) igbinary<br />
<br />
Кратко об установке.<br />
<b>JSON</b> раньше шел в стандартной поставке php. Сейчас нужно поставить дополнительное расширение php5-json.<br />
<b>msgpack</b><br />
Сайт: http://msgpack.org/<br />
Исходники: https://github.com/msgpack/msgpack-php и http://pecl.php.net/package/msgpack<br />
Ставим:<br />
<br />
<code>
cd /tmp<br />
wget http://pecl.php.net/get/msgpack-0.5.5.tgz<br />
tar xzf msgpack-0.5.5.tgz<br />
cd msgpack-0.5.5<br />
phpize<br />
./configure<br />
make<br />
make test<br />
</code><br />
Если тесты прошли нормально, то создаем пакет и ставим:<br />
<code>sudo checkinstall -D --install=no<br />
sudo dpkg -i msgpack_0.5.5-1_amd64.deb<br />
</code>
<br />
<b>igbinary</b><br />
Исходники: https://github.com/phadej/igbinary/tree/master и http://pecl.php.net/package/igbinary<br />
Далее опять<br />
<code>
cd /tmp<br />
wget http://pecl.php.net/get/igbinary-1.1.1.tgz<br />
tar xzf igbinary-1.1.1.tgz<br />
cd igbinary-1.1.1<br />
phpize<br />
./configure<br />
make<br />
make test<br />
sudo checkinstall -D --install=no<br />
sudo dpkg -i igbinary_1.1.1-1_amd64.deb<br /><br />
</code>
<br />
msgpack добавляет функции<br />
<code>
BinData msgpack_pack(phpValue);<br />
phpValue msgpack_unpack(BinData);<br /><br />
</code>
<br />
igbinary добавляет функции<br />
<code>
BinData igbinary_serialize(phpValue);<br />
phpValue igbinary_unserialize($BinData);<br /><br />
</code>
<br />
Что бы они заработали, нужно незабыть включить их в php.ini:<br />
<code>
[igbinary]<br />
extension=igbinary.so<br />
<br />
; Enable or disable compacting of duplicate strings<br />
; The default is On.<br />
;igbinary.compact_strings=On<br />
<br />
[msgpack]<br />
extension=msgpack.so<br />
</code>
<br />
<br />
Что еще важно отметить.<br />
serialize - стандартная функция php. JSON - старое и стабильное расширение. igbinary - тоже достаточно старая библиотека, давно вышедшая в стабильную ветку. msgpack - на данный момент все еще находится в стадии beta. С msgpack мне реально доводилось ловить глюки в ее предыдущих релизах. И если я решусь внедрять ее в продакшен, то там где, ее ошибки не принисут фатального ущерба.<br />
<br />
Собственно тесты:<br />
<br />
<hr />
<b>1. </b>Массив вида<br />
<strong><code>array (<br /> 'v0' =><br /> array (<br /> 0 => 0,<br /> 1 => 1,<br /> 2 => 2,<br /> ...<br /> 3 => 3,<br /> 23 => 23,<br /> 24 => 24,<br /> ),<br /> 'rnd0' => '2e0c883df6e2cb771103f4409f053549094d6787',<br /> ..........<br />)</code></strong><br />
c 16384 элементами<br />
<table border="1" cellpadding="1" cellspacing="1" style="width: 500px;"><tbody>
<tr><td><br /></td><td>Время<br />сериализации (msec)</td><td>Время<br />десериализации (msec)</td><td>размер упакованных данных (Kb)</td></tr>
<tr><td>MessagePack</td><td style="text-align: center;">9</td><td style="text-align: center;">25</td><td style="text-align: center;">678</td></tr>
<tr><td>igbinary<br />compact_strings=Off</td><td style="text-align: center;">9</td><td style="text-align: center;">32</td><td style="text-align: center;">1278</td></tr>
<tr><td>igbinary<br />compact_strings=On</td><td style="text-align: center;">16</td><td style="text-align: center;">32</td><td style="text-align: center;">1120</td></tr>
<tr><td>JSON</td><td style="text-align: center;">14</td><td style="text-align: center;">318</td><td style="text-align: center;">1022</td></tr>
<tr><td>SERIALIZE</td><td style="text-align: center;">62</td><td style="text-align: center;">39</td><td style="text-align: center;">2486</td></tr>
</tbody></table>
<hr />
<strong>2</strong>.Массив вида<br />
<strong><code>array (<br /> 0 => 3183,<br /> 1 => 4527,<br /> 2 => 4084,<br /> 3 => 4032,<br /> 4 => 3920,<br />...<br /> 262144 => 4455,<br />)</code></strong><br />
<br /><table border="1" cellpadding="1" cellspacing="1" style="width: 500px;"><tbody>
<tr><td><br /></td><td>Время<br />сериализации (msec)</td><td>Время<br />десериализации (msec)</td><td>размер упакованных данных (Kb)</td></tr>
<tr><td>MessagePack</td><td style="text-align: center;">8</td><td style="text-align: center;">30</td><td style="text-align: center;">769</td></tr>
<tr><td>igbinary<br />compact_strings=Off</td><td style="text-align: center;">9</td><td style="text-align: center;">33</td><td style="text-align: center;">1920</td></tr>
<tr><td>igbinary<br />compact_strings=On</td><td style="text-align: center;">9</td><td style="text-align: center;">33</td><td style="text-align: center;">1920</td></tr>
<tr><td>JSON</td><td style="text-align: center;">15</td><td style="text-align: center;">107</td><td style="text-align: center;">1281</td></tr>
<tr><td>SERIALIZE</td><td style="text-align: center;">86</td><td style="text-align: center;">44</td><td style="text-align: center;">3988</td></tr>
</tbody></table>
<hr />
<strong>3</strong>.Массив вида<br />
<pre><strong>array (
0 => 7679461759223599104,
1 => 4898705982311625344,
2 => 5880628818820227328,
...
262144 => 6940876209816891904,
)</strong>
</pre>
<table border="1" cellpadding="1" cellspacing="1" style="width: 500px;"><tbody>
<tr><td><br /></td><td>Время<br />сериализации (msec)</td><td>Время<br />десериализации (msec)</td><td>размер упакованных данных (Kb)</td></tr>
<tr><td>MessagePack</td><td style="text-align: center;">10</td><td style="text-align: center;">29</td><td style="text-align: center;">2305</td></tr>
<tr><td>igbinary<br />compact_strings=Off</td><td style="text-align: center;">11</td><td style="text-align: center;">33</td><td style="text-align: center;">3456</td></tr>
<tr><td>igbinary<br />compact_strings=On</td><td style="text-align: center;">11</td><td style="text-align: center;">33</td><td style="text-align: center;">3456</td></tr>
<tr><td>JSON</td><td style="text-align: center;">20</td><td style="text-align: center;">172</td><td style="text-align: center;">5121</td></tr>
<tr><td>SERIALIZE</td><td style="text-align: center;">92</td><td style="text-align: center;">49</td><td style="text-align: center;">7828</td></tr>
</tbody></table>
<hr />
<strong>4</strong>.Массив вида<strong>array (<br /> 0 => 0.00038631346578366,<br /> 1 => 0.00016131634134538,<br /> 2 => 0.00043595779928503,<br /> 3 => 0.00011754334410814,<br /> 4 => 0.00049353469548909,<br /> 5 => 5.2391680201184E-5,<br /> .....<br /> 262144 => 0.00041876046901173,<br />)</strong><br />
<table border="1" cellpadding="1" cellspacing="1" style="width: 500px;"><tbody>
<tr><td><br /></td><td>Время<br />сериализации (msec)</td><td>Время<br />десериализации (msec)</td><td>размер упакованных данных (Kb)</td></tr>
<tr><td>MessagePack</td><td style="text-align: center;">9</td><td style="text-align: center;">28</td><td style="text-align: center;">2305</td></tr>
<tr><td>igbinary<br />compact_strings=Off</td><td style="text-align: center;">11</td><td style="text-align: center;">33</td><td style="text-align: center;">3456</td></tr>
<tr><td>igbinary<br />compact_strings=On</td><td style="text-align: center;">11</td><td style="text-align: center;">33</td><td style="text-align: center;">3456</td></tr>
<tr><td>JSON</td><td style="text-align: center;">75</td><td style="text-align: center;">197</td><td style="text-align: center;">5061</td></tr>
<tr><td>SERIALIZE</td><td style="text-align: center;">264</td><td style="text-align: center;">176</td><td style="text-align: center;">8538</td></tr>
</tbody></table>
<hr />
<strong>5</strong>.Массив вида<pre>array (
0 => 'f7df8cb47630b8cd7eb73d0da7a23b9c01aaaa84f718499c1c8cef6730f9fd03c8125cab',
1 => 'd30f79cf7fef47bd7a5611719f936539bec0d2e93bcf6eecb2611212e088d0d91f2ade9c',
2 => '86bce22a4d2805649853ac7909c4efb4dd18f255086af6e4641abb18caafc151b9aa95c8',
3 => '63afd0edc0371ad842d7a7ecc76260be4bc3e8c0da6cb383f8f9e58f2c8af88a8c0eb65e',
4 => '13c80015875a668e8fc059517ffd124abbda63c12d95666e2649fcfc6e3af75e09f5adb9',
...
32768 => '0e3808238b738aafc13a2a62f36d2a49dec4e191c22abfa379f38b5b0411bc11fa9bf92f',
)
</pre>
<table border="1" cellpadding="1" cellspacing="1" style="width: 500px;"><tbody>
<tr><td><br /></td><td>Время<br />сериализации (msec)</td><td>Время<br />десериализации (msec)</td><td>размер упакованных данных (Kb)</td></tr>
<tr><td>MessagePack</td><td style="text-align: center;">4</td><td style="text-align: center;">5</td><td style="text-align: center;">2401</td></tr>
<tr><td>igbinary<br />compact_strings=Off</td><td style="text-align: center;">4</td><td style="text-align: center;">6</td><td style="text-align: center;">2464</td></tr>
<tr><td>igbinary<br />compact_strings=On</td><td style="text-align: center;">21</td><td style="text-align: center;">6</td><td style="text-align: center;">2463</td></tr>
<tr><td>JSON</td><td style="text-align: center;">28</td><td style="text-align: center;">16</td><td style="text-align: center;">2401</td></tr>
<tr><td>SERIALIZE</td><td style="text-align: center;">10</td><td style="text-align: center;">7</td><td style="text-align: center;">2806</td></tr>
</tbody></table>
<br />
<br />
Замечу что приведенные в таблицах данные являются примерными и
зависят от данных. Т.к. данные у меня заполнялись случайным образом, то
цифры получались разные, но разница не существенна и в целом эти цифры
отражают реальную картину.<br />
<br />
valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com1tag:blogger.com,1999:blog-3900514035470574480.post-14688627784069079432013-12-02T03:55:00.001-08:002013-12-02T04:28:29.997-08:00разжился SSD диском<br />
<div style="-webkit-composition-fill-color: rgba(175, 192, 227, 0.230469); -webkit-composition-frame-color: rgba(77, 128, 180, 0.230469); -webkit-tap-highlight-color: rgba(26, 26, 26, 0.296875);">
Вот и я разжился SSD диском.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-XpcpHpXxECM/UpxzhQTgK1I/AAAAAAAACI8/ves9VwG-DeE/s1600/02.12.13+-+1" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="314" src="http://4.bp.blogspot.com/-XpcpHpXxECM/UpxzhQTgK1I/AAAAAAAACI8/ves9VwG-DeE/s320/02.12.13+-+1" width="320" /></a></div>
<div>
Будет на чем тестить NoSQL SSD хранилища. </div>
<div>
В планах потестить на нем RocksDB, LevelDB и, возможно, RethinkDB.<br />
PS а вот так он встал в мой ноут<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-GcYxBaYk1HY/Upx8WZHS-rI/AAAAAAAACJg/0wpQCmuhZp8/s1600/02.12.13+-+2" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="239" src="http://3.bp.blogspot.com/-GcYxBaYk1HY/Upx8WZHS-rI/AAAAAAAACJg/0wpQCmuhZp8/s320/02.12.13+-+2" width="320" /></a></div>
<br /></div>
valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-57347135344694688702013-03-04T00:50:00.003-08:002013-03-04T00:50:56.674-08:00Пластелиновый мультикСделали с дочей мультик из пластилина.<br />
Делается так:<br />
<code>convert -delay 20 -loop 0 *.jpg mygif.gif</code>
<br />
Вот результат:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsIIAqyxYBQVQss5ObJd7V32q8bkcQHZKMVmgDUv2utniS9IzVuRJpxyqtZwmfeQjuhW6j1aoM4-Qk-WP4rncMA92MZgNQAdip61XfZ8Yq4Haiw6PNFPcR6oNfh1Lj7ZfbARLPeKxcnMA/s1600/myimage.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="239" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsIIAqyxYBQVQss5ObJd7V32q8bkcQHZKMVmgDUv2utniS9IzVuRJpxyqtZwmfeQjuhW6j1aoM4-Qk-WP4rncMA92MZgNQAdip61XfZ8Yq4Haiw6PNFPcR6oNfh1Lj7ZfbARLPeKxcnMA/s320/myimage.gif" width="320" /></a></div>
Еще полезное:<br />
Сделать из кадров ролик:<br />
<code>convert -delay 20 -loop 0 *.jpg mympg.mpg</code>
<br />
<code>mov из gif:<br />convert mygif.gif mymov.mov</code>
<br />
<div class="separator" style="clear: both; text-align: center;">
<object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://0.gvt0.com/vi/_oHiKSMMwAA/0.jpg"><param name="movie" value="http://www.youtube.com/v/_oHiKSMMwAA&fs=1&source=uds" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="http://www.youtube.com/v/_oHiKSMMwAA&fs=1&source=uds" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<br />valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-45392504486496960372013-03-01T01:32:00.000-08:002013-03-01T01:57:27.394-08:00Топ 7 ботов за суткиПо результатам выборки из логов сервера за 1 сутки.<br />
<br />
<ol>
<li><b>Googlebot</b> - 43229 запросов</li>
<li><b>YandexDirect</b> - 21260</li>
<li><b>Mediapartners-Google</b> - 14386 </li>
<li><b>Mail.RU_Bot</b> - 13715</li>
<li><b>YandexBot</b> - 13079</li>
<li><b>AhrefsBot</b> - 11997</li>
<li><b>openstat ru/Bot</b> - 2709</li>
</ol>
Выводы. Гугл предсказуемо обошел всех и вся. Честь и хвала ему.<br />
Удивил Mail.RU, который обошел Яндекс.<br />
Что касается Яндекса, то очевидно, что приоритет Яндекса - их рекламная сеть. И уже потом поисковые технологии.<br />
Можно сравнить какое значение Гугл и Яндекс уделяют своим поисковым и рекламным технологиям в процентном соотношении:<br />
<i>YandexDirect</i> - <b>62%</b> <i>YandexBot</i> - <b>38%</b><br />
<i>Mediapartners-Google</i> - <b>25%</b> <i>Googlebot</i> - <b>75%</b><br />
<br />
Далее AhrefsBot - собиратель беклинков. бесполезная (а иногда и вредная) нагрузка на сервер. Вредная потому что, конкуренты смогут видеть то, что им видеть не положено. Его блочим в robots.txt.<br />
Поскольку есть самомнения, что он вообще читает robots.txt, то для профилактики делаем примерно так:<br />
<code></code><br />
<pre><code>if ($http_user_agent ~* (Wget|ApacheBench|SISTRIX|<b>AhrefsBot</b>|Teleport) ) {
return 502;
}
</code></pre>
Ну и Bot openstat, я считаю, вообще недостоин нашего внимания.<br />
<br />
PS. Чуть не забыл.<br />
Получить Top список IP адресов можно так<br />
<pre><code>
cat <i>ваши_лог_фалы</i> | cut -c -15 | sort | uniq -c | sort -nr | sed -r 's!\s*([0-9]+)\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*!\1\t\2!g' > top.log </code></pre>
<br />
А выборку по отдельным ботам можно получить grep'ом<br />
<br />valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-80174384118872352352013-01-24T12:46:00.000-08:002013-01-24T12:50:13.556-08:00Google Chrome и "-" 400 0 "-" "-"Еще раз к вопросу <a href="http://www.valmat.ru/2013/01/ban-bot-2.html">откуда в логах берутся строки вида</a>
<br />
<pre><code>1.1.1.1 - - [19/Jan/2013:07:19:23 +0400] "-" 400 0 "-" "-"</code></pre>
<br />
При медленном соединении удалось отловить эффект появления таких записей в браузере и увидеть все в живую<br />
Вот тут видно, как хром отправил два запроса, держит соединение открытым, а потом закрывает
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggYD31CO6bwdYM-ZPtQvHThDQI34CZPpbl0SghoAc_Nu5BAYUYcqu30JZxLA8WdQewbftWBDyrVmwznDyihFiMnURb1kHCJussOa1ypB9zNkz_ZMcJ-oAvk56kc3Js6Tldo8b37JXKZSA/s1600/404-chrome.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="77" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggYD31CO6bwdYM-ZPtQvHThDQI34CZPpbl0SghoAc_Nu5BAYUYcqu30JZxLA8WdQewbftWBDyrVmwznDyihFiMnURb1kHCJussOa1ypB9zNkz_ZMcJ-oAvk56kc3Js6Tldo8b37JXKZSA/s320/404-chrome.png" width="320" /></a></div>
<br />
А секундой позже уже загружает то, что его просили.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9XeSBXY3LV5u5VQJVwArYo3ua3X8D7sTom_8VG3XO0YCEL4od2AG1mMSFnIpB7uMZw5fTjUa0MDxjVaymi4JFL-3uHk9ZINP8uD4iayTwnscpoq2rqcEkr9-fpORyj0K7bGyXCZGRb-k/s1600/404-chrome-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="76" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9XeSBXY3LV5u5VQJVwArYo3ua3X8D7sTom_8VG3XO0YCEL4od2AG1mMSFnIpB7uMZw5fTjUa0MDxjVaymi4JFL-3uHk9ZINP8uD4iayTwnscpoq2rqcEkr9-fpORyj0K7bGyXCZGRb-k/s320/404-chrome-1.png" width="320" /></a></div>
<br />
Успел сделать снимки экрана.
<br />
<br />
Повторить эксперимент можно либо подключившись к медленному каналу, либо намеренно ограничив скорость соединения на стороне веб сервераvalmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-76481945134900416732013-01-23T06:21:00.000-08:002013-01-24T12:51:56.202-08:00Баним ботов. Часть 2Небольшой анализ логов сервера. Какие странные сущности обитают в Интернете. И как с ними бороться.
<br />
<h3>
Открытые подключения</h3>
В логах nginx'а обнаружил десятки тысяч записей вида:<br />
<pre><code>
1.1.1.1 - - [19/Jan/2013:07:19:23 +0400] "-" 400 0 "-" "-"
1.1.1.1 - - [19/Jan/2013:07:19:23 +0400] "-" 400 0 "-" "-"
1.1.1.1 - - [19/Jan/2013:07:19:23 +0400] "-" 400 0 "-" "-"
1.1.1.1 - - [19/Jan/2013:07:19:34 +0400] "-" 400 0 "-" "-"
1.1.1.1 - - [19/Jan/2013:07:19:34 +0400] "-" 400 0 "-" "-"
1.1.1.1 - - [19/Jan/2013:07:19:34 +0400] "-" 400 0 "-" "-"
1.1.1.1 - - [19/Jan/2013:07:19:34 +0400] "-" 400 0 "-" "-"
</code></pre>
<br />
Судя по количеству и частоте запросов достаточно большое число таких запросов сделано именно ботами.<br />
Казалось бы, легко создать правило для fail2ban и забанить их всех.<br />
Но такие записи могут создавать и обычные пользователи. Например, если пользователь остановит загрузку или при быстром переходе со страницы на страницу (у меня получилось <a href="http://www.valmat.ru/2013/01/-400-0-.html">отловить такой эффект в Google Chrome</a>).<br />
Суть таких записей такова: открытое и не закрытое соединение.<br />
Например если открыть соединение телнетом и оставить его, то по истечении таймаута появится именно такая запись.<br />
<b><code>$telnet site.ru 80</code></b>
<br />
<pre><code>
Trying 127.0.0.1...
Connected to site.ru.
Escape character is '^]'.
</code></pre>
<br />
Или можно так: <code>
php -r 'for($i=0;$i>500;$i++){$v="s".$i;$$v=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);socket_connect($$v,"localhost", 80);}' </code>
<br />
Особого вреда такие атаки нанести не могут, т.к. в силу своего асинхронного характера nginx может держать <a href="http://forum.nginx.org/read.php?21,129983,129986#msg-129986" target="_blank">достаточно</a> <a href="http://nginx.org/ru/docs/ngx_core_module.html#worker_connections" target="_blank">большое</a> число открытых соединений, но специально для таких случаев (а так же других недоатак) существуют такие вещи, как модули <a href="http://nginx.org/ru/docs/http/ngx_http_limit_req_module.html" target="_blank">ngx_http_limit_req_module</a> и <a href="http://nginx.org/ru/docs/http/ngx_http_limit_conn_module.html" target="_blank">ngx_http_limit_conn_module</a>
<br />
Про них написано достаточно много, простым гуглением все находится.<br />
Можно только добавить не забыть всавить в robots.txt строчку вроде этой<br />
<code>Crawl-delay: 1</code>
<br />
(можно дробные значения), что бы ненароком не забанить поисковых поуков.<br />
limit_req_zone должна обязательно стоять (в секции http) до подключения секций server. т.е. до <code>include /etc/nginx/conf.d/*.conf;</code>
<br />
<br />
Еще, некоторых ленивых роботов, передающих не все заголовки, можно развернуть вот таким кодом в секции server<br />
<pre><code>
if ( $http_user_agent = "" ){
return 444;
}
</code></pre>
<br />
<h3>
try proxy</h3>
Следующая разновидность ботов пытается использовать nginx в качестве открытого проксисервера. Точнее пытается определить такую возможность.<br />
Дело в том, что если, например, телнетом передать заголовок <br />
не<br />
<pre><code>GET /index.htm HTTP/1.1
</code></pre>
а<br />
<pre><code>GET http://site.ru/index.htm
</code></pre>
То nginx не разворачивает такой запрос с кодом 400, а обрабатывает его.<br />
И дальше все зависит от настройки конфигов.<br />
В каких то случаях, таким образом можно получить <a href="http://forum.nginx.org/read.php?21,226769,227097#msg-227097" target="_blank">открытый http прокси</a> сервер.<br />
В общем случае, если site.ru определен в nginx, как<code> </code><br />
<code> server_name site.ru;
</code><br />
То дальше вашего сервера запрос не уйдет.<br />
Вот реальный пример из log-файла:<br />
<pre style="border: 1px solid #000; overflow-y: scroll; padding: 5px;"><code>
178.77.67.27 - - [20/Jan/2013:19:09:43 +0400] "GET http://www.scanproxy.net:80/p-80.html HTTP/1.0" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KuKu 0.65)"
82.145.35.123 - - [10/Jan/2013:08:11:20 +0400] "GET http://proxyjudge2.proxyfire.net/fastenv HTTP/1.1" 404 564 "-" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"
80.82.215.45 - - [01/Jan/2013:08:59:03 +0400] "GET http://www.scanproxy.net:80/p-80.html HTTP/1.0" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KuKu 0.65)"
62.193.243.32 - - [01/Jan/2013:23:38:53 +0400] "GET http://www.scanproxy.net:80/p-80.html HTTP/1.0" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KuKu 0.65)"
46.32.65.23 - - [11/Dec/2012:19:20:15 +0400] "GET http://www.santeh.ru/cgi-bin/textenv.pl HTTP/1.0" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0)"</code></pre>
<br />
В основном, лечится это так:<br />
Запретить использование дефолтного сервера и обработку запросов <a href="http://nginx.org/ru/docs/http/request_processing.html#how_to_prevent_undefined_server_names" target="_blank">без имени сервера</a>.<br />
<br />
<code>server {<br /> listen 80 default_server;<br /> server_name "";<br /> return 444;<br />}<br /><br />
</code>Далее, при передаче заголовка (без HTTP/1.1 или HTTP/1.0)<br />
<pre><code>GET http://site.ru/index.htm</code></pre>
Все остальные строки запроса будут проигнорированы.<br />
Т.е. в запросе (вместо<code> GET /index.htm </code><code> HTTP/1.1 </code>написано<code> GET http://site.ru/index.htm</code>)<br />
<pre><code>GET http://site.ru/index.htm
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset:windows-1251,utf-8;q=0.7,*;q=0.3
Accept-Language:ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Host:site.ru
Referer:site.ru/index.htm
User-Agent:TelnetTester
</code></pre>
Будет учтена только первая строка. А значит поможет уже знакомая нам конструкция<br />
<pre><code> if ( $http_user_agent = "" ){
return 444;
}
</code></pre>
Но такая ситуация встречается не часто.<br />
Кроме ботов, запросы вида <code> GET http://site.ru/index.htm HTTP/1.1</code> шлет опера<code></code>. Во всяком случае у меня в логах достаточно много строк вроде этой: <br />
<pre style="border: 1px solid #000; overflow-y: scroll; padding: 5px;"><code>188.162.15.86 - - [05/Jan/2013:09:18:41 +0400] "GET http://opera10beta-turbo.opera-mini.net:80//img/spb_b_1456.jpg HTTP/1.1" 404 162 "http://images.yandex.ru/yandsearch?p=..." "Opera/9.80 (Windows NT 5.1) Presto/2.12.388 Version/12.10"</code></pre>
<br />
<h4>
Битые заголовки</h4>
<pre style="border: 1px solid #000; overflow-y: scroll; padding: 5px;"><code>94.41.37.135 - - [11/Jan/2013:08:51:57 +0400] "ЪьЪЮ\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00ЪЧ\x00;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 75" 400 166 "-" "-"
176.213.180.115 - - [07/Jan/2013:16:27:16 +0400] "ЪьЪЮ\x00\x10JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00Ъш\x00C\x00\x02\x01\x01\x02\x01\x01\x02\x02\x02\x02\x02\x02\x02\x02\x03\x05\x03\x03\x03\x03\x03\x06\x04\x04\x03\x05\x07\x06\x07\x07\x07\x06\x07\x07\x08\x09\x0B\x09\x08\x08" 400 166 "-" "-"
</code></pre>
Такие строки создают некоторые браузеры. Как это происходит я так и не понял. Но нечто подобное я нашел в логах на локальной машине - там, где никаких ботов быть не может. Предположительно, Google Chrome.<br />
Так же весьма вероятно, подобные записи могут создаваться некоторыми ботами ищущими уязвимости вебсервера.<br />
Вот например <a href="http://disorder.ru/archives/908">http://disorder.ru/archives/908</a> человек описал эксплоит для старых версий Nginx, а вот это:<br />
<pre style="border: 1px solid #000; overflow-y: scroll; padding: 5px;"><code>188.138.88.171 - - [19/Jan/2013:20:05:45 +0400] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400 166 "-" "-"
50.63.136.60 - - [19/Jan/2013:20:32:27 +0400] "GET /w00tw00t.at.ISC.SANS.Win32:) HTTP/1.1" 400 166 "-" "-"</code></pre>
явно адресовано IIS<br />
Такие записи прост можно игнорировать. В случае особой осанистости помогает способ с ngx_http_limit_req_module описанный в предыдущем пункте.valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-6210580404081535222013-01-20T03:07:00.003-08:002013-01-20T03:37:41.964-08:00Баним ботов. Часть 1В один прекрасный день мне надоело видеть у себя в логах такое вот безобразие:<br />
<pre style="border: 1px solid #000; overflow-y: scroll; padding: 5px;"><code>
113.204.67.51 - - [19/Jan/2013:07:22:08 +0400] "GET /phpmyadmin/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:12 +0400] "GET /PMA/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:17 +0400] "GET /pma/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:17 +0400] "GET /admin/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:18 +0400] "GET /dbadmin/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:19 +0400] "GET /sql/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:20 +0400] "GET /mysql/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:20 +0400] "GET /myadmin/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:21 +0400] "GET /phpmyadmin2/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:22 +0400] "GET /phpMyAdmin2/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:23 +0400] "GET /phpMyAdmin-2/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:23 +0400] "GET /php-my-admin/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:24 +0400] "GET /sqlmanager/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:25 +0400] "GET /mysqlmanager/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:26 +0400] "GET /p/m/a/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:26 +0400] "GET /php-myadmin/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:27 +0400] "GET /phpmy-admin/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:28 +0400] "GET /webadmin/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:29 +0400] "GET /sqlweb/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:30 +0400] "GET /websql/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:31 +0400] "GET /webdb/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:31 +0400] "GET /mysqladmin/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
113.204.67.51 - - [19/Jan/2013:07:22:32 +0400] "GET /mysql-admin/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
</code></pre>
<br />
и решил я всех этих мерзких ботов забанить.<br />
Для чего был создан fail2ban скрипт phpmyadmin.conf следующего содержания:<br />
<blockquote>
<span style="color: #666666;"># Fail2Ban configuration file</span><br />
<span style="color: #666666;">#</span><br />
<span style="color: #666666;"># Author: Valmat</span><br />
<span style="color: #666666;">#</span><br />
<span style="color: #009900;">[</span>Definition<span style="color: #009900;">]</span><br />
failregex <span style="color: #339933;">=</span> <span style="color: #339933;">^<host><host></host></host></span><span style="color: #009999;"><host></host></span> <span style="color: #339933;">-</span> <span style="color: #339933;">-</span> <span style="color: #009900;">[</span><span style="color: #339933;">.*</span><span style="color: #009900;">]</span> <span style="color: red;">"GET /(?:phpmyadmin|PMA|pma|admin|dbadmin|sql|mysql|myadmin|phpmyadmin2|phpMyAdmin2|phpMyAdmin-2|php-my-admin|sqlmanager|mysqlmanager|p/m/a|php-myadmin|phpmy-admin|webadmin|sqlweb|websql|webdb|mysqladmin|mysql-admin)/ HTTP/1.1"</span> <span style="color: #cc66cc;">404</span><br />
<br />
ignoreregex <span style="color: #339933;">=</span> </blockquote>
В /etc/fail2ban/jail.conf нужно добавить секцию<br />
<blockquote>
<span style="color: red;">[</span>phpmyadmin<span style="color: red;">]</span><br />
<br />
enabled <span style="color: #600000;">=</span> <span style="color: purple;">true</span><br />
port <span style="color: #600000;">=</span> http,https<br />
filter <span style="color: #600000;">=</span> phpmyadmin<br />
logpath <span style="color: #600000;">=</span> <span style="color: #000060;">/var/log/nginx/localhost.access.log</span><br />
bantime <span style="color: #600000;">=</span> <span style="color: red;">86400</span><br />
maxretry <span style="color: #600000;">=</span> <span style="color: red;">1</span> </blockquote>
<br />
За основу для построения скрипта был взят список<br />
<pre style="border: 1px solid #000; padding: 5px;"><code>phpmyadmin
PMA
pma
admin
dbadmin
sql
mysql
myadmin
phpmyadmin2
phpMyAdmin2
phpMyAdmin-2
php-my-admin
sqlmanager
mysqlmanager
p/m/a
php-myadmin
phpmy-admin
webadmin
sqlweb
websql
webdb
mysqladmin
mysql-admin
2phpmyadmin
MyAdmin
admin/db
admin/pMA
admin/phpMyAdmin
admin/phpmyadmin
admin/sqladmin
admin/sysadmin
admin/web
administrator/PMA
administrator/admin
administrator/db
administrator/phpMyAdmin
administrator/phpmyadmin
administrator/pma
administrator/web
database
db
mysql/admin
mysql/db
mysql/dbadmin
mysql/mysqlmanager
mysql/pMA
mysql/pma
mysql/sqlmanager
mysql/web
phpMyAdmin
phpMyadmin
phpmy
phpmyAdmin
phppma
program
sql/myadmin
sql/php-myadmin
sql/phpMyAdmin
sql/phpMyAdmin2
sql/phpmanager
sql/phpmy-admin
sql/phpmyadmin2
sql/sql-admin
sql/sql
sql/sqladmin
sql/sqlweb
sql/webadmin
sql/webdb
sql/websql
PMA2005
pma2005
phpmanager
</code></pre>
Учитывая логику работы ботов, то что в первую очередь они простукивают каталоки первого уровня, а лишь затем уровнем выше, этот список можно сократить до такого:<br />
<pre style="border: 1px solid #000; padding: 5px;"><code>phpmyadmin
PMA
pma
admin
dbadmin
sql
mysql
myadmin
phpmyadmin2
phpMyAdmin2
phpMyAdmin-2
php-my-admin
sqlmanager
mysqlmanager
p\/m\/a
php-myadmin
phpmy-admin
webadmin
sqlweb
websql
webdb
mysqladmin
mysql-admin
2phpmyadmin
MyAdmin
PMA2005
administrator
database
db
phpMyAdmin
phpMyadmin
phpmanager
phpmy
phpmyAdmin
phppma
pma2005
program</code></pre>
В результате получается приведенный выше конфиг.<br />
<br />
<br />
Для проверки используем команду:<br />
fail2ban-regex <span style="color: red;">'113.204.67.51 - - [19/Jan/2013:07:22:25 +0400] "GET /mysqlmanager/ HTTP/1.1" 404 564 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"'</span> <span style="color: red;">'^<host><host><host> - - [.*] "GET /(?:phpmyadmin|PMA|pma|admin|dbadmin|sql|mysql|myadmin|phpmyadmin2|phpMyAdmin2|phpMyAdmin-2|php-my-admin|sqlmanager|mysqlmanager|p/m/a|php-myadmin|phpmy-admin|webadmin|sqlweb|websql|webdb|mysqladmin|mysql-admin|2phpmyadmin|MyAdmin|PMA2005|administrator|database|db|phpMyAdmin|phpMyadmin|phpmanager|phpmy|phpmyAdmin|phppma|pma2005|program)/ HTTP/1.1" 404'</host></host></host></span>valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-47201359115716232732013-01-17T08:07:00.002-08:002013-01-17T08:12:27.791-08:00Как в php узнать протокол (https)Оказывается, узнать, что сайт использует <b>SSL</b> и страница открыта по протоколу <b>https</b> не настолько
тривиальная задача, что бы решить ее с наскока.<br />
Однако, решение оказалось достаточно простое.<br />
<br />
Проблема заключается в том, что для определения протокола могут быть использованы переменные<br />
<pre class="php" style="font-family: monospace;"><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">[</span><span style="color: blue;">'HTTPS'</span><span style="color: #009900;">]</span>
<span style="color: #000088;">$_SERVER</span><span style="color: #009900;">[</span><span style="color: blue;">'HTTP_SCHEME'</span><span style="color: #009900;">]</span>
<span style="color: #000088;">$_SERVER</span><span style="color: #009900;">[</span><span style="color: blue;">'HTTP_X_FORWARDED_PROTO'</span><span style="color: #009900;">]</span></pre>
И косвенно<br />
<pre class="php" style="font-family: monospace;"><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">[</span><span style="color: blue;">'SERVER_PORT'</span><span style="color: #009900;">]</span></pre>
Но все эти переменные, кроме номера порта почти наверняка будут отсутствовать.<br />
Определять http-схему основываясь только на номере порта -- приемлемое, но не очень гибкое решение.<br />
<br />
Я сделал так:<br />
<pre class="php" style="font-family: monospace;"><span style="color: #000088;">$scheme</span> <span style="color: #339933;">=</span> <span style="color: #990000;">isset</span><span style="color: #009900;">(</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">[</span><span style="color: blue;">'HTTP_SCHEME'</span><span style="color: #009900;">]</span><span style="color: #009900;">)</span> ? <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">[</span><span style="color: blue;">'HTTP_SCHEME'</span><span style="color: #009900;">]</span> <span style="color: #339933;">:</span> <span style="color: #009900;">(</span>
<span style="color: #009900;">(</span>
<span style="color: #009900;">(</span><span style="color: #990000;">isset</span><span style="color: #009900;">(</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">[</span><span style="color: blue;">'HTTPS'</span><span style="color: #009900;">]</span><span style="color: #009900;">)</span> <span style="color: #339933;">&&</span> <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">[</span><span style="color: blue;">'HTTPS'</span><span style="color: #009900;">]</span> <span style="color: #339933;">!=</span> <span style="color: blue;">'off'</span><span style="color: #009900;">)</span> <span style="color: #339933;">||</span>
<span style="color: #cc66cc;">443</span> <span style="color: #339933;">==</span> <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">[</span><span style="color: blue;">'SERVER_PORT'</span><span style="color: #009900;">]</span>
<span style="color: #009900;">)</span> ? <span style="color: blue;">'https'</span> <span style="color: #339933;">:</span> <span style="color: blue;">'http'</span>
<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
</pre>
<br />
И для надежности, что бы <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">[</span><span style="color: blue;">'HTTP_SCHEME'</span><span style="color: #009900;">]</span> была определена, в nginx.conf добавил строчку<br />
<br />
<pre class="tcl" style="font-family: monospace;"><span style="color: grey; font-style: italic;"># for SSL</span>
fastcgi_param HTTP_SCHEME <span style="color: #ff3333;">$scheme</span><span style="color: #66cc66;">;</span></pre>
<br />
<br />valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-19530573097898197162012-12-06T13:56:00.000-08:002012-12-07T04:41:41.924-08:00Мозаика из фотографий с помощью convert (imageMagic)Из фотографий или картинок одинакового размера можно сделать мозаику. Получается интересный эффект.<br />
Для этого я написал два bash скрипта.<br />
Первый уменьшает размеры фотографий, второй делает из миниатюр мозаику.<br />
<br />
<div style="border: 1px solid #000; overflow-y: scroll; padding: 5px;">
<pre class="bash" style="font-family: monospace;"><span style="color: #666666; font-style: italic;">#!/bin/bash</span>
<span style="color: #007800;">SW</span>=<span style="color: black;">150</span>
<span style="color: #007800;">SH</span>=<span style="color: black;">150</span>
<span style="color: #007800;">FROMDIR</span>=<span style="color: red;">"fromdir"</span>
<span style="color: #007800;">TODIR</span>=<span style="color: red;">"todir"</span>
<span style="color: black; font-weight: bold;">for</span> name <span style="color: black; font-weight: bold;">in</span> $<span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #c20cb9; font-weight: bold;">ls</span> <span style="color: #007800;">$FROMDIR</span><span style="color: #7a0874; font-weight: bold;">)</span>; <span style="color: black; font-weight: bold;">do</span> convert <span style="color: #660033;">-resize</span> <span style="color: maroon;">${SW}</span>x<span style="color: maroon;">${SW}</span> <span style="color: #660033;">-strip</span> <span style="color: #007800;">$FROMDIR</span><span style="color: black; font-weight: bold;">/</span><span style="color: #007800;">$name</span> <span style="color: #007800;">$TODIR</span><span style="color: black; font-weight: bold;">/</span><span style="color: #007800;">$name</span>; <span style="color: black; font-weight: bold;">done</span></pre>
</div>
<br />
Здесь <br />
<span style="color: #007800; font-family: monospace;">SW</span>
- ограничение ширины миниатюры; <span style="color: #007800; font-family: monospace;">SH</span> - ограничение высоты миниатюры; <span style="color: #007800; font-family: monospace;">FROMDIR</span> - каталог, в котором находятся фотографии; <span style="color: #007800;"><span style="font-family: monospace;">TODIR</span></span> - каталог, в который будут сложены миниатюры.<br />
<br />
Далее скрипт, который по миниатюрам создает мозаику:<br />
<br />
<div style="border: 1px solid #000; overflow-y: scroll; padding: 5px;">
<pre class="bash" style="font-family: monospace;"><span style="color: #666666; font-style: italic;">#!/bin/bash</span>
<span style="color: #007800;">SW</span>=<span style="color: black;">150</span>
<span style="color: #007800;">SH</span>=<span style="color: black;">112</span>
<span style="color: #007800;">COLS</span>=<span style="color: black;">15</span>
<span style="color: #007800;">REZFILE</span>=<span style="color: red;">"mosaic-<span style="color: #780078;">`date "+%Y-%m-%d_%H_%M_%S"`</span>.jpg"</span>
<span style="color: #007800;">FDIR</span>=<span style="color: red;">"small"</span>
$<span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"convert <span style="color: #007800;">$(i=0 && for name in $(ls $FDIR | sort -R)</span>; do echo -n "</span> <span style="color: #660033;">-page</span> +$<span style="color: #7a0874; font-weight: bold;">[</span><span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #007800;">$i</span><span style="color: black; font-weight: bold;">%</span><span style="color: #007800;">$COLS</span><span style="color: #7a0874; font-weight: bold;">)</span><span style="color: black; font-weight: bold;">*</span><span style="color: #007800;">$SW</span><span style="color: #7a0874; font-weight: bold;">]</span>+$<span style="color: #7a0874; font-weight: bold;">[</span><span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #007800;">$i</span>-<span style="color: #007800;">$i</span><span style="color: black; font-weight: bold;">%</span><span style="color: #007800;">$COLS</span><span style="color: #7a0874; font-weight: bold;">)</span><span style="color: black; font-weight: bold;">/</span><span style="color: #007800;">$COLS</span><span style="color: #7a0874; font-weight: bold;">)</span><span style="color: black; font-weight: bold;">*</span><span style="color: #007800;">$SH</span><span style="color: #7a0874; font-weight: bold;">]</span> <span style="color: #007800;">$FDIR</span><span style="color: black; font-weight: bold;">/</span><span style="color: #007800;">$name</span><span style="color: red;">" && i=$[<span style="color: #007800;">$i</span>+1]; done) -mosaic </span><span style="color: red;"><span style="color: #007800;">$REZFILE</span>"</span><span style="color: #7a0874; font-weight: bold;">)</span></pre>
</div>
<br />
Здесь <br />
<span style="color: #007800; font-family: monospace;">SW</span>
- ширина миниатюры; <span style="color: #007800; font-family: monospace;">SH</span> - высота миниатюры; <span style="color: #007800; font-family: monospace;">COLS</span> - количество столбцов; <span style="color: #007800;"><span style="font-family: monospace;">REZFILE</span></span> - файл с мозаикой; <span style="color: #007800;"><span style="font-family: monospace;">FDIR</span></span> - каталог миниатюрами.<br />
Еще раз напомню, все миниатюры должны быть одинакового размера. Иначе будут пустоты.<br />
Что бы мозаика повторяла пропорции исходных фотографий должно быть<br />
<div style="text-align: center;">
<b>SW==SH</b></div>
Число фотографий должно равняться произведению<br />
<div style="text-align: center;">
<b>SW*SH</b></div>
В последнем скрипте <b>sort -R</b> для случайного упорядочивания. Если его убрать, будет тот порядок, в котором выдает <b>ls</b>.<br />
Вот пример мозаики из аватарок пользователей сайта:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjylXNoB0GECkudGt_tndN-NWoDVf4mZb-bSHEwblf7uNN3V1LyfHDECy74L1EuflQfR3Zaw4Jh-Lj9iMbt2VOgb8adADyzlXCb7UoFkdE5g0KgRtaY5NkGy469gI6L8qPxj9Y9enswpBs/s1600/mosaic-xmpl.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjylXNoB0GECkudGt_tndN-NWoDVf4mZb-bSHEwblf7uNN3V1LyfHDECy74L1EuflQfR3Zaw4Jh-Lj9iMbt2VOgb8adADyzlXCb7UoFkdE5g0KgRtaY5NkGy469gI6L8qPxj9Y9enswpBs/s320/mosaic-xmpl.jpg" width="320" /></a></div>
<br />valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-81055007031485131032011-12-02T23:05:00.001-08:002011-12-04T10:22:26.250-08:00Установка Redis via unix.socket<h2>
О том, как установить Redis в качестве сервера на Linux и обращаться к нему через Unix.socket</h2>
<br />
По мотивам куцей доки: <a href="http://redis.io/topics/quickstart">http://redis.io/topics/quickstart</a> и <a href="http://redis.io/download">http://redis.io/download</a><br />
<br />
От рута делаем<br />
<b>mkdir /usr/src/redis<br />
cd /usr/src/redis</b><br />
<br />
<b>wget http://redis.googlecode.com/files/redis-2.4.4.tar.gz<br />
tar xzf redis-2.4.4.tar.gz<br />
cd redis-2.4.4<br />
make && make test</b><br />
<br />
Если тесты прошли нормально (должно быть написано что то вроде этого: "\o/ All tests passed without errors!"), то двигаемся дальше<br />
<br />
<b>mv ../redis-2.4.4.tar.gz ./redis-2.4.4.tar.gz</b><br />
<br />
<b>cp src/redis-server /usr/local/bin/<br />
cp src/redis-cli /usr/local/bin/</b><br />
<br />
<b>mkdir /etc/redis<br />
mkdir /var/redis</b><br />
<br />
Далее в доке предлагается сделать 'cp utils/redis_init_script /etc/init.d/redis_6379', где 6379 - номер дефолтного порта, но я планирую что Redis будет работать у меня через unix.socket,<br />
поэтому, будет так (везде далее нолик появляется именно по этой же причине):<br />
<br />
<b>cp utils/redis_init_script /etc/init.d/redis_0</b><br />
<br />
Теперь нужно подредактировать конфиг:<br />
<b>nano /etc/init.d/redis_0</b><br />
<br />
Собственно, редактированию там подлежит только номер порта (6-я строка):<br />
REDISPORT=6379 --> REDISPORT=0<br />
Если номер порта не менять, то и редактировать ничего не нужно.<br />
<br />
Но в моем случае, <i>поскольку</i> я планирую запускать редис <i>через unix socket</i>, то нужно еще внести несколько изменений:<br />
Добавляем переменную<br />
UNIXSOCK=/tmp/redis.sock<br />
и выражение '$CLIEXEC -p $REDISPORT shutdown' в секции "stop" заменяем на '$CLIEXEC -s $UNIXSOCK shutdown'<br />
<br />
<br />
Вот что получилось:<br />
<div style="border: 1px solid rgb(0, 0, 0);">
<pre class="bash" style="font-family: monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
<span style="color: #007800;">REDISPORT</span>=<span style="color: black;">0</span>
<span style="color: #666666; font-style: italic;">#REDISPORT=6379</span>
<span style="color: #007800;">UNIXSOCK</span>=<span style="color: black; font-weight: bold;">/</span>tmp<span style="color: black; font-weight: bold;">/</span>redis.sock
<span style="color: #007800;">OWNER</span>=nobody
<span style="color: #007800;">EXEC</span>=<span style="color: black; font-weight: bold;">/</span>usr<span style="color: black; font-weight: bold;">/</span>local<span style="color: black; font-weight: bold;">/</span>bin<span style="color: black; font-weight: bold;">/</span>redis-server
<span style="color: #007800;">CLIEXEC</span>=<span style="color: black; font-weight: bold;">/</span>usr<span style="color: black; font-weight: bold;">/</span>local<span style="color: black; font-weight: bold;">/</span>bin<span style="color: black; font-weight: bold;">/</span>redis-cli
<span style="color: #007800;">PIDFILE</span>=<span style="color: black; font-weight: bold;">/</span>var<span style="color: black; font-weight: bold;">/</span>run<span style="color: black; font-weight: bold;">/</span>redis_<span style="color: maroon;">${REDISPORT}</span>.pid
<span style="color: #007800;">CONF</span>=<span style="color: red;">"/etc/redis/<span style="color: #007800;">${REDISPORT}</span>.conf"</span>
<span style="color: black; font-weight: bold;">case</span> <span style="color: red;">"$1"</span> <span style="color: black; font-weight: bold;">in</span>
start<span style="color: #7a0874; font-weight: bold;">)</span>
<span style="color: black; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #660033;">-f</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #7a0874; font-weight: bold;">]</span>
<span style="color: black; font-weight: bold;">then</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"<span style="color: #007800;">$PIDFILE</span> exists, process is already running or crashed"</span>
<span style="color: black; font-weight: bold;">else</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Starting Redis server..."</span>
<span style="color: #007800;">$EXEC</span> <span style="color: #007800;">$CONF</span>
<span style="color: black; font-weight: bold;">fi</span>
<span style="color: black; font-weight: bold;">;;</span>
stop<span style="color: #7a0874; font-weight: bold;">)</span>
<span style="color: black; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: black; font-weight: bold;">!</span> <span style="color: #660033;">-f</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #7a0874; font-weight: bold;">]</span>
<span style="color: black; font-weight: bold;">then</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"<span style="color: #007800;">$PIDFILE</span> does not exist, process is not running"</span>
<span style="color: black; font-weight: bold;">else</span>
<span style="color: #007800;">PID</span>=$<span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #007800;">$PIDFILE</span><span style="color: #7a0874; font-weight: bold;">)</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Stopping ..."</span>
<span style="color: #666666; font-style: italic;">#$CLIEXEC -p $REDISPORT shutdown</span>
<span style="color: #007800;">$CLIEXEC</span> <span style="color: #660033;">-s</span> <span style="color: #007800;">$UNIXSOCK</span> shutdown
<span style="color: black; font-weight: bold;">while</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #660033;">-x</span> <span style="color: black; font-weight: bold;">/</span>proc<span style="color: black; font-weight: bold;">/</span><span style="color: maroon;">${PID}</span> <span style="color: #7a0874; font-weight: bold;">]</span>
<span style="color: black; font-weight: bold;">do</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Waiting for Redis to shutdown ."</span>
<span style="color: #c20cb9; font-weight: bold;">sleep</span> <span style="color: black;">0.5</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #660033;">-n</span> <span style="color: red;">".."</span>
<span style="color: #c20cb9; font-weight: bold;">sleep</span> <span style="color: black;">0.5</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #660033;">-n</span> <span style="color: red;">".."</span>
<span style="color: black; font-weight: bold;">done</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Redis stopped"</span>
<span style="color: black; font-weight: bold;">fi</span>
<span style="color: black; font-weight: bold;">;;</span>
restart<span style="color: #7a0874; font-weight: bold;">)</span>
<span style="color: black; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: black; font-weight: bold;">!</span> <span style="color: #660033;">-f</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #7a0874; font-weight: bold;">]</span>
<span style="color: black; font-weight: bold;">then</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"<span style="color: #007800;">$PIDFILE</span> does not exist, process is not running"</span>
<span style="color: black; font-weight: bold;">else</span>
<span style="color: #007800;">PID</span>=$<span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #007800;">$PIDFILE</span><span style="color: #7a0874; font-weight: bold;">)</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Stopping ..."</span>
<span style="color: #666666; font-style: italic;">#$CLIEXEC -p $REDISPORT shutdown</span>
<span style="color: #007800;">$CLIEXEC</span> <span style="color: #660033;">-s</span> <span style="color: #007800;">$UNIXSOCK</span> shutdown
<span style="color: black; font-weight: bold;">while</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #660033;">-x</span> <span style="color: black; font-weight: bold;">/</span>proc<span style="color: black; font-weight: bold;">/</span><span style="color: maroon;">${PID}</span> <span style="color: #7a0874; font-weight: bold;">]</span>
<span style="color: black; font-weight: bold;">do</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Waiting for Redis to shutdown ..."</span>
<span style="color: #c20cb9; font-weight: bold;">sleep</span> <span style="color: black;">1</span>
<span style="color: black; font-weight: bold;">done</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Redis stopped"</span>
<span style="color: black; font-weight: bold;">fi</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Starting Redis server..."</span>
<span style="color: #007800;">$EXEC</span> <span style="color: #007800;">$CONF</span>
<span style="color: black; font-weight: bold;">;;</span>
<span style="color: black; font-weight: bold;">*</span><span style="color: #7a0874; font-weight: bold;">)</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Please use start or stop as first argument"</span>
<span style="color: black; font-weight: bold;">;;</span>
<span style="color: black; font-weight: bold;">esac</span></pre>
</div>
Далее нам нужно скопировать файл конфига:<br />
cp redis.conf /etc/redis/0.conf<br />
И отредактировать его:<br />
nano /etc/redis/0.conf<br />
В нем меняем следующее:<br />
<br />
<i>#daemonize no<br />
daemonize yes</i><br />
<br />
<i>#pidfile /var/run/redis.pid<br />
pidfile /var/run/redis_0.pid</i><br />
<br />
<i>#port 6379<br />
port 0</i><br />
<br />
Для меня вроде как не актуально, но на всякий случай раскоментил строку<br />
<i>bind 127.0.0.1</i><br />
<br />
Также раскоментил<br />
<i>unixsocket /tmp/redis.sock<br />
unixsocketperm 755</i><br />
<br />
<i>#loglevel verbose<br />
loglevel warning</i><br />
<br />
<i>#logfile stdout<br />
logfile /var/log/redis_0.log</i><br />
<br />
<i>#databases 16<br />
databases 1</i><br />
<br />
В секции "SNAPSHOTTING" можно поменять стратегию дампов. Я сделал так:<br />
<br />
<i>save 54000 10<br />
save 3600 5000<br />
<br />
dir /var/redis/dumps/<br />
dbfilename dump_0.rdb</i><br />
<br />
Поскольку в сеть смотреть мой редис не будет, то репликацию я в нем отключил (секция 'REPLICATION'):<br />
<br />
<i>#slave-serve-stale-data yes<br />
slave-serve-stale-data no</i><br />
<br />
Далее, поскольку, как и сказано в конфиге, я обираюсь использовать редис не в качестве основной БД, а в качестве кеша, то стоит установить maxmemory, что бы редис ненароком не сожрал всю память:<br />
# 256 MB<br />
<i>maxmemory 268435456</i><br />
<br />
Поскольку maxmemory установлен, то нужно установить и maxmemory-policy<br />
<br />
<i># maxmemory-policy volatile-lru<br />
maxmemory-policy volatile-ttl</i><br />
<br />
Выбрал volatile-ttl потому что не знаю как работает алгоритм LRU<br />
<br />
Отключаем appendfsync<br />
<i>appendfsync no</i><br />
<br />
Все на этом правки конфига закончены.<br />
Для логов мы указывали каталог /var/redis/dumps. Его нужно не забыть создать:<br />
<br />
<b>mkdir /var/redis/dumps</b><br />
<br />
Проверяем Все ли работает. Проверить можно так:<br />
запускаем<br />
<b>/etc/init.d/redis_0 start</b><br />
Потом<br />
<b>redis-cli -s /tmp/redis.sock</b><br />
redis 127.0.0.1:6379> <b>SET key1 "Test"</b><br />
OK<br />
redis 127.0.0.1:6379> <b>GET key1</b><br />
"Test"<br />
redis 127.0.0.1:6379><br />
<br />
Если все нормально, то добавляем в автозагрузку:<br />
<br />
<b>update-rc.d redis_0 defaults</b><br />
<br />
PS<br />
В логах редиса он сообщил мне следующее предупреждение:<br />
WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.<br />
<br />
Поскольку я готов мериться с тем, что он не будет дампить себя на диск, то это предупреждение проигнорирую.<br />
А вообще решение вижу таким:<br />
В /etc/sysctl.conf ничего естественно не вносим, но в /etc/init.d/redis_0<br />
В секции старт, перед запуском редиса, сохраняем системное значение overcommit_memory<br />
touch /tmp/overcommit_memory_bfr_redis<br />
chmod 0600 /tmp/overcommit_memory_bfr_redis<br />
cat /proc/sys/vm/overcommit_memory > /tmp/overcommit_memory_bfr_redis<br />
sysctl vm.overcommit_memory=1<br />
А в секцию стоп, возвращаем системное значение:<br />
OCMSYS=$(cat /tmp/overcommit_memory_bfr_redis)<br />
sysctl vm.overcommit_memory=$OCMSYS<br />
<div style="border: 1px solid rgb(0, 0, 0);">
<pre class="bash" style="font-family: monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
<span style="color: #007800;">REDISPORT</span>=<span style="color: black;">0</span>
<span style="color: #666666; font-style: italic;">#REDISPORT=6379</span>
<span style="color: #007800;">UNIXSOCK</span>=<span style="color: black; font-weight: bold;">/</span>tmp<span style="color: black; font-weight: bold;">/</span>redis.sock
<span style="color: #007800;">OWNER</span>=nobody
<span style="color: #007800;">EXEC</span>=<span style="color: black; font-weight: bold;">/</span>usr<span style="color: black; font-weight: bold;">/</span>local<span style="color: black; font-weight: bold;">/</span>bin<span style="color: black; font-weight: bold;">/</span>redis-server
<span style="color: #007800;">CLIEXEC</span>=<span style="color: black; font-weight: bold;">/</span>usr<span style="color: black; font-weight: bold;">/</span>local<span style="color: black; font-weight: bold;">/</span>bin<span style="color: black; font-weight: bold;">/</span>redis-cli
<span style="color: #007800;">PIDFILE</span>=<span style="color: black; font-weight: bold;">/</span>var<span style="color: black; font-weight: bold;">/</span>run<span style="color: black; font-weight: bold;">/</span>redis_<span style="color: maroon;">${REDISPORT}</span>.pid
<span style="color: #007800;">CONF</span>=<span style="color: red;">"/etc/redis/<span style="color: #007800;">${REDISPORT}</span>.conf"</span>
<span style="color: #666666; font-style: italic;">#fix WARNING obout overcommit_memory</span>
<span style="color: #007800;">FWOBOM</span>=FALSE
<span style="color: black; font-weight: bold;">case</span> <span style="color: red;">"$1"</span> <span style="color: black; font-weight: bold;">in</span>
start<span style="color: #7a0874; font-weight: bold;">)</span>
<span style="color: black; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #660033;">-f</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #7a0874; font-weight: bold;">]</span>
<span style="color: black; font-weight: bold;">then</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"<span style="color: #007800;">$PIDFILE</span> exists, process is already running or crashed"</span>
<span style="color: black; font-weight: bold;">else</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Starting Redis server..."</span>
<span style="color: #666666; font-style: italic;"># --> fix WARNING obout overcommit_memory</span>
<span style="color: black; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: red;">"TRUE"</span> = <span style="color: #007800;">$FWOBOM</span> <span style="color: #7a0874; font-weight: bold;">]</span>
<span style="color: black; font-weight: bold;">then</span>
<span style="color: #c20cb9; font-weight: bold;">touch</span> <span style="color: black; font-weight: bold;">/</span>tmp<span style="color: black; font-weight: bold;">/</span>overcommit_memory_bfr_redis
<span style="color: #c20cb9; font-weight: bold;">chmod</span> 0600 <span style="color: black; font-weight: bold;">/</span>tmp<span style="color: black; font-weight: bold;">/</span>overcommit_memory_bfr_redis
<span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: black; font-weight: bold;">/</span>proc<span style="color: black; font-weight: bold;">/</span>sys<span style="color: black; font-weight: bold;">/</span>vm<span style="color: black; font-weight: bold;">/</span>overcommit_memory <span style="color: black; font-weight: bold;">></span> <span style="color: black; font-weight: bold;">/</span>tmp<span style="color: black; font-weight: bold;">/</span>overcommit_memory_bfr_redis
sysctl vm.overcommit_memory=<span style="color: black;">1</span>
<span style="color: black; font-weight: bold;">fi</span>
<span style="color: #666666; font-style: italic;"># <--</span>
<span style="color: #007800;">$EXEC</span> <span style="color: #007800;">$CONF</span>
<span style="color: black; font-weight: bold;">fi</span>
<span style="color: black; font-weight: bold;">;;</span>
stop<span style="color: #7a0874; font-weight: bold;">)</span>
<span style="color: black; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: black; font-weight: bold;">!</span> <span style="color: #660033;">-f</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #7a0874; font-weight: bold;">]</span>
<span style="color: black; font-weight: bold;">then</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"<span style="color: #007800;">$PIDFILE</span> does not exist, process is not running"</span>
<span style="color: black; font-weight: bold;">else</span>
<span style="color: #007800;">PID</span>=$<span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #007800;">$PIDFILE</span><span style="color: #7a0874; font-weight: bold;">)</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Stopping ..."</span>
<span style="color: #666666; font-style: italic;">#$CLIEXEC -p $REDISPORT shutdown</span>
<span style="color: #007800;">$CLIEXEC</span> <span style="color: #660033;">-s</span> <span style="color: #007800;">$UNIXSOCK</span> shutdown
<span style="color: black; font-weight: bold;">while</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #660033;">-x</span> <span style="color: black; font-weight: bold;">/</span>proc<span style="color: black; font-weight: bold;">/</span><span style="color: maroon;">${PID}</span> <span style="color: #7a0874; font-weight: bold;">]</span>
<span style="color: black; font-weight: bold;">do</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Waiting for Redis to shutdown ."</span>
<span style="color: #c20cb9; font-weight: bold;">sleep</span> <span style="color: black;">0.5</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #660033;">-n</span> <span style="color: red;">".."</span>
<span style="color: #c20cb9; font-weight: bold;">sleep</span> <span style="color: black;">0.5</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #660033;">-n</span> <span style="color: red;">".."</span>
<span style="color: black; font-weight: bold;">done</span>
<span style="color: #666666; font-style: italic;"># --> fix WARNING obout overcommit_memory </span>
<span style="color: black; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: red;">"TRUE"</span> = <span style="color: #007800;">$FWOBOM</span> <span style="color: #7a0874; font-weight: bold;">]</span>
<span style="color: black; font-weight: bold;">then</span>
<span style="color: #007800;">OCMSYS</span>=$<span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: black; font-weight: bold;">/</span>tmp<span style="color: black; font-weight: bold;">/</span>overcommit_memory_bfr_redis<span style="color: #7a0874; font-weight: bold;">)</span>
sysctl vm.overcommit_memory=<span style="color: #007800;">$OCMSYS</span>
<span style="color: black; font-weight: bold;">fi</span>
<span style="color: #666666; font-style: italic;"># <--</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Redis stopped"</span>
<span style="color: black; font-weight: bold;">fi</span>
<span style="color: black; font-weight: bold;">;;</span>
restart<span style="color: #7a0874; font-weight: bold;">)</span>
<span style="color: black; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: black; font-weight: bold;">!</span> <span style="color: #660033;">-f</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #7a0874; font-weight: bold;">]</span>
<span style="color: black; font-weight: bold;">then</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"<span style="color: #007800;">$PIDFILE</span> does not exist, process is not running"</span>
<span style="color: black; font-weight: bold;">else</span>
<span style="color: #007800;">PID</span>=$<span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #007800;">$PIDFILE</span><span style="color: #7a0874; font-weight: bold;">)</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Stopping ..."</span>
<span style="color: #666666; font-style: italic;">#$CLIEXEC -p $REDISPORT shutdown</span>
<span style="color: #007800;">$CLIEXEC</span> <span style="color: #660033;">-s</span> <span style="color: #007800;">$UNIXSOCK</span> shutdown
<span style="color: black; font-weight: bold;">while</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #660033;">-x</span> <span style="color: black; font-weight: bold;">/</span>proc<span style="color: black; font-weight: bold;">/</span><span style="color: maroon;">${PID}</span> <span style="color: #7a0874; font-weight: bold;">]</span>
<span style="color: black; font-weight: bold;">do</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Waiting for Redis to shutdown ..."</span>
<span style="color: #c20cb9; font-weight: bold;">sleep</span> <span style="color: black;">1</span>
<span style="color: black; font-weight: bold;">done</span>
<span style="color: #666666; font-style: italic;"># --> fix WARNING obout overcommit_memory </span>
<span style="color: black; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: red;">"TRUE"</span> = <span style="color: #007800;">$FWOBOM</span> <span style="color: #7a0874; font-weight: bold;">]</span>
<span style="color: black; font-weight: bold;">then</span>
<span style="color: #007800;">OCMSYS</span>=$<span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: black; font-weight: bold;">/</span>tmp<span style="color: black; font-weight: bold;">/</span>overcommit_memory_bfr_redis<span style="color: #7a0874; font-weight: bold;">)</span>
sysctl vm.overcommit_memory=<span style="color: #007800;">$OCMSYS</span>
<span style="color: black; font-weight: bold;">fi</span>
<span style="color: #666666; font-style: italic;"># <--</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Redis stopped"</span>
<span style="color: black; font-weight: bold;">fi</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Starting Redis server..."</span>
<span style="color: #666666; font-style: italic;"># --> fix WARNING obout overcommit_memory</span>
<span style="color: black; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: red;">"TRUE"</span> = <span style="color: #007800;">$FWOBOM</span> <span style="color: #7a0874; font-weight: bold;">]</span>
<span style="color: black; font-weight: bold;">then</span>
<span style="color: #c20cb9; font-weight: bold;">touch</span> <span style="color: black; font-weight: bold;">/</span>tmp<span style="color: black; font-weight: bold;">/</span>overcommit_memory_bfr_redis
<span style="color: #c20cb9; font-weight: bold;">chmod</span> 0600 <span style="color: black; font-weight: bold;">/</span>tmp<span style="color: black; font-weight: bold;">/</span>overcommit_memory_bfr_redis
<span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: black; font-weight: bold;">/</span>proc<span style="color: black; font-weight: bold;">/</span>sys<span style="color: black; font-weight: bold;">/</span>vm<span style="color: black; font-weight: bold;">/</span>overcommit_memory <span style="color: black; font-weight: bold;">></span> <span style="color: black; font-weight: bold;">/</span>tmp<span style="color: black; font-weight: bold;">/</span>overcommit_memory_bfr_redis
sysctl vm.overcommit_memory=<span style="color: black;">1</span>
<span style="color: black; font-weight: bold;">fi</span>
<span style="color: #666666; font-style: italic;"># <--</span>
<span style="color: #007800;">$EXEC</span> <span style="color: #007800;">$CONF</span>
<span style="color: black; font-weight: bold;">;;</span>
<span style="color: black; font-weight: bold;">*</span><span style="color: #7a0874; font-weight: bold;">)</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: red;">"Please use start or stop as first argument"</span>
<span style="color: black; font-weight: bold;">;;</span>
<span style="color: black; font-weight: bold;">esac</span></pre>
</div>
<br />
PPS overcommit_memory влияет на выделение памяти ядром и на работу OOM Killer. vm.overcommit_memory=0 - более безопасный вариант, т.к. кто его знает кого грохнет OOM Killer, если память кончится.<br />
PPPS Если tcp сокет устраивает, а нужно только (возможно задать порт), то в каталоге utils с исходниками есть скрипт install_server.sh, запуск которого сделает большую часть грязной работы описанной выше.valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com1tag:blogger.com,1999:blog-3900514035470574480.post-76929443298260985072011-10-01T04:24:00.001-07:002011-10-03T08:47:40.351-07:00Библиотека для загрузки фотографий на сайтtransImage - это <b>PHP библиотека для простой загрузки фотографий на сайт</b>.<br />
Она умеет:
<br />
<ul>
<li> Получать изображение из файла, автоматически нормализовать его размер для экономии памяти</li>
<li> Автоматически поворачивать исходное изображение по данным Exif</li>
<li> Создавать копии себя с изменненными размерами, изменять свой размер</li>
<li> Наносить водяные знаки. Поддерживает любые водяные знаки, соответствующие интерфейсу waterMark (см код)</li>
<li> Выводить результат клиенту или сохранять его в файловую систему</li>
<li> Подкладывать белый фон, если исходное изображение поддерживает прозрачность.</li>
<li>Быстро создавать миниатюру для предпросмотра, используя миниатюру из Exif.</li>
<li>Преобразовывать изображения в строку, для использования их с dada:URI. В этом случае небольшие изображения можно передовать с другими параметрами в JSON формате (при использовании Ajax).</li>
</ul>
Для более подробной информации, смотрите комментарии в коде.<br />
<br />
Подходит большенству сайтов, которым нужно получить от клиента фотографию, правильно преобразовать ее в соответствии с Exif, создать несколько вариантов с разными размерами, и, возможно, нанести водяной знак.<br />
Не рекомендую использовать ее для выдачи клиенту (браузеру) изображений больших размеров. Эта функция несет исключительно демонстративную нагрузку.<br />
<br />
Лицензия BSD.<br />
<br />
GitHub repo: <br />
<div class="separator" style="clear: both; text-align: left;">
<img border="0" height="45" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3h7ReevZStNWnSeXoJ5DFhHLnisbXTIsqRvlEhiLJ076UZ39DdXt5Jgiv3nbkQl0jeu5x90wRhXK_Fo0_2OHG3eJm3tbI57tntQ5GGNfgaFBlDWmw3r__-XLn-AkLq_UAyBBOSs6qvgk/s200/ghlogo.png" width="100" /></div>
<br />
<a href="https://github.com/valmat/transImage">https://github.com/valmat/transImage</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBHYKTFi1v1rJBNUegtkKxvq_es-_d6RwsvD6Qb68ndgnZuo48dcYhqvfh3-Td3VsX9o7Vb6Gu0S3HivNFK39XDGowWC_xeDT0GlG3Wa8lLy6cZi3V4-8dG9MYZ6VEOB1ix3F1dyW6kvo/s1600/transImage_640x480.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBHYKTFi1v1rJBNUegtkKxvq_es-_d6RwsvD6Qb68ndgnZuo48dcYhqvfh3-Td3VsX9o7Vb6Gu0S3HivNFK39XDGowWC_xeDT0GlG3Wa8lLy6cZi3V4-8dG9MYZ6VEOB1ix3F1dyW6kvo/s320/transImage_640x480.png" width="240" /></a></div>
valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-89573152855997972772011-09-02T10:23:00.000-07:002011-09-02T11:00:01.024-07:00Замена салонного фильтра на Fiat AlbeaДля замены салонного фильтра понадобятся<ul><li>фильтр</li><li>крестовая отвертка</li><li>фонарик</li><li>тряпка под коленки</li><li>хорошая погода</li></ul>Операция занимает 15 минут. Перед входом со стороны переднего пассажира лучше бросить тряпку. Потому что, что бы добраться до фильтра придется встать на колени и залезть под бардачок.
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimCiEqHunIhhFhDLRi60BxKjXCZ2D7GF4Zv7OlN7qTbUQt6nSPdupDXtV6KpqWynbClT3MAwtcc2mLYjf2I71VtfMBU6cH7lQN5F4U5mck88O9GZluEXEZEUuhej9OosyESRczlSwev_4/s1600/1.jpg_new.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 309px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimCiEqHunIhhFhDLRi60BxKjXCZ2D7GF4Zv7OlN7qTbUQt6nSPdupDXtV6KpqWynbClT3MAwtcc2mLYjf2I71VtfMBU6cH7lQN5F4U5mck88O9GZluEXEZEUuhej9OosyESRczlSwev_4/s400/1.jpg_new.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647815360999430866" /></a>
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCZtXmrxEUyk9jhDf2_SKJMRR4WOhbRyIW5iId-pXQf-c7FjvhFs4u7T4zVxc9uRcPFMv5iGmS1KNsoy8gd_TQJwY3IlNjGChOleDeZfKn9fkzO4r98gKv6qoDtG6UC2c4Byz0gbQ-FbY/s1600/2.jpg_new.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCZtXmrxEUyk9jhDf2_SKJMRR4WOhbRyIW5iId-pXQf-c7FjvhFs4u7T4zVxc9uRcPFMv5iGmS1KNsoy8gd_TQJwY3IlNjGChOleDeZfKn9fkzO4r98gKv6qoDtG6UC2c4Byz0gbQ-FbY/s400/2.jpg_new.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647815359635696434" /></a>
<br />Фильтра находится под бардачком.
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCh3LfKnDLjNHOYAqydHHCYPfZ2DOmwu4ljGSJP3YEo9dCDIBhIt7idjtlP4TjPemBmeosUbiYS4saqnevxQ0B-4mfzRtxo0h-FS3mtIzEj91p6eM7OUSWQWsMrtz9AhcA_MCECJKk2gU/s1600/3.jpg_new.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 300px; height: 400px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCh3LfKnDLjNHOYAqydHHCYPfZ2DOmwu4ljGSJP3YEo9dCDIBhIt7idjtlP4TjPemBmeosUbiYS4saqnevxQ0B-4mfzRtxo0h-FS3mtIzEj91p6eM7OUSWQWsMrtz9AhcA_MCECJKk2gU/s400/3.jpg_new.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647815366101165538" /></a>
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXAOrvtCc6x6utjLHnQWB85g7Xrspwz74LfdbQw4lpd3ZgLBq8KMkI4NJLEKt5PLuRjr3MZSt7S70SlStG6sqD4cy3fm8AAqWBqmblQ2SsgEOK9LZ56KvecscdzTsYmjpTRxnfcjpqiLk/s1600/4.jpg_new.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 267px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXAOrvtCc6x6utjLHnQWB85g7Xrspwz74LfdbQw4lpd3ZgLBq8KMkI4NJLEKt5PLuRjr3MZSt7S70SlStG6sqD4cy3fm8AAqWBqmblQ2SsgEOK9LZ56KvecscdzTsYmjpTRxnfcjpqiLk/s400/4.jpg_new.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647815367185710050" /></a>
<br />Крепится двумя шурупами.
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilKETdm5Zp3He-gUOhVNFtiET3gp7HnLGjZlEANOw9D7l8tlTOmQGKIpEX2BdA6BoAMGCrtNEdYe7s75Yj-8KRBFrTYzPjtpGXO51ozpkm98YrFkICAU-CyXdiZC9f8BaEbk3E22q4-xc/s1600/5.jpg_new.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 300px; height: 400px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilKETdm5Zp3He-gUOhVNFtiET3gp7HnLGjZlEANOw9D7l8tlTOmQGKIpEX2BdA6BoAMGCrtNEdYe7s75Yj-8KRBFrTYzPjtpGXO51ozpkm98YrFkICAU-CyXdiZC9f8BaEbk3E22q4-xc/s400/5.jpg_new.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647815373248840562" /></a>
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZNb6R1E2QNaB2zkMbfndKjgIAUT1fGFzj5qY7Xz1L6nVpq8vMVD07VsBUJW4N80KX7aQegc2OZaqb5BwqD9bH_7sJkHqhdM9WHglSgzhyphenhyphen06TlRzVO77PFIFKJ9hRV_qppEz83MO-xYPY/s1600/6.jpg_new.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 300px; height: 400px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZNb6R1E2QNaB2zkMbfndKjgIAUT1fGFzj5qY7Xz1L6nVpq8vMVD07VsBUJW4N80KX7aQegc2OZaqb5BwqD9bH_7sJkHqhdM9WHglSgzhyphenhyphen06TlRzVO77PFIFKJ9hRV_qppEz83MO-xYPY/s400/6.jpg_new.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647815854969471906" /></a>
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQVcn1Bq9IdsdjXPhXANjb2QKgRHVdRpoQKkCt4hw-O03ZzdeEYD0ueKcJpNHU15fx0O1bNIoEwfW4PUCvpv3K1dFFZSS9YDSdSdz5_cP-znSGq_sDoGpPIOALivlejYVCFQapiVxRie4/s1600/7.jpg_new.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQVcn1Bq9IdsdjXPhXANjb2QKgRHVdRpoQKkCt4hw-O03ZzdeEYD0ueKcJpNHU15fx0O1bNIoEwfW4PUCvpv3K1dFFZSS9YDSdSdz5_cP-znSGq_sDoGpPIOALivlejYVCFQapiVxRie4/s400/7.jpg_new.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647815853059574770" /></a>
<br />Следующие две фотографии должны сподвигнуть увидевших их на срочную замену фильтра в своей машине.
<br />Я не менял два года.
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH_whLsCLIXCuLy7IUBxfUg4-iQZXar-EZTkGbjgNrr8wisIXr2A1XnpGaSf10hWegwC9tnWDZae9kaMgKm8wwp1pgw7KFZutMvKBxVR0Gb6YHcgzqiCXj-hinJp-LZcyY9xUsM_osELM/s1600/8.jpg_new.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 300px; height: 400px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH_whLsCLIXCuLy7IUBxfUg4-iQZXar-EZTkGbjgNrr8wisIXr2A1XnpGaSf10hWegwC9tnWDZae9kaMgKm8wwp1pgw7KFZutMvKBxVR0Gb6YHcgzqiCXj-hinJp-LZcyY9xUsM_osELM/s400/8.jpg_new.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647815859564514354" /></a>
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqGSs54_TqKxb1vGEG-4uoBV5_SAPUCxAwoUCgXQrA3MuHPxg9YBXtKxhjynkRsyBO15neT-CL08NbvlN7NqmgV7ixKOEoaBmiRFBlIGuUMsK_lDYB6s42tPV9uyViXP3uhom77YhX4oc/s1600/9.jpg_new.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqGSs54_TqKxb1vGEG-4uoBV5_SAPUCxAwoUCgXQrA3MuHPxg9YBXtKxhjynkRsyBO15neT-CL08NbvlN7NqmgV7ixKOEoaBmiRFBlIGuUMsK_lDYB6s42tPV9uyViXP3uhom77YhX4oc/s400/9.jpg_new.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647815856232219346" /></a>
<br />
<br />Я поставил себе угольный фильтр. Его год: <b>9.7.541</b> (260 руб на екзисте)
<br />Можно не извращаться и поставить обычный. Будет дешевле. Код обычного фильтра: <b>9.7.540</b> (150 руб на екзисте)valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com16tag:blogger.com,1999:blog-3900514035470574480.post-21584053097490820862011-09-02T07:58:00.000-07:002011-09-02T11:00:51.175-07:00Установка ветровиков на Fiat AlbeaНаконец то установил ветровики на свой Фиат.
<br />Вот что получилось:
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCTjkzDRa6b8yVmoP-fQQnzXSrvSlTdbOPBNv3dKvE8DHOGOHKmjDq8Fx8ChhfyjJDgR6af4GK8Xo4oo09pKWKVlhwmnALiT1ZUM7EwG-s6vtY9eSAkK8gVdqWXsaXctqBdAz-PLzoPGg/s1600/02092011133.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCTjkzDRa6b8yVmoP-fQQnzXSrvSlTdbOPBNv3dKvE8DHOGOHKmjDq8Fx8ChhfyjJDgR6af4GK8Xo4oo09pKWKVlhwmnALiT1ZUM7EwG-s6vtY9eSAkK8gVdqWXsaXctqBdAz-PLzoPGg/s400/02092011133.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647779150803377394" /></a>
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6d7jvX2yFCXjcocGYLx0Jyj2C3ctPk3UhC4BQ2aeAg0yWEnTa8PMO75jEk5Y5ANW2jtVrIASJMgn6KvW4cGKK7A3mZuhadxmWS0W-DokcT28uS_5GNiwhSjK0OhrWgzuz0MXgqLIJp0U/s1600/02092011134.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6d7jvX2yFCXjcocGYLx0Jyj2C3ctPk3UhC4BQ2aeAg0yWEnTa8PMO75jEk5Y5ANW2jtVrIASJMgn6KvW4cGKK7A3mZuhadxmWS0W-DokcT28uS_5GNiwhSjK0OhrWgzuz0MXgqLIJp0U/s400/02092011134.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647779153704937106" /></a>
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXvJxagwTE6bLInN2o8yJJKzL4fDkrW4nDRoS-jySbYv-j8SXNpUCsxj2CHahjhk3u_9yoXQt1gVNs6tU8v-cDnMPVEnUI1PFPYte63GuSpBFFnPYwnXyiFVHej-tZoE00HFQmoDXX-Ok/s1600/02092011135.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXvJxagwTE6bLInN2o8yJJKzL4fDkrW4nDRoS-jySbYv-j8SXNpUCsxj2CHahjhk3u_9yoXQt1gVNs6tU8v-cDnMPVEnUI1PFPYte63GuSpBFFnPYwnXyiFVHej-tZoE00HFQmoDXX-Ok/s400/02092011135.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647779156489426178" /></a>
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyOthLuz5XtvAFkF1jtFF8ylGg8yNPB6An9LbkuXWORpGCd1pxk8FrO0R0MwFgBq31jCWRYgdGZd3D4W8r7DerJnzF5WT0CGFAh9wFjI4snEXeEgd2HvSn63nMlrBEO4R5jA7T80eKKbw/s1600/02092011136.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyOthLuz5XtvAFkF1jtFF8ylGg8yNPB6An9LbkuXWORpGCd1pxk8FrO0R0MwFgBq31jCWRYgdGZd3D4W8r7DerJnzF5WT0CGFAh9wFjI4snEXeEgd2HvSn63nMlrBEO4R5jA7T80eKKbw/s400/02092011136.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647779163795464738" /></a>
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlnueaDyqQripcz2LR6eUzJwE8reC1dluVZMLx7MLSTDovNHu95GtmXIdfoFXAmXyk2M4Qco87eYY9IA3IsHTQrvhc5RQ5j9v15-P9dOMNqDxfzbqG7VcKCsoRHW5FP7iddsuj1rQK-ek/s1600/02092011137.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 300px; height: 400px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlnueaDyqQripcz2LR6eUzJwE8reC1dluVZMLx7MLSTDovNHu95GtmXIdfoFXAmXyk2M4Qco87eYY9IA3IsHTQrvhc5RQ5j9v15-P9dOMNqDxfzbqG7VcKCsoRHW5FP7iddsuj1rQK-ek/s400/02092011137.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647780987094969698" /></a>
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhshHXhpIkxU58msYkw0Zr8Qn3wfJspCgkj9BlkwSjJGSBB0zlI7ufj98a1fBCUVJT97wPKBo8xe34mzL6V4QHzeTXK9vaHRJSNVVW5pYJjsDQATdGC0R_KvHDynG-qYDYhOF78WgpoBXg/s1600/02092011138.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhshHXhpIkxU58msYkw0Zr8Qn3wfJspCgkj9BlkwSjJGSBB0zlI7ufj98a1fBCUVJT97wPKBo8xe34mzL6V4QHzeTXK9vaHRJSNVVW5pYJjsDQATdGC0R_KvHDynG-qYDYhOF78WgpoBXg/s400/02092011138.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647780993341346658" /></a>
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiB9SVrYFnQQhvkvJugF62WPqFCoi8NYWWyGJJOeladxM3wHD0ARkGnexWvTcRmRmuKdE1aqZ6VKAMjeDDcShwFTaBMG-sdeyTXS0_Kt1Lp-KfK1m80NxgCMWEhdGK4DSQHnqsqmB717u8/s1600/02092011139.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiB9SVrYFnQQhvkvJugF62WPqFCoi8NYWWyGJJOeladxM3wHD0ARkGnexWvTcRmRmuKdE1aqZ6VKAMjeDDcShwFTaBMG-sdeyTXS0_Kt1Lp-KfK1m80NxgCMWEhdGK4DSQHnqsqmB717u8/s400/02092011139.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647780996224920338" /></a>
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9WU32Lc0FgQ4srfCl7jQWzus9m9Q-308cpGUSuE8gTL4LnAE6QwIsBpxMPcBvGv9B5bgoVvIHSHQ3T90YOxXeKn3WV53r5tZ1F20LwnixsZAsCse75N2QkWvmhN1EnbVfBXVjRp7NxEk/s1600/02092011140.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9WU32Lc0FgQ4srfCl7jQWzus9m9Q-308cpGUSuE8gTL4LnAE6QwIsBpxMPcBvGv9B5bgoVvIHSHQ3T90YOxXeKn3WV53r5tZ1F20LwnixsZAsCse75N2QkWvmhN1EnbVfBXVjRp7NxEk/s400/02092011140.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647780998127471970" /></a>
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTAg0cWNMfu14EYklX8tMZueqKGEcNzgoQqPsyMg1ObgeWpvOXfN6eghmZ20wiQygorDhsdegJ-9probdOnmlSAOib8f1x8FQWsT8BH1hPAo61HMZ86Ktb03CYX1TuK-M-SVzOlCxz53g/s1600/02092011142.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTAg0cWNMfu14EYklX8tMZueqKGEcNzgoQqPsyMg1ObgeWpvOXfN6eghmZ20wiQygorDhsdegJ-9probdOnmlSAOib8f1x8FQWsT8BH1hPAo61HMZ86Ktb03CYX1TuK-M-SVzOlCxz53g/s400/02092011142.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647781002769852786" /></a>
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh05GoLEqkpZWKLbXH7sUWoN7R-zuX_2Un79g4MEnFYv3FKWF_2Obc5EYfBVtEIl1W5n-WmXaZuFfRabChqdEWapbESxPrmbo8ZQvoUUMWXRqHl5rAzavkAvD7Xn6QQDW69c8rhv-BFdU8/s1600/02092011143.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh05GoLEqkpZWKLbXH7sUWoN7R-zuX_2Un79g4MEnFYv3FKWF_2Obc5EYfBVtEIl1W5n-WmXaZuFfRabChqdEWapbESxPrmbo8ZQvoUUMWXRqHl5rAzavkAvD7Xn6QQDW69c8rhv-BFdU8/s400/02092011143.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5647781580442840498" /></a>
<br />
<br />Код дефлекторов: D07061
<br />valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-26971484536049231722011-04-11T09:22:00.000-07:002011-04-11T10:26:37.981-07:00Рыбацкие снасти из КитаяСегодня наконец то пришла моя рыбацкая посылка из Гонконга.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiy86wk7CiK-W7UUjb6MtFqjStZbUANhrMf5pOFpbYyfdYJQPax2njJwYZWBjleHIuCKecBpOuAVDMCQ2u_IqWGBdzqwTAz6UfmBX4JVP9mTDROD-hF1s8l6ar7Q47awS3EJWyvCOMAoMM/s1600/0.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 348px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiy86wk7CiK-W7UUjb6MtFqjStZbUANhrMf5pOFpbYyfdYJQPax2njJwYZWBjleHIuCKecBpOuAVDMCQ2u_IqWGBdzqwTAz6UfmBX4JVP9mTDROD-hF1s8l6ar7Q47awS3EJWyvCOMAoMM/s400/0.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5594370704164151698" /></a><br />А именно, сделал небольшой пробный заказ на китайском сайте focalprice.com.<br />До этого заказывал только на dealextreme.com.<br />Заказывал:<br /><ol><br /><li><a href="http://www.focalprice.com/detail_HL568X.html">Воблера</a></li><br /><li><a href="http://www.focalprice.com/detail_HL555X.html">Набор воблеров</a></li><br /><li><a href="http://www.focalprice.com/detail_HL289X.html">Набор виброхвостов</a></li><br /><li><a href="http://www.focalprice.com/detail_HL332G.html">Доставалку крючка из щучьей пасти</a></li><br /></ol><br />Шло около месяца, хотя я надеялся, что придет быстрее. Рыболовный сезон откроется не скоро, но тем неменее стоит учитывать. Отправили на следующий день после заказа. Это, безусловно, "+" В делекстриме бывает по две недели ждет отправки.<br />Качество товара вполне ожидаемое. Примерно тоже самое продается у нас в 90% рыбацких магазинов, но за большие деньги.<br />Воблер пришел другой расцветки. Я заказывал желтого цвета, пришел серебристый с красной башкой:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXbo1Dt1stFklJWY2YGD85SueGc16E220a_8sH6vmM7eg3h-PA3iJHOkMbLw185cK5MJ-QpXI2w-DYx7n2V16RH201cCsxstUH5GeKCSNPy6spIOeGhl1xQPPoc1QkcIlU0u2qXQ62KrY/s1600/HL568X.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 384px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXbo1Dt1stFklJWY2YGD85SueGc16E220a_8sH6vmM7eg3h-PA3iJHOkMbLw185cK5MJ-QpXI2w-DYx7n2V16RH201cCsxstUH5GeKCSNPy6spIOeGhl1xQPPoc1QkcIlU0u2qXQ62KrY/s400/HL568X.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5594369862124006178" /></a><br /><br />Виброхвосты, я ожидал, должны были быть по-больше. Но тут уж сам виноват. На сайте размеры указаны. Хотя, впрочем, я не расстроился. Маленькую рыбу тоже нужно чем то ловить<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiXun4F4BZfvAmmGnGPCAdiTWwD5RnvwgOWQ5zEKc2BZ9zj3Lls_M0dMQpR3TLTf0KiBcrmCE36qCgoUHBP62lMrQQv2WgtURnXxfcj18mKRChHjMlRmAmmYys2lwy0L5nc6V3WlWcHxU/s1600/6.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 278px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiXun4F4BZfvAmmGnGPCAdiTWwD5RnvwgOWQ5zEKc2BZ9zj3Lls_M0dMQpR3TLTf0KiBcrmCE36qCgoUHBP62lMrQQv2WgtURnXxfcj18mKRChHjMlRmAmmYys2lwy0L5nc6V3WlWcHxU/s400/6.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5594373612251311106" /></a><br />Джиги, как видно тоже маленькие. Грамм по пять.<br /><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRZnDNP0boPqteBent-3-4lwNCrzZn2YhCP9DuoM0Q0ekjR9_6w-oDQ58f4NYe0JznnibXxXWtluH9iOUSyhi14SuvxHakAtquv1wLvKZyl01dRKff9P85iUZRPWzm64yMkU6DeBfN_-A/s1600/2.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 288px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRZnDNP0boPqteBent-3-4lwNCrzZn2YhCP9DuoM0Q0ekjR9_6w-oDQ58f4NYe0JznnibXxXWtluH9iOUSyhi14SuvxHakAtquv1wLvKZyl01dRKff9P85iUZRPWzm64yMkU6DeBfN_-A/s400/2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5594376966752769714" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwkNSYWVDX4keHHKgX3GQM0ePljKpwoWvKvC1wSer_b-nbe2q3c6msvsIdweG_RXBkEjPB-c4ROZOHAc_6Nslcl4C7CrqCCh0CcS-xh5z553lk4OnFOT95SubvqJACVFZoJL3pI-vmVas/s1600/1.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 379px; height: 400px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwkNSYWVDX4keHHKgX3GQM0ePljKpwoWvKvC1wSer_b-nbe2q3c6msvsIdweG_RXBkEjPB-c4ROZOHAc_6Nslcl4C7CrqCCh0CcS-xh5z553lk4OnFOT95SubvqJACVFZoJL3pI-vmVas/s400/1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5594376916023737618" /></a><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAhzCtpWzSUZ8QGVeUk6EBTJ4PGnT58DvXPRmtX1E5_bvGmYFi3562fuUBWgfFBZPNeEqHbM1PN_tigf6PQYKhqDf2scvy0kuXsTif9isZgxZzxaLK4aiKdf9XH_RVXrNIaqTgNbZQ1Ag/s1600/4.jpg"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAhzCtpWzSUZ8QGVeUk6EBTJ4PGnT58DvXPRmtX1E5_bvGmYFi3562fuUBWgfFBZPNeEqHbM1PN_tigf6PQYKhqDf2scvy0kuXsTif9isZgxZzxaLK4aiKdf9XH_RVXrNIaqTgNbZQ1Ag/s400/4.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5594377269975011938" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhA_Ag56_QX_oHBZONetg2wb0m9w3GBXu0dtFqkmzfCBQYRKOLeZHnvsUQlHeUU8AzADQ-yB77MOi3L_ILhn0R0u-Rs1-dx6CuRsXKuFcDoQGWMCkA7el9xI5m5ycKQcN4gswXPoEuzIy0/s1600/3.jpg"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhA_Ag56_QX_oHBZONetg2wb0m9w3GBXu0dtFqkmzfCBQYRKOLeZHnvsUQlHeUU8AzADQ-yB77MOi3L_ILhn0R0u-Rs1-dx6CuRsXKuFcDoQGWMCkA7el9xI5m5ycKQcN4gswXPoEuzIy0/s400/3.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5594377266311010530" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkeuF_Hpa2XSzE7d9kTTXses6zGV6nV43_TqWUdrdeiOTBAmLlxFXGeGbhFn36ZalJzqJN3DnRHSq1OfMtghQwWvfGq03svrH6FqHFxnvI5sj4Uyd84NqPgpg2eGO5TcR7z9G-11-dh-E/s1600/7.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 308px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkeuF_Hpa2XSzE7d9kTTXses6zGV6nV43_TqWUdrdeiOTBAmLlxFXGeGbhFn36ZalJzqJN3DnRHSq1OfMtghQwWvfGq03svrH6FqHFxnvI5sj4Uyd84NqPgpg2eGO5TcR7z9G-11-dh-E/s400/7.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5594377612964296914" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihv3qS_oVa62WhK6kFKJ1iugnPb2A4fD2qUPy84tBRz8Jzr8E9Hb1urVmmq9zfn7PqIX4haeVvaLNg9wcopWIUB32HY2KsW5HYTWh9yLAY4_cpqeAQxyIl3858EglOOTViaJuig9FgCa0/s1600/5.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihv3qS_oVa62WhK6kFKJ1iugnPb2A4fD2qUPy84tBRz8Jzr8E9Hb1urVmmq9zfn7PqIX4haeVvaLNg9wcopWIUB32HY2KsW5HYTWh9yLAY4_cpqeAQxyIl3858EglOOTViaJuig9FgCa0/s400/5.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5594377608386172402" /></a><br />Так же обратил внимание, что посылка почему0то шла через Брянск и на Брянской таможне ее вскрывали:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj44L04IDVgBE2Bo3EzhN6Dpd8-iCZ8HJW_6UExFdvZ_C6vXs5Ap5hLjc7Ppg6QjJgdaHOZF1g98ftmE-260mp6w17d6qPHjI7Ly-YuD2RLE9Ig__TKt__B9aGtSVdz5wwJ15DcvAjLkCQ/s1600/10.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 140px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj44L04IDVgBE2Bo3EzhN6Dpd8-iCZ8HJW_6UExFdvZ_C6vXs5Ap5hLjc7Ppg6QjJgdaHOZF1g98ftmE-260mp6w17d6qPHjI7Ly-YuD2RLE9Ig__TKt__B9aGtSVdz5wwJ15DcvAjLkCQ/s400/10.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5594377915178057250" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUvd_CnE-LCh0RR0Bsv9rAINRGG20uTimI5R78N4cYttyKHZL9kkVDjoV3y9qp3CuO6o_a6Z1nm2eCEWxnjswAZvgjQu4Qlal3lVRzxcluR5TqjI7DwrayVeA6UngoZOcgm4dKDZFir7g/s1600/9.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 239px; height: 400px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUvd_CnE-LCh0RR0Bsv9rAINRGG20uTimI5R78N4cYttyKHZL9kkVDjoV3y9qp3CuO6o_a6Z1nm2eCEWxnjswAZvgjQu4Qlal3lVRzxcluR5TqjI7DwrayVeA6UngoZOcgm4dKDZFir7g/s400/9.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5594377908591021506" /></a>valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com2tag:blogger.com,1999:blog-3900514035470574480.post-2263911063859877452010-10-30T03:48:00.000-07:002010-10-30T04:46:46.489-07:00php CacherОпубликовал набор классов для кеширования:<br /><a href="http://github.com/valmat/Cacher">http://github.com/valmat/Cacher</a><br />Опубликовано под лицензией <br />GPL v.3 <a href="http://www.gnu.org/licenses/gpl.txt">http://www.gnu.org/licenses/gpl.txt</a><br />Т.е. свободно для использования и изменения. Разумеется, приветствуются любые исправления и дополнения.<br /><h2>Назначение</h2><br />Мне нужен был очень простой, но в то же время мощный кеширующий модуль с понятной логикой. При этом он должен быть пригодным для работы на односерверном, но в тоже время нагруженном проекте.<br />Так же немаловажным моментом является возможность прозрачно менять стратегию кеширования в зависимости от текущего уровня нагрузки проекта.<br />Т.е.решение должно удовлетворять требованию изменять стратегию кеширования по мере роста нагрузки на проект и по мере изменения аппаратных возможностей (речь об ОЗУ) сервера.<br /><h2>Архитектура</h2><br />Основными логическими единицами являются:<br /><ul><li><b>Cacher</b> - фронтен к кеширующим классам.</li><li><b>Cacher_Backend</b> - собственно сами кеширующие классы.</li><li><b>Слоты</b> - кеширование и доступ к кешу осуществляется через слоты.</li><li><b>Теги</b> - для упрощения управления кешем, и, главным образом, для переуеширования.</li><li><b>Типы кеширования</b> - для прозрачного изменения стратегии кеширования. Т.е. конкретный кеширующий бекенд подключается только через слот (или тег), которые в свою очередь оперируют типами. Таким образом для изменения тратегии кеширования нужно всего лишь поменять привязку типов к бекендам.</li><br /></ul><br /><h2>Использование</h2><br /><h3>class Cacher</h3><br />Требует наличия классов унаследованных от Cacher_Backend - семейство классов, реализующих бэкэнд для класса Cacher<br />Все операции с кешем осуществляется на низшем уровне через тот или иной бекенд<br />Бэкэндом может быть файловая система, shared memory, memcache, Sqlite и другие системы кеширования<br />Для работы с классом представляются слоты и теги. Слоты реализованы в виде набора дружественных функций и неявно зашиты в интерфейс текущего класса<br /><br />Пример использования:<br /><br />define AnyObj // может быть класс, массив или дрогой объект. На основании эого объекта слот функция вычислит ключь и, возможно другиие параметры (бэкэнд и время жизни).<br />Cacher::Slot('AniObj',AniObj); // Инициализируем слот кеширования. Первый параметр для определения имени слота, второй - наш объект<br /><br />Получаем данные<br />if (false === ($CacheData = Cacher::get())) { // Если данные из кеша получить не удалось...<br /> $CacheData = GetFromAnyExternal(); // Получаем данные из внешнего хранилища<br /> Cacher::addTag(Cacher::newTag('AniTagData',AniTagDataObj)); // Создаем и сразуже добавляем новый тег к слоту перед сохрананеием в кеш<br /> $tag2 = Cacher::newTag('AniTagData2',AniTagDataObj1) // Создаем новый тег<br /> Cacher::addTag($tag2); // добавляем новый тег к слоту перед сохрананеием в кеш<br /> Cacher::set($CacheData); // Кешируем данные<br />}<br /> ...<br /> ...<br /> Если затем нужно сбросить какой нибудь тег, то нужно будет сделать так:<br /> Cacher::newTag('AniTagData2',AniTagDataObj1)->clear() // Очищаем кеш тегаvalmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-27655734921704842942010-10-28T12:00:00.000-07:002010-10-28T13:16:52.213-07:00define vs const в phpКак известно, при разработке крупных веб приложений помимо архитектуры постоянно приходится задумываться так же и о производительности. Этим постом я хотел бы открыть серию постов по тестированию php на производительность.<br />Речь пойдет о сравнении способа хранения констант в приложении на php<br />А именно сравниваются два подхода:<br /><code><font size="3" face="Consolas, Courier New, Courier, Monospace" color="black">define(<font color="#008000">'CONST1'</font>, <font color="#008000">'val11'</font> );<br/>define(<font color="#008000">'CONST2'</font>, <font color="#008000">'val12'</font> );<br/>define(<font color="#008000">'CONST2'</font>, <font color="#008000">'val13'</font> );</font></code><br />и<br /><code><font size="3" face="Consolas, Courier New, Courier, Monospace" color="black"><font color="#0000ff">class</font> Consts{<br/> <font color="#0000ff">const</font> CONST1 = <font color="#008000">'val1'</font>;<br/> <font color="#0000ff">const</font> CONST2 = <font color="#008000">'val2'</font>;<br/> <font color="#0000ff">const</font> CONST3 = <font color="#008000">'val3'</font>;<br/>}<br/> <br/></font></code><br /><br />В первом случае случае, вроде бы как должна использоваться специальная область памяти и такой способ уж если и не экономит память, так точно должен быть быстрее. Второй способ в некоторых случаях существенно удобнее. Так как позволяет не захламлять глобальную область видимости.<br />В общем чего думать и годать провел тесты.<br /><h2>Тест 1. Инициализация</h2><br />Инициализируем 100 констант при помощи <span style="font-weight:bold;">define</span><br /><code>define(<font color="#008000">'CACHER_TYPE_1'</font>, <font color="#008000">'b60861c4492f88589429aab0c67abdd4'</font> );<br/><font color="#696969">/*</font><br/><font color="#696969"> ...</font><br/><font color="#696969"> */</font><br/>define(<font color="#008000">'CACHER_TYPE_100'</font>, <font color="#008000">'a66aedeafbc3f1e9fcbaa6a9e8060739'</font> );</code><br /><br />memory_start: 114.7578125Кб<br />time: <span style="font-weight:bold;">0.4</span>42981719971 ms<br />memory_finish: 120.8515625Кб<br />memory_diff: <span style="font-weight:bold;">6.09375Кб</span><br /><br />$ab -n 1000 http://test/test/mem_class.php<br /><code><br />Requests per second: 714.52 [#/sec] (mean)<br />Time per request: <span style="font-weight:bold;">1.400</span> [ms] (mean)<br /></code><br /><br />Теперь инициализируем через константы класса<br /><code><br/><font color="#0000ff">class</font> SlotType{<br/> <font color="#0000ff">const</font> TYPE_CACHER_1 = <font color="#008000">'b60861c4492f88589429aab0c67abdd4'</font>;<br/><font color="#696969">/*</font><br/><font color="#696969"> ...</font><br/><font color="#696969"> */</font><br/> <font color="#0000ff">const</font> TYPE_CACHER_100 = <font color="#008000">'a66aedeafbc3f1e9fcbaa6a9e8060739'</font>;<br/>} <br/></code><br />memory_start: 114.7578125Кб<br />time: <span style="font-weight:bold;">0.034</span>0938568115 ms<br />memory_finish: 114.9921875Кб<br />memory_diff: <span style="font-weight:bold;">0.234375Кб</span><br /><br />$ab -n 1000 http://test/test/mem_class.php<br /><code><br />Requests per second: 818.27 [#/sec] (mean)<br />Time per request: <span style="font-weight:bold;">1.222</span> [ms] (mean)<br /></code><br /><h2>Тест 2. Чтение</h2><br />Считываем все константы определенные через <span style="font-weight:bold;">define</span>:<br /><code>$var = CACHER_TYPE_1 . CACHER_TYPE_2 . /*...*/ . CACHER_TYPE_100;</code><br />time: <span style="font-weight:bold;">0.4</span> ms<br />memory_diff: <span style="font-weight:bold;">9.3</span>Кб<br />ab -n1000:<br />Requests per second: 488.63 [#/sec] (mean)<br />Time per request: <span style="font-weight:bold;">2.047</span> [ms] (mean)<br /><br />Считываем<br /><code>$var = SlotType::TYPE_CACHER_1 . SlotType::TYPE_CACHER_2 . /*...*/ . SlotType::TYPE_CACHER_100;</code><br />time: <span style="font-weight:bold;">0.12</span> ms<br />memory_diff: <span style="font-weight:bold;">3.5</span>Кб<br />ab -n1000:<br />Requests per second: 609.62 [#/sec] (mean)<br />Time per request: <span style="font-weight:bold;">1.640</span> [ms] (mean)<br /><h2>Вывод</h2><br />Надо сказать, результат меня несколько удивил. Я ожидал, что по крайней мере скорость обработки с define будет выше. Оказывается Использование варианта<br /><code><font color="#0000ff">class</font> Consts{<br/> <font color="#0000ff">const</font> CONST1 = <font color="#008000">'val1'</font>;<br/> <font color="#0000ff">const</font> CONST2 = <font color="#008000">'val2'</font>;<br/> <font color="#0000ff">const</font> CONST3 = <font color="#008000">'val3'</font>;<br/>}<br/> </code><br />не только удобней, но и эффективней как по скорости исполнения, так и по расходу памяти.valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com1tag:blogger.com,1999:blog-3900514035470574480.post-1235107011229526662010-10-27T23:02:00.000-07:002010-10-27T23:31:50.513-07:00php CounterВыложил на github.com свой класс Counter<br />В основном сделал это что бы потестить сам GitHub<br />Адрес страницы на гитхабе: <a href="http://github.com/valmat/MC_Counter">http://github.com/valmat/MC_Counter</a><br />Как использовать:<br /><i><br />class Counter<br />Это образец реализации счетчика на memcache<br />Можно построить другие реализации на общем интерфейсе<br />Сохранение результатов применения значений счетчика осуществляется по заданному числу.<br />Можно реализовать сохранение по заданному интервалу времени<br /> *<br />Конструктор принимает три аргумента: ключ, имя слота, и идентификатор для инициализации слота.<br />Для чего это сделано: инримент счетчика должен быть очень быстрой операцией.<br />Не целесообразно тратить время и сстемные ресурсы на создание объетов, которые е будут использовны.<br />Поэтому передается только имя слот класа, который создается только в случае необходимости.<br />К таким случаям относитсяя обмен данными между локальным и постоянным хранилищем счтчика.<br />Слоты необхоимы, так как Counter не может знать о способе хранения данных в постоянном хранилище и путях доступа к ним.<br />Для предотвращения состаяния гонки, необходим механизм блокировок.<br />При наличии блокировки, процессы не получившие эксклюзивные права на получение данных будут писать во временное хранилище, а процесс,<br />установивший блокировку по окончанию своей работы инкриментирует счетчик данными из временного хранилища<br /> *<br />При сбросе данных в постоянное хранилище по условию достежения кратности значения счетчика ($this->Val%$this->upd_delim),<br />блокировка не требуется, т.к. в этом случае (при достаточно большом значении $this->upd_delim) в текущий момент времени только один процесс<br />приходит к неоходимости сброса данных<br /><br />Пример использования:<br /> *<br /> $cnt = new Counter('anykey', 'AnySlot',15);<br /> echo $cnt->increment();<br /> echo $cnt->get();<br /> echo $cnt->set(11);<br /><br /></i>valmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com0tag:blogger.com,1999:blog-3900514035470574480.post-12756191960105059562010-10-18T11:04:00.000-07:002010-10-18T11:34:17.883-07:00Восстановление удаленных и поврежденных данных в LinuxКогда то давно, лет десять назад случалось мне отформатировать раздел жесткого диска под виндой. На диске была важная и нужная информация, поэтому встала задача данные восстановить. Помню путем продолжительного гугления были найдены несколько замечательных программ и кряков к ним. И данные были хоть и частично, но восстановлены. Назывались эти программы, вроде бы easy recovery, recover4all и какая то еще.<br />И вот на днях мне принесли жесткий диск с разделом, на который была поставлена винда по верх старой и вся нужная владельцу винта информация была благополучно потерта.<br />Поскольку сейчас винды у меня нет, то была выгуглена чудесная Линуксовая утилита под названием <b>foremost</b><br />Вот, все таки, за что я люблю Линукс, это за лаконичность и изящность решений (ну и за логичность архитектуры, конечно).<br />Для восстановления данных потребовалась всего одна строчка в терминале:<br /><center style="font-weight:bold">#foremost -t jpg -o /dev/sdb1 -i ~/bak </center><br />Теперь по порядку, что к чему.<br /><ul><br /><li># - запускаем от root'а что бы не было проблем с чтением</li><br /><li>-t - восстанавливаемых файлов. Можно написать -t all что бы восстановить файлы всех типов, либо одно из значений из списка: avi, bmp, dll, doc, exe, gif, htm, jar, jpg, mbd, mov, mpg, pdf, png, ppt, rar, rif, sdw, sx, sxc, sxi, sxw, vis, wav, wmv, xls, zip</li><br /><li>-o /dev/sdb1 - здесь указываем раздел, который нужно сканировать. Поддерживаются разные файловые системы. Тот диск, который приносили мне был с ntfs.</li><br /><li>-i ~/bak - куда складывать результат</li><br /></ul><br />Если запустить с опцией -t all, то будут созданы разные каталоги под каждый тип файлов, что само по себе очень удобно.<br />Я особо не вглядывался что он там на восстанавливал, но при беглом обзоре можно было заключить, что в своей массе почти все файлы были восстановлены корректно. Было несколько битых фотографий, но так ведь раздел был не пустой. Его не просто отформатировали но и успели по писать на него.<br />PS есть в репозитарии Ubuntu.<br />Т.е. установить можно так:<br />sudo apt-get install foremostvalmathttp://www.blogger.com/profile/02177628419344651242noreply@blogger.com1