在我们实现的分布式服务器中,每个节点都存有时空数据,这些节点上的时空数据利用RTree进行索引。每个节点同时保存着路由(邻居节点)信息。客户端可以向服务器端发送数据查询请求。服务器负责接收请求,并根据请求的类型进行相应的处理, 包括查询本地的数据,转发请求到邻居节点。
时空数据是以数据流的形式源源不断的插入到服务器中。当某个节点的数据达到系统预定义的阈值时,该节点将分裂成两个节点。我们将计算数据的***划分策略划分数据,并将划分的数据迁移到新的节点上。同时更新当前节点和新建节点的路由信息。
针对上面的要求,我们的服务器需要满足以下两个目标:
-
满足高并发的数据查询请求和数据传输请求
-
同时处理长连接和短连接
服务器中同时存在两种连接方式:长连接和短连接。长连接是指Client端与Server端先建立通讯连接,连接建立以后不断开,然后再进行报文的发送和接收。长连接常用于点对点的通讯,在服务器中,数据传输采用长连接。短连接是指Client端和Server端只有在进行一次报文收发操作时才进行通讯连接,操作完毕以后立即关闭连接。短连接一般针对一点对多点的通讯,如多个Client连接一个Server。在服务器中,数据查询请求采用短连接。
常见的网络服务器采用以下几种方式:
-
一个线程服务一个客户端,使用阻塞I/O
-
一个线程服务多个客户端,使用非阻塞I/O
-
一个线程服务多个客户端,使用异步I/O
第1种方式缺点在于当并发连接数过高时,操作系统同时处理几百个线程会有性能问题。而且在服务器硬件配置不改变的情况下,随着连接数的增加,将会导致性能急剧下降。第3种方式目前在Unix上还没有普遍的应用,因此,在我们的系统中并没有采用。第2种方式是将网络句柄设置为非阻塞模式,然后使用select或者poll IO多路复用技术来告知那个句柄已经有数据在等待处理。在此模型下,由系统内核来告知应用程序某个网络句柄的状态。这种模型也就是传统的IO多路复用模型,是目前大部分网络服务器的解决方案。
我们的服务器是基于Linux开发的,在Linux上,实现IO多路复用有几个主要的技术,分别是select模型,poll模型和epoll模型。
select模型***的缺点是***并发数限制,因为一个进程所打开的socket FD(文件描述符)是有限制的,默认是1024,因此select模型的***并发数就被限制了。当然,我们可以通过修改系统参数增大***并发数,然而由于select的每次调用都会线性扫描全部的socket FD集合。当socket FD增大时,会导致服务器效率线性下降。
poll模型基本上和select在效率上是一样的,select的问题在poll模型中也没有被解决。
epoll模型是目前比较优秀的IO多路复用模型,首先,epoll没有***并发连接的限制,上限是整个系统***可以打开的socket FD数目,这个数远大于2048,一般这个数目和系统内存关系很大,1G内存的机器的***sockef FD数目可以达到10万左右。其次,epoll***的优点在于它只关心活跃的连接,而跟连接总数无关。因此在实际的网络环境中,epoll的效率会远高于select和poll。
鉴于epoll的优点,我们的服务器采用了epoll作为IO多路复用的基本技术。
常见的基于epoll的设计模式主要为单线程的事件循环,用于一些非阻塞的业务逻辑开发是很高效的,然而,在我们的服务器开发中,涉及传输数据。转发请求的需求,耗时比较长。因此,单线程的epoll并不能满足我们的需要。下面用一个简单的例子来说明单线程模式下epoll的缺点。
由于是单线程模型,当某个客户端的请求处理时间较长时,会影响服务器接收来自其他客户端的连接请求,进而影响整个服务器的并发性能。
因此,单线程的epoll模型在我们的分布式服务器中并不适用。下面是我们服务器的设计方案:
图2 图3
上面这种设计模式一般称为Reactor模式,Reactor模式是处理并发I/O比较常见的一种模式,中心思想是首先将所有要处理的I/O事件添加到一个中心的多路复用器上(epoll), 同时主线程阻塞在多路复用器上;一旦有连接到来或者是准备就绪,多路复用器将返回并将相应的I/O事件分发到对应的处理线程中。
我们的服务器采用了多个Reactor,也就是多线程的epoll。 Reactor被分为main reactor和sub reactors,分别对应图2 和图3。每个reactor中都有独立的epoll来作为多路复用器。其中main reactor中的epoll负责监听连接请求,一旦有连接到来,利用一定的分发策略将连接socket加入到sub reactors的epoll中。对于每个sub reactor的epoll,主要的工作就是监听连接socket,一旦某个连接socket的I/O准备就绪,则通知相应的handler来接收数据并处理请求。
通过使用非阻塞I/O的多路复用技术epoll,并将连接请求与连接建立的之后的逻辑分离,我们设计了基于Reactor设计模式的服务器,满足了高并发的处理数据查询请求与数据传输请求。并能够同时处理长连接与短连接。 同时,还有一些细节我们可以改进:
-
main reactor 到sub reactors的分发策略
目前我们采用了Round-robin的方式,这样有可能产生负载不均衡的现象。 后面我们可以使用一定的策略,将main reactor接收到的连接请求分发到相对空闲的sub
reactor中。保证整个系统的负载均衡。
-
sub reactor的多线程化
对于每个sub reactor来说,这是单线程的。 我们同样可以将sub reactor进一步划分, 将数据的接收与请求的处理分离,请求的处理采用线程池的方式。这将进一步提高服务 器的并发能力。
原文链接:http://www.cnblogs.com/meibenjin/p/3604389.html