Pubertyly
本文描述了一个CG树顶端节点集群的设计与实现,主要内容有:
详细阐述了顶端节点集群的设计方案。该方案维持集群节点间的通信,当集群内节点失效时能及时发现;负载均衡器(LB)能够将客户端的请求通过一定的调度策略转发给下面的真实服务器(RS);能够保证所有真实服务器上的数据库的一致性。
实现了一个顶端节点集群的系统原型,技术分析和实验结果表明,该集群系统具有稳定性和高可用性。
[关键词] 集群 CG树 LVS 顶端节点集群
This paper describes the design and implementation for the top node cluster in CG-Tree. The major contents include:
[Keywords] Cluster, CG-Tree, LVS, Top Node Cluster
Internet 的飞速发展给网络带宽和服务器带来巨大的挑战。从网络技术的发展来看,网络带宽的增长远高于处理器速度和内存访问速度的增长。热门网站引发前所未有的访问流量,很多网络服务因为访问次数爆炸式地增长而不堪重负。一些新兴的网络技术如视频点播,动态网页,CGI 等带来更大的网络带宽需求。这时单一的计算机系统,如单处理器或者SMP 系统,往往因为巨大的网络负载而不堪重负,其存在着诸多的问题,主要表现在:扩展能力差并且扩展的代价昂贵;升级导致的服务中断会带来巨大的商业损失,并造成原有计算资源的浪费;单点故障发生的概率较高导致无法提供持续的可靠服务。解决网络服务的可伸缩性和可靠性已是非常紧迫的问题。
通过高性能网络或局域网互联的服务器集群[1]正成为实现高可伸缩的、高可用网络服务的有效结构。这种松耦合结构的服务器集群系统有下列优点:
提高性能
一些计算密集型应用,如:天气预报、核试验模拟等,需要计算机有很强的运算处理能力。这时,一般都使用计算机集群技术,集中几十台甚至上百台计算机的运算能力来满足要求。提高处理性能一直是集群技术研究的一个重要目标之一。随着网络的普及和计算机硬件性能的不断提高,集群系统的应用领域越来越广,目前集群系统主要应用于Web服务、Cache服务、媒体服务、科学计算以及数据库应用等领域。
降低成本
组成集群系统的 PC 服务器或RISC 服务器和标准网络设备因为大规模生产降低成本,价格低,具有很高的性能价格比。若整体性能随着节点数的增长而接近线性增加,该系统的性能价格比接近于PC 服务器。所以,这种松耦合结构比紧耦合结构的多处理器系统具有更好的性能价格比。
提高可扩展性
用户若想扩展系统能力,不得不购买更高性能的服务器,才能获得额外所需的CPU和存储器。如果采用集群技术,则只需要将新的服务器加入集群中即可,对于客户来看,服务无论从连续性还是性能上都几乎没有变化,好像系统在不知不觉中完成了升级。
增强可靠性
集群技术使系统在故障发生时仍可以继续工作,将系统停运时间减到最小。集群系统在提高系统的可靠性的同时,也大大减小了故障损失。
目前集群系统因其诸多的优点,已被广泛应用于 Web 服务,Cache 服务,媒体服务,科学计算及数据库等领域。
对于视频点播这种大流量的服务需求,服务器这一端的带宽将在很大程度上影响媒体服务的质量,如果将服务器节点限制在单个局域网内,媒体集群将受到网关流量的制约而提供很有限的服务。
CG树[2,3]是适用于分布式集群的一种模型,CG树将集群的节点分级分层,组织成以前端调度节点为根节点,服务器池的所有节点分组管理的树形结构。该模型下前端负载均衡器不必跟服务器池的所有节点通信,有效减少了前端节点的负载。集群节点采用分级分层的结构,能有效减轻集群前端负载均衡器的负担,并能有效地减少跨网络集群节点间的通信开销,具有较高的实用价值,是跨网络集群的一个较好的解决方案。
如图1-1是一棵CG 树的结构图。
在以往的CG树的实现中,顶端节点(如图1-2)需要负责处理客户端的请求,数据库的查询,CG森林的维护,资源的调度等任务,导致顶端节点的压力非常大,成为了整个系统的瓶颈。其中,数据库的查询操作占据了节点的绝大多数的资源。对于此,本文对顶端节点的性能做出过测试,在千兆局域网内选择了1台计算机作为顶端节点,其详细配置为:
然后客户端不断地发送请求,由客户端记录发送请求和收到响应的数量。实验结果表明,顶端节点在满负荷的条件下,每秒钟只能执行数据库查询一万次左右,即每秒钟可以处理客户端的一万次左右的资源请求。如果系统面向全世界服务,其性能显然无法满足客户的需求,因此,顶端节点成为了整个系统的瓶颈。
为了解决这一问题,本文提出了一种将顶端节点修改为顶端节点集群(如图1-3)的做法。这种做法的思路是,用分布的做法让多台服务器组成顶端节点集群来分担原来单个顶端节点的工作,从而提高系统的整体性能。顶端节点集群由两层计算机组成,第一层仅仅负责请求的转发,第二层由多台计算机组成,作为真实服务器,负责请求的处理,其数量取决于整个CG树的规模。由于顶端节点仅仅在选择真实服务器的时候需要与客户端通讯,真正提供服务时是由真实服务器与客户端直接进行通讯的,因此,基于CG树结构的服务器在管理规模上几乎没有限制。
本文设计与实现了一种CG树顶端节点集群的设计方案,主要包括以下内容:
本论文共有七章。
所谓socket[4]通常也称作“套接字”,应用程序通常通过“套接字”向网络发出请求或者应答网络请求。有两种常用的Socket类型:流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式Socket是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。
用户数据报协议(UDP)
UDP是一个简单的传输层协议,应用进程往一个UDP套接字写入一个消息,该消息随后被封装到一个UDP数据报,该UDP数据报进而又被封装到一个IP数据报,然后发送到目的地。UDP不能保证UDP数据报会到达其最终目的地,不保证各个数据报的先后顺序跨网络后保持不变,也不保证每个数据报只到达一次。
传输控制协议(TCP)
TCP不同于UDP,它提供客户与服务器之间的连接,TCP客户首先与服务器建立一个连接,然后通过该连接与服务器交换数据,然后终止这个连接。TCP提供了可靠的数据传输和流量控制,但是其开销要大于UDP。
在本文的设计方案中,心跳信息的传递使用UDP协议,数据库更新信息和节点之间的其他信息的传递使用TCP协议。
由于本文涉及的系统涉及到多个功能模块的并发操作,对于并发操作主要有两种方式实现:多进程结构和多线程结构。在多进程结构中,程序通过创建子进程来实现并发操作,如此可以充分发挥多核CPU的性能。然而创建子进程的开销是非常昂贵的,每创建一个子进程,需要把父进程的内存映像复制到子进程,且进程间的通信非常复杂。而线程则可以解决上述问题,线程的创建和切换的开销要比进程小得多。同一进程内的所有线程可以共享相同的全局内存,使得线程之间易于共享信息,随之而来的同步问题则可以通过互斥量来解决。
为了提高系统运行的效率,本系统将采用多线程技术实现任务的并发操作。本系统使用的是POSIX线程[5],也称为Pthread。
MySQL[6]是最流行的开放源码关联数据库管理系统。关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大的仓库内。这样就增加了速度并提高了灵活性。MySQL的SQL指得是“结构化查询语言”。SQL是用于访问数据库的最常用标准化语言,它是由ANSI/ISO SQL标准定义的。MySQL数据库服务器具有快速、可靠和易于使用的特点。
以往的CG树由一个顶端节点负责控制一个CG森林,顶端节点需要负责整个集群系统的维护、客户端请求的处理以及资源的调度等等,这样使得顶端节点的负担很重,成为整个系统的瓶颈,为了解决这一问题,本文提出了将顶端节点改为顶端节点集群的办法,其结构图如图3-1所示。
顶端节点集群为两层结构,第一层是一台负载均衡器,第二层由若干台真实服务器组成。负载均衡器负责接收第二层节点的心跳信息,保存它们的相关信息。第二层的每台服务器都维持一个同样内容的数据库,保存CG树叶子节点上相关资源的信息。由负载均衡器接受客户端的请求,然后按照一定的转发策略转发给第二层的真实服务器,真实服务器通过数据库查询操作得到保存客户端请求资源的CG树节点,将查询结果发送给客户端。
LVS[7]是基于IP层负载均衡技术的典型代表。用户通过虚拟IP地址(Virtual IP Address)访问服务时,访问请求的报文会到达负载均衡器,由它进行负载均衡调度,从一组真实服务器选出一个,将报文的目标地址Virtual IP Address改写成选定服务器的地址,报文的目标端口改写成选定服务器的相应端口,最后将报文发送给选定的服务器。真实服务器的回应报文经过负载均衡器时,将报文的源地址和源端口改为Virtual IP Address和相应的端口,再把报文发给用户;或者真实服务器直接将回应报文的源地址和源端口改为Virtual IP Address和相应的端口,发给用户。
以LVS为代表的典型集群在结构上一般分为三层:负载调度器(load balancer),它作为整个集群系统对外的前端,负责将客户的请求发送到后台的一组服务器上执行,客户不需要知道真实服务器的IP地址;服务器池(server pool),位于后台的一组真正提供应用程序服务的服务器,他们之间通过传递心跳信息来维持可用的服务器列表;共享存储(shared storage),它为服务器提供一个共享的存储区,这样很容易使得服务器池拥有相同的内容,提供相同的服务。
图2-1展示了一个LVS系统的基本结构。
LVS集群由负载调度器、服务器池和共享存储三大部分组成,本文的设计方案借鉴了LVS,同样有一个负载调度器,一组真实服务器。因为CG树顶端节点处理客户请求仅仅需要查询数据库,因此,不需要设置共享存储。
对于MySQL分布式数据库,LVS的一般做法是使用高冗余的同步集群(MySQL Cluster)或者相对简单的异步集群(MySQL replication)来实现。同步集群的特点是配置和管理方便,不会丢失数据,但是其需要较多的内存且速度一般。异步集群的特点是使用主从(mater/slave)模式,速度较快,但是往往会导致主数据库的压力过大且可能会丢失数据。无论哪种数据库集群,其都会产生较大的数据冗余。
在本系统的应用中,客户端的请求是查询所需资源的地址,而数据库的更新操作只有在CG树叶子节点上的资源更新时才会发生。因此,本文根据这个特点设计了一种简单的数据库的维护方式,即每台真实服务器保留一个数据库的完整副本,从而提高数据库的查询效率。
心跳机制[8]是高可用集群的重要技术之一。心跳周期性的检测集群中节点机器的工作状态,当节点机器的工作状态发生改变时,能够通知集群软件的其他部件。
本集群将采用心跳机制来维持系统的高可用性,由第二层的真实服务器周期性地向第一级的负载均衡器发送心跳信息,以告知负载均衡器其最新的状态。负载均衡器接收到心跳信息后,更新节点的状态信息,记录节点的心跳时间,同时设置一个心跳超时时间,其一般为心跳周期的2到3倍,若负载均衡器在超时时间内没有接收到真实服务器的心跳信息,则认为该节点发生故障,将节点状态设为故障。在实际应用上,可在心跳信息中捎带其他信息,如节点的工作负载等。
因为心跳的发送频繁,为了减少网络通信的开销,本文使用UDP协议来进行心跳的传递。
因为本文的设计方案中,集群中第二层的所有节点使用内容相同的数据库,因此保持数据库的一致性就是我们要关心的问题之一。
在本文的设计方案中,负载均衡器和真实服务器都要创建一个用于数据库更新的线程,CG树节点向负载均衡器发出数据库更新消息,当负载均衡器接受到数据库更新消息后,通过TCP将更新消息转发给每一台真实服务器,由真实服务器执行数据库的更新操作,从而保证每台服务器数据库的一致性。
本文为了提供整个集群的可用性,共实现了三种请求的转发调度策略[9],分别是:
轮转调度是最简单的调度策略,当负载均衡器接收到客户端的请求时,将请求轮询式的转发给第二层的节点。使用这种调度策略,负载均衡器的负担最小,同时,当客户端请求资源少而频繁时,此调度策略具有非常高的效率。但是,当请求服务时间变化比较大时,轮转调度算法容易导致服务器间的负载不平衡。
// 轮转调度算法
// 假设有一组服务器S = {S0, S1, …, Sn-1},一个指示变量i表示上一次选择的服务器,W(Si)表示服务器Si的权值,大于0表示服务器可用。变量i被初始化为n-1,其中n > 0
j = i;
do {
j = (j + 1) mod n;
if (W(Sj) > 0) {
i = j;
return Si;
}
} while (j != i);
return NULL;
通过源调度哈希转发即通过哈希函数将客户端的IP映射到唯一的一台服务器上。该调度算法可以使请求得到较均匀的分布。
// 源地址哈希调度算法
// 假设有一组服务器S = {S0, S1, …, Sn-1},W(Si)表示服务器Si的优先级,0表示服务器不可用。ServerNode[]是一个有256个桶(大小可调整)的Hash表,变量i表示上一次选择的服务器,变量ip表示客户端IP,getNext表示使用轮转获取下一个可用节点。算法的初始化是将所有服务器顺序、循环地放置到ServerNode表中
j = hash(ip);
if (W(Sj) == 0) {
j = getNext(i);
}
Return Sj;
hash(unsigned int ip) {
return (ip * 2654435761) & HASH_TAB_MASK;
}
// 其中,2654435761UL是2到2^32 (4294967296)间接近于黄金分割的素数。
// 2654435761 / 4294967296 = 0.618033987
为了解决集群第二层服务器性能可能存在差异的问题,可以使用加权轮转调度。其具体实现就是根据每台服务器的性能为每个节点设置一个优先级,性能越好,优先级越高。当服务器向负载均衡器注册时,同时告知优先级信息。在客户端发来请求时,负载均衡器根据优先级转发给第二层的真实服务器。
// 加权轮转调度算法
// 假设有一组服务器S = {S0, S1, …, Sn-1},W(Si)表示服务器Si的优先级,变量i表示上一次选择的服务器,变量cw表示当前调度的权值,max(S)表示集合S中所有服务器的最大权值,gcd(S)表示集合S中所有服务器优先级的最大公约数。变量i初始化为-1,cw初始化为零。
while (true) {
i = (i + 1) mod n;
if (i == 0) {
cw = cw - gcd(S);
if (cw <= 0) {
cw = max(S);
if (cw == 0)
return NULL;
}
}
if (W(Si) >= cw)
return Si;
}
例如,有三个服务器A、B和C分别有权值4、3和2,则在一个调度周期内调度序列为AABABCABC。当第二层服务器性能差异较大时,相对于轮询转发,此转发策略可以提高每台服务器的使用效率。
LB模块运行于集群第一层的负载均衡器上,负责转发客户端的请求、维持集群的运作、转发数据库更新消息等。
LB模块的主要数据结构为:
class TopNode{
/**< 存放节点信息的容器 */
vector<Node *> nodeVector;
/**< 转发请求时,下一个节点的序号 */
vector<Node *>::size_type m_nextNode;
/**< m_nextNode的互斥锁 */
pthread_mutex_t m_nextNodeLock;
/**< property的互斥锁 */
pthread_mutex_t m_propertyLock;
/**< threadNum的互斥锁 */
pthread_mutex_t m_threadNumLock;
/**< 数据库更新的互斥锁 */
pthread_mutex_t m_dbUpdateLock;
/**< 接收心跳的端口 */
int m_heartbeatPort;
/**< 接收消息的端口 */
int m_messagePort;
/**< 接受数据库更新消息的端口 */
int m_dbPort;
/**< 对外提供服务的端口 */
int m_servicePort;
/**< 客户端请求转发策略 1:轮转调度 2: 源地址哈希转发 3:加权轮转调度 */
int m_policy;
/**< 提供服务的套接字 */
int m_sockfd;
/**< 接受请求计数 */
int m_count;
/**< 二层服务器的数量 */
int m_rsNum;
/**< 数据库连接池 */
ConnPool *m_pool;
};
/** @brief the arg of the function thread_handleRequest */
struct requestArgs{
/**< 指向TopNode */
TopNode *topNode;
/**< 客户端的地址结构*/
struct sockaddr_in cliaddr;
/**< 客户端的socket套接字*/
int connfd;
/**< 客户端的请求内容*/
string *request;
};
class Node
{
/**< store node's priority information */
s_propertyMesg m_sProMesg;
/**< 数据库更新的套接字 */
int m_sockdbfd;
/**< 节点ID */
string ID;
/**< 节点状态 */
int status;
/**< 节点接收请求的端口 */
int m_servicePort;
/**< 节点上次发出心跳的时间 */
time_t heartBeatTime;
/**< 节点接收请求的地址结构 */
struct sockaddr_in m_serviceAddr;
/**< 节点状态的互斥锁 */
pthread_mutex_t statusLock;
/**< 节点心跳时间的互斥锁 */
pthread_mutex_t heatBeatTimeLock;
};
RS模块提供的接口为:
class TopNode{
/**< 初始化 */
void init();
/**< 轮询获得下个可用节点 */
Node *getNextNode();
/**< 读取配置文件 */
void readConf(char *);
/**< 对外提供服务 */
void *serve(void *arg);
/**< 接收心跳 */
void *receiveheartbeat(void *arg);
/**< 接收消息 */
void *receiveMessage(void *arg);
/**< 检查各字节点状态 */
void *changeStatus(void *arg);
/**< 对请求进行处理 */
void *handleRequest(int, const struct sockaddr_in *, string *);
/**< 对消息进行处理 */
void *handleMesg(int, const struct sockaddr_in *);
/**< 通过IP获得下个可用节点 */
Node *getNextNodeByIP(uint32_t);
/**< 通过负载获得下个可用节点*/
Node *getNextNodeByLoad();
/**< 通过优先级获得下个可用节点*/
Node *getNextNodeByProperty();
/**< 处理数据库更新消息*/
void *handledbUpdate(int);
/**< 接受数据库更新消息*/
void *dbUpdate(void *arg);
};
class Node
{
/**< 连接服务器,返回套接字 */
int connectServer();
/**< 关闭套接字 */
void closeServer(int);
/**< 向服务器发送消息 */
void sendtoServer(int, char *, size_t);
};
RS模块运行于集群第二层的真实服务器上,负责处理客户端的请求,并把处理结果发送给客户端。
RS模块的数据结构为:
class RealServer{
/**< 负载均衡服务器的地址 */
char m_lbIP[20];
/**< 负载均衡服务器的接收心跳的端口 */
int m_lbHbPort;
/**< 负载均衡服务器的接收消息的端口 */
int m_lbMessagePort;
/**< 节点ID */
string m_ID;
/**< 提供服务的端口 */
int m_servicePort;
/**< 接收数据库更新的端口 */
int m_dbPort;
/**< 数据库连接池 */
int m_property;
/**< 数据库连接池 */
ConnPool *m_pool;
/**< 处理请求数 */
int m_connNum;
/**< 处理数据库更新次数 */
int m_dbNum;
/**< 提供服务的套接字 */
int m_sockfd;
/**< 日志文件 */
FILE *m_log;
};
/**< 用于创建线程时传递参数 */
struct requestArgs{
/**< 指向RealServer */
RealServer *realServer;
/**< 客户端的地址结构*/
struct sockaddr_in cliaddr;
/**< 客户端的socket套接字*/
int connfd;
/**< 客户端的请求内容*/
string *request;
};
RS模块提供的接口为:
/**< 发送心跳 */
void *heartbeat(void *arg);
/**< 向LB注册 */
int registerToTopNode();
/**< 初始化服务器 */
void init();
/**< 对外提供服务 */
void *serve();
/**< 处理客户端请求 */
void *handleRequest(int, const struct sockaddr_in *, string *);
/**< 读取配置文件 */
void readConf(char *);
/**< 数据库更新 */
void *dbUpdate(void *);
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。在高并发的条件下,数据库连接池可以明显提高数据库操作的效率。因此,为了提高效率,本系统实现了一个简单的数据库连接池。
数据库连接池的数据结构为:
/** @brief 存放每个连接的地址和状态*/
typedef struct _sConStatus
{
/**< 数据库连接地址 */
MYSQL *connAddr;
/**< 数据库连接状态 0:空闲 1:使用中*/
int status;
}sConStatus;
class connPool {
/**< 数据库地址 */
string m_strHost;
/**< 数据库用户名 */
string m_strUser;
/**< 密码 */
string m_strPwd;
/**< 数据库名 */
string m_strDbName;
/**< 数据库服务器端口 */
int m_intMysqlPort;
/**< 最大连接数 */
int m_intConnNum;
/**< 存放连接的容器 */
vector<sConStatus *> m_vectorConn;
/**< 从连接的地址,快速找到索引 */
map<sConStatus *, int> m_mapVI;
/**< 从连接快速找到状态 */
map<MYSQL *, sConStatus *> m_mapMysqlScs;
/**< 互斥锁 */
pthread_mutex_t m_mutexScs;
};
数据库连接池对外提供的接口为:
/**< 初始化数据库连接池 */
int init(char *strHost, char *strUser, char *strPwd, char *strDbName, int intMysqlPort, int intConnNum);
/**< 创建一个数据库连接 */
MYSQL *createOneConn();
/**< 从连接池取一个连接 */
MYSQL *getOneConn();
/**< 将连接放回连接池。以便其他人用*/
void retOneConn(MYSQL *pMysql);
在千兆局域网内选择了6台计算机,其详细配置为:
测试方法:由三台计算机作为客户端,不断的发送UDP请求并记录发出的请求次数,服务器记录收到的请求次数。
UDP数据报格式:
测试结果:当发送速率在40万次/秒、50万次/秒、60万次/秒、65万次/秒的条件下,服务器收到包的成功率分别为100%、99.89%、93.19%、84.12%。
发送速率(万/秒) | 接受成功率 |
---|---|
40 | 100% |
50 | 99.89% |
60 | 93.19% |
65 | 84.12% |
结果分析:在丢包率允许的范围内,服务器每秒钟最大可以接受50万次左右的请求,未来整个系统的搭建应该考虑网络的上限。
测试方法:选择一台计算机作为CG树的顶端节点,同时建立一个数据库,其规模为200万条记录,记录资源的相关信息。客户端不断的发送请求,每次请求1到10个资源,服务器负责查询数据库,将保存资源的CG树节点IP告知客户端。客户端记录收到的响应数,服务器端记录处理的请求数以及数据库查询操作的次数。
测试结果:在满负荷的条件下,服务器平均每秒钟处理客户端请求1790次,数据库查询操作9836次。
图5-1记录了顶端节点的CPU、内存以及网络使用等负载情况。
结果分析:从图5-1中可以看出,CPU的使用率已经达到了90%以上,而每秒钟数据库的查询操作只有不到一万次,整个系统的性能会收到严重的制约。
测试方法:类似于上小节的测试方法,将顶端节点改为顶端节点集群,一台计算机作为负载均衡器,分别选择2、3、4台计算机作为真实服务器,进行同样的测试。
测试结果:当真实服务器的数量分别为2、3、4台时,整个集群平均每秒钟处理的请求数分别为3746次、5346次、7670次,平均每秒钟数据库查询次数分别为20600次、29405次、42190次。
满负荷运行时,真实服务器的负载情况如图5-2所示。
当挂载四台真实服务器时,整个集群最大负荷条件下,负载均衡器的负载情况如图5-3所示。
结果分析:将顶端节点改为顶端节点集群后,整个系统的处理能力大大加强。表5-1给出了性能测试的统计结果。
真实服务器数量 | 客户端请求数(次/秒) | 数据库查询次数(次/秒) | 性能 |
---|---|---|---|
0(即顶端节点) | 1790 | 9836 | 1 |
2 | 3746 | 20600 | 2.09 |
3 | 5346 | 29405 | 2.99 |
4 | 7670 | 42190 | 4.28 |
根据表中数据可以看出,整个系统的性能几乎是和真实服务器的数量成正比的。
另外,由图5-3所示,因为负载均衡器仅仅负责转发,所以在真实服务器满负荷的条件下,负载均衡器的CPU使用率只有15%左右,在网络条件允许的情况下完全可以挂载更多的服务器,从而继续增强整个系统的处理能力。
测试方法:使用五台计算机组成顶端节点集群,由另外一台计算机向集群发出插入、更新、删除记录的消息,由每台真实服务器统计执行操作的次数,并人工检查几个数据库是否保持了一致性。
测试结果
然后测试更新语句的执行,每次更新一条记录,整个集群的更新效率是每秒钟更新16000条记录。
最后测试删除语句的执行,每次删除一条记录,整个集群的删除效率是每秒钟删除15000条记录。(以上的测试数据会随着数据库的规模改变以及查询条件的改变而有所波动)
最后检查所有数据库的内容,可以保证所有数据库内容一致。
结果分析
由于每台服务器上都有一个数据库,所以数据库更新时,所有的真实服务器都需要进行更新,真实服务器的增加不会使整个集群的效率增加,反而会增加网络的负担。但是由于CG树数据库更新操作较少,大部分的数据库操作都是查询操作,因此数据库一致性保持上所损失的性能是可以接受的。
测试方法:使用五台计算机组成顶端节点集群,由另外的计算机分别发出客户端请求和数据库更新消息,统计满负荷下集群处理客户请求的数量。
测试结果:当以每秒钟1000次左右的速率发送数据库更新消息时,整个集群每秒钟可以处理客户请求7600次左右,数据库查询42000次左右。
结果分析:当数据库更新操作数量有限时,对整个集群客户端请求处理能力影响不大。考虑到CG树节点更新频率不高,因此本文的集群方案是可行的。
本章对本文的工作做了一个全面的总结,并指出了不足之处和下一步的研究内容。
本文首先介绍了一种适用于分布式集群的模型——CG树,并且分析了CG树顶端节点存在的问题,然后引出了将顶端节点改为顶端节点集群的想法。
然后本文介绍了一种顶端节点集群的设计方案,包括心跳设计、数据库一致性的保持以及调度策略等内容。
随后,本文给出了顶端节点集群的详细设计,并利用socket编程以及多线程技术实现了顶端节点集群。
最后,本文利用顶端节点集群搭建了一个简单服务器,并对其性能进行了测试,并与以往的顶端节点做出了比较。实验结果表明,顶端节点集群处理客户端请求的能力明显提高,具有一定的可行性。
本文的实现方案中,第二层的所有服务器都使用相同的数据库,有较大的数据冗余,同时增加了数据库同步的开销,如果数据库的规模达到一定的程度,可以考虑将第二层的服务器分组,从而进步一减轻每台服务器的负担。
另外,本文的系统建立于数据库更新操作不频繁的基础上,如果要应用于数据库更新频繁的平台,数据库的更新策略需要修改。
本文的实现只针对Linux操作系统,在系统的实现中大量用到了Linux系统相关的API,今后如果有意把系统用在面向跨平台应用上,这些部分都需要进行扩充和修改。
[1] William Stallings. 操作系统——精髓与设计原理(第五版)[M],北京:电子工业出版社,2006.
[2] 刘维峰. 分布式媒体集群的设计与实现[D],厦门:厦门大学,2005.
[3] 吴国才. 基于CG树的分布式服务器集群的设计与实现[D].,厦门:厦门大学,2008.
[4] W.Richard Stevens,UNIX网络编程卷一:套接字联网API(第三版)[M],北京:人民邮电出版社,2010.
[5] W.Richard Stevens,UNIX环境高级编程(第二版)[M],尤晋元等译,北京:人名邮电出版社,2006.
[6] MySQL官方网站,http://www.mysql.com/.
[7] 章文嵩. LVS项目介绍[Z],http://www.linuxvirtualserver.org/zh/lvs1.html,2002.
[8] 李大夜. 基于Linux的集群和心跳设计[D],哈尔滨:哈尔滨工业大学,2006.
[9] 章文嵩. LVS集群的负载调度[Z],http://www.linuxvirtualserver.org/zh/lvs4.html,2002.
大学本科生活即将结束,回首总结这四年的求学生涯,许多老师、同学和朋友给予了我真诚、无私的指导和帮助,在此我要表示我最真挚的感激和谢意。
首先,我要衷心感谢指导我完成毕业设计的老师。老师对我们认真负责,严格要求,从课题确定到最后论文的定稿,为我们倾注了许多的心血与汗水。在毕业设计期间,老师每周都抽出时间与我们讨论,了解我们毕设的进展,并提出了许多宝贵的建议和意见。正是由于老师的严格要求和悉心指导,本文才得以顺利完成。
其次,我要感谢在这四年里教导我的所有老师们,是你们的辛苦付出让我在计算机学科道路上不断成长,不断成熟。
感谢实验室里的几位学长,在毕业设计中给了我很大的支持。
最后,特别感谢我的父母和家人,一直以来你们给予了我最大的关爱和帮助。在这二十年的学习生活中,正是因为有了你们作为我的坚强后盾,我才能在人生道路上一往无前,也正是有了你们,在我遇到挫折的时候,你们给了我避风的港湾。
keyboard_arrow_left上一篇 : 基于Node.js中间层的微信图书借阅平台网站的设计与实现 基于SMTP协议的E-MAIL电子邮件发送客户端软件C#实现 : 下一篇keyboard_arrow_right