当前位置 博文首页 > whao2world:Ice系列--强大如我IceGrid

    whao2world:Ice系列--强大如我IceGrid

    作者:whao2world 时间:2021-01-21 18:05

    前言

    IceGrid是一个提供服务定位和服务激活的组件,但它的功能远不止于此。从它的命名可以看出它的设计理念—网格计算(grid computing)。网格计算被定义为由一系列关联的廉价计算机组成的计算网络。将写好的应用运行于网格计算中的主机上,只是应用整个生命周期中一部分工作。虽然Ice为应用的各个组成部分的之间通信提供了基础设施(RPC通信框架),但是我们还会面临很多挑战:

    • 如何安装升级网格计算中的应用
    • 如何跟踪网格计算中运行的服务
    • 如何分发负载到所有的主机
    • 如何将服务从一个主机迁移到另外一个主机
    • 如何快速添加一个主机到网格中

    今天看到这些分布式应用也面临问题时,是不是立马会想到容器,K8S,这个当下比较主流的解决方案。要知道Ice在十几年前就实现了一个成熟解决方案--IceGrid。以下是它的特性:

    • 定位服务(Location service)
    • 按需激活服务器(On-demand server activation)
    • 应用分发(Application distribution)
    • 复制和负载均衡(Replication and load balancing)
    • 会话和资源分配(Sessions and resource allocation)
    • 自动故障恢复(Automatic failover)
    • 动态查询(Dynamic queries)
    • 管理(Adminstration)
    • 部署(Deployment)

    IceGrid使得开发人员摆脱了这些低级的任务,加快了应用构建,简化了应用部署管理。

    原理框架

    IceGrid主要有两个重要的组成:注册中心(registry)和节点(node)。注册中心主要是维护服务路由信息,以及一个客户端请求过来后,去启动指定服务器;

    或者根据各个主机的负载情况,返回路由信息。节点可以看做一个服务器集合,管理着这些服务器。如下图,一个简单的IceGrid应用:

    从客户端角度,registry就是一个名字服务,将间接代理标识串,如 SimplePrinter@PrinterAdapter转化成服务器连接端点。

    以一次客户端调用为例:

    1.客户端先向注册中心发起定位请求,通过间接代理标识串获取到对象适配器(PrinterAdapter)的服务地址端口

    2.通过服务地址端口与Server(PrinterServer)建立连接

    3.调用checkedCast,检验对象(SimplePrinter)是否存在

    4.如果服务对象存在,则发起远程调用过程。不存在则抛出异常

    环境部署

    软件包安装参考官方文档。本文章运行的环境是:ubuntu 16.04,ice 3.7.2

    registry和node的启动脚本和配置文件见:https://github.com/GodMonking/ice-demo/tree/main/deploy

    启动registry

    配置文件registry.cfg:

    # Registry properties
    IceGrid.InstanceName=MKIceGrid
    
    Ice.Default.Locator=MKIceGrid/Locator:tcp -p 4061
    
    IceGrid.Registry.ReplicaName=Master
    #IceGrid.Registry.Client.Endpoints=tcp -p 4061
    IceGrid.Registry.Client.Endpoints=tcp -p 4061
    IceGrid.Registry.Server.Endpoints=tcp
    IceGrid.Registry.Internal.Endpoints=tcp
    
    IceGrid.Registry.AdminPermissionsVerifier=MKIceGrid/NullPermissionsVerifier
    IceGrid.Registry.AdminPermissionsVerifier=MKIceGrid/NullPermissionsVerifier
    IceGrid.Registry.SSLPermissionsVerifier=MKIceGrid/NullSSLPermissionsVerifier
    IceGrid.Registry.AdminSSLPermissionsVerifier=MKIceGrid/NullSSLPermissionsVerifier
    IceGrid.Registry.Discovery.Interface=127.0.0.1
    
    IceGrid.Registry.LMDB.MapSize=10
    #注册中心数据保存路径
    IceGrid.Registry.LMDB.Path=/data/ice-demo/deploy/registry
    IceGrid.Registry.DynamicRegistration=1
    
    IceGrid.Registry.Trace.Node=1
    IceGrid.Registry.Trace.Replica=1
    
    #
    # Dummy username and password for icegridadmin.
    #
    IceGridAdmin.Username=foo
    IceGridAdmin.Password=bar
    View Code

    执行命令:

    /usr/bin/icegridregistry --Ice.Config=./config/registry.cfg --daemon

    启动node

    启动两个node节点

    配置文件node.cfg:

    # Node properties
    #默认定位器,即注册中心的服务地址端口
    Ice.Default.Locator=MKIceGrid/Locator:tcp -p 4061
    IceGrid.Node.Endpoints=tcp
    IceGrid.Node.Name=node1
    #数据存储路径
    IceGrid.Node.Data=/data/ice-demo/deploy/node1
    #日志输出路径
    IceGrid.Node.Output=/tmp/node1
    IceGrid.Node.Trace.Replica=2
    IceGrid.Node.Trace.Activator=3
    IceGrid.Node.Trace.Adapter=3
    IceGrid.Node.Trace.Server=3
    View Code

    拷贝node.cfg :cp node.cfg node2.cfg

    修改配置node2.cfg结果如下:

    # Node properties
    Ice.Default.Locator=MKIceGrid/Locator:tcp -p 4061
    IceGrid.Node.Endpoints=tcp
    IceGrid.Node.Name=node2
    IceGrid.Node.Data=/data/ice-demo/deploy/node2
    IceGrid.Node.Output=/tmp/node2
    IceGrid.Node.Trace.Replica=2
    IceGrid.Node.Trace.Activator=3
    IceGrid.Node.Trace.Adapter=3
    IceGrid.Node.Trace.Server=3
    View Code

    执行命令:

    /usr/bin/icegridnode --Ice.Config=./config/node.cfg –daemon
    /usr/bin/icegridnode --Ice.Config=./config/node2.cfg –daemon

    通过命令行工具查看是否部署成功:

    /usr/bin/icegridadmin -H localhost -P 4061

    由于注册中心没有开启鉴权,所以这里账号密码任意输入。

    也可以通过IceGrid GUI工具查看。Windows下安装IceGrid GUI,打开IceGrid GUI,新建一个连接,登录注册中心

     

    服务部署

    部署配置文件,客户端程序和服务端程序代码见:

    https://github.com/GodMonking/ice-demo/tree/main/IceGrid/Printer

    简单应用开发

    服务端部分代码:

    int
    main(int argc, char* argv[])
    {
        try
        {
            if (argc < 2)
            {
                cerr << "not input config file" << endl;
                return 1;
            }
    
            Ice::CommunicatorHolder ich(argc, argv);
            auto communicator = ich.communicator();
            auto properties = communicator->getProperties();
            cout << "adapter: " << properties->getProperty("SimplePrinterAdapter.AdapterId") << endl;
            //注意这里的对象适配器名字要与下文的部署配置中的adaptor的属性name保持一致
            auto adapter = ich->createObjectAdapter("SimplePrinterAdapter");
            auto servant = make_shared<PrinterI>();
            adapter->add(servant, Ice::stringToIdentity("SimplePrinter"));
            adapter->activate();
            cout << "activate complete..." << endl;
            ich->waitForShutdown();
        }
        catch(const std::exception& e)
        {
            cerr << e.what() << endl;
            return 1;
        }return 0;
    }
    View Code

    客户端程序代码:

    #include <Ice/Ice.h>
    #include <Printer.h>
    #include <stdexcept>
     
    using namespace std;
    using namespace Demo;
     
    int
    main(int argc, char* argv[])
    {
        try
        {
            //Ice::CommunicatorHolder ich(argc, argv, "config.client");        
            Ice::CommunicatorHolder ich(argc, argv);        
            auto base = ich->stringToProxy("SimplePrinter@SimplePrinterAdapter");
            auto printer = Ice::checkedCast<PrinterPrx>(base);
            if(!printer)
            {
                throw std::runtime_error("Invalid proxy");
            }
     
            printer->printString("Hello World!");
        }
        catch(const std::exception& e)
        {
            cerr << e.what() << endl;
            return 1;
        }
        return 0;
    }
    View Code

    "SimplePrinter@SimplePrinterAdapter"表示一个间接代理的标识字符串,

    SimplePrinterAdapter表示对象适配器ID,对应下文部署配置中adaptor的属性id值。

    客户端配置文件config.client:

    Ice.Default.Locator=MKIceGrid/Locator:tcp -p 4061

    上述配置表示一个定位器,定位器即注册中心提供服务地址端口。

    部署配置文件

    应用程序部署配置文件主要是向注册中心描述几个重要元素:Nodes,Servers,Object adaptors,Objects。如下图配置文件:

    <icegrid>
        <application name="Ripper">
            <node name="node1">
                <server id="PrinterServer" exe="/data/ice-demo/IceGrid/Printer/server" activation="on-demand">
                    <adapter name="SimplePrinterAdapter" id="SimplePrinterAdapter" endpoints="tcp"/>
                    <property name="Ice.Trace.Network" value="1"/>
                    <property name="Ice.PrintStackTraces" value="1"/>
                    <property name="Ice.Admin.Endpoints" value="tcp" />
                </server>
            </node>
        </application>
    </icegrid>

    上图中,元素node描述了server归属于node1节点,即表明PrinterServer部署在node1所在主机上。元素server的属性exe则描述可执行文件的路径,

    属性activation描述服务器激活方式,“on-demand”表示按需激活,即有请求达到时才被激活。元素adaptor描述了对象适配器(Object adaptor)的信息。

    通过IceGrid GUI部署应用

    点击如下箭头所指按钮

     打开配置文件 

     加载之后生成表单,如下;点击箭头所指按钮,将配置保存到注册中心

     可以看到node1下面已经有服务PrinterServer

    验证服务

    执行客户端程序

    ./client --Ice.Config=config.client

    可以看到服务被激活

     

     选择服务右击鼠标,查看标准输出信息:

     

    结尾

    IceGrid不仅提供了定位服务,负载均衡等功能,同时还简化了服务发布和部署。本文介绍了IceGrid的一个简单应用,后续文章会介绍它的高级部署模式。