前言

前一篇文章介绍了IceGrid的简单应用。这篇文章来介绍一下它的高端玩法—如何将模板,复制组,知名对象应用于部署方案及其作用。

基于模板的部署方案

之前介绍了xml格式的配置文件通过各种描述符如node,server,adaptor等,描述应用部署信息。当服务部署复杂度增加时,书写这些描述符是件头疼的事。

模板(Template)能大大简化描述符的书写;同时参数化使得模板的使用更加灵活。我们可以为描述符serverservice定义模板,这个章节主要介绍

Server Template,在IceBox部署章节再介绍Service Template。

服务器模板(Server Templates)

我们继续使用之前的例子做一下扩展,将PrinterServer部署到两个node节点。

<icegrid>
<application name="Ripper">
<node name="node1">
<server id="PrinterServer1" exe="/data/ice-demo/IceGrid/Printer/server" activation="on-demand">
<adapter name="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>
<node name="node2">
<server id="PrinterServer2" exe="/data/ice-demo/IceGrid/Printer/server" activation="on-demand">
<adapter name="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>

上述xml文件中,先来看一下最上面的模板定义,server-template作为服务器模板的描述符描述了一个模板的信息,属性id作为区别其他模板的标识。

模板参数的定义,通过parameter描述符来定义,name指定参数名称,default指定其默认值。这里“index”就是模板参数名,其值通过”${index}”方式获取。

模板中其他描述符的定义与之前没有差别。server-instance描述符是用来实例化一个server的,它属性template,index都是作为参数,template指定了

模板(PrinterServerTemplate),index作为参数传递给了模板。

通过IceGrid GUI工具部署服务,如下:

使用之前Printer客户端程序测试一下:

结果抛出异常,对象适配器id“SimplePrinterAdapter”没有注册。

由于上面xml只是定义adaptor的name,没有定义id。所以有可能对象适配器的Id可能不是“SimplePrinterAdapter”。

通过界面工具查看到PrinterServer1的SimplePrinterAdapter的适配器ID为”PrinterServer1.SimplePrinterAdapter”。

PrinterServer2的SimplePrinterAdapter的适配器ID为”PrinterServer2.SimplePrinterAdapter”

从这里可以看出,如果用户不定义描述符adaptor的id则系统会生成一个${server}.${name}的对象适配器ID。

修改客户端程序:

...
try
{
//Ice::CommunicatorHolder ich(argc, argv, "config.client");
Ice::CommunicatorHolder ich(argc, argv);
auto base = ich->stringToProxy("SimplePrinter@PrinterServer1.SimplePrinterAdapter");
auto printer = Ice::checkedCast<PrinterPrx>(base);
if(!printer)
{
throw std::runtime_error("Invalid proxy");
} printer->printString("Hello World!");
}
catch(const std::exception& e)
...

测试调用成功:

这里就有一个问题了,同一个服务,两个实例分别部署在两个节点。客户端调用服务还需要间接代理指定不同对象适配器ID才能请求到不同实例。

是不是感觉这个有点low,不应该像DNS那样一个域名解析请求,返回多个IP地址吗?Ice作为RPC框架的佼佼者,这个小问题怎么可能没有考虑到。

之前提到过的对象适配器复制和复制组(Replica Group)就是为了解决这个问题,同时也是实现对客户端透明的负载均衡的基础。

复制组(Replica Group)

之前文章做过简单介绍,对象适配器复制简单地讲就是多个服务实例,复制组就是一个对象适配器集合,这个集合映射到多个服务实例的地址端口;

这个映射关系是由注册中心来维护的。所以客户端可以将复制组看做一个虚拟对象适配器,不需要关心它与实际服务实例的映射。

使用复制组来部署Printer服务:

<icegrid>
<application name="Printer">
<replica-group id="PrinterAdapters">
<load-balancing type="random" n-replicas="0"/>
<!-- 此处还可以添加知名对象的定义(Well-Know Object) -->
</replica-group>
<server-template id="PrinterServerTemplate">
<parameter name="index"/>
<server id="PrinterServer${index}" exe="/data/ice-demo/IceGrid/Printer/server" activation="on-demand">
<adapter name="SimplePrinterAdapter" endpoints="tcp" replica-group="PrinterAdapters"/>
<property name="Ice.Trace.Network" value="1"/>
<property name="Ice.PrintStackTraces" value="1"/>
<property name="Ice.Admin.Endpoints" value="tcp" />
</server>
</server-template>
<node name="node1">
<server-instance template="PrinterServerTemplate" index="3"/>
</node>
<node name="node2">
<server-instance template="PrinterServerTemplate" index="4"/>
</node>
</application>
</icegrid>

这个版本的xml文件相比之前,添加了复制组的定义和在描述adaptor添加了属性replica-group,这表示将对象适配器加入了复制组。

通过IceGrid GUI工具部署服务,如下:

修改客户端程序,将对象适配器ID—“PrinterServer1.SimplePrinterAdapter”替换成复制组ID—“PrinterAdapters”,代码如下:

...
try
{
//Ice::CommunicatorHolder ich(argc, argv, "config.client");
Ice::CommunicatorHolder ich(argc, argv);
auto base = ich->stringToProxy("SimplePrinter@PrinterAdapters");
auto printer = Ice::checkedCast<PrinterPrx>(base);
if(!printer)
{
throw std::runtime_error("Invalid proxy");
} printer->printString("Hello World!");
}
catch(const std::exception& e)
...

测试一下,执行n次调用之后

调用都有请求到了PrinterServer3,PrinterServer4。

知名对象(Well-Known Object)

上一个小节留下了一个坑,现在来填。可能有人觉得这种形式“SimplePrinter@PrinterAdapters”的间接代理不够简洁,接下来介绍一种更简洁的--知名代理。

它只由一个对象ID组成,而这样的对象被定义为知名对象。注册中心不仅存储了知名对象ID与代理的关系,同时还有对象类型。这此对象类型一般是加上

完整的命名空间的Slice Type,如::Demo::Printer;它的主要作用还是用来进行服务查询。

在上一节的例子基础上,加入知名对象,进行部署:

<icegrid>
<application name="Printer">
<replica-group id="PrinterAdapters">
<load-balancing type="random" n-replicas="0"/>
<!-- 此处还可以添加知名对象的定义(Well-Know Object) -->
<object identity="SimplePrinter" type="::Demo::Hello" />
</replica-group>
<server-template id="PrinterServerTemplate">
<parameter name="index"/>
<server id="PrinterServer${index}" exe="/data/ice-demo/IceGrid/Printer/server" activation="on-demand">
<adapter name="SimplePrinterAdapter" endpoints="tcp" replica-group="PrinterAdapters"/>
<property name="Ice.Trace.Network" value="1"/>
<property name="Ice.PrintStackTraces" value="1"/>
<property name="Ice.Admin.Endpoints" value="tcp" />
</server>
</server-template>
<node name="node1">
<server-instance template="PrinterServerTemplate" index="3"/>
</node>
<node name="node2">
<server-instance template="PrinterServerTemplate" index="4"/>
</node>
</application>
</icegrid>

IceBox集成入IceGrid

之前文章介绍过IceBox,这个非常有用的组件不集成到IceGrid部署方案中,岂不浪费。

部署IceBox Server

一个简单IceBox Server部署配置文件如下:

<icegrid>
<application name="IceBoxDemo">
<node name="node1">
<icebox id="IceBoxServer" exe="/usr/bin/icebox++11" activation="always" pwd="/opt/ice/Hello">
<env>LD_LIBRARY_PATH=/opt/ice-demo/IceGrid/lib:$LD_LIBRARY_PATH</env>
<property name="Ice.Admin.Endpoints" value="tcp" />
<service name="Hello" entry="HelloI:create">
<adapter name="${service}" endpoints="tcp"/>
<property name="Ice.Trace.Network" value="1" />
<property name="Ice.Trace.ThreadPool" value="1"/>
<property name="Ice.PrintStackTraces" value="1"/>
</service>
</icebox>
</node>
</application>
</icegrid>

可以看到这里出现了两个新的描述符iceboxservice,跟部署server很相似,不同点在于serviceservice也包含对象适配器,配置属性这些描述信息。

一个icebox下可以定义多个serviceservice的顺序决定了被加载的顺序。

通过IceGrid GUI工具部署,结果如下:

Service Templates

server template很类似,service template是用来描述service的。废话不多说,先来看一个简单实例:

<icegrid>
<application name="IceBoxDemov2">
<service-template id="ServiceTemplate">
<parameter name="name" />
<service name="${name}" entry="HelloI:create">
<adapter name="${service}" endpoints="tcp"/>
<property name="${service}.Identity" value="${server}-${service}"/>
<property name="Ice.Trace.Network" value="1" />
<property name="Ice.PrintStackTraces" value="1"/>
</service>
</service-template>
<node name="node1">
<icebox id="IceBoxServerv2" exe="/usr/bin/icebox++11" activation="on-demand" pwd="/opt/ice/Hello">
<env>LD_LIBRARY_PATH=/data/ice-demo/IceGrid/lib:$LD_LIBRARY_PATH</env>
<property name="Ice.Admin.Endpoints" value="tcp" />
<service-instance template="ServiceTemplate" name="Liming"/>
<service-instance template="ServiceTemplate" name="Jane"/>
<service-instance template="ServiceTemplate" name="Machel"/>
</icebox>
</node>
</application>
</icegrid>

此icebox server(IceBoxServerv2)下通过service模板定义三个模板实例。可以看到icebox server的定义依然,不够简洁。

升级版Service Templates

在Server Template中实例化Service Template:

<icegrid>
<application name="IceBoxDemov3">
<service-template id="ServiceTemplate">
<parameter name="name" />
<service name="${name}" entry="HelloI:create">
<adapter name="${service}" endpoints="tcp"/>
<property name="${service}.Identity" value="${server}-${service}"/>
<property name="Ice.Trace.Network" value="1" />
<property name="Ice.PrintStackTraces" value="1"/>
</service>
</service-template>
<server-template id="ServerTemplate">
<parameter name="icebox_id" />
<parameter name="name" />
<icebox id="${icebox_id}" exe="/usr/bin/icebox++11" activation="on-demand">
<env>LD_LIBRARY_PATH=/data/ice-demo/IceGrid/lib:$LD_LIBRARY_PATH</env>
<property name="Ice.Admin.Endpoints" value="tcp" />
<service-instance template="ServiceTemplate" name="${name}" />
</icebox>
</server-template>
<node name="node1">
<server-instance template="ServerTemplate" icebox_id="IceBoxServerv3-1" name="Babala" />
</node>
<node name="node2">
<server-instance template="ServerTemplate" icebox_id="IceBoxServerv3-2" name="Maria" />
</node>
</application>
</icegrid>

负载均衡

之前讲过复制组的另一个作用就是负载均衡;ICE的负载均衡是在注册中心实现的。IceGrid的节点会向注册中心上报主机系统负载信息,注册中心会根据复制组(replica groups)配置的负载均衡策略来决定如何处理定位请求。

IceGrid的负载均衡能力可以帮助客户端获取一个包含服务连接端点集合的代理,与服务者建立一个连接。一旦客户端建立了一个连接,在没有与注册中心进一步交互协商的情况下,所有后续请求都是发送到同一个Server。这就是说如果客户端想动态的获取路由信息,需要周期性主动发起定位请求更新服务连接端点。

复制组的负载均衡

复制组可以包含负载均衡描述符(load-balancing),来决定如何根据系统负载来返回服务路由信息。负载均衡描述符包含几个属性来描述负载均衡的策略:

  • 类型

  支持的几种负载均衡类型

  • 取样间隔

  以一定的间隔采样各个节点负载信息

  • 复制数量

  配置数值为N。若未配置,默认配置为1。若N>1,则返回对象适配器连接端点数量最多为N;N=0,则返回所有连接端点。

格式如下:

<replica-group id="ReplicatedAdapter">
  <load-balancing type="adaptive" load-sample="5" n-replicas="2"/>
</replica-group>

负载均衡的类型

  • 随机(Random)

  不考虑节点系统负载,随机返回服务连接端点

  • 自适应(Adaptive)

  根据系统负载,返回负载最少的节点的服务连接端点

  • 循环(Round Robin)

  不考虑节点系统负载,返回最近最少被使用的对象适配器的服务连接端点。

  • 排序(Order)

  根据对象适配器配置的优先级,来排序返回服务连接端点

最终部署方案

一个客户端调用简单,动态配置,服务冗余,负载均衡的方案--IceBox + Server Templates + Service Templates + 复制组。

<icegrid>
<application name="IceBoxDemov3">
<service-template id="ServiceTemplate">
<parameter name="name" />
<service name="${name}" entry="HelloI:create">
<adapter name="${service}" endpoints="tcp" replica-group="HelloGroup" />
<property name="${service}.Identity" value="${server}-${service}"/>
<property name="Ice.Trace.Network" value="1" />
<property name="Ice.PrintStackTraces" value="1"/>
</service>
</service-template>
<server-template id="ServerTemplate">
<parameter name="icebox_id" />
<icebox id="${icebox_id}" exe="/usr/bin/icebox++11" activation="on-demand">
<env>LD_LIBRARY_PATH=/opt/ice/Hello-v3/lib:$LD_LIBRARY_PATH</env>
<property name="Ice.Admin.Endpoints" value="tcp" />
<service-instance template="ServiceTemplate" name="Liming" />
</icebox>
</server-template>
<replica-group id="HelloGroup">
<load-balancing type="adaptive" load-sample="5" n-replicas="1" />
<object identity="HelloImp" type="::Demo::Hello" />
</replica-group>
<node name="node1">
<server-instance template="ServerTemplate" icebox_id="IceBoxServerv4-1" />
</node>
<node name="node2">
<server-instance template="ServerTemplate" icebox_id="IceBoxServerv4-2" />
</node>
</application>

结尾

IceGrid的各种部署方案基本介绍完了,完整用例源码见文章最后的github连接。

ICE这个框架细节的东西比较多,只有实践才能慢慢掌握它,希望这篇文章能帮助想入坑ICE的同学打开大门。

注:源码连接 https://github.com/GodMonking/ice-demo/tree/main/IceGrid

Ice系列--基于IceGrid的部署方案的更多相关文章

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

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

  2. 基于webhook方案的Git自动部署方案

    之前已经用Git实现了自己博客的提交自动部署,并自动提交到GitHub和coding以备不时之需.平时项目代码都托管在Coding或者GitHub上,也已经用上了coding提供的webhook功能, ...

  3. Ice系列--强大如我IceGrid

    前言 IceGrid是一个提供服务定位和服务激活的组件,但它的功能远不止于此.从它的命名可以看出它的设计理念-网格计算(grid computing).网格计算被定义为由一系列关联的廉价计算机组成的计 ...

  4. 重复造轮子系列——基于Ocelot实现类似支付宝接口模式的网关

    重复造轮子系列——基于Ocelot实现类似支付宝接口模式的网关 引言 重复造轮子系列是自己平时的一些总结.有的轮子依赖社区提供的轮子为基础,这里把使用过程的一些觉得有意思的做个分享.有些思路或者方法在 ...

  5. spring boot 自动部署方案

    现在主流的自动部署方案大都是基于Docker的了,但传统的自动部署方案比较适合中小型公司,下面的方案就是比较传统的自动部署方案. 1.为什么需要自动部署 基于微服务的架构,自动部署显得非常重要.因为每 ...

  6. iOS动态部署方案

    转载: iOS动态部署方案 前言 这里讨论的动态部署方案,就是指通过不发版的方式,将新的内容.新的业务流程部署进已发布的App.因为苹果的审核周期比较长,而且苹果的限制比较多,业界在这里也没有特别多的 ...

  7. 【Xamarin开发 Android 系列 1】环境部署搭建

    原文:[Xamarin开发 Android 系列 1]环境部署搭建 开篇自然先扯一段,近几年移动互联网如果熊猫零食一样,蔓延迅速.楼主身为一个微软忠实的粉丝,无奈,老爹不给力.Silverlight开 ...

  8. JS组件系列——基于Bootstrap Ace模板的菜单Tab页效果优化

    前言:之前发表过一篇  JS组件系列——基于Bootstrap Ace模板的菜单和Tab页效果分享(你值得拥有) ,收到很多园友的反馈,当然也包括很多诟病,因为上篇只是将功能实现了,很多细节都没有处理 ...

  9. Kvm虚拟化的一种打包及部署方案(采用tar包,lvm方式)

    Kvm虚拟化的一种打包部署方案(采用tar包,lvm方式) –-–-–-2016年终总结 一 毕业之后跟师兄学到的第一块主要内容,理解花了不少时间.期间经历了shell的入门.linux基础知识入门. ...

随机推荐

  1. oranges 笔记第六章

    OS 第六次实验随笔 第六章6.1-6.3相关的问题 进程状态保存与恢复 哪些状态 何时保存 保存在哪 如何恢复 特权级变换 用户进程到内核 内核回到用户进程 再次理解TSS .堆栈 从外环进入内环( ...

  2. [OI笔记]三种逆元的求法

    其实这篇博客只是搬运一下我之前(大概是NOIP那会)写在word里的笔记- 下面直接复制原话,题目是洛谷上求逆元的模板题:https://www.luogu.org/problemnew/show/P ...

  3. 制作3D小汽车游戏(上)

    之前一段时间家里和公司的事太多,一直没有时间写博客,最近腾出一段时间,看了一遍官方的examples,收货颇多,想整理一点东西出来,又苦于没有好的东西,three写点东西真是太难了.好吧,今天郭先生就 ...

  4. Java安全之Shiro 550反序列化漏洞分析

    Java安全之Shiro 550反序列化漏洞分析 首发自安全客:Java安全之Shiro 550反序列化漏洞分析 0x00 前言 在近些时间基本都能在一些渗透或者是攻防演练中看到Shiro的身影,也是 ...

  5. Autofac官方文档翻译--一、注册组件--1注册概念

    官方文档:http://docs.autofac.org/en/latest/register/registration.html 一.注册概念 使用Autofac 注册组件,通过创建一个Contai ...

  6. CentOS7 实战源码部署apache网站服务器

    简介:实战演练apache网站服务器的搭建 Apache简介: Apache软件基金会的一个开源免费的网页服务器,也是目前世界上使用最广泛的一种web server , apache最出名的是它跨平台 ...

  7. [LeetCode]实现数学计算

    乘方 思路是:pow(x,n) = pow(x,n/2)*pow(x,n-n/2) 递归实现 public double myPow(double x, int n) { if (n==0) retu ...

  8. 通过naa在esxi主机上找到物理磁盘的位置

    因为有一块磁盘告警,需要找到这个块磁盘.通过网络搜索就找到了这个shell脚本. 感谢 Jorluis Perales, VxRail TSE 2 shell脚本: # Script to obtai ...

  9. OpenGL投影矩阵(Projection Matrix)构造方法

    (翻译,图片也来自原文) 一.概述 绝大部分计算机的显示器是二维的(a 2D surface).在OpenGL中一个3D场景需要被投影到屏幕上成为一个2D图像(image).这称为投影变换(参见这或这 ...

  10. 使用sqlmap

    实验环境要求: 1.安装win7或win10的笔记本或PC电脑一台,硬盘100GB,内存8GB 2.安装VMware Workstation 14以上 总体目标:基于centos7搭建dvwa web ...