实用云计算环境简述

 

如今it领域没听说过云计算的绝对是out了,虽然大家都知道云计算,虽然很多高校很多专业都开设了云计算专业,虽然很多人都在讨论云计算,虽然也有少数人走在了应用云计算的前列,然而,可悲的是,大多数人对云计算的认识仅限于amazongooglemicrosoftibm有能力架设云计算环境,其他公司都靠边,甚至唯他们的云计算才叫云计算,别的企业根本不可能做云计算,各级政府部门最搞笑了,动不动花多少钱引进某某云计算环境,填补某某空白,多少cpu多少机器每秒多少万亿次计算,最终是不是一堆浪费电力的摆设也没有人知道,也没人去过问。

略感欣慰的是,很多企业都在务实地部署自己的云计算环境,大如腾讯、淘宝、百度、小如我们这样刚成立的小公司,其实要部署一个私有云计算环境并没有那么难,以我个人的经验来看,如果有一个精干的小团队,几个人一个月部署一个私有云计算环境是完全可能可行的。在我看来,所谓云计算就是分布式存储+分布式计算,不局限于底下oswin还是*nix,也不局限于是局域网环境还是广域网环境,也不管上面跑的是c++的程序还是javascript的程序,下面简单介绍下我设计的一个即时查询价格的云计算体系:

我一直在win下开发,win用得非常熟练,所以我把云计算环境部署在windows之上,当然也考虑到windows的机器众多,tasknode可轻易找到非常多的目标机器,我部署的云计算环境主要分两类节点,jobservertasknodejobserver主管任务切割、任务调度,tasknode是计算节点。另外还有一些节点,jobowner可连接jobserver并提交任务,并可查询该任务的执行情况,admin可连接jobserver查询jobserver的状态。

 

其实这些上篇博客已经写过,我再讲的详细一点,看具体的执行情况,首先jobownerjobserver提交package,这个package是一个zip文件,包含一组文件,jobowner提交package之后jobserver会根据约定的规则管理package,并在jobserver展开该package,如下:

 

 

Jobowner连到jobserver之后,发出如下的命令到jobserver

0x49 0x0 0x0 0x0 0x2 0x0 0xb 0x0 127.0.0.1 0x0 ppsget.dll 0x0

{type:[0,1,2,3,4],rmax:5,wb:"pc",text:"诺基亚 e63"} 0x0

上面是用我设计的一种混合显示格式显示的包数据,可以看到里面带上了ppsget.dll,这就是指定包内部名,其实还可以这样ppsget.dll:getpage,如此一个dll就可支持多个IJobTask输出,getpage只是获得其中一个IJobTask接口(关于IJobTask接口参考上一篇云计算实践2的文章)。具体命令是json格式,主要是为了方便信息传输和解析。Jobserver接收到该命令之后,调用ppsget.dllIJobTask接口中的split函数,将该任务分解,之后调度Tasknode执行,tasknode收到jobserver发过来的任务之后,检查包名称,如果缺少就会主动向jobserver要求发送相应的包,并进行部署,待部署完成之后从包获取指定的IJobTask接口,执行该接口的map函数,将结果按照约定的格式发给jobserver,最后由jobserver调用IJobTask中的reduce函数进行打包,最后将结果发给jobowner并记录相关Log

上图中还可看到一个HashCrackCloud.dll,这是另一个云计算环境下破解md5密码的dll,这个上篇文章也写了一下,这里就不详述了。

 

为使得tasknode可适应各种机器环境,我把tasknode设计为一个dll,该dll内部自己管理消息及任务执行,该dll可被加载到各种容器进程(如gui进程、console进程、service进程)等执行,看下我的tasknode和它的容器进程:

 

这也算是我的得意设计吧,这样设计的tasknodewindows系统下的确具有很高的灵活性。

这样的tasknode甚至可直接加载在jobserver进程,也可被任意win系列机器的任意进程加载参与运算,用主动加载或被动加载都很方便,极大的方便了云计算环境的部署,反正具体执行的任务都由package完成,tasknode只要按照约定的规则部署 package即可,所以这种云计算环境是非常轻量级又非常灵活的,开发一个新的任务只要做一个新的IJobTask即可,目前我这套体系除了没有考虑太多安全性之外,这个云计算环境的实施还是非常容易的,实际上我们这个价格查询的后台云计算环境只用了不到2周的时间就开发完成。

再看下jobserver记录的每个joblog

 

log中可很容易的分析出一个job每个task的执行情况,并可根据这些数据进行相应的优化处理。

之所以把jobservertasknode以及package都写出来,主要是为了表达一个看法,要实现一个简单的云计算环境其实并不难,有经验的团队很容易就能做出来,参考下googlemap/reduce论文,按照自己的需要简化实现,真理在实践中,如果只是仰望googleamazon,那就真的是在云中雾里,另一个想要表达的就是云的形式是多种多样的,并不一定amazonegoogle的云计算环境才是标准的,对实用派来说,形式都是次要的,实用才是关键的。

posted @ 2010-10-03 14:23 袁斌 阅读(1780) | 评论 (1)编辑 收藏

之前的文章讲过,我设计的网络框架有几组线程,分别是io、异步、同步、定时器,各个不同应用server几组线程组合形式不尽相同,简单的可只有io线程,复杂一点的可io+同步,更复杂一点的也可io+同步+异步+定时器,总之我以几组线程的自由组合方式应付各种应用,在我负责的server全是这一套框架实现的,不管是支持几万人连接的服务器,还是只有几个用户连接的内部服务器,这套框架也算是久经考验,稳定运行多年,内部使用也非常简单,如给sync线程组发一个消息只要PostSyncEvent,如果要给异步线程发一个消息只要发PostAsyncEvent,虽然只能开发的时候确定哪个任务在哪组线程执行,但修改还是非常方便的,执行体就是一组这样的函数:

OnSyncEvent(DWORD dwEvent, DWORD wParam, DWORD lParam);

OnAsyncEvent(DWORD dwEvent, DWORD wParam, DWORD lParam);

一眼就知道是在哪个线程组里面执行,当然有的线程组是一个线程,有的线程组是多个,这涉及到有的资源是不是要加锁,有经验的开发人员很容易理解。

说了一下框架才容易理解我的问题,之前定时器是一个独立的线程组,同步线程组、异步线程组、io组都没有定时器功能,定时器触发后要发送消息到相应线程组,有的要发给异步线程组,有的要发给同步线程组,这就会引起线程切换,这是问题之一,还有一个问题,之前的定时器是由windows的时钟队列实现的,这个定时器优点是很明显的,定时精确,功能强大,参数众多,独立线程组,但也有很明显的问题,如果要删除一个定时器则有线程依赖,就是要在定时器线程才能删除定时器,这个依赖约束很大,也很容易引起问题,用起来很不方便,使得一些资源的释放不能够即时进行。正因为有这么些问题,也为了使得时钟模块更容易移植,我设计了一个新时钟模块,为实现以下目标:

1、无线程依赖,随便调用者在哪个线程调用都可删除指定的定时器。

2、和事件消息集成在一个线程内,实现无需切换的定时器功能,这样主线程、同步线程组、异步线程组都可在内部处理定时器消息,无需单独的定时器线程辅助,方便很多。

为实现以上目标,我引入了libevent里面的minheap管理定时器,并根据之前管理事件的处理办法,继续使用iocp队列管理线程消息,在每个线程组用iocp管理事件,根据最短触发的定时器计算wait时间,这样就在同一组线程内实现了定时器和事件合并处理,当然实现方法有很多,也可用iocp+WaitableTimer等,也可用apc,但那些实现的windows烙印都太深刻,虽然精度更高,实现更容易,我用minheap+iocp队列方式的实现相对来说对windows的依赖较少,因为替换一个iocp队列处理事件是很容易的,这样也方便移植和复用代码。经这样修改之后,各个线程组包括主线程都可处理定时器和事件消息,也使得以前鸡肋式的主线程终于可当同步线程发挥作用,以前的定时器线程组也不一定需要了,既减少了线程,也减少了切换,现在各个线程组(包括主线程)都有完全一致的消息处理和时钟处理函数。

事件函数:

OnTimerEvent(DWORD dwEvent, DWORD wParam, DWORD lParam);

OnSyncEvent(DWORD dwEvent, DWORD wParam, DWORD lParam);

OnAsyncEvent(DWORD dwEvent, DWORD wParam, DWORD lParam);

OnServiceEvent(DWORD dwEvent, DWORD wParam, DWORD lParam);

定时器函数:

OnTimerTimer(TlsInfo *ptls, EventTimer *et);

OnSyncTimer(TlsInfo *ptls, EventTimer *et);

OnAsyncTimer(TlsInfo *ptls, EventTimer *et);

OnIoTimer(TlsInfo *ptls, EventTimer *et);

OnServiceTimer(TlsInfo *ptls, EventTimer *et);

可以给线程组增加定时器删除定时器

AddTimerAddSyncTimerAddAsyncTimerAddServiceTimerAddIoTimer

DelTimerDelSyncTimerDelAsyncTimerDelServiceTimerDelIoTimer

可给各线程组发消息

PostTimerEventPostSyncEventPostAsyncEventPostServiceEvent

 

这套框架是我多年服务器端开发的得意之作,体现了我简洁实用的设计思想,用起来非常方便,可任意组合,适应各种需求的应用,由于除主线程之外的io线程组、同步线程组、异步线程组、定时器线程都是可以关、开1个、开多个,所以组合非常灵活,开1个可当同步线程,开多个可当异步线程(内部抢资源),关闭就不存在该组线程,即使是io线程组也是可关的,这样就使得这套框架不仅仅用在标准server上,就算是当作一般的消息队列服务器也没问题,高度的灵活性使得这套框架可适应各种规模的应用,这次对定时器的改造使得这种组合更灵活,虽然现在的实现方法定时器的精度有一些下降,但瑕不掩瑜,这样改造之后功能无疑是更强大了。

posted @ 2010-10-03 14:23 袁斌 阅读(677) | 评论 (0)编辑 收藏

云计算实践2

 

上一篇《基于云计算的价格查询实现》就算是云计算实践1吧,所以这篇就叫《云计算实践2》。其实今年开始研究云计算有一段时间了,约3个月前研究md5破解(http://www.shprog.com/HashCrack.aspx),那个项目就是选来玩云计算的,当时觉得md5破解这个小项目好玩,逻辑很简单,密码字母组合可长可短,规模可大可小,1台机器不嫌少,1万台不嫌多,所以就选中了它,没想到第一个md5破解版本后来演变成了主要是密码数据库的制造,虽然第一版没有做成标准云计算,但也算有个结果,而且存储效率、制造速度还是令人满意的,也就是说那个项目只是云计算研究的副产品,我的本意并不是想做一个md5破解或者qq密码破解,但结果就产生了这么一个产品,也算是努力了一个多月的结果,期间对hash算法、存储格式等绞尽脑汁思考了很久,也因此对云计算倒是考虑得不多,最终偏离了大目标。

好在后续研究基于云计算的价格查询终于又回到云计算上来了,而且仿照googlemap/reduce做了一个标准的jobserver + tasknode形式的实现,虽然兄弟们未必对价格查询项目看好,但对这个基于windows实现的云计算框架还是一致看好的,价格查询项目第一阶段基本完成预定目标,所以昨天我又将以前md5破解的东西写了一个在线版的dll,拿到云计算框架里面来试图云破解,不过这个不是特别成功,主要是即时计算耗时有些多,平均1task计算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等不好,我以前也是这么跟别人讲的,接口不要使用这些东西,但看了googlemap/reduce实现用的都是MapInputReduceInput之后我改变了看法,暂时就这样定义吧,大不了各个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,起初是为了找错误,后来是为了追踪jobtask执行,倒是意外的发现了一些问题,也获得了一些意外的收获。

云计算好啊,早年我做过一个远程控制的程序,当时做了一条命令broadcast,可以广播其他任意命令,当时很得意于这个设计,也有指挥千军万马的感觉,但当时各自执行,结果并不汇总,各个任务完全独立。现在给云计算环境下达一个任务,也有同样的感觉,可能对使用我的价格查询(http://www.oldworm.com/pps.aspx)的用户或者使用google查询的用户根本感觉不到,他这一个查询提交下去后面有那么多机器联动运算,但作为开发人员,真真切切的看到后面那么多机器在执行任务,真的是很爽的一件事情,一起看下我两台机器联动执行任务的场面共勉吧:

 

 

 

图看得不是很清楚,实际上第一个taskmanager是一台机器,另一个taskmanager是另一台机器,那两个都是在远程桌面里面运行的,下面ie是我的网页,可以看到我在网页里面查询nokia的时候,上面两台机器的tasknodeapp里面就接收到任务并执行了任务,那个tasknodeapp是我临时用来演示的,事实上里面都是调用tasknode.dlltasknode的主要任务都是tasknode.dll执行的,为这个dll做了好几个不同的容器,有service的有普通mfc的还有console的,这也是我的得意设计哦。

未来还将继续云计算实践,期待有相同兴趣爱好的朋友一起交流。

posted @ 2010-10-03 14:23 袁斌 阅读(348) | 评论 (0)编辑 收藏

基于云计算的价格查询实现

 

 

上篇博客提到价格查询功能,当时正在考虑做成云计算模式,所以当时连多线程都没考虑,就是准备将功能都交给云计算系统的,由云计算内部管理线程和调度问题,所以当时实现就根本不用考虑多线程,现在功能基本实现,下面大致讲讲我的做法。

国内很多人谈到全文检索就必提lucene,提到云计算就必提googlemap/reduce、开源的hadoop、amazonec2,似乎只有那些东西才叫云计算,咱是实战派,没兴趣口舌之争,在俺看来分布式存储+分布式计算就叫云计算,俺就看了看googlemap/reduce论文,照其思想在win下做了个简单的job/task调度系统,使其能支撑俺的第一个实战应用价格查询,图示如下:

 

 

 

 

    adminclient承担管理功能,可查看任务及执行情况,可查看Tasknode机器情况,如果需要可管理Task,目前只支持简单的几条命令,adminclient主动连jobserver登录成功后可发送管理命令。

 

    JobOwner提交一个Job之后返回一个jobid,如果意外断开可通过下次重连的时候提交jobid和一个sessionid可提取job结果数据,job提交通过提交一个zip包即可,参数等文件都打在包里面,tasknode可直接解包执行里面的dllJobowner主动连jobserver,登录成功后可发job命令。

 

    TaskNode是执行具体任务的客户端,job包用zip打包后发布给tasknodetasknode参与计算并反馈结果。TaskNode设计成多线程模式,一个线程保持和jobserver的通信,其他线程参与运算,Tasknode可同时执行多个不同的任务,如a线程执行价格查询,b线程执行hash破解等。Tasknode主动连jobserver,登录后可接受jobserver分派的任务,由于tasknode是主动连jobserver的,所以即使是内网机器或者任意有闲置资源的机器都可作为Tasknode,不管它是家里的、公司的、还是网吧的,这也是该系统基于windows实现的一个重要前提,因为win的机器是如此的多,在国内win的机器无处不在。

 

JobServerjob调度器,管理包分发以及任务分割、调度,典型的执行流程是这样,jobowner提交一个命名的包给jobserverjobserver将该包部署管理,之后jobowner 可给jobserver提交任务,jobserver收到任务后根据任务指定的包配置执行,如部署包后装载dll并执行任务分割操作,分割是将一个job分割为多个task,之后再将每个task提交给一个tasknode执行,并管理tasknode的输出以及可能的出错,出错现在的处理是交给另一个tasknode执行,当剩下最后一个tasknode的时候会将该tsaknode同步叫给另一个不同的tasknode执行,不管谁最后成功执行这个tasknode,只要该task执行成功立即结束整个job,并将结果反馈给jobownerjobowner也可在执行中提交查询命令,jobserver会将被查询job当前的输出返回,这样碰到需要长时间执行的任务也能适用。

 

从以上介绍可以看到,具体任务是由包执行的,这个包实际上可能是一个dll,也可能是几个dll加上一些配置文件组成,之所以设计成这种模式,主要是考虑整个系统在win上方便部署,主dll需要支持几个固定的接口:

 

//任务dll初始化函数

typedef bool (*jobtask_init_)(jobtaskfunc *jtfunc, bool tasknode);

//map分割函数

typedef size_t (*jobtask_split_)(jobtaskfunc *jtfunc,

                                   const char *input, size_t len,

                                   std::vector<CAutoBuffer *> &vbuf);

//reduce打包函数

typedef size_t (*jobtask_reduce_)(jobtaskfunc *jtfunc,

                                         std::vector<CAutoBuffer *> &vbuf,

                                         CAutoBuffer &buf);

//Task执行函数

typedef bool (*jobtask_map_)(jobtaskfunc *jtfunc, const char *cmdline, CAutoBuffer &outbuf);

//释放函数

typedef bool (*jobtask_free_)(jobtaskfunc *jtfunc);

 

 

上面init函数主要执行线程相关的初始化,该函数典型的可能是空,或者是

CoInitialize(NULL);

Split函数是用来将job输入分割为Ntasknode输入的,该函数由jobserver调用,每个tasknode输入就是map函数的输入,tasknode的任务就是调用map函数,并传递输入,最后将输出返回给jobserverjobserver在需要的时候调用reduce将各个tasknode的输出打包返回,free函数是个辅助函数,释放资源的。

熟悉googlemap/reduce的应该知道,我的实现简化了reduce,在我的实现里面并没有独立的reduce worker,该任务由jobserver自己做了,这一方面是简化实现,另方面也是适应需求的结果,毕竟在我的需求里面输入是很少的(一个典型任务100字节量级)tasknode的计算是很多的,输出也是不多的(1k量级),所以由jobserver打包整个输出也很轻松,用不着一组独立的reduce来管理输出。另外可以看到上面接口用了我的自定义类CAutoBuffer,这个类主要管理不定长数据的,其实用vector<char>也可,但考虑方便,我的实现内部都用了CAutoBuffer。一个典型的分布式应用只要做一个dll,有上面几个函数,并输出一个

 

struct jobtaskfunc

{

        //初始化函数

        jobtask_init_ init;

        //释放函数

        jobtask_free_ free;

 

        //以下被tasknode调用

        jobtask_map_ map;

 

        //以下被jobserver调用

        jobtask_split_ split;

        jobtask_reduce_ reduce;

};

typedef jobtaskfunc *(WINAPI *create_jobtask_)();

函数即可。

 

学习map/reduce重要的是学习其思想,并不拘泥于实现形式,我想这大概正是国内环境欠缺的,国内能说得头头是道的人太多,能动手干出结果来的人很少,真正坐下来做实事的不多,只喜欢抄抄概念,拿别人的东西过来架设一下,就是这样的人也能混成大拿。我从map/reduce思想出发,学习其思想,简化其实现,为实际应用服务,虽然这个东西很简单,甚至可以说有些简陋,但实际效果不错,虽然现在只部署了两个点,但总体上还是令人满意的。

 

实现这个jobserver/tasknode系统并部署价格查询花了不到两周时间,实际上花在jobservertasknode上的时间大概只有一周多一点,ppsget.dll(具体干活的dll)用正则表达式分析网页并提取输出,该dll被应用到多线程环境后也出了一些问题,用boost::reg的时候居然偶尔会出现异常,原以为boost::reg这样的应用应该是非常明确的,要么找到,要么没有找到,除此不应该有第三态,没想到boost::reg这个不争气的东西不但不是二态的,还容易出现异常,试用了一下tr1::regex也是类似的问题,无奈只能在外面包了一层异常处理,虽然不再被异常搞死,但一旦出现异常就是很慢的,要10s左右才返回,现在也没有特别好的办法,只在异常的时候将页面保存,事后分析并改写正则表达式,尽量将正则表达式做小,将非贪婪式查找用少一点。

下面看看我们价格查询网站 http://www.shprog.com/pps.aspx 的输出:

 

 

那个360的价格居然是图片,ocr模块是俺同事搞的,现在识别率能达到99%以上,还是很不错的。

posted @ 2010-10-03 14:22 袁斌 阅读(198) | 评论 (0)编辑 收藏

花了四天写了个价格查询的web体验版,大致结构是这样的,前端web界面:

 

web通过tcp连接后台一个ppsserverppsserver调用一个ppsget.dll从一些配置好的网站现拉网页分析产品价格等信息,说起来是很简单的,要是画出结构图来也是很简单的,看看效果:

 

 

 

为了写这个东西查了比价网等很多资料,看来看去觉得现在的一些比价网都把自己当购物门户了,上面什么信息都有,数据都是缓存的,有的还隐藏原始链接,用户点进去也都是缓存的数据,不再链接到原始出处,看了几个网站数据误差较大,有个网站排在最前面价格最低的链接点进去之后发现根本没有那个低价格,也不知道那个价格信息是什么时候的,或者根本就提取错了。看了那么多比价网站,时间误差最小的也超过10个小时,很令我失望,总之我的出发点和这些网站不同,我希望做一个界面很简洁的、实时查询的服务,而且速度要求很快,一次查询速度最好小于1秒,当然我现在技术预览版离这个目标还差得很远。界面简洁使得用户即使是使用手机也能得到很好的输出,也不占用多少带宽,我还希望前端接上条码扫描功能,这样很多不会输入的人就可直接对着条码就能查询网店价格,多方便啊,呵呵。不过做这个功能发现技术不是大问题,我4天除了布好了架构还做了5家网店的网页分析,可见这些基本技术都不太难,最大的矛盾是实时查询数据量太大,就算只查询一个产品,分析5个网站的数据加在一起估计接近1M,这要是每秒有个几百几千人访问那还得了啊,得要多大的带宽才能撑得住啊,难怪看了那么多比价网站没有一家提供实时查询的,不是他们做不了实时查询,的确是因为带宽太大,所以我想接下来做一套分布式查询模型,将很多无固定ip的机器接入ppscontrolserver,一起参与为用户提供查询服务,今天在看mapreduce,希望自己不要闭门造车,其实很多年前就想做这个功能了,只是一直没有下手,加上那个时候也没有一套稳定的网络库,现在条件都具备了,希望最近可以做一个简单的分布式计算框架出来,那样以后要做类似功能就容易了,可能只要加入一个简单的dll发布一个计算命令就可以了。这个分布式计算模型做出来之后,传统的比价网站就只能望俺项背了。

posted @ 2010-10-03 14:21 袁斌 阅读(479) | 评论 (0)编辑 收藏

一直想测试一下json的解析速度,前些天终于花了一点时间测了一下,在我的破笔记本上,解析一个包含10个元素(各种类型都有)的objectjson1秒钟大概只能解析不到10w次,就算把内存池用到极致也只能解析12.5w次左右,换用自己定义的一种bjson格式,速度快了一些,但也不超过20w次,想想工作量也的确很大,生成一个包含10个子元素的object,需要动态分配最少10次,还要做最少10hashinsert,还有各种格式的转换工作,里面有arrayobject还要额外分配容器并处理子对象,这可都是耗时操作,终于明白了为什么webserver为何一秒钟只能处理几千个请求甚至只能处理几百个请求了,看来要将游戏协议完全用json暂时还是不大可取,从效率上看折中点的做法依然是struct+jsonstruct+string\0string\0…,这些我以前的blog都写过,只是现在找到了效率上的依据,毕竟游戏服务器一秒都是要处理几万数据包的,要是全是json光解析json就把时间耗光了,更不用说去处理其他任务了。

posted @ 2010-10-03 14:21 袁斌 阅读(891) | 评论 (0)编辑 收藏

HashCrack跑起来了一段时间,一直没有写架构方面的总结,今天在地铁上画了一张图:

照此架构理论上是可以支持非常巨大的后端数据的,如果将web也弄成多个,分别连不同的SN则可支持非常巨大的用户量。

posted @ 2010-10-03 14:20 袁斌 阅读(200) | 评论 (0)编辑 收藏

从开始研究HashCrack两个多月了,虽然中间忙其他项目间断了近一个月,但总的耗在HashCrack上的时间也有一个多月,最近几天又把web部分完善了一下,顺便做了其他几种加密算法,现在HashCrack支持MD5SHA1MYSQL5HASHQQHASH四种算法,每种算法都制造了46亿数据,总共占磁盘34.2 * 3Gqqhashmd5复用同一份数据。好在之前架构做得比较好,换一种加密算法只要换两个函数即可,所以加后面三种算法只花了1天时间。为了让界面更友好一点,临时学了下ajax,并学习了一下.net里面调用c++ dll,顺便用c++做了一个dll提供四种算法的加密供web调用。新web页面地址是 http://www.shprog.com/hashCrack.aspx,部分界面如下:

 

 

看上去一个简单页面,背后2服务器程序(1web 1 hashcrackserver),103G数据,3dllhashencrypt.dll, page.dll, data.dll),一个制造数据的exe,还有一个client工具,那工具好久没升级了,client工具支持一次多条查询。Hashcrackserver支持分布,client端工具也支持数据分布和运算,总的是一个云计算系统。

现在觉得我的这个页面比www.cmd5.com www.md5.com.cn免费版有价值一点,他们虽然总的数据可能多一些,但开放的数据很少,特别mysql5 qqhash sha1要么没有,要么没开放或只开放了一点点数据,对免费用户实际用处不大。

posted @ 2010-10-03 14:19 袁斌 阅读(233) | 评论 (0)编辑 收藏

HashCrack程序数据及索引设计2

 

 

上个月写了《HashCrack程序数据及索引设计》里面已经提到早期设计的几种存储方法,最后达到了每条记录15个字节左右的水平,但这个存储效果还是很差的,而且是单体文件,受制于内存限制,后来又设计了几种复合索引格式,支持1万亿记录一个复合索引,下面简单讲讲之后的研究成果。

6、将内容区和索引区合并,索引位置不再提供指向内容区的size_t,内容区不再需要,直接在索引区,这样索引区indexnode

Struct indexnode

{

        Size_t nextoffset;

        Char str[0];

};

经过此修改之后稍微不好的地方就是如果一个文件里面要管理不同长度的字符串那么只能取最长的字符串长度,以便indexnode保持相同大小容易索引。

这种方法虽然效果不错,但平均下来一个字符串还是要占用11个左右的字节,而且不同长度的字符串有一些浪费的地方。

 

7、以上的存储方法虽然已经比较紧凑,但还不是最紧凑的方法,如果不保存字符串只是保存字符串在序列中的位置,那么不同字符串也没有长度不同,也可以用同样的大小去保存,如果一个db保存42亿以下的字符串,那么只要4个字节就可以了,如果一个db保存1万亿以下的数据,那么只要5个字节就可以,这真是个非常有创意的想法,其实我当初想到这个想法的时候很担心计算效率,迟迟没有动手代码,但思考了几天之后打消了我对效率的担心,相反,只保存一个position比复制N个字符串可能还要快一点,这样我们就只要9个字节描述indexnode了,看定义:

Struct indexnode

{

        Size_t lpos;

        Byte hpos;

        Size_t nextoffset;

};

精确到9个字节表示一条记录,很不错,也没有更多的限制。事实上9字节版本的速度比方法6的确是要快一点,还没优化的时候就比6方法要快一些了,当然查询的时候由于要多计算一些信息,理论上是要慢一点的,但由于都是内存计算,其实影响不是很大。

 

8、上述9个字节的方法虽然已经很紧凑,但如果给nextoffset做一点限制,让一个区段的数据为1667w以下,那么描述nextoffset 只需要3个字节即可,这样indexnode总的长度就只需要8个字节,这真是很好的想法,我为这个想法骄傲,看下indexnode8字节版本

Struct indexnode

{

        Size_t lpos;

        Size_t hpos:8;

        Size_t nextoffset:24;

};

精确的8字节indexnode,如此我们最终实现了最紧凑的md5数据库,每条记录8个字节,几乎无法再减少了,期待哪天突然灵光闪现再创造出更紧凑的存储方法吧,呵呵,这个实现其实已经超越了我最初的估计了,我以为能减少到12个字节已经到顶了,没想到还能减少到8个字节。

8字节的版本最初写出来的时候效率下降得很厉害,因为以前nextoffset当指针用,现在3个字节无法当指针,只能转换,多一个转换函数效率下降了一些,其他地方刚写的时候也是非优化算法,所以第一个8字节版本效率比9字节降低了一半以上,但花了一个早上优化之后效率又上去了,现在制造复合索引只需要82秒就可完成1亿条记录,速度比方法6快不少,方法6需要120秒左右。

 

或许我讲得比较简单,如果不是深入研究这一块的人或许看不明白,但精华我基本上讲出来了,实现上其实有很多技巧,如果要做到象我一样的速度其实是需要很深功力的,我测试用的机器是朋友的入门级服务器E5504 2.0cpu4G内存,普通7200转硬盘。

posted @ 2010-10-03 14:19 袁斌 阅读(170) | 评论 (0)编辑 收藏

从需求角度看NOSQL发展

 

早先当640kb就足够使用的观点流行的时候,数据处理规模很小,需求也不多,于是简单的文件存储即可满足需求,发展一段时间之后ISAM之类的简单存储就可满足需求,再之后sql流行,当sql为了适应各种需求变得越来越庞大的时候,效率也止步不前,在将缓存和多线程性能榨取完了之后,sql各项性能还只停留在满足常规应用的地步,难于处理1秒万次以上的读写操作,也难于解决万个以上的并发连接,一般的企业不可能动不动就上硬件,所以nosql发展是时代的需要是需求的推动。当然一般sql对传统企业还是足够满足的,所以我们在nosql的发展上没看到传统企业的身影,只看到当前发展最快的SNS公司积极推动nosql不断发展,著名的如:Facebook 推动Cassandra发展,Linkedin推动Voldemort发展,这都是最大的一类sns网站,这些网站都有几千万以上的用户,巨量数据读写,所以这些数据库都是极其强调分布式应用的,并不单纯的强调每个点的读写性能。再看小一点的mixi推动的Tokyo CabinetTokoy Tyrantgreen.jp推动Flare的发展,这些数据库都满足于几千万条数据的高速访问,也没看到特别的强调并发性,只强调他们的速度,当然几千万条数据还是有可能全放在内存里面的,就算放不下全部数据也至少可完全放下全部索引,这样读写当然快了,据说tt到亿条之后写性能急剧下降,大概就是这个原因吧。纯内存式数据库也必须要提一下,典型的如LiveJournal开发的memcached以及另一个新秀Redis等,前面提到的tt也支持memcached的协议,虽然这类数据库有很多局限,但在某些场合的确又很适合,memcahced其实连持续存储都不支持,为了解决持续存储问题,又有人发展了一些,如tt其实就是一个支持存储的memcached,国内新浪团队也给memcached加上berkeleydb支持持续存储。

上面说了这么多,无非想说一句话,需求推动技术进步,每一个技术进步其实都是为了满足某种需求的结果,就如google的三大基石bigtablegfsmap/reduce都是为了解决它的巨量数据而折腾出来的东西,google也正是靠这几个核心技术把持了互联网近十年的风光。同理我们可以想见,虽然百度没有大力的宣传他们的底层技术,但我们很容易想到,他们一定也是需要这些技术的,而且他们内部就算没有这些技术,但一定有类似的接替代产品,否则支撑不了他们那么巨量的数据,虽然替代产品未必有google的产品那么好,但大概是略差一点或相当的水平吧。国内互联网巨头腾讯支持了国内最大的im应用 10亿级,最大的棋牌游戏近亿在线,加上他们布局网络门户,布局qzone等,都是巨量用户,可以想见他们一定有类似的方案,早先听说他们棋牌游戏是通过很多mysql + proxy来完成的,虽然这个方式现在看起来也不是很完美,但至少是一个可行的解决方案,臆测下可以这样使用,proxy有个巨大的hash表,每个qqid计算一下就知道在哪个区段,重定向到哪个区段读写数据即可,说起来容易做起来难啊,就算我玩种菜都不知道遇到多少次他们数据出故障了,说明他们的系统面对巨大数据压力的时候还是碰到了很多问题。国内还有个公司不得不提,阿里巴巴淘宝,马云团队发迹很快,淘宝每年不知道要成交多少笔,但他们的数据也是一个天量,看了下他们dba团队的主页,牛一点的dba都笼络了不少,就是自己开发能力稍弱了一点,纵观国内对巨量数据需求最迫切的也就这几家公司了,虽然之后的51、开心网、盛大等也有类似需求,但数据量总归还是没有超过前面几家公司。

在需求的推动下,国内的nosqlkey-value应用也慢慢发展了一些,如张宴在新浪搞的memcachedb,到金山之后搞的dbcached,豆瓣开发的beansdb等,还有一些没开源没介绍不大为外界知道的应该也有一些,但总的来看水平还是比较低,有点不成气候的样子,靠的大多是1-2个牛人支撑,离开了这么几个人就不行了,东西也没人维护,的确,离开了巨量数据的需求一般的企业用sql就能满足也不会去研究这些东西,少数小一点的互联网企业有这个需求又没有相应的人才有能力去研究,年轻一点的开发人员都在玩概念想做也做不出这些东西,毕竟做这些东西没有很深厚的数据结构知识,没有3-5年的深入编程磨练是不可能真正做好一个像样东西的,矛盾啊。

最后说下我最近在做的一个东西,分布式md5计算,这个东西网上随便查一下就知道做的人不少,提供网站服务的都不少,但搜了几篇文章,看了几个网站www.cmd5.com www.md5.com.cn就知道,水平之低下超出了我的想象,基本上还是停留在用sql数据库的层次上,根据这些网站写的时间节点感觉他们大多数时间就是在制造数据,速度大概是几个月制造几十亿条数据,都号称有几万亿条数据,但事实上提供公开查询的数据只有区区几亿条,其他都要收费才能查询,天知道到底有没有那几万亿条记录,看上很吸引人,其实用处不算很大,用我最近整的md5数据制造方法1秒制造100w条数据,1亿条数据也就在2分钟内搞定,几亿条数据也不过10分钟左右就生成好了,1亿条记录耗费空间1.5G左右,不过10G左右空间即可,技术含量可见并不是很高。 其实我做这个项目并不是想做个类似的网站,主要是觉得这个东西玩技术很有意思,可大可小,一台机器也可玩,1T硬盘放600亿数据没问题,1万台机器也不多,全字母遍历到10位就算是上1w台机器也不够用,分布式存储分布式计算典型云计算概念,clientp2p可不p2p,很多技术元素都可参与其中,很有玩性的一个程序,所以就较上劲了,也好,正好练练技术,玩玩nosql的概念。

各种新兴技术出来都看到国内有深入分析,就说nosql系列的吧,深入分析memcached,深入分析tt,深入分析Cassandra的文章不计其数,到底也没看到有几个国人能写类似的东西,分析得头头是道,做的时候白痴一样,就算是使用都难用好,更别说自己动手做个这方面的好产品了,国情如此,略感欣慰的是国内现在也有一些公司和一些高水平的人真正参与其中,未来还是有可能有所突破的,正入本文所说,需求会推动技术发展,但短期肯定还是国外为主,国内的产品最多是一丝点缀。

posted @ 2010-10-03 14:18 袁斌 阅读(400) | 评论 (0)编辑 收藏

仅列出标题
共4页: 1 2 3 4