(同一个世界,同一个梦想,交流学习C++Builder and Delphi XE10,传承c++builder and Delphi的魅力!欢迎各地朋友加入我的QQ群484979943,进群密码“BCB”,已购书的读者请加入QQ群876403118,同时也请将该群号广为宣传,希望能够广集各方高手,共同进步)
【阅读倡议】
1、有问题请留言;
2、没问题请点赞;
3、看连载请加群;
4、下源码请加群;
【开发工具】
1、C++Builder and Delphi 10.3.3
2、FMSoft_uniGUI_Complete_Professional_1.70.0.1555(正版)
本人主笔的国内第一本《UniGUI入门到精通》《移动开发指南》和《Flexcel开发EXCEL入门到精通》教学案例代码已诞生,分为cbuilder和delphi两个版本,买代码送手册,需要的朋友可以加入我的QQ技术交流群484979943、876403118给我(群主)留言。资料简介:
https://www.meipian.cn/20b86ayo?share_from=others&user_id=64168117&uuid=a8a75af8c0cc31e6a21b8a79a2b07398&share_depth=1&first_share_uid=64168117&utm_medium=meipian_android&share_user_mpuuid=94b70e99e8b6986c71b270a9883befb2
————————————————
HyperServer是提升UniGUI项目稳定性的一个方法,属于在单台硬件服务器内以软件形式构建的多服务器节点负载均衡方案。UniGUI一直在致力研究真正的负载均衡方案,服务器农场(HyperServer Farm)就是UniGUI最新推出的支持多台硬件服务器负载均衡的解决方案。如下图所示,架构图的上半部分和原来的HyperServer方案一样,架构图的下半部分增加了三套HyperServer配置,其实服务器农场就是基于原来的HyperServer软负载均衡方案的组合和扩展。这里引入一个新概念,服务器节点(ServerNode)。HyperServer服务器农场集群由一个主服务器节点(Master)和多个从服务器节点(Slave)构成。服务器节点其实是运行在服务器上的HyperServer实例。HyperServer服务器农场集群的进入点(主控点)其实也是一个运行HyperServer实例的服务器节点,只不过它被配置为主服务器节点。
- 配置一个服务器农场集群
服务器农场集群的配置并不复杂,和普通的HyperServer配置没有太大差别,假设我们想搭建一个服务器农场集群总共由四个节点构成,我们需要准备四台独立的物理服务器(如果你想使用四个虚拟化分区也可以,但是基于一个平台的虚拟化未必那么靠谱),每台服务器配置一个HyperServer实例,一个作为主实例其它作为从实例,HyperServer实例也叫服务器节点(ServerNode)。一般情况下,集群里有一个主服务器实例负责接受所有的客户端请求,然后将客户端请求转发给自己内部的软服务节点和其它外部的从服务器节点。
- 配置主服务器节点
在主服务器节点的CFG配置文件里添加各个子服务器节点的配置信息,下面的例子就是在主服务器节点的配置文件里添加了三个子服务器节点的集群配置信息。
[server-0]
enabled=1
url=http://192.168.1.32:8077
name=HP-ML150
token=gmvsek210828175924563
[server-1]
enabled=1
url=http://192.168.1.33:8077
name=DELL-7080
token=eftrgj210828180420097
[server-2]
enabled=1
url=http://192.168.1.34:8077
name=DELL-7081
token=eftrgj210828180420024
每个服务器节点的配置信息由五部分组成,以“[server-*]”开头加“enabled、url、name、token”四个参数构成,说明如下:
- [server-*]
以“server-”开头+一个唯一性数字构成每个服务器节点的配置信息开始段,比如“server-0”、“server-1”、“server-2”等。
- enabled
节点的服务控制开关,1-启用、0-停用,如果设置为0,则主服务器节点不会把客户端请求分配到这个节点。
- url
url是这个服务器节点的访问地址,这个url地址被用来和这个服务器节点进行通讯,可以有如下几种常用的表达方式:
http://192.168.1.33:8077 URL with physical IP Address
http://webserver-1:8077 URL with network name of a local server
http://mycompanydomain.com:8077 Global URL with a domain name
- name
name是服务器节点的别称,可以使用计算机名称,也可以是其它名称。
- token
token是各个服务器节点的唯一标识,用于授权主服务器节点访问从服务器节点的服务控制器,如果没有这个token,每次访问从服务器节点的服务控制器时都需要输入授权信息。这个token值由每个从服务器节点自动生成在CFG文件里,当你首次运行从服务器节点的hyper_server服务程序时系统就会自动在CFG文件里生成一个token值,我们需要把每个从服务器节点的token值复制到主服务器节点的配置文件里。现阶段每次修改这些参数后都需要重启生效,未来uniGUI会把参数配置功能增加到控制面板里,到那时候就可以动态生效了。
- 配置从服务器节点
从服务器节点的配置工作和标准的HyperServer服务器节点配置基本相同,把它当成配置一个独立的HyperServer服务器来配置就行了,配置完毕后先在本机测试一下是否能正常运行。主要的区别是作为从服务器节点只能部署为服务模式(Service Mode,即Windows服务)或者独立服务器模式(Standalone Server Mode,即exe程序),exe模式可以用来做测试和debug,如果是部署生产环境最好部署为服务模式。但是,对于主服务器节点可以部署为支持的任何一种模式,包括ISAPI模式、Apache模式、Windows/Linux 服务模式、标准EXE程序模式(建议只用作test和debug)。配置完启动hyper_server服务后我们发现CFG配置文件里自动生成了token字符串:
server_title=Slave-8078
server_build=1.90.0.1552
dont_create_backup=0
allow_remote_config=1
token=gmvsek210828175924563
http_max_pool=1000
max_connections=1000
我们需要把上面的token复制到主服务器节点的配置文件里,如下所示:
[server-0]
enabled=1
url=http://192.168.1.16:8077
name=DELL-7080
token=gmvsek210828175924563
3)测试服务器农场集群
做完以上配置后就可以测试了,要先启动每个从服务器节点,然后再启动主服务器节点。假设我们的测试案例里共有2个服务器节点并且都部署在同一台电脑上,为了实现在同一台电脑上部署多个集群和应用,每个应用要监听不同的服务端口。访问http://127.0.0.1:8077/server打开主服务器节点的控制器:
我们看见在控制器里多了一个叫做“ServerNodes”的页面,这个页面里可以看到我们在CFG文件里配置过的从服务器节点,如果配置正确的话主服务器节点就可以和这些从服务器节点进行通讯了,我们也可以看到从服务器节点http://127.0.0.1:8078是在线状态,点击尾部Actions列的搜索图标就可以打开这个从服务器节点的控制器界面,在这里就可以远程管理从服务器节点的会话和资源了,如下图所示:
4)访问服务器农场的应用程序
在浏览器里输入主服务器节点的URL就可以访问我们的应用程序了,如果查看服务器节点的控制器,我们可以看到LocalNode-0里多了一个会话:
如果我们查看ServerNodes页面我们可以看到编号(Node Id)为1024的节点有一个活动的节点和会话,服务器农场集群会自动给每个服务器节点分配一个编号,编号从1024开始:
我们这个集群由一个主服务器节点和一个从服务器节点组成,主服务器节点可以扮演两个角色。第一个角色是只作为负载均衡器,将客户端请求按照一定规则分配给不同的从服务器节点;第二个角色是它本身也可以作为一个普通的服务器实例,拥有自己的本地节点(软节点)处理用户请求。如果设置max_nodes=0则主服务器节点就是单纯的负载均衡器,如果设置max_nodes>0则主服务器节点既是负载均衡器又是一个标准的HyperServer服务器。如果一个主服务器节点的max_nodes>0,运行一段时间后我们就会发现它正在处理多个会话,如下图所示:
5)始终使用服务器集群里的零号节点
如果你想让某个任务始终运行在从服务器节点的零号节点上,请设置该服务器节点的persistent_node_zero=1,同时向TUniServerModule.UniThreadTimer1Timer程序里添加几行代码:
procedure TUniServerModule.UniThreadTimer1Timer(Sender: TObject);
var
ExecIt : Boolean;
begin
ExecIt := NodeZero and (ServerNodeId = 1024); // My owner is first ServerNode with ID = 1024
if ExecIt or (not NodeMode) then // run code either if I'm Node #0 or I'm not a Node!
begin
// 添加你的代码
end;
end;
如果你想让你的任务运行在主服务器节点的零号节点,请设置该服务器节点的persistent_node_zero=1,然后将代码里的ServerNodeId从“1024”改为“-1”,上述代码如下修改:
procedure TUniServerModule.UniThreadTimer1Timer(Sender: TObject);
var
ExecIt : Boolean;
begin
ExecIt := NodeZero and (ServerNodeId = -1); // My owner is not a ServerNode (It is either a standard
HyperServer or a master HyperServer instance
if ExecIt or (not NodeMode) then // run code either if I'm Node #0 or I'm not a Node!
begin
// 添加你的代码
end;
end;
- 服务器农场集群如何分配流量
作为负载均衡器HyperServer会自动分配客户端的访问流量,每个服务器能够受理的并发请求量由其max_nodes参数控制,HyperServer就根据每个服务器节点的max_nodes参数在所有服务器节点的max_nodes参数和的占比来平均分配流量,假设主服务器节点的max_nodes=0其本身不处理客户端请求,各个从服务器节点的max_nodes配置如下表所示:
根据上表中的配置参数,0号和1号服务器节点将收到17%的流量请求,算法如下:
24 / ( 24 + 24 + 32 + 64 ) = 0.166 ~ 0.17
同样2号服务器节点将收到22%的流量请求,32/(24+24+32+64)=0.22,3号服务器节点将收到44%的流量请求,64/(24+24+32+64)=0.44。因此,在实际应用中我们需要根据每台服务器的硬件配置情况合理配置它的max_nodes参数,如果某台机器性能一般或者你想让它少干活,你就要将它的max_nodes设置的小一点儿。
- 在服务器农场里如何共享文件
UniGUI里有三种类型资源文件,一是静态资源文件、二是应用程序全局文件夹里的文件、三是客户会话自己文件夹里的文件。
- 静态资源文件
静态资源文件是一直存放在服务器上的资源文件,比如Ext JS库文件、JavaScript文件、theme样式文件、三方的JS&CSS文件,这些文件都存放在应用程序的/files目录里。大多数文件都是安装UniGUI Runtime和UniGUI Theme Pack程序包产生的,在一个集群里这两个软件包只需要安装在主服务器节点,从服务器节点一般情况下是不需要安装的,除非你需要在部署从服务器节点的机器上单独访问和测试应用程序。
需要分享的静态文件只需要部署在主服务器节点的/files目录下,子服务器节点上的/files文件资源外部是访问不到的,因此当外部用户访问http:/domain/files/common.pdf时HyperServer会直接到主服务器节点的/files目录下寻找文件。显然/files目录不能用来存放动态文件,因为从服务器节点的/files文件夹无法从外部URL访问。
- 应用程序全局缓存文件夹里的动态文件资源
UniGUI的Web项目里,全局缓存文件夹一般被用来存放动态创建的文件资源,UniGUI自动完成这个动作。正常情况下,你不需要在全局缓冲文件夹里创建任何文件,UniGUI使用特殊的锁机制来避免并发访问冲突问题,即使文件存放在远程的服务器节点,主HyperServer节点也能够定位和传递那些资源文件到需要的客户端。你可以使用UniServerModule.GlobalCachePath方法获得应用程序的全局缓存目录,你可以使用UniServerModule.GlobalCacheURL方法获得全局缓存URL。
- 会话自己缓存目录里的动态文件资源
UniGUI使用自己的缓存目录创建和保留自己独占的文件资源,放在自己缓存目录里的资源文件只能被这个会话自己使用,会话自己的临时文件都应该使用这个自己的缓存目录,主服务器节点有权访问和传递每个会话自己的独占文件给需要的客户端,即使文件在不同的远程服务器节点上。你可以使用UniServerModule.LocalCachePath方法得到当前会话自己的缓存目录,你可以使用UniServerModule.LocalCacheURL方法得到当前会话自己的缓存URL,你可以使用UniServerModule.NewCacheFileUrl方法得到一个唯一的本地缓存文件名用于存放各种文件,功能函数如下:
function NewCacheFileUrl(const Global:Boolean; const Ext, FileName, SubDir: string; var AUrl: string; AvoidBrowserCache: Boolean = False): string;
比如:
PdfFile := UniServerModule.NewCacheFileUrl(False, 'pdf', '', '', AUrl, True);
上面的代码,你可以获得一个自己的缓存文件名用于创建一个PDF文件,调用浏览器传入AUrl参数就可以打开这个PDF文件,如果想学习如何创建和使用会话自己的本地缓存文件,请查看UniGUI安装目录下提供的FastReport案例和Report builder案例(C:\Program Files (x86)\FMSoft\Framework\uniGUI\Demos\Desktop\FastReport – Dynamic和C:\Program Files (x86)\FMSoft\Framework\uniGUI\Demos\Desktop\Report Builder)。
- 如何在同一台机器上模拟多机部署
一般情况下,如果提及服务器农场集群都是指在多台机器上部署服务。每个服务器节点上的服务程序都是相同的,它们都具有相同的功能、它们都是相同的版本、它们都使用相同的端口,对于客户来说不管他的服务请求被哪个服务器节点处理,给他的感觉都是无差异的。有时为了方便我们想先在同一台机器上学习或测试服务器农场的集群部署,那么是否可以在同一台机器上部署多服务器集群呢?答案是肯定滴。你可以在同一台机器上运行多个服务器实例,但是他们应该安装在不同的目录下,并且需要使用各自独立的端口范围避免端口重叠。为了有效演示如何在同一台机器上模拟多服务器节点部署,我们规划了一个四个服务器节点的服务器农场集群,一个主服务器节点(ServerNode-Main)和三个从服务器节点(ServerNode-0、ServerNode-1、ServerNode-2),主服务器节点使用默认端口8077,也是对外提供服务的端口,三个从服务器节点分别使用8800、8811、8822端口,系统架构如下图所示:
本书将以EXE程序部署为例讲解如何单机部署多服务器节点集群,开发一个最简单的演示demo程序,为了标识每个客户的访问请求被分配到了哪个服务器节点上,我们把我们的演示程序demo编译成四个不同版本exe程序,每个demo的MainForm上放一个UniLabel控件,分别设置不同的Caption以显示区别,如下表所示:
服务器节点名称 | 程序目录 | ServerModule | MainForm | |
ServerModule->Port | Title | UniLabel->Caption | ||
ServerNode-Main | D:\ServerNode | 8077 | ServerNode-Main | ServerNode-Main:8077 |
ServerNode-0 | D:\ServerNode0 | 8800 | ServerNode-0 | ServerNode-0:8800 |
ServerNode-1 | D:\ServerNode1 | 8811 | ServerNode-1 | ServerNode-1:8811 |
ServerNode-2 | D:\ServerNode2 | 8822 | ServerNode-2 | ServerNode-2:8822 |
- 建立文件和目录结构
如下图所示,建立四个服务器节点目录,将你的四个不同版本的demo.exe程序和C:\Program Files (x86)\FMSoft\Framework\uniGUI\HyperServer\bin目录下的hyper_server.exe、hyper_server.cfg程序分别拷贝到四个目录下。
- 修改四个服务器节点的端口配置
这里要修改binary_name对应的程序,要修改port程序端口,要修改每个服务器节点的server_title,还要修改每个服务器节点的开始端口start_port,开始端口默认16384,在同一台机器里部署多个软集群时需要根据每个节点的max_nodes参数计算每个集群的开始端口大小,详见10.2.9章节介绍的端口分配规则增加,本节为了简单直接在默认参数16384基础上位每个子服务器节点的开始端口增加100。
① 主服务器节点
[hyper_server]
binary_name=demo.exe
port=8077
server_title=ServerNode-Main
[http_transport]
start_port=16384 默认值
② 0号从服务器节点
[hyper_server]
binary_name=demo.exe
port=8800
server_title=ServerNode-0
[http_transport]
start_port=16484 加100
③ 1号从服务器节点
[hyper_server]
binary_name=demo.exe
port=8811
server_title=ServerNode-1
[http_transport]
start_port=16584 加100
④ 2号从服务器节点
[hyper_server]
binary_name=demo.exe
port=8822
server_title=ServerNode-2
[http_transport]
start_port=16684 加100
- 生成三个子服务器节点的令牌值
分别运行三个“从服务器节点”目录下的hyper_server.exe,记住是在从服务器上运行、是运行hyper_server.exe而不是运行你的demo.exe,uniGUI将自动在hyper_server.cfg里生成token值:
[hyper_server]
binary_name=demo.exe
。。。
port=8800
allow_remote_config=1
token=elsvwn220115120518308
- 修改主服务器节点的配置文件
根据前面每个从服务器生成的token值和访问URL,在主服务器节点的hyper_server.cfg配置文件里增加每个从服务器的配置段:
[transport]
pool_size=0
command_timeout=20000
request_timeout=300000
connect_timeout=20000
[http_transport]
start_port=16384
[hyper_server]
binary_name=demo.exe
initial_nodes=2
max_nodes=0 为0时只做负载均衡转发、非0时兼职做服务处理
。。。
port=8077 集群对外公布的服务器端口
。。。
server_title=ServerNode-Main 集群服务控制器的标题
[login-0] 配置一个访问服务控制器界面的用户和密码
user_name=admin
password=111111
admin=1
[server-0]
enabled=1
url=http://127.0.0.1:8800
name=DELL-00
token=elsvwn220115120518308
[server-1]
enabled=1
url=http://127.0.0.1:8811
name=DELL-11
token=qozuaf220115120601471
[server-2]
enabled=1
url=http://127.0.0.1:8822
name=DELL-22
token=lmwmgg220115120913951
通过如上五步我们就成功搭建了一个单机多服务器节点集群的模拟环境,先运行三个从服务器节点目录下的hyper_server.exe,然后分别在本机打开浏览器访问每个从服务器节点确认从服务器节点的可用性,如果配置正确的话访问结果如下:
http://127.0.0.1:8800/(可用)、http://127.0.0.1:8811/(可用)、http://127.0.0.1:8822/(可用),此时,在本机访问我们集群的对外服务地址http://127.0.0.1:8077/或在其它电脑访问http://你的地址:8077/是失败的。好啦,现在请启动主服务器节点目录下的hyper_server.exe吧,再次访问对外服务地址时我们发现我们开发的demo项目的界面出现了,在浏览器里不断“打开新的标签页”访问这个8077端口的地址,我们发现每次出现的界面是变化的,UniLabel的Caption在“ServerNode-0:8800”、“ServerNode-1:8811”、“ServerNode-2:8822”之间不断变化,如果将主服务器节点的max_nodes参数设置为非0值,还会出现“ServerNode-Main:8077”。至此,你已经成功学会了如何搭建一个单机多服务器节点服务器农场集群环境。通过实践我们发现,虽然我们对外服务的端口是8077,但是主服务器节点和调用各个从服务器节点的服务端口未必是8077,也就是说在使用多台机器搭建服务器农场集群环境时,主服务器节点和从服务器节点之间的调用端口是可以差异化配置的,如果把从服务器节点的服务端口配置成和主服务器节点的端口不一样,也许在某种程度上能够提升从服务器的安全性。但是,这么做也有一点麻烦,你需要为每台从服务器编译一个使用不同端口的软件版本和修改每个从服务器节点的配置文件。
访问http://127.0.0.1:8077/server进入服务器集群的主控制器界面,HyperServer->Nodes界面里显示的是主服务器节点的节点资源,本案例将主服务器节点的max_nodes设置为0,它只做负载均衡转发,所以它将只有两个基本服务的软节点没有对客户提供服务的软节点。
切换到HyperServer->ServerNodes页面将显示服务器农场集群里配置的三个从服务器节点,它们的NodeId分别是1024、1025、1026,节点编号从1024开始由集群自动分配,在下图我们可以看到每个从服务器节点的节点编号、服务状态、访问URL、节点昵称、最大软节点数、当前软节点数、当前会话数信息。
点击一个从服务器节点记录末尾的“Actions”列里的搜索按钮,就可以打开该从服务器节点的服务控制器界面,比如打开第一个从服务器节点DELL-0,HyperServer->DELL-0->HyperServer->Nodes,我们就可查看从服务器节点DELL-0当前启动的软服务节点的数量和各个软服务节点的在线状态、活动时间、空闲时间、并发会话数等信息,如下图所示:
- 关于服务器农场集群的稳定性
我们部署服务器农场集群的目的就是提升我们应用程序的稳定性和可用性,往集群里多部署几个服务器节点很轻松就能大大提升系统的并发能力,但这并不是彻底提升系统稳定性和可用性的全部。大多数情况下我们的应用系统都需要访问一个后台数据库,HyperServer和HyperServer Farm都能提升应用系统的并发能力,但是后台数据库的并发能力并不能自动提升。在做系统集群设计时请不要忘记提升后台数据库的并发能力,当前端向服务器农场集群发起大量的并发访问时,很容易就会导致后台数据库服务器瘫痪。为了解决这个问题,后台数据库服务器也应该使用它们自有的集群部署技术和链接池技术。像FireDAC、Oracle等数据库都支持链接池,对于不支持链接池的数据库就得使用中间层实现连接池,Data Abstract和kbmMW都是可以在Delphi下开发数据库中间层的三方控件。