<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Xupeng's blog]]></title>
  <link href="http://blog.xupeng.me/feed/" rel="self"/>
  <link href="http://blog.xupeng.me/"/>
  <updated>2012-02-04T07:34:52+08:00</updated>
  <id>http://blog.xupeng.me/</id>
  <author>
    <name><![CDATA[Xupeng]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[MySQL 的临时目录]]></title>
    <link href="http://blog.xupeng.me/2012/02/04/how-mysql-uses-tmpdir/"/>
    <updated>2012-02-04T07:18:00+08:00</updated>
    <id>http://blog.xupeng.me/2012/02/04/how-mysql-uses-tmpdir</id>
    <content type="html"><![CDATA[<p>MySQL 服务器设置的 binlog 单文件最大为 1GB，偶然发现会有十几 GB 大小的 binlog 文件，从产生的时间上看像是某个 cron job 使用了超大的 transaction，为了找出“罪魁祸首”，我需要分析一下 binlog。</p>

<!-- more -->


<p>在使用 mysqlbinlog 将 binary log 转换为文本文件时，发现根分区很快就被塞满了，使用 lsof 发现 mysqlbinlog 在往 /tmp 下写临时文件：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># lsof -p 17423
</span><span class='line'>COMMAND     PID USER   FD   TYPE DEVICE    SIZE/OFF      NODE NAME
</span><span class='line'>mysqlbinl 17423 root    1w   REG   0,19   791765366   3186036 /mfs/user/xupeng/tmp/bigbinlogs/bigbinlog.sql
</span><span class='line'>mysqlbinl 17423 root    2u   CHR  136,7         0t0        10 /dev/pts/7
</span><span class='line'>mysqlbinl 17423 root    3r   REG   0,19 13863171331   3172073 /mfs/user/xupeng/tmp/bigbinlogs/log.000323
</span><span class='line'>mysqlbinl 17423 root    4u   REG    8,1   612122624 135332782 /tmp/tmp.rWTNda (deleted)
</span><span class='line'>mysqlbinl 17423 root    5u   REG    8,1     2490368 135332784 /tmp/tmp.spKjTA (deleted)
</span><span class='line'>
</span><span class='line'>…</span></code></pre></td></tr></table></div></figure>


<p>看 mysqlbinlog 的 Man page，发现并没有参数可以指定临时目录，翻了一下 mysqlbinlog (client/mysqlbinlog.cc) 的代码，看到了下面的代码：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'>  <span class="n">MY_TMPDIR</span> <span class="n">tmpdir</span><span class="p">;</span>
</span><span class='line'>  <span class="n">tmpdir</span><span class="p">.</span><span class="n">list</span><span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">dirname_for_local_load</span><span class="p">)</span>
</span><span class='line'>  <span class="p">{</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">init_tmpdir</span><span class="p">(</span><span class="o">&amp;</span><span class="n">tmpdir</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
</span><span class='line'>      <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span><span class='line'>    <span class="n">dirname_for_local_load</span><span class="o">=</span> <span class="n">my_strdup</span><span class="p">(</span><span class="n">my_tmpdir</span><span class="p">(</span><span class="o">&amp;</span><span class="n">tmpdir</span><span class="p">),</span> <span class="n">MY_WME</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p><code>init_tmpdir</code> 定义在 <code>mysys/mf_tempdir.c</code> 中：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="n">my_bool</span> <span class="nf">init_tmpdir</span><span class="p">(</span><span class="n">MY_TMPDIR</span> <span class="o">*</span><span class="n">tmpdir</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">pathlist</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="kt">char</span> <span class="o">*</span><span class="n">end</span><span class="p">,</span> <span class="o">*</span><span class="n">copy</span><span class="p">;</span>
</span><span class='line'>  <span class="kt">char</span> <span class="n">buff</span><span class="p">[</span><span class="n">FN_REFLEN</span><span class="p">];</span>
</span><span class='line'>  <span class="n">DBUG_ENTER</span><span class="p">(</span><span class="s">&quot;init_tmpdir&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="n">DBUG_PRINT</span><span class="p">(</span><span class="s">&quot;enter&quot;</span><span class="p">,</span> <span class="p">(</span><span class="s">&quot;pathlist: %s&quot;</span><span class="p">,</span> <span class="n">pathlist</span> <span class="o">?</span> <span class="n">pathlist</span> <span class="o">:</span> <span class="s">&quot;NULL&quot;</span><span class="p">));</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">pthread_mutex_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">tmpdir</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">,</span> <span class="n">MY_MUTEX_INIT_FAST</span><span class="p">);</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="n">my_init_dynamic_array</span><span class="p">(</span><span class="o">&amp;</span><span class="n">tmpdir</span><span class="o">-&gt;</span><span class="n">full_list</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
</span><span class='line'>    <span class="k">goto</span> <span class="n">err</span><span class="p">;</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">pathlist</span> <span class="o">||</span> <span class="o">!</span><span class="n">pathlist</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</span><span class='line'>  <span class="p">{</span>
</span><span class='line'>    <span class="cm">/* Get default temporary directory */</span>
</span><span class='line'>    <span class="n">pathlist</span><span class="o">=</span><span class="n">getenv</span><span class="p">(</span><span class="s">&quot;TMPDIR&quot;</span><span class="p">);</span>  <span class="cm">/* Use this if possible */</span>
</span><span class='line'><span class="cp">#if defined( __WIN__) || defined(__NETWARE__)</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">pathlist</span><span class="p">)</span>
</span><span class='line'>      <span class="n">pathlist</span><span class="o">=</span><span class="n">getenv</span><span class="p">(</span><span class="s">&quot;TEMP&quot;</span><span class="p">);</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">pathlist</span><span class="p">)</span>
</span><span class='line'>      <span class="n">pathlist</span><span class="o">=</span><span class="n">getenv</span><span class="p">(</span><span class="s">&quot;TMP&quot;</span><span class="p">);</span>
</span><span class='line'><span class="cp">#endif</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">pathlist</span> <span class="o">||</span> <span class="o">!</span><span class="n">pathlist</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</span><span class='line'>      <span class="n">pathlist</span><span class="o">=</span><span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span> <span class="n">P_tmpdir</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">...</span>
</span></code></pre></td></tr></table></div></figure>


<p>可以看到，在没有指定 pathlist 时，会使用 <code>TMPDIR</code> 这个环境变量指定的目录作为临时目录，如果 <code>TMPDIR</code> 这个环境变量也不存在，在 Windows 下会接着查找 <code>TEMP</code> 和 <code>TMP</code> 这两个环境变量，从环境变量查找临时目录失败，会使用 <code>P_tmpdir</code> 作为默认临时目录，在 Linux 上 <code>P_tmpdir</code> 是 <code>/tmp</code> (定义在 stdio.h 中）。</p>

<p>所以在运行 mysqlbinlog 之前设置 <code>TMPDIR</code> 这个环境变量就好了。</p>

<p>MySQL server 和 客户端工具都使用这个临时目录查找策略，怪不得使用 <code>mysqlbinlog tmp directory</code> 作为关键词没有搜到需要的结果，而使用 <code>mysql tmp directory</code> 作为关键词，第一条搜索结果就是 <a href="http://dev.mysql.com/doc/refman/5.0/en/temporary-files.html">Where MySQL Stores Temporary Files</a>，选择正确的关键词很重要啊。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Code Swarm]]></title>
    <link href="http://blog.xupeng.me/2012/01/12/code-swarm/"/>
    <updated>2012-01-12T06:49:00+08:00</updated>
    <id>http://blog.xupeng.me/2012/01/12/code-swarm</id>
    <content type="html"><![CDATA[<p><a href="http://www.michaelogawa.com/code_swarm/">Code swarm</a> 是一个可视化项目，最常见的用途是把代码仓库的提交历史可视化，changesets 以时间顺序回放，每个发生变更的文件作为一个闪亮的光点从各处汇聚在对应的 committer 身上，把项目的演进历史以视频的方式形象地呈现出来，通常还会配上激动人心的背景音乐，令程序员们潸然泪下。</p>

<!-- more -->


<p>很多著名的开源项目比如 <a href="http://vimeo.com/1093745">Python</a>、<a href="http://vimeo.com/1265258">Subversion</a>、<a href="http://vimeo.com/1223937">Django</a>、<a href="http://vimeo.com/1081680">PostgreSQL</a>、<a href="http://www.vimeo.com/1076588">Apache</a> 等等都有 code swarm 视频，很多互联网公司也都有 code swarm 视频，比如 <a href="http://vimeo.com/9225227">Twitter</a>、<a href="http://vimeo.com/2249514">Last.fm</a>。</p>

<p>可视化是一项伟大的技术，它使非专业人士也能形象地感受到“虚无事物”的发展历程，向致力于可视化的科学家和程序员致敬！</p>

<p>豆瓣发展至今已经有 7 年了，2008 年的时候 <a href="http://www.douban.com/people/hongqn/">hongqn</a> 做过一个 <a href="http://www.youtube.com/watch?v=4f2xkvKAAXo">code swarm 视频</a>，时至今日，豆瓣的工程师队伍已经壮大了数倍，再次做了 code swarm 视频。</p>

<p>这次我使用了 <a href="http://www.michaelogawa.com/code_swarm/">code_swarm</a> 项目的一个 <a href="https://github.com/rictic/code_swarm">fork</a>，这个 fork 最大的亮点是加入了头像支持，除了 committer 的 ID 之外，还可以显示头像，使辨识度更高，按照项目的简要文档可以很容易地为单仓库生成视频。</p>

<p>code_swarm 接受的输入是一个配置文件和一个 XML 格式的 events 序列，每一个发生变更的文件加上 commiter ID 和时间（1970-01-01 00:00:00 起的毫秒数 / UNIX timestamp * 1000）组成一个 event，最终的 events 文件会是类似这个样子：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="cp">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
</span><span class='line'><span class="nt">&lt;file_events&gt;</span>
</span><span class='line'>  <span class="nt">&lt;event</span> <span class="na">date=</span><span class="s">&quot;1104508800000&quot;</span> <span class="na">author=</span><span class="s">&quot;bo&quot;</span> <span class="na">filename=</span><span class="s">&quot;/trunk/luz/doulist/douledit_ui.ptl&quot;</span><span class="nt">&gt;&lt;/event&gt;</span>
</span><span class='line'>  <span class="nt">&lt;event</span> <span class="err">…</span><span class="nt">&gt;&lt;/event&gt;</span>
</span><span class='line'><span class="nt">&lt;/file_events&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>为了生成 events 文件，需要先将代码仓库的变更历史导出，code_swarm 的 <a href="https://github.com/rictic/code_swarm/blob/master/bin/convert_logs.py">convert_logs.py</a> 工具提供了对多种版本仓库的支持，可以从仓库导出历史并转换为 events log，不过不太符合我的需求。</p>

<p>为了把很多个代码仓库做为一个整体来呈现，需要把所有仓库的历史按时间顺序合并到一起，于是我将这个过程分成了四个串行的步骤：</p>

<ol>
<li>从各个仓库导出历史</li>
<li>解析历史为中间格式并合并为一个文件：<code>&lt;committer ID&gt; &lt;timestamp&gt; &lt;file path&gt;</code></li>
<li>对中间格式的文件按时间排序</li>
<li>生成最终需要的 events log</li>
</ol>


<p>这个过程不再赘述，每个步骤都比较简单，这中间比较比较麻烦的是，在不同的代码仓库中尤其是分布式版本仓库中同一个 committer 的 ID 可能是不一样的，甚至同一个 committer 会有很多个不同的 ID，需要 normalize 为辨识度最高的那一个，另外还有一些系统账号的自动 commit，也需要排除在外。</p>

<p>另外一个输入是配置文件，可以在 <a href="https://github.com/rictic/code_swarm/blob/master/defaults/code_swarm.config">默认配置文件</a> 基础上做调整，以达到比较好的可视效果，这个步骤是整个过程中耗时最长，也是耗费硬件资源最多的，为了在大屏幕上有一个较好的效果，可能还需要修改一些硬编码在代码中的参数、更换或微调整物理引擎，不同的项目不同的变更历史不同的 committer 数量需要使用的参数差别可能比较大，只能逐个调整并测试…</p>

<p>另外需要准备每个 committer 的头像，使用 PNG 格式，以 committer 的 ID 命名，需要注意的是，头像需要是正方形的，可以借助 PIL 或 imagemagick 来做辅助的切割和格式、大小转换，长宽相差比较多的头像可能需要手工裁剪才能得到比较好的可视效果。</p>

<p>code_swarm 直接实时地呈现视频，但并不是直接输出视频文件，而是生成一帧一帧的图片文件，这样比较方便对最终的视频做定制，比较遗憾的是，code_swarm 没有 headless 模式，没有办法选择不显示实时视频而只生成图片文件，所以这个过程会很慢，在我的 MBP 990 上生成 7 年 12780 帧图片需要 40 分钟以上…</p>

<p>图片生成之后，可以使用视频编码工具将图片合并为视频，强大的 mencoder 和 ffmpeg 都能轻松完成这个任务，比如使用 ffmpeg 生成 quicktime 格式的视频是这样：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>ffmpeg -f image2 -r 43 -i ./code_swarm_frames/%05d.png <span class="se">\</span>
</span><span class='line'>  -sameq ./codebang.mov -pass 2
</span></code></pre></td></tr></table></div></figure>


<p>其中 -r 43 是指每秒钟 43 帧，因为需要配乐，对音乐做裁剪相对麻烦并且影响听觉效果，所以可以直接生成与音乐长度相当的视频，这里的 43FPS 是总帧数除以音频文件秒数得到的，帧速可以使用小数，所以可以精确控制视频长度。</p>

<p>项目演进过程中肯定会发生很多大事件，以字幕的形式标注这些大事件是一个比较好的方法，srt 是最简单的字幕格式，每一节字幕是这样的：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>1
</span><span class='line'>00:00:07,414 --> 00:00:11,414
</span><span class='line'>2005年3月6日 豆瓣上线</span></code></pre></td></tr></table></div></figure>


<p>第一行是字幕序号，递增，第二行是起始时间和结束时间，精确到毫秒，控制字幕出现和隐去的时间，第三行之后是字幕，可以有多行。两节字幕之间以空行分割。因为有大事记，所以都会有具体的日期，根据视频的长度，和仓库变更的起始、结束日期，可以计算出每一节字幕在视频中的绝对位置，所以生成字幕这个步骤可以半自动化，在测试搭配不同长度的音乐时可以节省不少手工调整字幕的时间。</p>

<p>最后一个步骤是将视频、音频和字幕合成为一个文件，我使用了 mencoder：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>mencoder -o codebang.avi -ovc lavc <span class="se">\</span>
</span><span class='line'>  -lavcopts <span class="nv">vcodec</span><span class="o">=</span>mpeg4:mbd<span class="o">=</span>2:vbitrate<span class="o">=</span>16000 <span class="se">\</span>
</span><span class='line'>  -oac mp3lame -lameopts cbr:br<span class="o">=</span>320:q<span class="o">=</span>0 -sub codebang.srt <span class="se">\</span>
</span><span class='line'>  -utf8 -subfont-text-scale 2.5 -overlapsub <span class="se">\</span>
</span><span class='line'>  -font <span class="s2">&quot;Hiragino Sans GB W6&quot;</span> -subpos 92 codebang.mov <span class="se">\</span>
</span><span class='line'>  -audiofile background.mp3
</span></code></pre></td></tr></table></div></figure>


<p>要得到好的可视效果，这个过程实际上还是挺耗费精力的，不过很值得，工程师嘛，就这点追求&#8230;</p>

<p>更新：Code swarm 视频在<a href="http://v.youku.com/v_show/id_XMzQzNDc4MDk2.html">这里</a>。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[No SOPA! 将我的域名从 Godaddy 转出]]></title>
    <link href="http://blog.xupeng.me/2011/12/23/no-sopa-transfer-my-domains-out-of-godaddy/"/>
    <updated>2011-12-23T23:49:00+08:00</updated>
    <id>http://blog.xupeng.me/2011/12/23/no-sopa-transfer-my-domains-out-of-godaddy</id>
    <content type="html"><![CDATA[<p>近来美国在尚未通过的 <a href="http://en.wikipedia.org/wiki/Stop_Online_Piracy_Act">SOPA</a> 法案上产生了巨大争议，该法案最邪恶的地方在于，它使得 ISP 和版权方有权利因为某网站上有一点侵权内容而“拔其网线” - 使其域名无法解析，此权利也很容易被滥用。</p>

<!-- more -->


<p>此举最大的获益者可能是日益衰落不思进取的传统出版、娱乐等行业，而代表先进技术生产力的互联网和互联网企业则遭受极大威胁，这是以损害创新为代价、以知识产权保护为名来庇护濒死的产业模式，实在是饮鸩止渴，阻碍信息传播和技术进步。</p>

<p>我的域名一直都是在 Godaddy 注册的，而 Godaddy 站在了 <a href="http://en.wikipedia.org/wiki/Stop_Online_Piracy_Act">SOPA</a> 支持者行列，颇让人意外，其实公开表示支持的公司还挺多的，比如 <a href="http://judiciary.house.gov/issues/Rouge%20Websites/SOPA%20Supporters.pdf">这里</a> 就有一个不完全列表，但令人感到欣慰的是，我喜欢或者因其而受益的美国公司或组织全都是坚定的 SOPA 反对者，比如：</p>

<ul>
<li><a href="http://www.google.com">Google</a></li>
<li><a href="http://www.facebook.com">Facebook</a></li>
<li><a href="https://twitter.com/">Twitter</a></li>
<li><a href="http://www.wikipedia.org">Wikipedia</a></li>
<li><a href="http://www.quora.com/">Quora</a></li>
<li><a href="http://www.linode.com/?r=cd5198f9daf6a668424aea5534f74baf343f4759">Linode</a></li>
<li><a href="https://github.com/">Github</a></li>
<li><a href="http://www.opendns.com/">OpenDNS</a></li>
<li>&#8230;</li>
</ul>


<p>等等等等。</p>

<p>鉴于此，我打算将我在 Godaddy 的域名全部 transfer 到别的域名注册商，name.com 和 namecheap.com 都是不错的选择，做了一些比较之后，我打算将域名 transfer 到 name.com，之所以选择 name.com，主要是因为 name.com 也算是一个比较老牌的注册商/代理商了，另外也是因为 name.com 的价格比较公道。</p>

<p>Transfer 的详细步骤就不重复了，互联网上已经有很多详细的流程解析，比如：</p>

<ul>
<li><a href="http://blog.jeffepstein.me/post/14629857835/a-step-by-step-guide-to-transfer-domains-out-of-godaddy">Transfer 到 namecheap</a></li>
<li>Transfer 到 name.com 可以参考上面链接的 Godaddy 部分和 <a href="http://www.name.com/faq/transfer-into-name.com">这里</a></li>
</ul>


<p>不同的域名注册商/代理商的 Transfer 步骤大同小异，大致的必要步骤是这样：</p>

<ol>
<li>从转出方获取域名授权码（Authorization Key / EPP Key)</li>
<li>在转入方填写要 transfer 的域名和对应的 EPP key</li>
<li>等待转入方向域名的 Administrative Contact email 发送验证邮件，收到邮件后根据提示确认</li>
<li>等待转入方开始 transfer，之后可能需要到转出方处授权允许转出</li>
<li>等待 transfer 完成，这个步骤需要几个小时到几天不等，耐心等待就好</li>
</ol>


<p>需要注意的是：</p>

<ol>
<li>域名需要是两个月之前注册的，比如 name.com 就不能 tranfser 两个月内新注册的域名</li>
<li>域名不能被锁定，也就是说 whois 信息中显示的状态里没有 clientTransferProhibited，可以先在转出方那里解锁</li>
<li>你能够通过 whois 信息中显示的 Administrative Contact email 接收邮件</li>
</ol>


<p>有一些 transfer 域名的小提示和建议：</p>

<ul>
<li>利用一些 coupon 节省开支，比如 name.com 可以使用 <code>NODADDY</code> 这个 coupon 节省 10% 的 transfer 费用</li>
<li>有的域名注册商会将转出方处设定的域名记录迁移过去，这样的话整个域名的迁移是平滑的，不至于有不可解析的时间</li>
<li>或者预先在转入方设定要使用的域名服务器，比如我使用的是 Linode 的 DNS 服务，我先在 name.com 处填写 Linode 的 DNS server，这样也可以做到平滑迁移</li>
</ul>


<p>另外，还有一个费用和域名有效期的问题，比如之前我的 xupeng.me 到期时间是 2013/10/29，我需要支付一年的 transfer 费用，transfer 完成之后，域名的有效时间延期一年到 2014/10/29。</p>

<p>更新（2011-11-24 08:36）：很高兴一早就看到了 Godaddy 不再支持 SOPA 的消息！一点微薄的行动有了效果，说不定我花两个小时迁出几个域名是压垮 Godaddy 的最后一根稻草 :) 就 Godaddy 支持 SOPA 这件事本身而言，从 Godady 转不转出域名都对个人都没什么大不了的影响， 转出只代表一种立场，代表眼里揉不得沙子的态度，用自己的实际行动投出微薄的一个反对票，使得反对者更多，最终使立法失败！</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[迁移到 Octopress]]></title>
    <link href="http://blog.xupeng.me/2011/12/14/migrate-to-octopress/"/>
    <updated>2011-12-14T22:23:00+08:00</updated>
    <id>http://blog.xupeng.me/2011/12/14/migrate-to-octopress</id>
    <content type="html"><![CDATA[<p>用了三年多 Wordpress，由于实在很懒，没有写过多少东西，但跑在 <a href="http://www.linode.com/?r=cd5198f9daf6a668424aea5534f74baf343f4759">Linode VPS</a> 上的 Wordpress 却一直占用了很多资源，几个 <a href="http://php-fpm.org/">PHP-FPM</a> 进程加上 MySQL 就用掉了将近 400MB 内存，却没有什么访问量，觉得很不划算，再加上 Wrodpress 越来越臃肿，就想把它换成一个静态内容发布系统。</p>

<!-- more -->


<p>简单看了一下，很快就找到了 <a href="http://octopress.org/">Octopress</a>，一眼就看上了，花了半个小时试用，还是很符合我的使用习惯的：</p>

<ol>
<li>配置简单，简单修个几个配置就能使用</li>
<li><a href="http://daringfireball.net/projects/markdown/">Markdown</a> 语法，VIM + Terminal 就能完成内容书写与发布</li>
<li>定制简单，plugin 看起来也不复杂，不过写 plugin 要学一点 ruby</li>
<li>默认的模版就很漂亮，也很便于阅读</li>
</ol>


<p>花了几个小时把 Wordpress 里旧的文章导出、导入到 Octopress，手工编辑了部分不像样的文章，一个焕然一新的静态发布 blog 就基本可用了，在这个过程中我主要参考了这些文档和文章：</p>

<ul>
<li><a href="http://octopress.org/docs/">http://octopress.org/docs/</a></li>
<li><a href="http://felipecypriano.com/2011/09/16/why-ive-migrated-to-octopress/">http://felipecypriano.com/2011/09/16/why-ive-migrated-to-octopress/</a></li>
<li><a href="http://mattgemmell.com/2011/09/12/blogging-with-octopress/">http://mattgemmell.com/2011/09/12/blogging-with-octopress/</a></li>
</ul>


<p>把这些读一遍就能顺利完成迁移和部署，所以就不重复步骤了。</p>

<p>问题也是有的，比如插件过少，甚至原作者都没有提供 Tag Cloud 支持，可能也有 bug，比如我试用时使用的 base URL 是 <code>http://o.xupeng.me</code>，迁移完毕换成正式的 URL <code>http://blog.xupeng.me</code> 后，重新生成的静态页面和 feed 内的 URL 会在新旧两个 URL 之间随机变化，导致 <a href="http://ifttt.com/">ifttt</a> 认为我 blog 上的文章全都发生了变化，向我的 twitter 上发了一大堆信息，我删除了 cache 目录之后这个问题没有再出现过。</p>

<p>不算是一个完美的系统，不过基本上能够满足我的需求，之后有空再补上缺少的东西吧。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[2.6.38 / 2.6.39 + XFS 的性能极差]]></title>
    <link href="http://blog.xupeng.me/2011/12/11/poor-performance-with-xfs-2-6-38-and-2-6-39/"/>
    <updated>2011-12-11T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2011/12/11/poor-performance-with-xfs-2-6-38-and-2-6-39</id>
    <content type="html"><![CDATA[<p>线上的 MySQL 服务器一直都在使用 XFS 文件系统，性能和稳定性都表现良好，使用的内核版本是 2.6.29，经过时间和访问压力的验证，表现也不错。</p>

<p>前一段时间在测试几款 SSD 产品，考虑到 XFS 在内核 2.6.38 之后才加入了对 FITRIM 的支持（<a href="http://xfs.org/index.php/FITRIM/discard">ref1</a>  <a href="http://xfs.org/index.php/Support_discarding_of_unused_sectors">ref2</a>），就在 2.6.38 和 2.6.39 上对 SSD 做了测试，测试结果却让人大跌眼镜，XFS 在 2.6.38 和 2.6.39 之上的性能差到完全不能接受。</p>

<!-- more -->


<p>我在内核 2.6.29 和 2.6.39 下使用 <a href="http://freecode.com/projects/fio">fio</a> 分别对 raw device、XFS 和 ext4 做了一个简单的 IO 测试，测试参数是这样的：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>fio --filename<span class="o">=</span><span class="nv">$PATH</span>-TO-TEST-FILE --direct<span class="o">=</span>1 --rw<span class="o">=</span>randrw --bs<span class="o">=</span>16k <span class="se">\</span>
</span><span class='line'>    --size<span class="o">=</span>50G --numjobs<span class="o">=</span>16 --runtime<span class="o">=</span>120 --group_reporting <span class="se">\</span>
</span><span class='line'>    --name<span class="o">=</span><span class="nb">test</span> --rwmixread<span class="o">=</span>90 --thread --ioengine<span class="o">=</span>psync
</span></code></pre></td></tr></table></div></figure>


<p>大意是：使用 non-buffered I/O，16 个并发 IO 线程，做 16KB 块大小的随机读写混合测试，读写比为 9:1</p>

<p>下面是 2.6.29 下的测试结果：</p>

<ul>
<li><a href="http://blog.xupeng.me/downloads/ext4-xfs-perf/2.6.29-raw.txt">2.6.29 + raw device</a></li>
<li><a href="http://blog.xupeng.me/downloads/ext4-xfs-perf/2.6.29-xfs.txt">2.6.29 + XFS</a></li>
<li><a href="http://blog.xupeng.me/downloads/ext4-xfs-perf/2.6.29-ext4.txt">2.6.29 + ext4</a></li>
</ul>


<p>可以看到，ext4, XFS 和 raw device 的 IOPS 都在 12000 上下，考虑到测试之间会有误差，基本可以认为三者的性能一样。</p>

<p>下面是 2.6.39 下的测试结果：</p>

<ul>
<li><a href="http://blog.xupeng.me/downloads/ext4-xfs-perf/2.6.39-raw.txt">2.6.39 + raw device</a></li>
<li><a href="http://blog.xupeng.me/downloads/ext4-xfs-perf/2.6.39-xfs.txt">2.6.39 + XFS</a></li>
<li><a href="http://blog.xupeng.me/downloads/ext4-xfs-perf/2.6.39-ext4.txt">2.6.39 + ext4</a></li>
</ul>


<p>ext4 和 raw device 的 IOPS 约为 12900，比在 2.6.29 下略有提升，但是 XFS 的性能就有点惨不忍睹了，竟然只有不到 4000。</p>

<p>尝试了很多种不同的 XFS 格式化、mount 参数，IOPS 都只是在 4000 左右徘徊，还没有找到解决方案，目前在部分服务器上尝试使用了 ext4，进一步监测 ext4 的性能和稳定性，或许未来会在数据库服务器上全部使用 ext4。</p>

<p>更新：在 XFS 邮件列表咨询之后，确认了这是 XFS 的已知 bug：</p>

<blockquote><p>commit 686da49e5aa50117d8d824c579c3fd9e0318fbc6<br/>Author: Dave Chinner <dchinner @redhat.com><br/>Date:   Thu Dec 1 17:27:39 2011 -0600</p><p>    xfs: don&#8217;t serialise direct IO reads on page cache checks<br/>    <br/>    commit 0c38a2512df272b14ef4238b476a2e4f70da1479 upstream.<br/>    <br/>    There is no need to grab the i_mutex of the IO lock in exclusive<br/>    mode if we don&#8217;t need to invalidate the page cache. Taking these<br/>    locks on every direct IO effective serialises them as taking the IO<br/>    lock in exclusive mode has to wait for all shared holders to drop<br/>    the lock. That only happens when IO is complete, so effective it<br/>    prevents dispatch of concurrent direct IO reads to the same inode.<br/>    <br/>    Fix this by taking the IO lock shared to check the page cache state,<br/>    and only then drop it and take the IO lock exclusively if there is<br/>    work to be done. Hence for the normal direct IO case, no exclusive<br/>    locking will occur.<br/></dchinner></p><footer><strong>Dave Chinner</strong> <cite><a href='http://www.spinics.net/lists/xfs/msg08688.html'>www.spinics.net/lists/xfs/&hellip;</a></cite></footer></blockquote>


<p>3.0.11, 3.1.5 和 3.2-rc1 中已经修复。XFS 用户在升级内核时需要注意，升级到修复后的版本，并做充分的性能测试。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[SCGI与线程]]></title>
    <link href="http://blog.xupeng.me/2011/12/08/scgi-and-threading/"/>
    <updated>2011-12-08T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2011/12/08/scgi-and-threading</id>
    <content type="html"><![CDATA[<p>最近在写一个配置推送客户端，结构如下图：</p>

<p><img src="http://blog.xupeng.me/downloads/2011/12/cfgreceiver.png" title="cfgreceiver architecture" alt="cfgreceiver architecture" /></p>

<p>每一个应用服务进程会起一个额外的线程，与 ZooKeeper 保持连接，需要变更配置时，将新配置更新到 ZooKeeper，ZooKeeper 将配置推送到所有的客户端，客户端收到配置之后，即时更新进程内的配置信息，并将更新配置成功与否、延时、错误等信息反馈到 redis，以这样的方式做到不重启服务更新配置。</p>

<!-- more -->


<p>同时也会有一个独立的客户端与 ZooKeeper 保持连接，收到 ZooKeeper 推送的配置之后，将配置写回并提交到 Puppet 配置仓库中，这样仍然保持只在一个地方修改配置的习惯。</p>

<p>这个推送客户端的第一个应用场景是更新线上的 MySQL 配置，线上服务是 Quixote + SCGI，由于在 SCGI server fork 子进程之前就已经 import 了部分自有库，其中包括这个配置推送客户端的使用者，因此，这个客户端必须是 lazy 的，只能在 fork 发生之后才能启动线程、建立与 ZooKeeper 和 redis 的连接。</p>

<p>将这个客户端与 Quixote + SCGI 服务进行联调时，奇怪的事情发生了，配置发生变更时，客户端并没有立刻收到 ZooKeeper 的推送，而是等到下一次用户请求到达时才会收到，起初以为是线程根本就没有在工作，后来发现，线程也并不是完全不工作，而是阻塞在了某个地方，当有用户请求到达时，线程才会接着执行。这就意味着，如果一个进程闲置了比较长的时间，ZooKeeper 会认为客户端已失去响应，从而断开连接，而客户端重连 ZooKeeper 也只会发生在下一次请求到来之后，这是个很别扭很诡异的问题。</p>

<p>去掉目前使用的 Quixote 包装，写了一个最简单的 Quixote app，发现同样的问题依然存在，这排除了自有 Quixote 包装的问题。接下来又写了一个裸的 SCGI app：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="c">#!/usr/bin/env python</span>
</span><span class='line'><span class="c"># t.py</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">sys</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">time</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">threading</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">T</span><span class="p">(</span><span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">):</span>
</span><span class='line'>    <span class="n">daemon</span> <span class="o">=</span> <span class="bp">True</span>
</span><span class='line'>    <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span><span class='line'>        <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
</span><span class='line'>            <span class="k">print</span> <span class="o">&gt;&gt;</span> <span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&#39;sleeping&#39;</span>
</span><span class='line'>            <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span><span class='line'>            <span class="k">print</span> <span class="o">&gt;&gt;</span> <span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&#39;id:</span><span class="si">%s</span><span class="s"> time:</span><span class="si">%s</span><span class="se">\n</span><span class="s">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="nb">id</span><span class="p">(</span><span class="bp">self</span><span class="p">),</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())</span>
</span><span class='line'>
</span><span class='line'><span class="n">t</span> <span class="o">=</span> <span class="n">T</span><span class="p">()</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="c">#!/usr/bin/env python</span>
</span><span class='line'><span class="c"># s.py</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">sys</span>
</span><span class='line'><span class="kn">from</span> <span class="nn">scgi</span> <span class="kn">import</span> <span class="n">scgi_server</span>
</span><span class='line'><span class="kn">from</span> <span class="nn">t</span> <span class="kn">import</span> <span class="n">t</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">MyHandler</span><span class="p">(</span><span class="n">scgi_server</span><span class="o">.</span><span class="n">SCGIHandler</span><span class="p">):</span>
</span><span class='line'><span class="k">def</span> <span class="nf">produce_cgilike</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">env</span><span class="p">,</span> <span class="n">bodysize</span><span class="p">):</span>
</span><span class='line'>    <span class="k">if</span> <span class="ow">not</span> <span class="n">t</span><span class="o">.</span><span class="n">is_alive</span><span class="p">():</span>
</span><span class='line'>        <span class="k">print</span> <span class="o">&gt;&gt;</span> <span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&#39;start thread: </span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="nb">id</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
</span><span class='line'>        <span class="n">t</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
</span><span class='line'>    <span class="k">else</span><span class="p">:</span>
</span><span class='line'>        <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&#39;Content-Type: text/plain</span><span class="se">\r\n\r\n</span><span class="s">&#39;</span><span class="p">)</span>
</span><span class='line'>        <span class="k">print</span> <span class="nb">id</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'><span class="n">scgi_server</span><span class="o">.</span><span class="n">SCGIServer</span><span class="p">(</span><span class="n">MyHandler</span><span class="p">,</span> <span class="n">host</span><span class="o">=</span><span class="s">&#39;0.0.0.0&#39;</span><span class="p">,</span><span class="n">port</span><span class="o">=</span><span class="mi">9002</span><span class="p">)</span><span class="o">.</span><span class="n">serve</span><span class="p">()</span>
</span></code></pre></td></tr></table></div></figure>


<p>这样的一个服务仍然有上面提到的问题，每有一次用户访问，就会输出一行 &#8220;id:xxx time:xxx&#8221;，然后输出一行 &#8220;sleeping&#8221;，之后就阻塞在了 time.sleep(1) 处（起码看起来是阻塞在了这里）。至此，也可以排除 Quixote 的问题，问题应该出在 SCGI 这里，向 <a href="http://www.douban.com/people/hongqn/">hongqn</a> 请教之后，最终定位到了问题所在。</p>

<p>在 SCGIHandler.serve 方法中：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="n">os</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">parent_fd</span><span class="p">,</span> <span class="s">&quot;1&quot;</span><span class="p">)</span> <span class="c"># indicates that child is ready</span>
</span><span class='line'><span class="n">fd</span> <span class="o">=</span> <span class="n">passfd</span><span class="o">.</span><span class="n">recvfd</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">parent_fd</span><span class="p">)</span><span class="o">&lt;/</span><span class="n">pre</span><span class="o">&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>passfd.recvfd 是一个阻塞读，它的代码是这样的：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span>
</span><span class='line'><span class="nf">passfd_recvfd</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="kt">int</span> <span class="n">sockfd</span><span class="p">,</span> <span class="n">fd</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">PyArg_ParseTuple</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="s">&quot;i:revcfd&quot;</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">sockfd</span><span class="p">))</span>
</span><span class='line'>        <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">if</span> <span class="p">((</span><span class="n">fd</span> <span class="o">=</span> <span class="n">recv_fd</span><span class="p">(</span><span class="n">sockfd</span><span class="p">))</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>        <span class="n">PyErr_SetFromErrno</span><span class="p">(</span><span class="n">PyExc_IOError</span><span class="p">);</span>
</span><span class='line'>        <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="n">PyInt_FromLong</span><span class="p">((</span><span class="kt">long</span><span class="p">)</span> <span class="n">fd</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>fd = recv_fd(sockfd) 是一个阻塞读，在开始阻塞读之前没有释放 GIL ，于是就导致了整个解释器阻塞，这也与之前问题的症状吻合。将代码作如下修改，在开始阻塞读之前释放 GIL，可以解决这个问题：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span>
</span><span class='line'><span class="nf">passfd_recvfd</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="kt">int</span> <span class="n">sockfd</span><span class="p">,</span> <span class="n">fd</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">PyArg_ParseTuple</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="s">&quot;i:revcfd&quot;</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">sockfd</span><span class="p">))</span>
</span><span class='line'>        <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">Py_BEGIN_ALLOW_THREADS</span>
</span><span class='line'>    <span class="n">fd</span> <span class="o">=</span> <span class="n">recv_fd</span><span class="p">(</span><span class="n">sockfd</span><span class="p">);</span>
</span><span class='line'>    <span class="n">Py_END_ALLOW_THREADS</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">fd</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>        <span class="n">PyErr_SetFromErrno</span><span class="p">(</span><span class="n">PyExc_IOError</span><span class="p">);</span>
</span><span class='line'>        <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="n">PyInt_FromLong</span><span class="p">((</span><span class="kt">long</span><span class="p">)</span> <span class="n">fd</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>当然了，还需要做进一步的测试和观察，看一下打这样的 patch 之后会不会有其他的副作用。</p>

<p>参考：<a href="http://docs.python.org/release/2.6.7/c-api/init.html#thread-state-and-the-global-interpreter-lock">http://docs.python.org/release/2.6.7/c-api/init.html#thread-state-and-the-global-interpreter-lock</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Lion下精确调整音量]]></title>
    <link href="http://blog.xupeng.me/2011/09/23/precisely-adjust-volume-in-lion/"/>
    <updated>2011-09-23T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2011/09/23/precisely-adjust-volume-in-lion</id>
    <content type="html"><![CDATA[<p>升级到 Lion 后一直在忍受着很大的音量，戴着入耳一格音量也觉得很大，找了两句 applescript，写成了一个符合我使用习惯的脚本，这下可以精确地把音量调整为舒适的大小了：</p>

<!-- more -->




<figure class='code'><figcaption><span>Adjust volume  (adjust-volume)</span> <a href='http://blog.xupeng.me/downloads/code/adjust-volume'>download</a></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='applescript'><span class='line'><span class="c">#!/usr/bin/osascript</span>
</span><span class='line'>
</span><span class='line'><span class="k">on</span> <span class="nv">usage</span><span class="p">()</span>
</span><span class='line'>    <span class="k">set</span> <span class="err">_usage</span> <span class="k">to</span> <span class="s2">&quot;Usage: adjust-volume number\n&quot;</span>
</span><span class='line'>    <span class="k">set</span> <span class="err">_usage</span> <span class="k">to</span> <span class="err">_usage</span> <span class="o">&amp;</span> <span class="s2">&quot;For example:\n&quot;</span>
</span><span class='line'>    <span class="k">set</span> <span class="err">_usage</span> <span class="k">to</span> <span class="err">_usage</span> <span class="o">&amp;</span> <span class="s2">&quot;  adjust-volume 2\t - increase volume by 2\n&quot;</span>
</span><span class='line'>    <span class="k">set</span> <span class="err">_usage</span> <span class="k">to</span> <span class="err">_usage</span> <span class="o">&amp;</span> <span class="s2">&quot;  adjust-volume -2\t - decrease volume by 2&quot;</span>
</span><span class='line'>    <span class="no">return</span> <span class="err">_usage</span>
</span><span class='line'><span class="k">end</span> <span class="nv">usage</span>
</span><span class='line'>
</span><span class='line'><span class="k">on</span> <span class="nb">run</span> <span class="nv">argv</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="nb">count</span> <span class="nv">argv</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">1</span> <span class="k">then</span>
</span><span class='line'>        <span class="no">return</span> <span class="nv">usage</span><span class="p">()</span>
</span><span class='line'>    <span class="k">end</span> <span class="k">if</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">set</span> <span class="nv">currentVolume</span> <span class="k">to</span> <span class="nv">output</span> <span class="na">volume</span> <span class="k">of</span> <span class="p">(</span><span class="nb">get volume settings</span><span class="p">)</span>
</span><span class='line'>    <span class="nb">set volume</span> <span class="nv">output</span> <span class="na">volume</span> <span class="p">(</span><span class="nv">currentVolume</span> <span class="o">+</span> <span class="p">(</span><span class="nb">item</span> <span class="mi">1</span> <span class="k">of</span> <span class="nv">argv</span><span class="p">))</span>
</span><span class='line'><span class="k">end</span> <span class="nb">run</span>
</span></code></pre></td></tr></table></div></figure>


<p>使用方法：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>Usage: adjust-volume number
</span><span class='line'>For example:
</span><span class='line'>  adjust-volume 2  - increase volume by 2
</span><span class='line'>  adjust-volume -2     - decrease volume by 2</span></code></pre></td></tr></table></div></figure>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[MySQL collation问题]]></title>
    <link href="http://blog.xupeng.me/2011/09/07/mysql-collation/"/>
    <updated>2011-09-07T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2011/09/07/mysql-collation</id>
    <content type="html"><![CDATA[<p>在从 5.0.x 向 5.1.x 升级的过程中，使用 mysqldump 备份某张表之后，向5.1.x中导入时却遇到重复数据的错误：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>ERROR 1062 (23000) at line 65: Duplicate entry '1003-' for key 'uk_cat_name'</span></code></pre></td></tr></table></div></figure>




<!-- more -->


<p>这张表的schema是这样的：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='sql'><span class='line'><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="o">`</span><span class="n">tag</span><span class="o">`</span> <span class="p">(</span>
</span><span class='line'>  <span class="o">`</span><span class="n">id</span><span class="o">`</span> <span class="nb">int</span><span class="p">(</span><span class="mi">11</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span> <span class="n">AUTO_INCREMENT</span><span class="p">,</span>
</span><span class='line'>  <span class="o">`</span><span class="n">name</span><span class="o">`</span> <span class="nb">varchar</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span> <span class="nb">CHARACTER</span> <span class="k">SET</span> <span class="n">ucs2</span> <span class="k">NOT</span> <span class="k">NULL</span> <span class="k">DEFAULT</span> <span class="s1">&#39;&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="o">`</span><span class="k">count</span><span class="o">`</span> <span class="nb">int</span><span class="p">(</span><span class="mi">11</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span> <span class="k">DEFAULT</span> <span class="s1">&#39;0&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="o">`</span><span class="n">cat_id</span><span class="o">`</span> <span class="n">mediumint</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span> <span class="n">unsigned</span> <span class="k">NOT</span> <span class="k">NULL</span> <span class="k">DEFAULT</span> <span class="s1">&#39;0&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="p">(</span><span class="o">`</span><span class="n">id</span><span class="o">`</span><span class="p">),</span>
</span><span class='line'>  <span class="k">UNIQUE</span> <span class="k">KEY</span> <span class="o">`</span><span class="n">uk_cat_name</span><span class="o">`</span> <span class="p">(</span><span class="o">`</span><span class="n">cat_id</span><span class="o">`</span><span class="p">,</span><span class="o">`</span><span class="n">name</span><span class="o">`</span><span class="p">),</span>
</span><span class='line'>  <span class="k">KEY</span> <span class="o">`</span><span class="n">idx_cat_count</span><span class="o">`</span> <span class="p">(</span><span class="o">`</span><span class="n">cat_id</span><span class="o">`</span><span class="p">,</span><span class="o">`</span><span class="k">count</span><span class="o">`</span><span class="p">)</span>
</span><span class='line'><span class="p">)</span> <span class="n">ENGINE</span><span class="o">=</span><span class="n">InnoDB</span> <span class="n">AUTO_INCREMENT</span><span class="o">=</span><span class="mi">2545965</span> <span class="k">DEFAULT</span> <span class="n">CHARSET</span><span class="o">=</span><span class="n">latin1</span>
</span></code></pre></td></tr></table></div></figure>


<p>分析 mysqldump 生成的 SQL 之后，发现数据本身并没有问题，并且向原有的 5.0.x 中导入也没有问题，那么问题应该是出在向 5.1.x 导入的过程中，但仍不明白其原因，于是去掉了 UNIQUE KEY constraint，导入数据后，发现的确有重复的数据：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>mysql> select name, cat_id, count(1) as cnt from tag group by cat_id, name having cnt>1;
</span><span class='line'>+--------------+--------+-----+
</span><span class='line'>| name         | cat_id | cnt |
</span><span class='line'>+--------------+--------+-----+
</span><span class='line'>| Günter_Gras  |   1001 |   2 |
</span><span class='line'>| Strauß       |   1001 |   2 |
</span><span class='line'>| Suskind      |   1001 |   2 |
</span><span class='line'>| sas          |   1002 |   2 |
</span><span class='line'>| Weise        |   1002 |   2 |
</span><span class='line'>| R.Strauß     |   1003 |   2 |
</span><span class='line'>| Strauß       |   1003 |   2 |
</span><span class='line'>+--------------+--------+-----+
</span><span class='line'>7 rows in set (2.30 sec)</span></code></pre></td></tr></table></div></figure>


<p>那就很奇怪了，使用 mysqldump 导出之前，数据是满足 UNIQUE KEY 约束的，并没有重复数据，导出的 SQL 也是正确的，为什么再次导入时反倒出现了重复数据呢？翻了几篇文档之后有了一些眉目，问题应该是出在 5.1.x 的 collation 上，有两个 &#8220;bug&#8221; tickets 描述了我遇到的情况：</p>

<ul>
<li><a href="http://bugs.mysql.com/bug.php?id=27877">http://bugs.mysql.com/bug.php?id=27877</a></li>
<li><a href="http://bugs.mysql.com/bug.php?id=43306">http://bugs.mysql.com/bug.php?id=43306</a></li>
</ul>


<p>那么 collation 是什么呢？collation 是在特定字符集内用于比较（排序）字符的规则，比如A和B谁在前谁在后，要不要区分大小写等等，不同的字符集有多种不同的比较（排序）规则，比如我们常见的 utf8_general_ci 就是一种大小写不敏感的规则，<a href="http://en.wikipedia.org/wiki/Collation">Wikipedia</a> 和 <a href="http://dev.mysql.com/doc/refman/5.1/en/charset-general.html">MySQL 文档</a> 有详细的描述。</p>

<p>在我遇到问题的这个场景下，相关字段的定义是 `name` varchar(255) CHARACTER SET ucs2 NOT NULL DEFAULT &#8221;，而 ucs2 这个字符集的默认 collation 是 ucs2_general_ci：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>mysql> show character set like 'ucs2';
</span><span class='line'>+---------+---------------+-------------------+--------+
</span><span class='line'>| Charset | Description   | Default collation | Maxlen |
</span><span class='line'>+---------+---------------+-------------------+--------+
</span><span class='line'>| ucs2    | UCS-2 Unicode | ucs2_general_ci   |      2 |
</span><span class='line'>+---------+---------------+-------------------+--------+
</span><span class='line'>1 row in set (0.00 sec)</span></code></pre></td></tr></table></div></figure>


<p>5.0.x 时没有问题，而 5.1.x 下有上面的 &#8220;bug&#8221; 中提到的问题，亦即导致我遇到的 duplicate key 问题的原因。</p>

<p>那么 ucs2 这个字符集的collation有哪些呢？</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>mysql> show collation like 'ucs2%';
</span><span class='line'>+--------------------+---------+-----+---------+----------+---------+
</span><span class='line'>| Collation          | Charset | Id  | Default | Compiled | Sortlen |
</span><span class='line'>+--------------------+---------+-----+---------+----------+---------+
</span><span class='line'>| ucs2_general_ci    | ucs2    |  35 | Yes     | Yes      |       1 |
</span><span class='line'>| ucs2_bin           | ucs2    |  90 |         | Yes      |       1 |
</span><span class='line'>| ucs2_unicode_ci    | ucs2    | 128 |         | Yes      |       8 |
</span><span class='line'>| ucs2_icelandic_ci  | ucs2    | 129 |         | Yes      |       8 |
</span><span class='line'>| ucs2_latvian_ci    | ucs2    | 130 |         | Yes      |       8 |
</span><span class='line'>| ucs2_romanian_ci   | ucs2    | 131 |         | Yes      |       8 |
</span><span class='line'>| ucs2_slovenian_ci  | ucs2    | 132 |         | Yes      |       8 |
</span><span class='line'>| ucs2_polish_ci     | ucs2    | 133 |         | Yes      |       8 |
</span><span class='line'>| ucs2_estonian_ci   | ucs2    | 134 |         | Yes      |       8 |
</span><span class='line'>| ucs2_spanish_ci    | ucs2    | 135 |         | Yes      |       8 |
</span><span class='line'>| ucs2_swedish_ci    | ucs2    | 136 |         | Yes      |       8 |
</span><span class='line'>| ucs2_turkish_ci    | ucs2    | 137 |         | Yes      |       8 |
</span><span class='line'>| ucs2_czech_ci      | ucs2    | 138 |         | Yes      |       8 |
</span><span class='line'>| ucs2_danish_ci     | ucs2    | 139 |         | Yes      |       8 |
</span><span class='line'>| ucs2_lithuanian_ci | ucs2    | 140 |         | Yes      |       8 |
</span><span class='line'>| ucs2_slovak_ci     | ucs2    | 141 |         | Yes      |       8 |
</span><span class='line'>| ucs2_spanish2_ci   | ucs2    | 142 |         | Yes      |       8 |
</span><span class='line'>| ucs2_roman_ci      | ucs2    | 143 |         | Yes      |       8 |
</span><span class='line'>| ucs2_persian_ci    | ucs2    | 144 |         | Yes      |       8 |
</span><span class='line'>| ucs2_esperanto_ci  | ucs2    | 145 |         | Yes      |       8 |
</span><span class='line'>| ucs2_hungarian_ci  | ucs2    | 146 |         | Yes      |       8 |
</span><span class='line'>+--------------------+---------+-----+---------+----------+---------+
</span><span class='line'>21 rows in set (0.00 sec)</span></code></pre></td></tr></table></div></figure>


<p>上面可以看到，有针对不同语言的排序规则，在我的场景下，并没有此需求，那么我尝试一下 ucs2_bin，按照二进制排序：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>mysql> alter table tag modify `name` varchar(255) CHARACTER SET ucs2 collate ucs2_bin not null default '';
</span><span class='line'>Query OK, 2436674 rows affected (56.40 sec)
</span><span class='line'>Records: 2436674  Duplicates: 0  Warnings: 0
</span><span class='line'>
</span><span class='line'>mysql> show create table tag\G
</span><span class='line'>*************************** 1. row ***************************
</span><span class='line'>       Table: tag
</span><span class='line'>Create Table: CREATE TABLE `tag` (
</span><span class='line'>  `id` int(11) NOT NULL AUTO_INCREMENT,
</span><span class='line'>  `name` varchar(255) CHARACTER SET ucs2 COLLATE ucs2_bin NOT NULL DEFAULT '',
</span><span class='line'>  `count` int(11) NOT NULL DEFAULT '0',
</span><span class='line'>  `cat_id` mediumint(8) unsigned NOT NULL DEFAULT '0',
</span><span class='line'>  PRIMARY KEY (`id`),
</span><span class='line'>  KEY `uk_cat_name` (`cat_id`,`name`),
</span><span class='line'>  KEY `idx_cat_count` (`cat_id`,`count`)
</span><span class='line'>) ENGINE=InnoDB AUTO_INCREMENT=2545965 DEFAULT CHARSET=latin1
</span><span class='line'>1 row in set (0.00 sec)
</span><span class='line'>
</span><span class='line'>mysql> select name, cat_id, count(1) as cnt from tag group by cat_id, name having cnt>1;
</span><span class='line'>Empty set (2.22 sec)</span></code></pre></td></tr></table></div></figure>


<p>可以看到，使用 ucs2_bin collation 之后，如预期的结果一样，原本不同的字符串被正确地区分开了。</p>

<p>对于如何选择合适的 collation，官方文档有描述，也有一些讨论，比如 <a href="http://stackoverflow.com/questions/367711/what-is-the-best-collation-to-use-for-mysql-with-php">What is the best collation to use for MySQL (with PHP)</a>。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Gentoo MySQL 5.0.92 数据表不可见的bug]]></title>
    <link href="http://blog.xupeng.me/2011/08/25/bug-of-invisible-tables-with-mysql-5-0-92-on-gentoo/"/>
    <updated>2011-08-25T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2011/08/25/bug-of-invisible-tables-with-mysql-5-0-92-on-gentoo</id>
    <content type="html"><![CDATA[<p>Gentoo 维护的 MySQL 5.0.92 有数据表不可见的 bug，表现为：</p>

<!-- more -->




<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>xupeng@localhost [(none)] mysql> use test;
</span><span class='line'>Database changed
</span><span class='line'>xupeng@localhost [test] mysql> create table testing (type tinyint) engine=innodb;
</span><span class='line'>Query OK, 0 rows affected (0.26 sec)
</span><span class='line'>
</span><span class='line'>xupeng@localhost [test] mysql> show tables;
</span><span class='line'>Empty set (0.00 sec)
</span><span class='line'>
</span><span class='line'>xupeng@localhost [test] mysql> show tables from information_schema;
</span><span class='line'>Empty set (0.00 sec)
</span><span class='line'>
</span><span class='line'>xupeng@localhost [test] mysql> select table_name from information_schema.tables where table_schema='test';
</span><span class='line'>+------------+
</span><span class='line'>| table_name |
</span><span class='line'>+------------+
</span><span class='line'>| testing    | 
</span><span class='line'>+------------+
</span><span class='line'>1 row in set (0.00 sec)
</span><span class='line'>
</span><span class='line'>xupeng@localhost [test] mysql> insert into testing values (1);
</span><span class='line'>Query OK, 1 row affected (0.04 sec)
</span><span class='line'>
</span><span class='line'>xupeng@localhost [test] mysql> select * from testing;
</span><span class='line'>+------+
</span><span class='line'>| type |
</span><span class='line'>+------+
</span><span class='line'>|    1 | 
</span><span class='line'>+------+
</span><span class='line'>1 row in set (0.00 sec)</span></code></pre></td></tr></table></div></figure>


<p>如上，数据表可正常读写，但 show tables 看不到，此问题和客户端无关。</p>

<p>5.0.92 官方版本则无此 bug。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[在防火墙后面部署PPTP server]]></title>
    <link href="http://blog.xupeng.me/2011/08/09/iptables-modules-needed-for-deploying-pptp-behind-nat/"/>
    <updated>2011-08-09T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2011/08/09/iptables-modules-needed-for-deploying-pptp-behind-nat</id>
    <content type="html"><![CDATA[<p>在防火墙后面部署 PPTP server 需要额外的 iptables 支持，所需要的 iptables module 有：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>nf_nat_pptp
</span><span class='line'>nf_nat_proto_gre
</span><span class='line'>nf_conntrack_pptp
</span><span class='line'>nf_conntrack_proto_gre</span></code></pre></td></tr></table></div></figure>




<!-- more -->


<p>在 Firewall server 上 modprobe 上述模块，并且添加如下的 iptables 规则：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>-A PREROUTING -p gre -j DNAT --to-destination IP-OF-PPTP-SERVER
</span><span class='line'>-A PREROUTING -p tcp -m tcp --dport 1723 -j DNAT --to-destination IP-OF-PPTP-SERVER</span></code></pre></td></tr></table></div></figure>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[诡异的MySQL内存突增问题]]></title>
    <link href="http://blog.xupeng.me/2011/08/08/weird-mysql-hog-problem/"/>
    <updated>2011-08-08T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2011/08/08/weird-mysql-hog-problem</id>
    <content type="html"><![CDATA[<p>一个稳定运行了大半年的 MySQL 5.0.84 实例，InnoDB buffer pool 为 15GB，正常情况下会使用 17GB 左右物理内存，但是它的物理内存使用量突然在五分钟内飙升至 35GB，导致 kernel 忙于 OOM 而使整个服务器处于假死状态，不得已重启了系统。</p>

<!-- more -->


<p>MySQL 的错误日志中没有记录下任何信息，也没有内存突增导致内存耗尽时的现场了，如何能够知道是什么原因导致 MySQL 的物理内存使用量骤增的呢？</p>

<p>服务器 OS 为 Gentoo，MySQL 为 5.0.84-r1，这是 Gentoo 官方维护的版本，打了一堆 patch，这些 patch 主要有：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
<span class='line-number'>113</span>
<span class='line-number'>114</span>
<span class='line-number'>115</span>
<span class='line-number'>116</span>
<span class='line-number'>117</span>
<span class='line-number'>118</span>
<span class='line-number'>119</span>
<span class='line-number'>120</span>
<span class='line-number'>121</span>
<span class='line-number'>122</span>
<span class='line-number'>123</span>
<span class='line-number'>124</span>
<span class='line-number'>125</span>
<span class='line-number'>126</span>
<span class='line-number'>127</span>
<span class='line-number'>128</span>
<span class='line-number'>129</span>
<span class='line-number'>130</span>
<span class='line-number'>131</span>
<span class='line-number'>132</span>
<span class='line-number'>133</span>
<span class='line-number'>134</span>
<span class='line-number'>135</span>
<span class='line-number'>136</span>
<span class='line-number'>137</span>
<span class='line-number'>138</span>
<span class='line-number'>139</span>
<span class='line-number'>140</span>
<span class='line-number'>141</span>
<span class='line-number'>142</span>
<span class='line-number'>143</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>xupeng@localhost [(none)] mysql> show patches \G
</span><span class='line'>*************************** 1. row ***************************
</span><span class='line'>   File: show_patches.patch
</span><span class='line'>   Name: SHOW PATCHES
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Jeremy Cole
</span><span class='line'>License: N/A
</span><span class='line'>Comment: 
</span><span class='line'>*************************** 2. row ***************************
</span><span class='line'>   File: microslow_innodb.patch
</span><span class='line'>   Name: Extended statistics in slow.log
</span><span class='line'>Version: 1.2
</span><span class='line'> Author: Percona &lt;info @percona.com>
</span><span class='line'>License: GPL
</span><span class='line'>Comment: 
</span><span class='line'>*************************** 3. row ***************************
</span><span class='line'>   File: profiling_slow.info
</span><span class='line'>   Name: profiling from SHOW PROFILE to slow.log
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Percona &lt;/info>&lt;info @percona.com>
</span><span class='line'>License: GPL
</span><span class='line'>Comment: 
</span><span class='line'>*************************** 4. row ***************************
</span><span class='line'>   File: userstatsv2.patch
</span><span class='line'>   Name: SHOW USER/TABLE/INDEX statistics
</span><span class='line'>Version: V2
</span><span class='line'> Author: Google
</span><span class='line'>License: GPL
</span><span class='line'>Comment: Added INFORMATION_SCHEMA.*_STATISTICS
</span><span class='line'>*************************** 5. row ***************************
</span><span class='line'>   File: microsec_process.patch
</span><span class='line'>   Name: Adds INFOMATION_SCHEMA.PROCESSLIST with TIME_MS column
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Percona &lt;/info>&lt;info @percona.com>
</span><span class='line'>License: GPL
</span><span class='line'>Comment: 
</span><span class='line'>*************************** 6. row ***************************
</span><span class='line'>   File: innodb_io_patches.patch
</span><span class='line'>   Name: Cluster of past InnoDB IO patches
</span><span class='line'>Version: 1.1
</span><span class='line'> Author: Percona
</span><span class='line'>License: GPL
</span><span class='line'>Comment: This patch contains fixed (control_flush_and_merge_and_read, control_io-threads, adaptive_flush)
</span><span class='line'>*************************** 7. row ***************************
</span><span class='line'>   File: mysqld_safe_syslog.patch
</span><span class='line'>   Name: Patch allows redirect output of error.log to syslog-ng
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Percona &lt;/info>&lt;info @percona.com>
</span><span class='line'>License: GPL
</span><span class='line'>Comment: Ported from Debian
</span><span class='line'>*************************** 8. row ***************************
</span><span class='line'>   File: innodb_locks_held.patch
</span><span class='line'>   Name: Add locks held, remove locked records in SHOW INNODB STATUS
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Baron Schwartz &lt;baron @xaprb.com>
</span><span class='line'>License: GPL
</span><span class='line'>Comment: Bug #29126 fix
</span><span class='line'>*************************** 9. row ***************************
</span><span class='line'>   File: innodb_show_bp.patch
</span><span class='line'>   Name: show innodb buffer pool content
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Percona &lt;info @percona.com>
</span><span class='line'>License: GPL
</span><span class='line'>Comment: 
</span><span class='line'>*************************** 10. row ***************************
</span><span class='line'>   File: innodb_check_fragmentation.patch
</span><span class='line'>   Name: Session status to check fragmentation of the last InnoDB scan
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Percona &lt;/info>&lt;info @percona.com>
</span><span class='line'>License: GPL
</span><span class='line'>Comment: The names are Innodb_scan_*
</span><span class='line'>*************************** 11. row ***************************
</span><span class='line'>   File: innodb_io_pattern.patch
</span><span class='line'>   Name: Information schema table of InnoDB IO counts for each datafile pages
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Percona &lt;/info>&lt;info @percona.com>
</span><span class='line'>License: GPL
</span><span class='line'>Comment: INFORMATION_SCHEMA.INNODB_IO_PATTERN
</span><span class='line'>*************************** 12. row ***************************
</span><span class='line'>   File: innodb_fsync_source.patch
</span><span class='line'>   Name: Information of fsync callers in InnoDB
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Google
</span><span class='line'>License: GPL
</span><span class='line'>Comment: 
</span><span class='line'>*************************** 13. row ***************************
</span><span class='line'>   File: innodb_show_hashed_memory.patch
</span><span class='line'>   Name: Adds additional information of InnoDB internal hash table memories in SHOW INNODB STATUS
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Percona &lt;/info>&lt;info @percona.com>
</span><span class='line'>License: GPL
</span><span class='line'>Comment: 
</span><span class='line'>*************************** 14. row ***************************
</span><span class='line'>   File: innodb_dict_size_limit.patch
</span><span class='line'>   Name: Limit dictionary cache size
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Percona
</span><span class='line'>License: GPL
</span><span class='line'>Comment: Variable innodb_dict_size_limit in bytes
</span><span class='line'>*************************** 15. row ***************************
</span><span class='line'>   File: innodb_extra_rseg.patch
</span><span class='line'>   Name: allow to create extra rollback segments
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Percona &lt;/info>&lt;info @percona.com>
</span><span class='line'>License: GPL
</span><span class='line'>Comment: 
</span><span class='line'>*************************** 16. row ***************************
</span><span class='line'>   File: thread_concurrency_timer_based.patch
</span><span class='line'>   Name: Use InnoDB timer based concurrency throttling (backport from MySQL 5.4.0)
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Percona &lt;/info>&lt;info @percona.com>
</span><span class='line'>License: GPL
</span><span class='line'>Comment: 
</span><span class='line'>*************************** 17. row ***************************
</span><span class='line'>   File: innodb_use_sys_malloc.patch
</span><span class='line'>   Name: InnoDB uses malloc directly (backport from InnoDB-Plugin)
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Percona &lt;/info>&lt;info @percona.com>
</span><span class='line'>License: GPL
</span><span class='line'>Comment: 
</span><span class='line'>*************************** 18. row ***************************
</span><span class='line'>   File: innodb_recovery_patches.patch
</span><span class='line'>   Name: Bugfixes and adjustments about recovery process
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Percona &lt;/info>&lt;info @percona.com>
</span><span class='line'>License: GPL
</span><span class='line'>Comment: 
</span><span class='line'>*************************** 19. row ***************************
</span><span class='line'>   File: innodb_split_buf_pool_mutex.patch
</span><span class='line'>   Name: InnoDB patch to fix buffer pool scalability
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Yasufumi Kinoshita
</span><span class='line'>License: BSD
</span><span class='line'>Comment: Backport from XtraDB
</span><span class='line'>*************************** 20. row ***************************
</span><span class='line'>   File: innodb_rw_lock.patch
</span><span class='line'>   Name: Fix of InnoDB rw_locks
</span><span class='line'>Version: 1.0
</span><span class='line'> Author: Yasufumi Kinoshita
</span><span class='line'>License: BSD
</span><span class='line'>Comment: 
</span><span class='line'>20 rows in set (0.00 sec)
</span><span class='line'>&lt;/info>&lt;/baron>&lt;/info>&lt;</span></code></pre></td></tr></table></div></figure>


<p>MySQL配置如下：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
</pre></td><td class='code'><pre><code class='ini'><span class='line'><span class="k">[mysqld]</span>
</span><span class='line'><span class="err">skip-name-resolve</span>
</span><span class='line'><span class="na">replicate-ignore-db</span><span class="o">=</span><span class="s">test</span>
</span><span class='line'><span class="na">max_connect_errors</span><span class="o">=</span><span class="s">999999999</span>
</span><span class='line'><span class="na">character-set-server</span> <span class="o">=</span> <span class="s">utf8 </span>
</span><span class='line'><span class="na">default-character-set</span> <span class="o">=</span> <span class="s">utf8</span>
</span><span class='line'><span class="na">user</span> <span class="o">=</span> <span class="s">mysql                </span>
</span><span class='line'><span class="na">port</span> <span class="o">=</span> <span class="s">3308                 </span>
</span><span class='line'><span class="na">socket</span> <span class="o">=</span> <span class="s">/var/run/mysqld/mysqld-orc.sock</span>
</span><span class='line'><span class="na">pid-file</span> <span class="o">=</span> <span class="s">/var/run/mysqld/mysqld-orc.pid</span>
</span><span class='line'><span class="na">log-error</span> <span class="o">=</span> <span class="s">/log/mysql-orc-log/mysqld.err</span>
</span><span class='line'><span class="na">basedir</span> <span class="o">=</span> <span class="s">/usr              </span>
</span><span class='line'><span class="na">datadir</span> <span class="o">=</span> <span class="s">/data/mysql-orc   </span>
</span><span class='line'><span class="err">skip-locking</span>
</span><span class='line'><span class="na">key_buffer</span> <span class="o">=</span> <span class="s">256M           </span>
</span><span class='line'><span class="na">thread_cache</span> <span class="o">=</span> <span class="s">48           </span>
</span><span class='line'><span class="na">max_allowed_packet</span> <span class="o">=</span> <span class="s">12M    </span>
</span><span class='line'><span class="na">max_connections</span> <span class="o">=</span> <span class="s">1500      </span>
</span><span class='line'><span class="na">max_user_connections</span> <span class="o">=</span> <span class="s">1450 </span>
</span><span class='line'><span class="na">table_cache</span> <span class="o">=</span> <span class="s">4096          </span>
</span><span class='line'><span class="na">sort_buffer_size</span> <span class="o">=</span> <span class="s">1M       </span>
</span><span class='line'><span class="na">net_buffer_length</span> <span class="o">=</span> <span class="s">8K      </span>
</span><span class='line'><span class="na">read_buffer_size</span> <span class="o">=</span> <span class="s">1M       </span>
</span><span class='line'><span class="na">read_rnd_buffer_size</span> <span class="o">=</span> <span class="s">1M   </span>
</span><span class='line'><span class="na">myisam_sort_buffer_size</span> <span class="o">=</span> <span class="s">1M</span>
</span><span class='line'><span class="na">language</span> <span class="o">=</span> <span class="s">/usr/share/mysql/english</span>
</span><span class='line'><span class="na">server-id</span> <span class="o">=</span> <span class="s">33083           </span>
</span><span class='line'><span class="err">log-slave-updates</span>
</span><span class='line'><span class="err">skip_slave_start</span>
</span><span class='line'><span class="na">expire_logs_days</span> <span class="o">=</span> <span class="s">7</span>
</span><span class='line'><span class="na">log-bin</span> <span class="o">=</span> <span class="s">/log/mysql-orc-log/binary-logs/log</span>
</span><span class='line'><span class="na">binlog-ignore-db</span> <span class="o">=</span> <span class="s">test</span>
</span><span class='line'><span class="na">sync_binlog</span> <span class="o">=</span> <span class="s">0</span>
</span><span class='line'><span class="na">relay-log</span><span class="o">=</span><span class="s">/log/mysql-orc-log/relay-logs/relay.log</span>
</span><span class='line'><span class="na">tmpdir</span> <span class="o">=</span> <span class="s">/log/mysql-orc-log/tmp</span>
</span><span class='line'><span class="err">innodb_file_per_table</span>
</span><span class='line'><span class="na">innodb_buffer_pool_size</span> <span class="o">=</span> <span class="s">15G</span>
</span><span class='line'><span class="na">innodb_additional_mem_pool_size</span> <span class="o">=</span> <span class="s">20M</span>
</span><span class='line'><span class="na">innodb_data_home_dir</span> <span class="o">=</span> <span class="s">/data/mysql-orc</span>
</span><span class='line'><span class="na">innodb_log_arch_dir</span> <span class="o">=</span> <span class="s">/data/mysql-orc</span>
</span><span class='line'><span class="na">innodb_log_group_home_dir</span> <span class="o">=</span> <span class="s">/data/mysql-orc</span>
</span><span class='line'><span class="na">innodb_data_file_path</span> <span class="o">=</span> <span class="s">ibdata1:2000M:autoextend</span>
</span><span class='line'><span class="na">innodb_log_file_size</span> <span class="o">=</span> <span class="s">128M</span>
</span><span class='line'><span class="na">innodb_log_buffer_size</span> <span class="o">=</span> <span class="s">8M</span>
</span><span class='line'><span class="na">set-variable</span> <span class="o">=</span> <span class="s">innodb_log_files_in_group=2</span>
</span><span class='line'><span class="na">innodb_flush_log_at_trx_commit</span> <span class="o">=</span> <span class="s">2</span>
</span><span class='line'><span class="na">innodb_flush_method</span> <span class="o">=</span> <span class="s">O_DIRECT</span>
</span><span class='line'><span class="na">innodb_sync_spin_loops</span> <span class="o">=</span> <span class="s">50</span>
</span><span class='line'><span class="na">innodb_lock_wait_timeout</span> <span class="o">=</span> <span class="s">50</span>
</span><span class='line'><span class="na">innodb_thread_concurrency</span> <span class="o">=</span> <span class="s">14</span>
</span><span class='line'><span class="na">wait_timeout</span> <span class="o">=</span> <span class="s">86400</span>
</span><span class='line'><span class="na">transaction-isolation</span> <span class="o">=</span> <span class="s">READ-COMMITTED</span>
</span><span class='line'><span class="na">report-host</span> <span class="o">=</span> <span class="s">treebeard</span>
</span><span class='line'><span class="na">report-port</span> <span class="o">=</span> <span class="s">3308</span>
</span><span class='line'><span class="na">read_only</span> <span class="o">=</span> <span class="s">1</span>
</span><span class='line'><span class="na">sql_mode</span> <span class="o">=</span> <span class="s">&quot;&quot;</span>
</span><span class='line'><span class="na">open_files_limit</span> <span class="o">=</span> <span class="s">65535</span>
</span><span class='line'><span class="na">default-storage-engine</span> <span class="o">=</span> <span class="s">innodb</span>
</span><span class='line'><span class="na">ft_min_word_len</span> <span class="o">=</span> <span class="s">1</span>
</span><span class='line'><span class="na">ft_stopword_file</span> <span class="o">=</span> <span class="s">&#39;/etc/mysql/douban.stopwords&#39;</span>
</span><span class='line'><span class="na">log-slow-queries</span> <span class="o">=</span> <span class="s">/log/mysql-orc-log/mysql-slow.log</span>
</span><span class='line'><span class="na">long_query_time</span> <span class="o">=</span> <span class="s">1</span>
</span></code></pre></td></tr></table></div></figure>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Gmail mute功能的bug？]]></title>
    <link href="http://blog.xupeng.me/2011/07/28/bug-of-gmail-mute/"/>
    <updated>2011-07-28T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2011/07/28/bug-of-gmail-mute</id>
    <content type="html"><![CDATA[<p>自从 Gmail 有了 <a href="http://mail.google.com/support/bin/answer.py?answer=47787">mute 功能</a> 之后我就没有停止过尝试使用它，但是遗憾的是，这个功能在我这里从来都没有真正工作过，被我 mute 了的会话被加上了 &#8220;Muted&#8221; 标签，但是这些会话仍然会不断地从我的 Inbox 里冒出来，完全不能阻止 mute 功能要对付的那些 &#8220;endless threads&#8221;，平添很多烦恼。</p>

<!-- more -->


<p>无奈之下只好仔细研究了一下原因，最终发现导致 mute 功能在我这里不生效的原因是：被我 mute 的邮件被 filter 匹配之后做了一个 &#8220;Never send it to Spam&#8221; 的动作，正是这个动作导致被 mute 的邮件会再次出现在 Inbox 里，去掉这个动作之后，mute 功能就能正常工作了。</p>

<p>&#8220;Never send it to Spam&#8221; 和 mute 本应是两个不相干的功能，各有各的用途，&#8221;Never send it to Spam&#8221; 使得我不会错过被误判为 Spam 的邮件，mute 让我可以忽略不是 Spam 但是我不关心的会话，使用了 &#8220;Never send it to Spam&#8221; 就使 mute 功能不工作，这应该算是 bug 吧？</p>

<p>目前找到了两个 workaround：</p>

<ul>
<li>不使用 &#8220;Never send it to Spam&#8221;</li>
<li>仍然使用 &#8220;Never send it to Spam&#8221;, 但是额外创建一个新的 filter，匹配包含 &#8220;is:muted&#8221; 的邮件，对这样的邮件执行 &#8220;Skip the Inbox (Archive it)&#8221;</li>
</ul>


<p>第一个不太合适，有可能会漏掉被误判为 Spam 的重要邮件。创建第二个方法使用的 filter 时会有这样一个警告：</p>

<p><img src="http://blog.xupeng.me/downloads/2011/07/gmail-filter-warning.png" alt="GMail filter warning" /></p>

<p>忽略之继续创建即可。</p>

<p>文档和实际行为之间各种不一致啊。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[如何打发路上的时光？]]></title>
    <link href="http://blog.xupeng.me/2011/05/26/time-spent-on-the-road/"/>
    <updated>2011-05-26T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2011/05/26/time-spent-on-the-road</id>
    <content type="html"><![CDATA[<p>几年前刚到北京那会儿，住在白广路，在三元桥上班，每天路上来回要花两三个小时，对于刚从三线城市到一线城市的我来说，这是极大的不适应，无尽的时间被痛苦地消磨过去，从那个时候起，我正式地有了打发每天路上几个小时的需求。</p>

<!-- more -->


<p>最初是拿一个爱国者的 MP3 Player 打算听 podcast，但是遇到了两个障碍，其实原因是同一个：资源问题，英语听力不好听英文的太费劲，中文的资源又很稀缺，于是听了没几天就放弃了。再之后慢慢地开始听随便找来的英文资源磨耳朵，后来找到了ESL，坚持听了一段时间之后又放弃了，每次更新新下载的 podcast 到 MP3、清除旧的 podcast 成为了我放弃的借口，即便后来换了 iriver 号称支持 podcast 更新和管理的 Lplayer，这个 podcast 更新过程对我来说仍然太麻烦了。</p>

<p>于是在几年内我上下班路上的时间都只能零零星星地被利用，有时候听一点点 podcast，有时候看几页书，有时候打印几张文档翻翻看，剩下的大部分的时间都被无聊地消磨掉了，所幸的是后来公司搬了家，我也搬到了公司附近住，这个需求渐渐地就没有那么强烈了。</p>

<p>再后来换了工作，住在造甲村，在酒仙桥上班，这下可好了，每天上下班来回需要五个多小时，一下子把首都人民上下班时间的后腿拖得一塌糊涂， 如何熬过这段时间成了一个必须要解决的问题。</p>

<p>先是买了 Kindle DX，每天路上来回差不多能看四个小时书，这倒是很不错，读了不少以前想读却以没时间为借口放下的书，但是缺点也非常明显，公交车摇摇晃晃时不时急刹车，晃得头晕恶心，过了一段时间之后视力也明显下降，这个方案不行，于是 Kindle DX 的角色变成了家用电器，除非有书需要赶时间看，就只在家里用了。</p>

<p>重新开始打听的主意，这次退路被逼的少了些，毕竟路上的时间实在是太长了，看又不行，那再不听还能做什么呢？努力克服资源更新的繁琐，但是问题很快又来了，路上时间长啊，听那么长时间耳朵真的受不了啊，耳塞换入耳、入耳换头戴、头戴再换入耳，实在忍不下去了于是我搬家了，住在离公司半个小时以内车程、来回需要两个小时左右的地方。</p>

<p>那为什么不住在公司旁边呢？因为自己的工作狂习惯。如果住在公司旁边，那我就真的完全没有上下班的界限了，如果到这个地步那就真的不能忍了。</p>

<p>既然路上有两个小时，那么这个时间还是需要合理利用的，借之前的经验，除非真的有东西要赶时间看，在公交车上看书是一个下策。相对来说听的优势就大多了，不受有没有座位限制，不受公交车拥挤程度限制，不受天气状况限制，唯一的限制是不能听的时间太长，我住的距离刚好打破了这个限制。</p>

<p>选定了方案，接下来就是实施，过程就不多提了，只总结一下这个过程中得到的经验吧：</p>

<ul>
<li>听 podcast，要有方便更新 podcast 的手段和设备。比如 iPod / iPhone + iTunes 就是一个绝佳的选择，在 iTunes 中订阅喜欢的 podcast 之后便几乎没有任何痛苦，每天需要做的就是把 iPod / iPhone 连上电脑，点一下 sync。别小看设备的重要性，它在我养成听 podcast 习惯的过程中是一个必要条件。</li>
<li>即便不发烧，也需要一个好一点的耳机。首先每天让耳朵听那么多，就得对耳朵好一点，其次这在爱不爱听，也就是能不能坚持听这个问题上，能够起到一个不容忽视的作用，对我来说这是一个非常重要的条件。至于耳机的选择，在嘈杂的户外环境下，一个入耳式耳机几乎是必须的。</li>
<li>选择有兴趣的 podcast。我常听的主要有 ESL, Business English Pod, The Geek Podcast,  Grammer Girl,  NPR Wait Wait&#8230;Don&#8217;t Tell Me!, OurSQL, TEDTalks，这些在 iTunes 里都能轻松找到</li>
</ul>


<p>在合适设备的帮助下养成听 podcast 的习惯之后，每天上下班路上两个小时的时间就变成了尽情享受的美好时光，我有这种享受，已经半年多了。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[远程开启 DELL 服务器的 Intel CPU VT 支持]]></title>
    <link href="http://blog.xupeng.me/2011/03/10/enable-vt-for-dell-server-remotely/"/>
    <updated>2011-03-10T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2011/03/10/enable-vt-for-dell-server-remotely</id>
    <content type="html"><![CDATA[<p>想提高服务器资源使用率，又不想在同一台物理服务器上混合部署多种服务，因为混合部署会带来更高的运维代价，使用虚拟化，物理隔离出部分计算资源，以虚拟机为单位重新分配不同时段的空闲计算资源，是综合成本更低的方案。</p>

<!-- more -->


<p>某批 DELL 服务器的原定用途不是虚拟化，因此在 BIOS 中禁用了 VT 支持，如何远程启用 VT 是亟待解决的问题，不然就得前往 IDC 一台一台重启，修改 BIOS 设置再重启。还好，DELL 的 Dell OpenManage Server Administrator (OMSA) 是可以远程修改 BIOS 设置的，这样就可以免除奔波之苦。但不巧的是，这是一批安装了 Gentoo 的服务器，上次 <a href="http://blog.xupeng.me/2010/09/07/configure-dell-idarc-remotely/">远程配置 iDrac </a>时利用 DELL 的出厂默认 IP/User/Password，耍了一点小技巧避免了在 Gentoo 上安装 OMSA，但这次这个问题无法回避了，除了 OMSA 之外，似乎没有别的技术手段可以远程修改 BIOS 配置，如果有别的更轻量的手段请告诉我。</p>

<p>幸运的是，已经有人遇到了和我一样的问题，并且已经解决了，方法是：在 Gentoo 上安装 debootstrap，之后使用 debootstrap 安装一个 Debian(200~300M而已)，接着 chroot 到 Debian 中，安装 Debian 版本的 OMSA，在 chroot 的 Debian 中使用 omconfig 工具完成对 BIOS 的修改 (omconfig chassis biossetup attribute=cpuvt setting=enabled)，原理很简单（第一个想到使用这个方法的人还是挺机灵的），操作也很简单，过程在<a href="http://anothersysadmin.wordpress.com/2008/02/22/howto-install-dell-openmanage-system-administrator-on-exotic-linux-distributions/">这里</a>，就不做重复劳动了。</p>

<p>我做了一个 disk image，放在分布式存储上，将 debian bootstrap 到这个 disk image 中，需要使用 OMSA 来做配置修改的服务器就 mount 这个 disk image 来使用，也算是在我的应用场景里，对这个聪明的办法做了一点有益的延伸吧。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Snow leopard 的诡异 DNS 问题]]></title>
    <link href="http://blog.xupeng.me/2010/10/25/weird-snow-leopard-dns-issue/"/>
    <updated>2010-10-25T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2010/10/25/weird-snow-leopard-dns-issue</id>
    <content type="html"><![CDATA[<p>用 Mac 一年来遇到最诡异的问题，就是 Snow leopard 的 DNS 问题了，最常遇到的状况是，dig/nslookup/host 都能够正确解析域名，但 ping 却不能解析任何域名，其他的一票软件如 ssh、浏览器等也因为解析不了域名而不能正常工作。</p>

<!-- more -->


<p>发生这种状况时，我一般会看看 mDNSResponder 是否异常，曾多次遇到 mDNSResponder CPU 占用 100%，这种情况下 kill 掉 mDNSResponder，等它自动重启之后，DNS 解析问题通常就会恢复正常。但也不尽如此，我越来越多次有类似的 DNS 解析问题时，重启 mDNSResponder 进程并不凑效，log 中也未能发现对我有意义的线索。</p>

<p>今天又遇到了这样的问题，与以前一样，dig/nslookup/host 能够正确解析所有域名，ping 和其他软件则不能，和之前略有不同的是，这次的状况是 VPN 内网的域名不能解析，而其他的外网域名可以正常解析，于是花了点时间做了些探索，同时也找到了一篇详尽<a href="http://www.afp548.com/article.php?story=20100329090657793">解释Snow leopard DNS解析问题的文章</a>。</p>

<p>简单说来，dig/nslookup/host 对 <code>/etc/resolv.conf</code> 中的 DNS server 直接进行查询，因此只要 DNS server 本身工作正常，这三个程序都可以正常解析。而系统的其他部分则不同，在 Mac OS X 10.6 Snow leopard 中，由 mDNSResponder 负责所有的 DNS 解析，包括单播 DNS(传统的域名解析)和多播 DNS(Bonjour)，mDNSResponder 并不使用 /etc/resolv.conf 中的 DNS，实际使用的 DNS 是使用 scutil 来设置的，并可以使用 scutil &#8211;dns 来查看当前使用的 DNS server 和顺序，而在 resolv.conf 中看到的 DNS，只是 mDNSResponder 列出来的 primary DNS resolvers。</p>

<p>以 xxx.douban.com 这个子域为例，假设内部 DNS 地址为 1.2.3.4，对于我遇到的内部域名不能正确解析的情况，可以使用 resolver(man 5 resolver) 来解决，方法是：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>sudo mkdir -p /etc/resolver
</span><span class='line'><span class="nb">echo</span> <span class="s2">&quot;nameserver 1.2.3.4&quot;</span> &gt; /etc/resolver/xxx.douban.com
</span></code></pre></td></tr></table></div></figure>


<p>意指使用 1.2.3.4 作为 xxx.douban.com 这个域的域名服务器。</p>

<p>resolver 的这个功能同时也给我带来了极大的便利，我以前指定用特定的服务器来解析某域时，通常是在本地跑一个 dnscache 实例，在 dnscache 中做类似配置，现在直接使用 resolver 即可，比如我可以在 openvpn 服务器端推送到 8.8.8.8 的路由记录，使得到 8.8.8.8 的链路经由 VPN 加密，然后在本地配置指定比如 twitter.com 使用 8.8.8.8 来解析，就可以解决国内劫持 twitter.com 域名的问题了。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[远程配置 DELL iDRAC]]></title>
    <link href="http://blog.xupeng.me/2010/09/07/configure-dell-idarc-remotely/"/>
    <updated>2010-09-07T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2010/09/07/configure-dell-idarc-remotely</id>
    <content type="html"><![CDATA[<p>DELL iDRAC(Integrated Dell Remote Access Controller) 可以用于服务器远程管理，比如远程电源管理、启动故障诊断、硬件故障报警监测等等。</p>

<p>新近的一批 DELL 服务器集成了 iDRAC Express，服务器已经上线运行数月，可惜当初没有进行过 iDRAC 的配置，因此也不能使用，简单查了一下，有两种方法可以配置 iDRAC：</p>

<!-- more -->


<ol>
<li>在开机时按照提示操作，进行 iDRAC 配置</li>
<li>在操作系统中安装 Dell OpenManage Server Administrator，使用 OpenManage Server Administrator 配置 iDRAC</li>
</ol>


<p>第一种方法有两个不便：需要人到服务器跟前，并且需要重启服务器，不可取。
第二种方法也不理想：DELL 只提供“商业” Linux 发行版的支持，在 Gentoo 上安装 OpenManage Server Administrator 会有麻烦，并且也违反我的服务器洁癖原则。</p>

<p>但是接下来的搜索表明不重启服务器配置 iDRAC 也是可行的，该型号的 DEL L服务器 iDRAC 默认配置是：</p>

<ul>
<li>IP: 192.168.0.120</li>
<li>User: root</li>
<li>Password: calvin</li>
</ul>


<p>那就好办了，使用该默认配置远程登陆 iDRAC 远程管理系统，修改配置即可。但也不是完全没有问题，因为同一批的服务器全都是默认配置，IP 地址都是 192.168.0.120，所以要成功地逐一访问，还是要耍点小技巧：在与要配置 iDRAC 的服务器同一物理网络的其他服务器上 ping 192.168.0.120，之后查看做响应的那个 &#8220;192.168.0.120&#8221; 的 MAC 地址：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ arp -n | grep 192.168.0.120
</span><span class='line'>192.168.0.120             ether   AA:BB:CC:DD:EE:FF   C                     lan</span></code></pre></td></tr></table></div></figure>


<p>然后绑定 192.168.0.120 和这个 MAC：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>sudo arp -s 192.168.0.120 AA:BB:CC:DD:EE:FF
</span></code></pre></td></tr></table></div></figure>


<p>这样就可以保证之后对 192.168.0.120 的访问都是同一台服务器。完成 iDRAC 配置之后删掉之前做的 IP-MAC 绑定：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>sudo arp -d 192.168.0.120
</span></code></pre></td></tr></table></div></figure>


<p>如此反复，就可以对所有的服务器完成 iDRAC 配置。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Context switch 和 TLB shootdowns]]></title>
    <link href="http://blog.xupeng.me/2010/09/01/context-switch-and-tlb-shootdowns/"/>
    <updated>2010-09-01T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2010/09/01/context-switch-and-tlb-shootdowns</id>
    <content type="html"><![CDATA[<p>memcache 缓存大对象失效，因此某个涉及4万条记录的查询每次都会把压力直接施加到 MySQL，致使 MySQL 服务器的 load 在几分钟内上升到 60+。</p>

<!-- more -->


<p>问题的解决当然是找出引发问题的查询，临时屏蔽发起该查询的页面，解决缓存失效的问题后再恢复，在此不多说。</p>

<p>在 MySQL 服务器 load 飙升时，有几个有趣的现象：</p>

<ol>
<li>85% 以上的 CPU(16个核) 时间花费在 system/kernel 态</li>
<li>有 80 个左右 MySQL 查询处于 sending data 状态，每个查询持续 20s 左右</li>
<li>内网流量 99.xMbps，但始终未突破 100Mbps</li>
<li>Context switch 78k/s</li>
<li>TLB shootdowns 135k/s</li>
</ol>


<p>查阅了一些资料，基本弄清楚了因果关系，先整理和翻译几段 wiki，解释一下 Context switch 和 TLB shootdowns：</p>

<ul>
<li>Context switch(上下文切换):  简单说来，如果可运行的线程数大于CPU的数量，那么OS最终会强行换出正在执行的线程，从而使其他线程能够使用CPU。这会引起上下文切换，它会保存当前运行线程的执行上下文，并重建新调入线程的执行上下文。</li>
<li>TLB(Translation Lookaside Buffer) shootdowns：TLB是虚拟内存地址到物理内存地址的映射表，有软件TLB和硬件TLB， x86架构使用硬件TLB。当虚拟内存地址到物理内存地址的映射发生变化时，TLB会被刷新，就产生了TLB shootdowns中断，对于x86架构来说是硬件中断。</li>
</ul>


<p>发生上下文切换时，TLB 中的部分条目会失效，不同 TLB 实现会有不同做法，x86 会清掉整个 TLB，而有的实现可以做到选择性地只 flush 部分条目。</p>

<p>那么因果关系应该是这样:</p>

<ol>
<li>memcache 失效，有很大结果集的查询直接施压到了 MySQL 上</li>
<li>80 个左右的活动 MySQL 查询长时间处于 sending data 状态，CPU 不停地在各个 MySQL 线程间切换（意味着有大量的上下文切换）</li>
<li>频繁的上下文切换导致频繁的 TLB 失效，引发大量的 TLB shootdowns 中断</li>
<li>于是大量的 CPU 时间耗费在处理中断上，CPU 的 run 队列等待了 60 个左右可运行线程，load 飙升到 60+</li>
</ol>


<p>由 MySQL 所产生的 99.xMbps 网络流量比较奇怪，不确定是否是因为网卡的中断分布不均（事发当时所有的网卡中断全部由第一个 CPU 核处理），因此在 CPU 忙于处理上下文切换、TLB shootdowns 中断以及其他中断时，网络吞吐量也受到了极大影响，但是这个接近 100Mbps 但又不超过 100Mbps 的数值的确蹊跷。</p>

<p>目前还没有想到有什么好的办法能够避免类似的情况再发生，<a href="http://www.facebook.com/MySQLatFacebook#!/notes/mysql-at-facebook/early-results-from-admission_control/415232480932">Facebook 的 patch </a>可以限制并发的查询数，应该可以缓解这类问题带来的压力，不过现在看来还不太成熟，在正式采用 Facebook 的 patch 并确认有效之前，可以依靠监控来及时发现问题，并尽快采取措施。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[苹果的吸入式光驱很挫]]></title>
    <link href="http://blog.xupeng.me/2009/12/07/apple-slot-loading-optical-drive-sucks/"/>
    <updated>2009-12-07T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2009/12/07/apple-slot-loading-optical-drive-sucks</id>
    <content type="html"><![CDATA[苹果的吸入式光驱真的很挫。

一张状态良好的DVD RW，放到苹果的吸入式光驱里，读不出来，一直在嘎吱嘎吱地响，又弹不出来，弹出键没用，Disk Utility的弹出也无效，drutil eject也无济于事，快要绝望的时候，看到<a href="http://osxdaily.com/2009/08/28/eject-a-stuck-disk-from-your-mac-dvd-super-drive/" target="_blank">这里</a>说实在弹不出来的话可以重新启动，然后一直按住鼠标/或触摸板，直到系统启动。没招了，重启试了一下，按了N久，光盘终于突然停止嘎吱嘎吱的声音，biu~的一声弹出来了&#8230;
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[换用 Mac 一周]]></title>
    <link href="http://blog.xupeng.me/2009/12/04/use-mac-for-one-week/"/>
    <updated>2009-12-04T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2009/12/04/use-mac-for-one-week</id>
    <content type="html"><![CDATA[<p>电脑不够用了，上周末去苹果家园买了台 MBP 990，这是目前已上市最新款中最低配的 MBP，标配 2G 内存，购机时给升到了 4G，内存有些贵（650元），不过用惯了 4G 内存的本本，不想再倒回到一年多以前，用了几天发现，升级到 4G 内存实在是一个非常明知的选择，并且 4G 内存用 Snow Leopard 也实在不算多。</p>

<!-- more -->


<p>几年来用过不少桌面操作系统（或者当作桌面用），DOS -> Win95 -> Win98 -> Win2000 -> WinXP -> Windows 2003 -> Windows 7, Bluepoint -> Redhat -> Turbo Linux -> Slackware -> Debian -> Ubuntu -> Gentoo / FreeBSD 等等，从使用的层面上讲，Mac / Snow Leopard算是上手最快的一个。</p>

<p>换用 Mac 一周，罗列一些感受到的优缺点吧：</p>

<p>优点：</p>

<ul>
<li>触摸板非常好用，这是目前我最满意的地方
-电池的续航能力还好，不开虚拟机的话，在日常工作的状态下能用差不多 5 个小时，但是仅仅一周电池的健康状态就变成 98% 了</li>
<li>大部分软件的UI和UE都不错</li>
<li>封闭系统也有封闭系统的好处，苹果自己的一整套软硬件带来的便利还是很明显的</li>
<li>&#8230;</li>
</ul>


<p>缺点：</p>

<ul>
<li>整个机器像是个吸尘器，加上办公室最近在装修施工，每天屏幕上的吸附的灰都到发指的程度</li>
<li>这 MBP 的散热似乎不太好，用虚拟机或者编译软件时 CPU 的温度动不动就到 80 度以上了，我还见过 95 度的高温，散热这点甚至还不如我之前的 Dell 笔记本</li>
<li>出现过一次四国文字，原因不明</li>
<li><code>mDNSResponder</code> 多次占用 CPU100%，这时 <code>syslogd</code> 疯狂写日志，占满另外一颗 CPU，CPU 温度迅速飙升到 90 度以上，除去软件问题不说，这散热&#8230;</li>
<li>跟我之前的 Dell + Gentoo 相比，软件系统的反应速度有些慢，这种慢是能够感觉到的</li>
<li>&#8230;</li>
</ul>


<p>我更容易容忍软件的问题，因为软件问题至少有很快被修复的希望，而硬件问题的就比较致命了，比如散热，不知道这 MBP 在夏天会热得疯狂到什么程度。</p>

<p>似乎我的抱怨比满意多，不过其实我对 Mac 整体的表现还是相对满意的，至少超出了我的预期。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[使用Nginx一分钟搭建全功能的Twitter/Twitter search API]]></title>
    <link href="http://blog.xupeng.me/2009/08/31/build-full-featured-twittertwitter-search-api-with-nginx-in-1-minute/"/>
    <updated>2009-08-31T00:00:00+08:00</updated>
    <id>http://blog.xupeng.me/2009/08/31/build-full-featured-twittertwitter-search-api-with-nginx-in-1-minute</id>
    <content type="html"><![CDATA[<p>现在有很多的 Twitter 代理软件，比如 <a href="http://code.google.com/p/tweetr/">tweetr</a> 和 [birdnest](http://code.google.com/p/birdnest/, 不过使用反向代理来做的话会更容易，并且得到的是一个 <em>全功能</em> 的 Twitter 代理，这是我在我的 VPS 上使用 Nginx 配置 Twitter 和 Twitter search API 代理的示例配置文件（当然了，这里写出来的域名是假的，哈哈）：</p>

<!-- more -->




<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>server {
</span><span class='line'>    listen          0.0.0.0:80;
</span><span class='line'>    server_name     tproxy.xupeng.me;
</span><span class='line'>
</span><span class='line'>    access_log      /var/log/nginx/tproxy.xupeng.me.access_log;
</span><span class='line'>    error_log       /var/log/nginx/tproxy.xupeng.me.error_log info;
</span><span class='line'>
</span><span class='line'>    location / {
</span><span class='line'>        proxy_pass              http://twitter.com/;
</span><span class='line'>        proxy_redirect          off;
</span><span class='line'>        proxy_set_header        X-Real-IP       $remote_addr;
</span><span class='line'>        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
</span><span class='line'>    }
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>server {
</span><span class='line'>    listen          0.0.0.0:80;
</span><span class='line'>    server_name     tsproxy.xupeng.me;
</span><span class='line'>
</span><span class='line'>    access_log      /var/log/nginx/tsproxy.xupeng.me.access_log;
</span><span class='line'>    error_log       /var/log/nginx/tsproxy.xupeng.me.error_log info;
</span><span class='line'>
</span><span class='line'>    location / {
</span><span class='line'>        proxy_pass              http://search.twitter.com/;
</span><span class='line'>        proxy_redirect          off;
</span><span class='line'>        proxy_set_header        X-Real-IP       $remote_addr;
</span><span class='line'>        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
</span><span class='line'>    }
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>



]]></content>
  </entry>
  
</feed>

