<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Flier&#039;s Sky &#187; development</title>
	<atom:link href="http://blog.flier.lu/category/development/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.flier.lu</link>
	<description>Just for Fun :P</description>
	<lastBuildDate>Sat, 18 Aug 2012 06:00:08 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.0.23</generator>
	<atom:link rel='hub' href='http://blog.flier.lu/?pushpress=hub'/>
	<item>
		<title>Gearman 性能调优</title>
		<link>http://blog.flier.lu/2010/04/gearman-performance-tunning/?source=rss</link>
		<comments>http://blog.flier.lu/2010/04/gearman-performance-tunning/#comments</comments>
		<pubDate>Tue, 20 Apr 2010 18:23:41 +0000</pubDate>
		<dc:creator><![CDATA[Flier Lu]]></dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[gearman]]></category>
		<category><![CDATA[performance tunning]]></category>

		<guid isPermaLink="false">http://blog.flier.lu/?p=102</guid>
		<description><![CDATA[Gearman是最早由LiveJournal内部开发并使用的一个通用并行任务调度框架，允许不同语言直接通过非常 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><a href="http://gearman.org">Gearman</a>是最早由<a href="http://www.livejournal.com">LiveJournal</a>内部开发并使用的一个通用并行任务调度框架，允许不同语言直接通过非常简单的方式进行互操作。前台提交工作任务(Task)和参数，由后台工作进程(Worker)完成实际工作。</p>
<p><img src="http://gearman.org/images/gearman_stack.png" alt="How Does Gearman Work?" /></p>
<p>例如前台提交用户需要进行渲染的图片，由Gearman调度到后台提供渲染服务的工作进程，在完成工作后返回结果给前台进行展示。提交工作和完成工作的代码只需要通过预先协商好的参数格式进行交互，具体任务的调度、负载均衡、可靠性等，由Gearman服务器来确保。而针对大规模应用，可以很容易进行多路节点的集群部署。</p>
<p><img src="http://gearman.org/images/gearman_cluster.png" alt="Gearman Cluster" /></p>
<p>在正式对外发布后，<a href="http://www.danga.com/">Danga Interactive</a>用C重写了整个服务器代码，支持<a href="http://docs.php.net/manual/en/book.gearman.php">PHP</a>, <a href="http://search.cpan.org/dist/Gearman/lib/Gearman/Client.pm">Perl</a>, <a href="http://samuel.github.com/python-gearman/docs/">Python</a>等常见脚本客户端，支持用memcached, sqlite, postgresql, tokyocabinet等作为任务持久化队列，基本上来说是便宜量又足。</p>
<p><span style="font-size: 13.3333px;"> </span></p>
<h2>线程模型</h2>
<p>在大规模使用的时候，需要针对应用类型进行参数设置，以使Gearman的性能达到最优，这首先应该了解Gearman的线程模型。</p>
<p>为确保具备对海量任务调度的支持能力，Gearman毫无悬念的选择<a href="http://www.monkey.org/~provos/libevent/">libevent</a>作为网络操作支撑库。因此Gearman的服务器Gearmand提供了三类线程角色：</p>
<ol>端口监听和管理线程，接受新连接请求并将之交给IO线程，1个</ol>
<ol>IO线程，完成实际的任务处理，包括命令解析，队列操作等，n个</ol>
<ol>处理线程，完成内部数据结构的管理，无系统调用尽可能简单，1个</ol>
<p>其中第1, 3种线程对全局处理性能没有直接影响，虽然处理线程有可能成为瓶颈，但他的工作足够简单消耗可忽略不计，因此我们的性能调优主要目标是在IO线程的数量。<br />
对每个IO线程来说，它都会有一个libevent的实例；所有Gearman的操作会以异步任务方式提交到处理线程，并由IO线程获取完成实际操作，因此IO线程的数量是与可并行处理任务数成正比。Gearmand 提供 -t 参数调整总IO线程数，需要使用 libevent 1.4 以上版本提供多线程支持。</p>
<h2>进程句柄数</h2>
<p>另外一个影响大规模部署的是进程句柄数，Gearman会为每一个注册的Worker分配一个fd(文件描述符)，而这个fd的总数是受用户限制的，可以使用 <a href="http://ss64.com/bash/ulimit.html">ulimit</a> -n 命令查看当前限制</p>
<blockquote><p>
flier@debian:~$ ulimit -n<br />
1024<br />
flier@debian:~$ ulimit -HSn 4096 // 设置进程句柄数的最大软硬限制<br />
4096
</p></blockquote>
<p>也就是说gearman缺省配置下，最多允许同时有小于1024个worker注册上来，fd用完之后的Worker和Client会出现连接超时或无响应等异常情况。因此，发生类似情况时，我们应首先检查 /proc/[PID]/fd/ 目录下的数量，是否已经超过 ulimit -n 的限制，并根据需要进行调整。而全系统的打开文件设置，可以参考 /proc/sys/fs/file-max 文件，并通过 sysctl -w fs.file-max=[NUM] 进行修改。</p>
<blockquote><p>flier@debian:~$ cat /proc/sys/fs/file-max<br />
24372<br />
flier@debian:~# sysctl -w fs.file-max=100000<br />
100000
</p></blockquote>
<p>更详细的设置请参考 <a href="http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/">Linux increase the maximum number of open files or file descriptors</a>。</p>
<p>Gearmand 本身也提供了调整句柄数量限制的功能，启动时则可以通过 &#8211;file-descriptors 参数指定，但非特权进程不能设置超过soft limit的数额。</p>
<blockquote><p>
-f, &#8211;file-descriptors=FDS  Number of file descriptors to allow for the process<br />
                             (total connections will be slightly less). Default<br />
                             is max allowed for user.
</p></blockquote>
<blockquote><p>
The soft limit is the value that the kernel enforces for the corresponding resource.  The hard limit acts as  a<br />
       ceiling  for the soft limit: an unprivileged process may only set its soft limit to a value in the range from 0<br />
       up to the hard limit, and (irreversibly) lower its hard limit.  A privileged process (under Linux: one with the<br />
       CAP_SYS_RESOURCE capability) may make arbitrary changes to either limit value.
</p></blockquote>
<h2>轮询调度</h2>
<p>此外，Gearmand 还提供了一些增强任务调度公平性的参数，例如 0.13 里面新增的 round-robin 模式，允许将任务公平的调度到多个 Worker，而不是用缺省按 Worker 注册函数的顺序进行调度，避免工作过于集中在少数设备上。</p>
<blockquote><p>-R, &#8211;round-robin           Assign work in round-robin order per<br />
workerconnection. The default is to assign work in<br />
the order of functions added by the worker.</p></blockquote>
<p>Gearmand 内部通过一个 Worker 队列，在 RR 模式下动态调整 Worker 的调度次序。</p>
<pre name="code"  class="c">  if (server_con-&gt;thread-&gt;server-&gt;flags.round_robin)
  {
    GEARMAN_LIST_DEL(server_con-&gt;worker, server_worker, con_)
    _server_con_worker_list_append(server_con-&gt;worker_list, server_worker);
    ++server_con-&gt;worker_count;
    if (server_con-&gt;worker_list == NULL) {
      server_con-&gt;worker_list= server_worker;
    }
  }</pre>
<h2>受限唤醒</h2>
<p>而通过 &#8211;worker-wakeup 参数，则可以指定收到任务时，需要唤醒多少个 Worker 进行处理，避免在 Worker 数量非常大时，发送大量不必要的 NOOP 报文，试图唤醒所有的 Worker。</p>
<blockquote><p>-w, &#8211;worker-wakeup=WORKERS Number of workers to wakeup for each job received.<br />
The default is to wakeup all available workers.</p></blockquote>
<p>根据 <a href="http://gearman.org/index.php?id=protocol">Gearman 协议</a>设计， Worker 如果发现队列中没有任务需要处理，是可以通过发送 PRE_SLEEP 命令给服务器，告知说自己将进入睡眠状态。在这个状态下，Worker 不会再去主动抓取任务，只有服务器发送 NOOP 命令唤醒后，才会恢复正常的任务抓取和处理流程。因此 Gearmand 在收到任务时，会去尝试唤醒足够的 Worker 来抓取任务；此时如果 Worker 的总数超过可能的任务数，则有可能产生惊群效应。</p>
<pre name="code"  class="c">  /* Queue NOOP for possible sleeping workers. */
  if (job-&gt;function-&gt;worker_list != NULL)
  {
    worker= job-&gt;function-&gt;worker_list;
    noop_sent= 0;
    do
    {
      if (worker-&gt;con-&gt;options &amp; GEARMAN_SERVER_CON_SLEEPING &amp;&amp;
          !(worker-&gt;con-&gt;options &amp; GEARMAN_SERVER_CON_NOOP_SENT))
      {
        ret= gearman_server_io_packet_add(worker-&gt;con, false,
                                          GEARMAN_MAGIC_RESPONSE,
                                          GEARMAN_COMMAND_NOOP, NULL);
        if (ret != GEARMAN_SUCCESS)
          return ret;

        worker-&gt;con-&gt;options|= GEARMAN_SERVER_CON_NOOP_SENT;
        noop_sent++;
      }

      worker= worker-&gt;function_next;
    }
    while (worker != job-&gt;function-&gt;worker_list &amp;&amp;
           (job-&gt;server-&gt;worker_wakeup == 0 ||
           noop_sent &lt; job-&gt;server-&gt;worker_wakeup));

    job-&gt;function-&gt;worker_list= worker;
  }</pre>
<p>除此之外，针对应用特点合理使用持久化队列，在大并发任务量的情况下对性能也会有直接影响。</p>
<p>归根结底，需要根据自己的应用场景，合理设计一些测试用例和自动化脚本，通过实际的运行状态进行参数调整。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.flier.lu/2010/04/gearman-performance-tunning/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>GCC和VS2010中对C++ 0x的支持</title>
		<link>http://blog.flier.lu/2010/04/cxx0x-in-gcc-and-vs2010/?source=rss</link>
		<comments>http://blog.flier.lu/2010/04/cxx0x-in-gcc-and-vs2010/#comments</comments>
		<pubDate>Thu, 15 Apr 2010 14:47:56 +0000</pubDate>
		<dc:creator><![CDATA[Flier Lu]]></dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[cxx0x]]></category>
		<category><![CDATA[gcc]]></category>
		<category><![CDATA[vs2010]]></category>

		<guid isPermaLink="false">http://blog.flier.lu/?p=97</guid>
		<description><![CDATA[根据GCC和VS2010的文档，大致整理了一下几个主流编译器对C++ 0x标准的支持程度。]]></description>
				<content:encoded><![CDATA[<p>根据<a href="http://gcc.gnu.org/projects/cxx0x.html">GCC</a>和<a href="http://blogs.msdn.com/vcblog/archive/2010/04/06/c-0x-core-language-features-in-vc10-the-table.aspx#">VS2010</a>的文档，大致整理了一下几个主流编译器对<a href="http://en.wikipedia.org/wiki/C%2B%2B0x">C++ 0x标准</a>的支持程度。</p>
<p><iframe src="http://docs.google.com/viewer?url=http%3A%2F%2Fblog.flier.lu%2Ffiles%2Fcxx0x.pdf&#038;embedded=true" width="600" height="780" style="border: none;"></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.flier.lu/2010/04/cxx0x-in-gcc-and-vs2010/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>函数式编程入门培训PPT</title>
		<link>http://blog.flier.lu/2010/02/functional_programming_intro_ppt/?source=rss</link>
		<comments>http://blog.flier.lu/2010/02/functional_programming_intro_ppt/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 10:18:23 +0000</pubDate>
		<dc:creator><![CDATA[Flier Lu]]></dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[functional programming]]></category>
		<category><![CDATA[ppt]]></category>
		<category><![CDATA[training]]></category>

		<guid isPermaLink="false">http://blog.flier.lu/?p=72</guid>
		<description><![CDATA[上周给公司同事做了一个函数式编程 (Functional Programming) 的介绍，原以为可以随便到网 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>上周给公司同事做了一个<a href="http://en.wikipedia.org/wiki/Functional_programming">函数式编程</a> (Functional Programming) 的介绍，原以为可以随便到网上找一个ppt讲讲，结果发现居然没有合适的可以直接用，只好根据 wiki 结合 python 示例自己整理了一个<a href="http://blog.flier.lu/files/函数式编程入门.pdf?source=rss">培训PPT</a>。大概涵盖了FP的发展历史、基本概念和一些简单例子，回头有空再把它细化一下，看看是否有必要继续深入讲。</p>
<p><iframe src="http://docs.google.com/viewer?url=http%3A%2F%2Fblog.flier.lu%2Ffiles%2F%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B%E5%85%A5%E9%97%A8.pdf&#038;embedded=true" width="100%" height="440" style="border: none;"></iframe></p>
<p>说起来<a href="http://en.wikipedia.org/wiki/Functional_programming">函数式编程</a> (Functional programming) 这个话题基本是个无底洞，属于在常青藤高校也能开几年课挂掉无数人的领域。如何在短短一个多小时的时间内，让听众有一些直观印象，进而有兴趣继续深入学习下去，这是让我最为头疼的事情。因此我基本放弃了对那些较为复杂概念的介绍，甚至连 <a href="http://en.wikipedia.org/wiki/Closure_(computer_science)">Closure</a> 都只敢简单提及，跟别提什么 <a href="http://en.wikipedia.org/wiki/Monad_(functional_programming)">Monad</a> 这种我自己都挠头的概念。</p>
<p>开讲前在几十个听众中做了个简单调查，果然是听说过和使用过 FP 的人基本都是个位数。这基本上可以说是天朝 CS/EE 教育失败的体现，要知道欧美大学第一年就会讲 <a href="http://book.douban.com/subject/1451622/">Structure and Interpretation of Computer Programs</a> 这种被 Joel 视为是否适合就读 CS 专业过滤器的 BT 课程 (<a href="http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures/">在线课程</a>)。</p>
<p><a href="http://book.douban.com/subject/1451622/"><img class="alignnone" title="Structure and Interpretation of Computer Programs" src="http://img2.douban.com/mpic/s1463770.jpg" alt="" width="101" height="146" /></a></p>
<p>因此在一开始的时间里，基本上都是集中在对 FP 的鼓吹上，基本集中在 (1) 应对复杂性，(2) 降低维护成本和 (3) 增强自信心三个角度。前面两个基本上是洗脑用套话，个人最赞同也最想灌输的是第三点。</p>
<p>如果实际参与开发过代码量上百万行，代码维护历史在5-7年以上，先后参与人数几十上百的产品，最直观的感受是应该就是对其自身复杂性的本能恐惧。因为对绝大多数技术人员来说，我们更倾向于参与具有确定性的工作，也就是说我们潜意识里认为，我们做的事情应该是有可预测结果的。但一旦代码复杂到了一定程度，解耦没有到位过过于到位，我们就会发现所有的修改，都有可能引发不确定的影响。为了缓解这种影响，我们搞出了各种各样的最佳实践，TDD、CI、peer review，blabla；但归根结底我们只是试图用这些尝试来确保，我们有胆量继续修改那些我们自己也逐渐无法控制的代码，就好象在黑夜中无助的抓住一个火把，却又大声喊叫说自己不怕黑暗。</p>
<p>FP 在这方面可以说具有天然的优势，在去除 <a href="http://en.wikipedia.org/wiki/Side_effect_(computer_science)">side effect</a> 和复杂控制逻辑后，我们通过 <a href="http://en.wikipedia.org/wiki/Purely_functional">Pure functions</a> 和 <a href="http://en.wikipedia.org/wiki/Recursion_(computer_science)">Recursion</a> 表达的是我们真正的计算目的，而非达成目标的方法。这也是声明式语言 (<a href="http://en.wikipedia.org/wiki/Declarative_programming">Declarative programming</a>) 与命令式语言 (<a href="http://en.wikipedia.org/wiki/Imperative_programming">Imperative programming</a>) 最大的差别所在。这也是为啥我在开发 <a href="http://code.google.com/p/rabbitmq-memcached/">rabbitmq-memcached</a> 时，真正能把大部分时间用在编写代码上的原因，实际上线调试反而只是简单而且直接的结果而非过程。</p>
<p><a href="http://www.info.ucl.ac.be/~pvr/paradigmsDIAGRAMeng101.jpg"><img class="alignnone" title="The principal programming paradigms" src="http://www.info.ucl.ac.be/~pvr/paradigmsDIAGRAMeng101.jpg" alt="" width="100%"  /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.flier.lu/2010/02/functional_programming_intro_ppt/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
