方国栋,张育钊
(华侨大学工学院,泉州362021)
随着网络技术的发展,通信行业发生了翻天覆地的变化[1]。目前,基于IP 的网络对讲机应用越来越广泛[2-3],当大量网络对讲机同时向服务器发起数据转发请求时,服务器需和对讲机建立大量的网络连接,此时面临高并发问题,若访问者采用TCP 的方式保持网络连接时,交换机会因为高并发TCP 流到达瓶颈率崩溃[4-6]。
虽然服务器的计算性能和存储能力均有了质的飞跃,但普通服务器根本无法处理高并发请求。对于这种问题,目前有两种解决方案,即采取高端服务器和使用普通服务器集群。虽然高端服务器的计算性能和存储能力比普通服务器更强,但产品少、价格高、运行和维护成本高等因素限制了它的推广使用。为此,构建服务器集群[7],通过组合多个普通服务器,形成一个高性能的服务器组,共同完成大量的存储和计算等任务就成为了首选。而怎样合理的将大量请求、计算和存储等服务分布到集群上、更好的处理高并发请求、提升集群的扩展性就成为了一个新的研究热点。
目前对于服务器处理海量数据和高并发访问方面的研究,主要分为基于线程池和非线程池两类方式。基于线程池的方式在实践中更为常见,已发表大量研究成果[8-11]。武雪芳等人[8]根据网络游戏服务器需满足高并发和及时性的特点,设计了一套高效的网络游戏服务器并发架构,该方案采用服务器集群处理高并发请求,并选择线程池策略提高响应速度。樊扬轲等人[9]通过结合epoll 和线程池技术,使服务器具有高并发处理的能力,其中epoll 技术用于做事件触发,线程池技术用于处理客户端请求。LING Yi-bei 等人[10]基于三个假设,即线程优先级和CPU 时间一致、Web 请求的I/O资源和内存均较小、并且系统资源可以整合到可观察成本中,计算出了线程池所要创建的核心线程大小的最优值,该方式能更有效的使用系统资源。刘新强等人[11]针对服务器需要不断的创建线程并与大量客户端通信时会消耗大量系统资源的问题,给出了一种优化方案以减少系统消耗。
线程池方式的结构图如图1 所示。集群中每个通信节点先根据预先设置的核心线程数创建核心线程,当大量的客户端向集群发起通信请求时,如果通信节点线程池中没有空闲线程,同时请求队列已满,节点将根据相应的处理策略将请求队列之前的请求丢弃或拒绝客户端请求。如果节点线程池中有空闲线程,则给客户端分配一个线程[12],否则,如果请求队列未满,节点先将请求放到请求队列中,直到线程池中有空闲线程时,再去请求队列中取出请求,完成通信。这种方式只缓解了服务器创建线程时需要消耗的系统资源,但没考虑如何联合集群中的各通信节点。
图1 线程池方式结构图
非线程池方式主要是通过多进程和I/O 复用[13]、集群负载均衡等方式提升集群的高并发处理性能[14-15]。刘万军等人[14]提出了基于蚁群算法的服务器集群资源调度算法,并引入等待因子的概念,采用等待因子动态选取服务器资源,其目的在于解决各个服务器节点由于负载能力差异较大,导致集群服务器在提供服务的时候产生的木桶效应,实验结果表明该方法可改善集群系统的整体性能和负载能力。段淮川等人[15]提出基于剩余负载率的动态负载均衡机制。他设计了一种结合基于流表的静态分配策略和基于负载预测的动态分配策略的任务分配策略来实现在集群系统各节点间任务的动态分配,降低服务器各节点之间任务重新调度的次数,达到提高集群系统的服务性能的目的。这种方式是为了提升高并发时集群的响应速度和平衡各节点资源,做到“能者多劳”。其不足之处是没有具体阐述如何维护集群各节点。
线程池方式和非线程池方式均没有阐述如何在集群中做任务分发、如何高效的管理集群中各个节点。本文依据改进型Chord[16-18]算法,提出面向网络对讲机语音小文件的高并发处理方案。仿真结果表明本文设计的服务器集群管理方案能对集群进行有效的管理,并能合理对集群中服务器节点进行任务分发,与使用线程池方式相比,本文方案的集群响应时间减少了约40%。
Chord[17]是一种由UC Berkeley 与MIT 共同提出的分布式查找算法,目的是在对等网络(P2P 网络)中建立一个分布式、可扩展和负载均衡的资源查找模式[19]。其文件查找过程的通信开销和系统维护的状态随着系统总节点数增加成指数关系[20]。Chord 网络采用SHA-1 算法给每一个节点和关键字分配m bit 的标识符[21],标识符范围为[0~2m-1],通常节点的标识符为其IP 哈希值,关键字的标识符为关键字哈希值,将所有标识符模2m后按大小顺时针排列组成Chord 环,如图2 所示。关键字落在节点标识符大于等于它的第一个节点上,称为关键字的后继节点,记N=successor(k),图中关键字4 的标识符小于节点6 标识符,且节点6 位关键字4 后的第一个节点,满足6=successor(4)。这种查询方式的复杂度为O(n),n 是节点个数,当系统规模越大时,查询效率越低。
为了加快节点的查询效率,改进型Chord 采用指针表(finger table)的查询方式,每个节点维护一个包含若干项记录的指针表,项数由标识符的位数m 所决定,环中最大节点标识符NID 需满足式(1):
图2 Chord环
并且节点N 在指针表中的第i 个表项节点S,满足式(2):
其中,s 和n 分别是节点S 和N 的标识符。图3 是节点10 的指针表,因为58<26,所以m 为6。对于指定的关键字,Chord 先判断关键字是否落在对应的节点中,是则结束查询,否则节点将查询请求发送到指针表中距离关键字最近的节点,重复该过程,直到找到指定节点。
图3 节点10指针表
这种查询方式每次都以2 的幂指数为间隔,所以每次减少整个环的一半容量,对于一个包含N 个节点的网络来说,这种关键字查询方式的时间复杂度为O(logN)[17]。
本文结合了改进型Chord 路由算法,提出了一种新的解决方案。首先,建立改进型Chord 环,将集群中各服务器节点分布到Chord 环上;其次,建立路由信息表,在集群中加入一个路由器节点,保存所有服务器节点的路由信息,同时各节点建立一个路由表,用于节点间的快速查找,最后,再设计一套集群软件管理策略,用于维护节点的加入和退出。
本文方案系统组成结构如图4 所示。系统各个部分功能模块图如图5 所示,路由器节点包含预取模块,能减少对讲机客户端向服务器发起请求的次数,以减轻集群压力;服务器节点包含节点加入、退出和线程池模块,分别用于处理新节点加入、已有节点退出和对讲数据转发等任务,同时需要和路由器时刻保持连接;网络对讲机是发起数据转发请求或接收服务器节点转发的数据的客户端,进行网络对讲前,先向路由器预取服务器节点信息,然后直接向服务器节点发起对讲转发请求,并等待节点转发对讲语音数据,如果该节点出现了问题,则根据相关的软件策略自动选择其后继节点进行服务。服务器端和客户端程序执行的流程图如图6、7 所示。
图4 系统结构图
图5 各部分功能模块图
图6 服务器端软件流程
(1)路由维护策略
用户维护和缓存各服务器节点的路由信息。如果在M 个周期内没有收到节点的心跳信息,则标记当前节点处于静默期,在N(N>M)个周期依旧没有收到节点的心跳信息,则从缓存中删除该节点的信息,并通知集群中其他的服务器节点更新路由表,而各节点只维护其后继节点路由信息,如果节点加入和退出的时间刚发生在客户端发起请求的时间段,通过路由器获取到的节点路由信息会导致无法找到节点,此时,客户端在本地查找该节点的后继节点,并发起通信请求,通过在节点上做二层路由维护,可以保证客户端和节点的通信安全。
图7 客户端软件流程
(2)节点加入策略
步骤1:节点加入到集群前,先向路由器进行路由信息注册;
步骤2:路由器接收到节点加入的请求后,缓存新加入节点的路由信息到路由表中,然后通知集群中其他节点更新路由表,其他节点按照式(4)更新本节点的路由信息表;
步骤3:新加入节点同样根据式(4)建立本节点的路由信息表,并将路由信息表缓存到内存中;
步骤4:当客户端向路由器发起预取路由信息请求时,路由器节点通知客户端有新节点加入,并返回更新后所有节点的路由信息;
步骤5:客户端更新本地缓存中的服务器节点路由信息表。
(3)节点退出策略
步骤1:节点退出时,路由器通知其他节点更新路由信息表;
步骤2:节点根据式(4)判定当前退出的节点是否属于其路由表中节点,如果属于则将缓存中该节点的路由信息移除;
步骤3:当客户端向路由器发起预取路由信息请求时,路由器节点通知客户端有节点退出,并返回更新后所有节点的路由信息;
步骤4:客户端更新本地缓存中的服务器节点路由信息表。
(4)客户端请求策略
客户端先向中心路由器节点预取其所维护的服务器集群的路由信息并在内存中保存;当客户端发起数据请求时,首先通过哈希函数SHA-1 求出客户端请求数据的哈希值V,计算方式为式(3):
然后检查其路由表缓存信息中是否能找到相应的节点,如果存在对应的服务器节点则直接向该服务器节点发起通信请求并由其转发对讲语音数据,否则先向该服务器节点发起路由转发请求,由该服务器节点在其路由信息表中查找目标节点,如果目标节点不在当前节点的路由信息表中,则该节点继续向其后继节点转发请求,直到找到目标节点。
为了分析本文所提出方案的性能,设计了如下实验方案。实验环境参数如表1 所示,实验中所用到的集群是采用线程方式来模拟的,包括有1 个路由器节点和6个对讲语音服务器节点,对讲机客户端使用进程模拟,一个客户端对应一个进程。主机使用TP-Link 路由器提供局域网网络,路由器节点、对讲语音服务器节点和对讲机客户端软件均是采用Java 语言进行编写的。
表1 测试环境
实验的客户端个数和每个客户端所发送的文件大小对应关系表如表2 所示。实验测试结果均采取计10次并发访问的响应时间和数据读写时间总和求平均值的方式,按以下6 种情况进行对比。
表2 实验测试情况表
(1)Chord 预取:集群使用Chord 路由算法维护各对讲语音服务器节点,且路由器节点提供预取机制。客户端在空闲时向路由器预取各服务器节点路由表信息,当客户端发起数据读写请求时,直接到内存中找到其对应的目标节点,然后向目标节点发起数据通信连接,各服务器节点使用线程池技术同客户端通信。
(2)无Chord 预取:集群不使用Chord 算法维护各对讲语音服务器节点,各节点使用线程池方式和对讲机客户端通信,但路由器节点提供预取机制。
从图8 可以看出,无Chord 预取和Chord 预取响应时间基本保持一致,这是由于对于客户端而言,都只和路由节点发起一次通信请求,不能体现Chord 算法在维护服务器集群路由表信息的优势。
(3)Chord 无预取:集群使用Chord 路由算法维护各个对讲语音服务器节点,但路由器节点不向客户端提供预取机制。客户端每次向目标节点发起数据读写请求时,都要先向路由器获取目标节点的路由表信息,然后客户端向目标节点发起数据通信连接。
图8 Chord预取与无Chord预取时间对比图
(4)无Chord 无预取:集群不使用Chord 算法维护各对讲语音服务器节点,各对讲语音服务器节点使用线程池方式和对讲机客户端通信,路由器也不提供预取机制。
从图9 可以看出,无Chord 无预取和Chord 无预取响应时间也基本保持一致,这是由于对于客户端而言,每次进行数据读写时都要向路由器节点发起一次通信请求,同样不能体现Chord 算法在维护服务器集群路由表信息的优势。
图9 Chord无预取与无Chord无预取时间对比图
(5)指针表跳转:当目标节点不在客户端缓存的路由表中时,客户端会向根据标识符值向指定服务器节点发起请求,再由该节点去找到目标节点。而使用线程池技术时,客户端会向路由器发起多次连接,直到路由器找到了和该客户端通信的节点。从图10 可以看出,使用Chord 管理方案比使用线程池技术的时间更少,响应更快。
图10 指针表跳转对比图
(6)路由器节点是否提供预取:实验用于对比预取机制是否可以加快集群的响应速度。如果路由器节点向对讲机客户端提供预取机制,则客户端在空闲的时候向路由器节点预取各对讲语音服务器节点路由信息,否则,客户端每次发起数据读写请求时都会向路由器节点发起请求,获取对应的对讲语音节点路由,然后向该节点发起数据读写操作。
从图11 可知,有预取比无预取的集群响应速度更快,这是因为有预取机制时,对讲机客户端不需要花费时间和路由器节点建立连接。
从以上6 个实验可以,集群使用Chord 算法维护集群各节点,集群并发访问的响应时间分别为使用线程池方式维护时的63.60%、65.60%、64.70%。
网络对讲机的广泛使用,使得服务器面临了大量网络对讲机请求时的高并发处理问题。本文介绍了目前用于高并发处理的多线程和多进程方案,并在此基础上结合Chord 路由算法,设计了一套高并发处理方案,以提高集群的响应速度,最后通过实验的方式,比较本文的方案和文中提到的其他方案在处理高并发访问时系统的响应时间。从实验的结果可以看出,本文提出的高并发处理方案在并发处理效率和时间代价等方面相比其他方案更加优越。
图11 Chord预取和Chord无预取对比图