锁定老帖子 主题:介绍一个基于NIO的异步框架Cindy
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2005-03-15
flier 写道 SEDA和ACE的思路本质上都是通过将一个处理过程切分为多个Stage或Task,然后通过松散的基于异步消息的队列等机制进行组合。这方面实际上Netty2和Cindy是针对网络处理做了特化,分成消息派发、消息识别和消息处理等几个固定步骤,并定义出相应的接口和使用模式。而SEDA和ACE则将这些模式进一步抽象,提供通用性更强的任务组合机制。例如ACE可以支持通过配置文件或运行时设定,对多个不同的Task进行组合,有点简化版工作流的味道。同时其基于消息队列的界面接口统一但功能松散耦合的架构,也使得根据实际情况进行处理能力调整成为可能。如SEDA就明确提出根据不同步骤处理能力,以负反馈的思路进行并发数和其他参数自动调整。再就是通过统一接口,让缓冲区的生命期能够从一而终,避免服务器程序中最头痛的多次数据拷贝等问题。这些方面用Netty2和Cindy虽然也能做,但还是需要使用者做相当多的薄记工作。
谢谢你的介绍,我的理解是这已经在Cindy的定位之外了,如果我自己有时间的话再去学习学习。另外多次数据拷贝这个问题也让我有些头痛:(,如实现HTTP协议标准,如果使用Content-Length这种类型的倒是好办,只需要拷贝一次;其他类型的就得当成字节流从缓冲区识别出来,然后再进行识别。我会去看看他们是如何做到的。 flier 写道 支持第三方框架是个很宽泛的概念了,但对于定位在通用性框架的Cindy来说,应该还是具有很大意义的。毕竟这个层面用户,最大的需求是能够很快把东西run起来,而不是仔细考虑如何与现有框架进行整合。而容器的作用,我觉得你理解的太简单了,呵呵。
我还是没理解你说的第三方框架是什么意思:)而我的意思就是让用户能够很快的把东西运行起来,除开Cindy用到的commons-logging.jar,用户无需任何的jar,就可以运行在任何环境中。我不知道你指的第三方框架的意思是不是指”容器“,但是Cindy是不需要考虑任何容器的存在的,因此我觉得似乎不用考虑Cindy和容器的整合问题,那是用户考虑的事情,只要用户喜欢,随便怎么配置都行。 容器的作用我当然理解,但是你觉得Socket需不需要和容器整合呢?DatagramSocket需不需要和容器整合呢?NIO需不需要和容器整合呢?对于它们而言,容器也不过是一个外部的调用者罢了,和其他的调用者没有任何区别。Cindy也是如此。Cindy用Session统一了所有的操作,而在JDK包的设计中,Socket和DatagramSocket是没有任何交集的。用户可以使用Session,容器负责组装,但那是用户的选择,我不觉得Cindy有必要在其框架内部对容器有什么支持:) flier 写道 呵呵,这个就要看实际需求了。实际上C10K问题之所以普遍存在,就是希望能够使用一台设备尽可能支持多的并发连接。如果设计时就考虑到负载均衡或者分布式处理,单机处理能力就不再是瓶颈所在。但大多数程序无法承担分布式带来的复杂性,或者因为分布式会造成一些设计上的限制。
希望一台设备尽可能支持更多的并发连接,而不考虑分布式处理,这样的赌注会不会太大?一台设备的并发数最多也就是个16位,到达瓶颈之后该怎么办,总不能重写所有代码。在我看来,如果强调并发数的应用,就势必得考虑分布式处理的问题,总得留一条后路。虽然更有效率的利用机器是程序员应尽的职责,但是赌注不能下的太大了:) flier 写道 btw: 这个文档对C10K问题在IO这个层面讲的比较全
http://www.kegel.com/c10k.html 是的,非常好的文章。 |
|
返回顶楼 | |
发表时间:2005-03-16
seda定位是一个处理大并发的的框架。
跟nio不是一个东西。 seda设计针对了目前http服务器以每个请求一个线程的处理方式, 由于线程上下文的切换会浪费大量的cpu时间,最终大量的并发请求 将使得服务器被自身的线程压夸。 所以,seda希望通过负载量动态调节线程数目来解决这种问题。 在设计上假设一个请求可以被切分成多个步骤,这些步骤在seda里称为一个stage: stage应该根据应用的实际情况进行设计,这样不同负荷的stage可以施以不同调节方式。 一个stage包括了一个线程池和一个待处理队列一个处理器,stage之间的通信只能通过stage的待处理队列,对于每个stage,seda框架将对队列和现程池进行动态的控制。 由于seda是一个异步的处理模型,在该框架下应用的io访问,需要nio的方式,否则该框架的设计就失去了意义。 seda项目的维护太差了,搞了些时间,httpserver都没起来。 |
|
返回顶楼 | |
发表时间:2005-03-17
楼猪再加加油,让我少写几个set,我在用cindy撑falsh客户端
|
|
返回顶楼 | |
发表时间:2005-03-18
seda项目初衷不错,但很久没有更新过了。正在看它的一些文档,希望能够有借鉴的地方。
现在2.3的正式版已经发布了,上面Arbow提到的那个问题已经解决了,至于set方法么,我觉得大部分情况下并不用set什么东西啊? UserGuide: http://cindy.sourceforge.net/UserGuide.pdf |
|
返回顶楼 | |
发表时间:2005-03-19
提点表面的问题
为什么会有 start(true), writeBlock() 为什么不是,start(BLOCK), write(..., BLOCK) 对于使用组件的人,他不晓得true是什么意思 另,为什么没有无需要参数的start()(默认非堵塞?) |
|
返回顶楼 | |
发表时间:2005-03-19
抽象一个Block类出来没有任何实际上的好处,要么阻塞,要么不阻塞,一个boolean类型就能很好的表达了,我也没感觉到传入一个自定义的Block类型会带来什么样的方便:)
blockWrite(Message)之所以存在,而不是write(Message,boolean),一是blockWrite有一个boolean型的返回值,而write没有;二是以前session接口不存在blockWrite的方法,这个方法是在后面的版本中加入的,为了保持兼容性,没有修改write()方法的定义。 无参数的start在javadoc里面已经写明白了,等价于start(false),仅仅是为了方便而已。因为我我觉得既然选择了NIO框架,那么大部分操作应该是非阻塞的,所以加了一个方便的用法:) |
|
返回顶楼 | |
发表时间:2005-03-20
我指的BLOCK就是一个boolean,只是方便大家
我以为原来没有write()..... 怪怪的,同样是阻塞方式,一个传参数,一个却用方法名表示 |
|
返回顶楼 | |
发表时间:2005-03-21
简单看了一下大牛写的Cindy框架。小弟纯粹是一个服务器应用的新手,发表一点个人意见。我发现Cindy的做法大概是这样的,Socket来开Chanel,然后把自己attach到key上。然后多个socket共用一个eventgenerator,里面有一个while(true)的循环,从selector中取出ready的key,然后从key的附件中取出这个key所属的socket(或者说session啦)。然后在循环内调用process然后是onEvent。如果对于多可客户端的情况,应该是服务器有两个基本的线程,主线程开socket,处理事件。generator内的线程获得nio那ready的key,触发事件。
我是完全的新手不知道这样的朴素的多线程交互会不会有问题,是不是有什么生产者消费者模型之类的东西啊。不过直觉上来说如果onEvent要处理很久的话,会影响selectKey的速度,也就是服务器的响应就慢了。基本的两线程并发应该是肯定无法满足性能要求的吧。呵呵,SEDA学习中。 |
|
返回顶楼 | |
发表时间:2005-03-21
taowen 写道 简单看了一下大牛写的Cindy框架。小弟纯粹是一个服务器应用的新手,发表一点个人意见。我发现 Cindy的做法大概是这样的,Socket来开Chanel,然后把自己attach到key上。然后多个socket共用一个 eventgenerator,里面有一个while(true)的循环,从selector中取出ready的key,然后从key的附件中取出这个 key所属的socket(或者说session啦)。然后在循环内调用process然后是onEvent。如果对于多可客户端的情况,应该是服务器有两个基本的线程,主线程开socket,处理事件。generator内的线程获得nio那ready的key,触发事件。
理解上基本正确,除开启动JVM的主线程外,最基本的线程应该只有一个,就是EventGenerator内部维护的一个线程。 taowen 写道 我是完全的新手不知道这样的朴素的多线程交互会不会有问题,是不是有什么生产者消费者模型之类的东西啊。不过直觉上来说如果onEvent要处理很久的话,会影响selectKey的速度,也就是服务器的响应就慢了。基本的两线程并发应该是肯定无法满足性能要求的吧。呵呵,SEDA学习中。
第一,Cindy并没有限制你使用什么样的模型。最基本的模型是所有的Session共用一个EventGenerator,即用一个线程handle所有的连接。你也可以每200个Session用一个,这要在实际的环境上进行测试调整,哪种模型效率最高就采用哪种模型。Cindy并没有规定一定要只使用一个线程handle所有的连接。 第二,OnEvent是在Session内部实现处理的,而不是由应用处理的,所以你想象中的那个“如果”其实是不存在的。应用是通过SessionListener来监听相应的事件,而这个事件是由Dispatcher来分发的。即使在上一步中,所有的Session都使用同一个EventGenerator,但是可以通过一个Dispatcher池来分发事件,彼此之间也不会阻塞。举个很简单的例子,比如两个Session共用一个EventGenerator,但是它们彼此的Dispatcher是不同的,这样即使其中一个在SessionListener中休眠,也不会影响到另一个Session处理网络操作。 第三,如果服务器只有一个CPU,用一个EventGenerator来handle所有的连接也并不会效率低下;但在多CPU的情况下结果会有些不同。建议可以读一读《Java NIO》一书4.5节“Selection Scaling”。 |
|
返回顶楼 | |
发表时间:2005-03-21
另外提一下,使用NIO来进行异步操作,基本上就是以下三种模型:
[list] 如果采用第二种模型,则可以通过Session.setDispatcher(Dispatcher),比如每个Session置一个独立的Dispatcher线程。这样SessionListener中进行长时间处理也不会影响到其他的网络连接。 如果要采用第三种模型,除开setDispatcher以为,还需要通过Session.setEventGenerator(EventGenerator)来设置事件生成器。比如可以若干个Session共用一个EventGenerator,另外的若干Session共用另一个。 这三种模型之间进行选择并不会影响用户的业务逻辑处理,可以在最后进行性能调优时,在具体情况下进行测试,再进行调节即可。 |
|
返回顶楼 | |