本套shell+gearman+PHP方案实现技术解析 |
发布: 2012-12-30 21:54 |
本套shell+gearman+PHP方案实现技术解析 *)配置信息文件 使用shell脚本的加载,source 命令加载配置信息文件, 这个脚本看上去是个ini文件,但这种语法也是shell脚本的基本变量声明语法, 这种方式对于复杂的脚本还是非常有用的,可以把脚本的控制逻辑与配置信息分离开。 *)简单进程控制, 使用shell相关的命令和功能实现, 获取运行脚本路径信息,$(readlink -f $0) 获取运行脚本的目录信息,$(dirname $(readlink -f $0)) 加载配置变量信息,后台启动PHP进程,并传递相应的参数, 使用$!获取启动的PHP进程的pid,存放到pid文件, 为下次关闭该进程或者查看该进程状态作准备。 为了防止启动PHP进程失败,使用shell的$?命令获取进程启动返回值,为0时成功。 使用shell的进程输出重定向功能">>",实现启动的PHP脚本程序输出日志存储在指定的日志文件中。 *)GearmanWorker的封装 gearman的PHP扩展实现了基本功能,但对于一个生产级的系统需要更多的控制。 该gearman封装则实现了许多实际环境中可能遇到的问题的处理封装,包括后续几个功能的PHP实现。 该封装主要实现了两种worker工作模式,监控模式与任务模式。 监控模式用来定时监控worker进程的状态,服务器状态,提供分布式worker进程控制的功能。 任务模式用于接收并运行各项目发送过来的任务,以及监控模式发送过来的任务和分布式控制指令。 *) gearmand服务器状态的下线监控与自动剔除 在gearman的worker中(包括监控worker与任务worker),当有服务器下线后,GearmanWorker::work()会返回一个特定的值,表示有gearmand服务器下线了。 这时的问题是gearman自身没有返回是哪个服务器下线了,并且因为一个服务器下线,导致整个worker服务都无法使用, 这一点是gearman的实现问题,实现细节还差不少啊。 不过,在应用封装可以通过比较直接的方法检测出来。 使用简单的TCP socket 连接测试,可以检测出配置的gearmand列表中哪个ip:port服务器下线了。 public static function check_tcp_service($ip, $port = 4730) { // socket链接测试,200ms超时 @$fp = fsockopen($ip, $port, $errno, $errstr, 0.2); if ($fp){ $fp && fclose($fp); return true; } else { return false; } } 在检测到已下线的服务器后,把它从列表中删除,并通过GearmanWorker::removeServers和GearmanWorker::addServers方法,让可用的服务器列表生效。 这样对gearmand的暂时下线或者永久下线作了处理。 再者,对于有已下线服务器时,还要通过相同的方式,定时或者不定时的检测gearmand服务器是否已经恢复, 再等到恢复后,重新加入到可用服务器列表中。否则会出现可用服务器列表越来越少,最终到可用列表为空而无法正常提供服务了。 *) worker进程的运行时监控机制 本方案的设计是在每一个节点上,启动一个监控进程,启动几十甚至上百个任务worker进程。 实际情况下,由于任务worker不停地执行各种任务,可能导致进程崩溃或者处理即将崩溃的状态。 监控进程除了执行监控任务外不再处理其他的处理,能够更长时间的稳定运行。 一般情况下,这个进程不会退出,不会中断,通过文件锁的方式表示它依然运行,除非在退出时,文件锁才会关闭。 *)worker脚本程序的修改检测与自动加载 由于任务worker是处于GearmanWorker::work的阻塞状态,无法自行检测是否有代码修改。 这个工作是由监控进程完成的,监控进程使用inotify扩展得知所有worker代码文件的改动通知, 一量确认代码有修改,则会调用所有worker进程的reload_worker任务通知有需要重新加载的worker。 任务worker得到通知,根据传递过来的参数,确定是哪些worker修改重新加载。 执行一遍任务worker的加载工作,并使用新的worker代码替换原来的worker代码。 由于PHP的普通函数或者类无法方便地实现替换,这里使用的是比较特殊的方式, 所有的worker都使用Closure方式编写,把worker的执行代码函数作为一个Closure代码放在一个变量中, 这样,只需要替换掉指向这个Closure的变量即可实现代码的替换。 *)指定区分不同服务器上不同类别worker的实现机制 由于worker节点可能不包括所有的worker,那么对于一个gearman worker集群, 可能有限制在某个节点上执行某个worker的需求,也可能有限制在某些节点上执行worker的需求。 根据gearman worker的特点,在注册给gearman时,可以通过worker别名的方式实现, 这个别名包含了节点的ip,项目的名称,甚至是一个worker进程的进程ID。 而这些别名则都指向一个worker的Clouse代码段,无论使用哪个别名,最后执行的都是相同的代码逻辑。 在需要指定的时候,可根据这些分类实现指定在特定的节点或者worker上执行某个任务worker。 *) 异步任务的结果查询机制 系统通过引入第三方的kv组件,像redis,memcache来存储任务worker的结果。 结果的存储是以任务的uuid作为key,任务的返回值为value存储的。 结果的存储是有有效时间的,在存储时以当前时间为限N天内必须来读取这个结果,否则将再也读取不到了。 对于还需要关心任务处理结果的项目来说,可以通过定时或者通知的形式来读取这个结果并做进一步处理。 *)改进 使用msgpack代替现有的json编码打包从client到worker的参数与返回值。 使用稳定的C/C++编写监控与管理进程,长时间运行不退出。 使用zeromq把多节点的监控进程与管理进程整合起来,实现真正的分布式gearman worker进程管理。 规范参数与返回值。 支持其他语言编写的worker运行在这个框架之内。 |
原文: http://qtchina.tk/?q=node/708 |
Powered by zexport
|