<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[Snooda]]></title> 
<link>http://www.snooda.com/index</link> 
<description><![CDATA[Snooda's Blog]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[Snooda]]></copyright>
<item>
<link>http://www.snooda.com/read/</link>
<title><![CDATA[Gearman的一些心得]]></title> 
<author>snooda &lt;admin@snooda.com&gt;</author>
<category><![CDATA[默认分类]]></category>
<pubDate>Sat, 02 Apr 2011 08:58:51 +0000</pubDate> 
<guid>http://www.snooda.com/read/</guid> 
<description>
<![CDATA[ 
	最近项目要用到Gearman，之前在《构建高性能Web站点》这本书上看到过，不过一直没有太注意。最近详细研究了一下，发现还是很有用的。<br />
<br />
Gearman是个可以把计算能力分布式部署的工具，由server，worker，client三部分组成。server在linux上叫做gearmand，使用gearmand -d即可运行，默认端口是4730。负责分配任务。<br />
worker由用户编写，可以使用多种语言，c，php,python等等均可，作用是像server注册一个函数，表示自己可以处理该类计算请求。client也是由用户编写，语言不必和worker相同，<br />
向server提交计算请求，并获取计算结果。<br />
<br />
关于gearman比较好的一篇blog：http://www.kongch.com/2010/04/gearman-how-to/<br />
<br />
之前一直疑惑server是如何根据worker的负载来分配任务的，看了原理后发现原来任务并不是由server分配，而是由worker主动领取的，<br />
这样就大大简化了server和worker的逻辑。<br />
如下是工作流程：<br />
1，Worker通过CAN_DO消息，注册到Job server上。<br />
2，随后发起GRAB_JOB，主动要求分派任务。<br />
3，Job server如果没有job可分配，就返回NO_JOB。<br />
4，Worker收到NO_JOB后，进入空闲状态，并给Job server返回PRE_SLEEP消息，告诉Job server:”如果有工作来的话，用NOOP请求我先。”<br />
5，Job server收到worker的PRE_SLEEP消息后，明白了发送这条消息的worker已经进入了空闲态。<br />
6，这时如果有job提交上来，Job server会给worker先发一个NOOP消息。<br />
7，Worker收到NOOP消息后，发送GRAB_JOB向Job server请求任务。<br />
8，Job server把工作派发给worker。<br />
9，Worker干活，完事后返回WORK_COMPLETE给Job server。<br />
<br />
不过看到这里我有一些疑问，就是在第六步的时候server向worker同时发送NOOP，会不会导致惊群效应？这个问题留待考证。<br />
<br />
现在版本的gearman并不能监控worker的状态，任务的分配过程对client又是透明的，如果在多台机器上部署多个worker的话并不能直接获取各worker的状态。<br />
<br />
不过通过编写一些函数还是可以实现这个功能的，甚至可以完全用gearman来监控多台服务器。网上有篇文章也讲到了这点，不过非常简略。我想了一个方式，比较幼稚，<br />
欢迎指正：<br />
worker基础函数及变量：<br />
setID()：用来接收监控端置入id，运行一次后注销。<br />
manage()：用来接收控制和状态查询请求，默认关闭，在setID中开启。<br />
functionInUse()：已注册的功能函数列表。<br />
functionNotUse()：未注册的功能函数列表。<br />
count数组：记录各个功能函数执行次数。<br />
exitWorker()：退出worker，导致worker进程退出，慎用。<br />
newWorker():启动新worker。<br />
unregisterFunction：注销指定功能函数。<br />
registerFunction：注册指定功能函数。<br />
<br />
<br />
<br />
1，新worker在启动时只注册setId函数。此时worker处在就绪未注册状态。<br />
2，监控client发送setId请求，参数为唯一id。<br />
3，就绪未注册状态worker收到setId请求，设置id为自己的id，返回自己的主机名和进程号，然后注册manage函数为manage_id，其中id为自己的id，最后注销setId函数，进入就绪已注册状态。<br />
4，监控client收到应答后将id与主机名进程号对应起来。<br />
5，监控client重复2，直到无就绪未注册状态worker。<br />
<br />
现在所有的worker都处在就绪已注册状态，监控client处也获得了所有worker的信息，此时初始化完毕，监控client通过调用manage_id来启动相应worker的指定功能函数，<br />
worker进入工作状态。<br />
<br />
此时整个系统开始正常工作。监控client可以周期性的调用manage_id来获取各worker的运行状态，并可以控制各个worker的注册功能函数数量。这时无论是根据负载自动调整各个worker还是上线新版本都是很方便的。<br />
<br />
<br />

]]>
</description>
</item><item>
<link>http://www.snooda.com/read/#blogcomment</link>
<title><![CDATA[[评论] Gearman的一些心得]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://www.snooda.com/read/#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>