前言

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

执行命令:

/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

拷贝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

执行命令:

/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;
}

客户端程序代码:

#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;
}

"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的一个简单应用,后续文章会介绍它的高级部署模式。

Ice系列--强大如我IceGrid的更多相关文章

  1. Ice系列--基于IceGrid的部署方案

    前言 前一篇文章介绍了IceGrid的简单应用.这篇文章来介绍一下它的高端玩法-如何将模板,复制组,知名对象应用于部署方案及其作用. 基于模板的部署方案 之前介绍了xml格式的配置文件通过各种描述符如 ...

  2. 深入浅出Mybatis系列 强大的动态SQL

    上篇文章<深入浅出Mybatis系列(八)---mapper映射文件配置之select.resultMap>简单介绍了mybatis的查询,至此,CRUD都已讲完.本文将介绍mybatis ...

  3. Ice系列--傻瓜式服务开发IceBox

    前言 相信大家在没有接触过框架之前,都自己或多或少的开发过一些应用服务.每个应用服务除了业务配置还有很多环境配置,资源配置等,这些跟部署相关的配置.服务跟配置文件是一种静态绑定的方式,更新配置还需要重 ...

  4. ICE系列之3对象接口定义语言——slice

         Slice 定义由编译器编译到特定的实现语言 .编译器把与语言无关的定 义翻译成针对特定语言的类型定义和 API.开发者使用这些类型和 API 来 提供应用功能,并与 Ice 交互.用于各种 ...

  5. ICE系列之2——ICE的服务与好处

    ice服务: IcePack         我们在第 12 页提到过, IcePack 是 Ice 的定位服务,用于在使用间接绑定时把符号性的 (symbolic)适配器名解析为协议-地址对. 除了 ...

  6. ZeroC Ice IceGrid Node和IceGrid

    IceGrid Node介绍 绝大多数分布式系统都有一个共同特点,即分布在各个主机上的节点进程并不是完全独立的,而是彼此之间有相互联系和通信的.集群对集群中的节点有一些控制指令,如部署.启停或者调整某 ...

  7. ice介绍 z

    什么是ICE(Internet Communications Engine)呢,它是由Zeroc公司开 发的一套开源中间件系统,与DCOM,CORBA,WEB SERVICEDcom类似,支持RPC( ...

  8. IceGrid负载均衡部署 z

    [IceGrid负载均衡部署步骤]1.环境主机1:IP=192.168.0.239,上面部署注册表服务器registry和节点node1,registry和node1运行在同一进程中:主机2:IP=1 ...

  9. 使用spring boot和thrift、zookeeper建立微服务

    Spring cloud适应于云端服务,也适用于企业信息化SOA建设.spring boot也是restful微服务开发的利器.但对于内网服务,即服务与服务之间的调用,spring并没有去刻意封装,也 ...

随机推荐

  1. springmvc表单标签库的使用

    springmvc中可以使用表单标签库,支持数据绑定,用来将用户输入绑定到领域模型. 例子来源<Servlet.JSP和SpringMVC学习指南> 项目代码 关键代码及说明 bean对象 ...

  2. 浅谈JAVA代码优化

    JAVA代码的优化分为两个方面: 一.减小代码的体积.二.提高代码的执行效率. ============================================================ ...

  3. 多任务-python实现-生成器相关(2.1.13)

    @ 目录 1.概念 2.创建方法 3.通过send方式来启动 1.概念 通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的,而且创建一个包含100万个元素的列表,不仅占 ...

  4. matplotlib的学习12-Subplot 多合一显示

    import matplotlib.pyplot as plt # matplotlib 是可以组合许多的小图, 放在一张大图里面显示的. 使用到的方法叫作 subplot. plt.figure() ...

  5. 免杀shellcode并绕过杀毒添加自启动

    https://www.wtfsec.org/posts/%E5%85%8D%E6%9D%80shellcode%E5%B9%B6%E7%BB%95%E8%BF%87%E6%9D%80%E6%AF%9 ...

  6. 工作流学习之 IDEA 使用activiti插件 出现乱码

    今天学习 工作流 (work flow ) 的时候遇到了一点小问题 就是在 activitit的插件的时候 出现了乱码,弄了很久,终于解决了,就做个总结 嘻嘻 当场懵了,我记得我改了编码呀 - (Se ...

  7. Protobuf简单类型直接反序列化方法

    我有一个想法,有一个能够进行跨平台的高性能数据协议规范,能够让数据在两个不同的程序之间进行读取,最好能够支持直接将object序列化,那就完美了. 目标 支持任意Object序列化 支持从类似Syst ...

  8. MySQL高可用(二)主备延时如何解决?

    从上篇文章我们知道主备同步是依赖于 binlog,主库负责生产 binlog,备库负责消费 binlog,从而实现主备同步. 今天我们来学习一下主备同步里的一个重点的问题:主备延时. 主备延时,简单来 ...

  9. 每天学习一点ES6(二)let 和 const

    let 命令 let 和 var 差不多,只是限制了有效范围. 先定义后使用 不管是什么编程语言,不管语法是否允许,都要秉承先定义,然后再使用的习惯,这样不会出幺蛾子.以前JavaScript比较随意 ...

  10. Java学习_Java核心类

    字符串和编码 字符串在String内部是通过一个char[]数组表示的,因此,可以按下面的写法: String s2 = new String(new char[] {'H', 'e', 'l', ' ...