前言
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的一個簡單應用,後續文章會介紹它的高階部署模式。