云计算实践2
上一篇《基于云计算的价格查询实现》就算是云计算实践1吧,所以这篇就叫《云计算实践2》。其实今年开始研究云计算有一段时间了,约3个月前研究md5破解(http://www.shprog.com/HashCrack.aspx),那个项目就是选来玩云计算的,当时觉得md5破解这个小项目好玩,逻辑很简单,密码字母组合可长可短,规模可大可小,1台机器不嫌少,1万台不嫌多,所以就选中了它,没想到第一个md5破解版本后来演变成了主要是密码数据库的制造,虽然第一版没有做成标准云计算,但也算有个结果,而且存储效率、制造速度还是令人满意的,也就是说那个项目只是云计算研究的副产品,我的本意并不是想做一个md5破解或者qq密码破解,但结果就产生了这么一个产品,也算是努力了一个多月的结果,期间对hash算法、存储格式等绞尽脑汁思考了很久,也因此对云计算倒是考虑得不多,最终偏离了大目标。
好在后续研究基于云计算的价格查询终于又回到云计算上来了,而且仿照google的map/reduce做了一个标准的jobserver + tasknode形式的实现,虽然兄弟们未必对价格查询项目看好,但对这个基于windows实现的云计算框架还是一致看好的,价格查询项目第一阶段基本完成预定目标,所以昨天我又将以前md5破解的东西写了一个在线版的dll,拿到云计算框架里面来试图云破解,不过这个不是特别成功,主要是即时计算耗时有些多,平均1个task计算1亿组合大约需要30秒,因此在我现在只有2个点参与运算的情况下遍历很大区间是很耗时的,也因此我没有做一个在线云破解md5的页面,这个工作作为研究性探索也只在我的控制端下了几个云计算的任务就告一段落,今后将致力于其他更实用的云计算实践。
为了做这第二个云计算的dll,我将原来定义的jobtask接口(可参见《基于云计算的价格查询实现》)修改了一下,不再使用原来的c风格接口,直接改成c++风格了,如下:
interface IJobTask
{
virtual HMODULE free() = 0;
//初始化函数,部署环境等
virtual bool init(bool tasknode) = 0;
//分割函数,分割输入
virtual size_t split(const char *input, size_t len, std::vector<CAutoBuffer *> &vbuf) = 0;
//task执行函数
virtual bool map(const char *cmdline, CAutoBuffer &buf, CAutoBuffer &ibuf) = 0;
//reduce打包输出函数
virtual bool reduce(std::vector<CAutoBuffer *> &vbuf, CAutoBuffer &buf) = 0;
//获取执行错误
virtual char *geterror() = 0;
};
有朋友批评我,说我的接口使用stl容器,使用自定义类CAutoBuffer等不好,我以前也是这么跟别人讲的,接口不要使用这些东西,但看了google的map/reduce实现用的都是MapInput、ReduceInput之后我改变了看法,暂时就这样定义吧,大不了各个dll都用同一版本的vc编译就是了,也没有什么大不了的,如果不行整体升级一下总可以吧,为了短时间盯住主要目标,也只能大刀阔斧不考虑过多细节了,这也算是一个平衡的结果吧。
这次修改除了修改了接口,简化了实现之外,还实现了一些特性,动态卸载,上一个版本装入之后就不卸载了,要关闭exe才能卸载这些dll,所以无法热更新,这个版本实现动态卸载之后就支持热更新了,关键就在那个free函数,
virtual HMODULE free() = 0;
该函数实例如下:
virtual HMODULE free()
{
HMODULE h = m_hlib;
delete this;
return h;
// if(h) FreeLibrary(h); 这里释放是有问题的,所以不能这样释放
}
在外部调用的地方
FreeLibrary(jf->free());
这样就实现了动态卸载dll的功能
用上云计算布局的价格查询的这段时间,还是有一些经验教训的,基于这种相隔很远,网络条件差别很大的机器布局的云计算环境,可靠性是很差的,大多数时间可能反应还是比较快,但有的时候反应就特别慢,可能网络延时会相差200ms,或者500ms,或者更多,我特意记录了每个task的实际执行时间和包括网络传输在内的总时间,就是从这两个时间看出差距的,所以如果要基于这种环境做实时性很高的计算还是不适合的,如果对节点反馈实时性要求很高,那一定要布置类似局域网形式的计算环境,点点反馈时间1ms内,而且响应稳定不易受到影响。此外磁盘Log时间是不定的,我记录最后一个task完成到job完成之间调用了两次WriteLog,对大多数job来说,最后一个完成的task的时间和job完成的时间一致,但偶尔有少数job时间和最后一个完成的task时间差别很大,甚至有超过1s的,原先没有这么精细的测量,这次在jobserver写了很多log,起初是为了找错误,后来是为了追踪job和task执行,倒是意外的发现了一些问题,也获得了一些意外的收获。
云计算好啊,早年我做过一个远程控制的程序,当时做了一条命令broadcast,可以广播其他任意命令,当时很得意于这个设计,也有指挥千军万马的感觉,但当时各自执行,结果并不汇总,各个任务完全独立。现在给云计算环境下达一个任务,也有同样的感觉,可能对使用我的价格查询(http://www.oldworm.com/pps.aspx)的用户或者使用google查询的用户根本感觉不到,他这一个查询提交下去后面有那么多机器联动运算,但作为开发人员,真真切切的看到后面那么多机器在执行任务,真的是很爽的一件事情,一起看下我两台机器联动执行任务的场面共勉吧:
图看得不是很清楚,实际上第一个taskmanager是一台机器,另一个taskmanager是另一台机器,那两个都是在远程桌面里面运行的,下面ie是我的网页,可以看到我在网页里面查询nokia的时候,上面两台机器的tasknodeapp里面就接收到任务并执行了任务,那个tasknodeapp是我临时用来演示的,事实上里面都是调用tasknode.dll,tasknode的主要任务都是tasknode.dll执行的,为这个dll做了好几个不同的容器,有service的有普通mfc的还有console的,这也是我的得意设计哦。
未来还将继续云计算实践,期待有相同兴趣爱好的朋友一起交流。