Apache Ignite 學習筆記(三): Ignite Server和Client節點介紹
在前兩篇文章中,我們把Ignite叢集當做一個黑盒子,用二進位制包自帶的指令碼啟動Ignite節點後,我們用不同的客戶端連線上Ignite進行操作,展示了Ignite作為一個分散式記憶體快取,記憶體資料庫的基本功能。從這篇文章開始,讓我們開啟這個黑盒子,逐步的深入到Ignite內部瞭解更多的特性。
Ignite叢集沒有采用master/slave架構設計。在叢集裡,每個節點都是平等的,並且可以互相通訊,這樣的架構保證Ignite叢集可以新增,移除節點,對叢集的記憶體容量進行不間斷的擴容/減容。也使得Ignite叢集有很強的容錯能力,可以快速的檢測到一個或多個失效節點並恢復。 但在前面的文章中,我們提到過在Ignite叢集裡有client和server節點,還有thin client。剛開始我也不理解為什麼要引入這麼多不同角色的節點,但Ignite作為一個數據網格,計算網格以及服務網格,不同角色的節點在不同的場景下都有其作用。 這篇文章裡,我們先比較一下client和server節點有什麼不同;然後介紹下不同場景下,應該採用什麼樣的節點來搭建叢集;最後我們看看如何在你自己的Java程式裡啟動一個server或者client節點。
Client和Server節點比較
- Serve節點:儲存資料,參與快取,執行計算和流處理,部署服務網格。換句話說,server節點是功能最全的節點。預設情況下,啟動一個Ignite節點都是以server節點的角色啟動。
- Client節點:不儲存資料,但是可以通過Ignite APIs連線到server節點上,進行快取的讀寫,參與計算任務,流處理,事務和服務網格。和server節點不同,如果需要把一個節點作為client節點,需要修改預設的配置。Client節點和server節點同時組成了Ignite叢集,所以它們可以相互發現,相互連線。
- Thin client:上一篇文章我們做過介紹,thin client不會加入Ignite的叢集拓撲,它也不儲存資料,也不參與執行計算和流處理。和Ignite原生的client節點不同,它並不感知叢集的拓撲結構變化(增加/刪除節點後,thin client並不知道),而且一次只能和Ignite叢集中的一個節點連線通訊,當該節點失效後,它會從事先配置好節點列表中挑選一個新的節點,重新連線。
下圖就展示了不同節點能提供的能力,以及它們互相之間的連線關係:
Thin client是跑在Ignite叢集外的,它只能連線叢集中某些節點,所有的操作和資料傳輸都需要通過這些節點。Client和server節點組成了Ignite叢集的拓撲,它們之間是可以互相發現以及互相通訊的,可以充分利用不同節點間的頻寬進行資料傳輸。除了不能儲存資料,client和server節點基本一樣。那為什麼Ignite還需要引入client和server不同的節點呢?Ignite同時提供了資料網格,計算網格和服務網格服務,通過client和server節點,可以很方便的實現儲存和計算分離的架構。設想一下,如果所有服務都部署在同一組節點來提供,如果計算任務需要消耗大量系統資源,或者需要升級計算/服務網格,勢必要影響要影響資料服務。反之,對資料網格的減容,擴容也會影響計算和服務網格。因此,我們可以將計算網格和服務網格部署在client節點上,而資料網格部署在server節點上,這樣保證了計算和資料服務不會互相競爭資源,而且可以獨立的對計算和資料網格進行減容/擴容。當然,這麼做的一個缺點client節點都需要通過server節點獲取資料,對一些追求高效能的計算任務來說,網路延時和頻寬就有可能成為瓶頸。對於這種場景,我們可以將client節點和server節點部署在同一臺主機上,減少一部分的網路傳輸。
在應用程式中啟動Ignite server/client節點
前兩篇文章,我們通過二級制安裝包中的指令碼啟動幾個server節點,組成Ignite叢集,現在讓我們來看看怎麼在自己的程式碼裡啟動一個server節點或者是client節點。
啟動server節點程式碼
我們先來看看啟動server節點的程式碼:
public class IgniteServerNodeExample {
public static void main(String[] args) {
Ignite ignite;
if(args.length == 1 && !args[0].isEmpty())
{
//如果啟動時指定了xml配置檔案,則用指定的配置檔案
System.out.println("Use " + args[0] + " to start.");
ignite = Ignition.start(args[0]);
}
else
{
//如果啟動時沒指定配置檔案,則生成一個配置檔案
System.out.println("Create an IgniteConfiguration to start.");
TcpDiscoverySpi spi = new TcpDiscoverySpi();
TcpDiscoveryMulticastIpFinder ipFinder = new TcpDiscoveryMulticastIpFinder();
ipFinder.setMulticastGroup("224.0.0.251");
spi.setIpFinder(ipFinder);
IgniteConfiguration cfg = new IgniteConfiguration();
cfg.setDiscoverySpi(spi);
ignite = Ignition.start(cfg);
}
// 建立一個TEST快取並寫入一些資料, key是城市的名字,value是省的名字
IgniteCache<String, String> cityProvinceCache = ignite.getOrCreateCache("TEST");
cityProvinceCache.put("Edmonton", "Alberta");
cityProvinceCache.put("Markham", "Ontario");
cityProvinceCache.put("Montreal", "Quebec");
}
}
在啟動Ignite節點時,我們需要傳入節點的配置資訊。程式碼裡我們用了兩種方式:1)如果啟動時傳入一個xml配置檔案路徑,我們就用該配置檔案啟動節點;2)如果沒指定配置檔案,我們就在程式碼裡生成一個IgniteConfiguration物件,並配置Ignite節點用multicast的方式發現區域網內的其他節點並組成叢集(除了multicast,Ignite還支援指定靜態ip地址或者用zookeeper進行節點探測發現,具體的配置方式會有一篇文章專門來介紹)。xml配置檔案中的每個配置項都可以通過IgniteConfiguration物件用程式碼進行配置,所以二者是等效的。和程式碼裡IgniteConfiguration物件等效的xml配置如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="discoverySpi">
<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
<property name="ipFinder">
<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
<property name="multicastGroup" value="224.0.0.251"/>
</bean>
</property>
</bean>
</property>
</bean>
</beans>
在用Ignite.start()啟動節點後,我們在server節點上建立了一個名字叫“TEST”的快取,快取的key是城市的名字(String),value是城市所在省份的名字(String)。 然後往快取裡插入三條資料。
啟動Client節點的程式碼
下面是啟動client節點的程式碼:
public class IgniteClientNodeExample {
public static void main(String[] args) {
Ignite ignite;
if(args.length == 1 && !args[0].isEmpty())
{
//如果啟動時指定了配置檔案,則用指定的配置檔案
System.out.println("Use " + args[0] + " to start.");
ignite = Ignition.start(args[0]);
}
else
{
//如果啟動時沒指定配置檔案,則生成一個配置檔案
System.out.println("Create an IgniteConfiguration to start.");
TcpDiscoverySpi spi = new TcpDiscoverySpi();
TcpDiscoveryMulticastIpFinder ipFinder = new TcpDiscoveryMulticastIpFinder();
ipFinder.setMulticastGroup("224.0.0.251");
spi.setIpFinder(ipFinder);
IgniteConfiguration cfg = new IgniteConfiguration();
cfg.setDiscoverySpi(spi);
//顯式配置client模式啟動該節點.
cfg.setClientMode(true);
ignite = Ignition.start(cfg);
}
//從ignite中讀取快取,並讀取資料
IgniteCache<String, String> cityProvinceCache = ignite.getOrCreateCache("TEST");
System.out.println("Montreal is in " + cityProvinceCache.get("Montreal"));
System.out.println("Edmonton is in " + cityProvinceCache.get("Edmonton"));
System.out.println("Markham is in " + cityProvinceCache.get("Markham"));
System.out.println("Toronto is in " + cityProvinceCache.get("Toronto"));
}
}
和server節點的程式碼類似,啟動client節點時我們同樣可以傳入一個xml配置檔案,或者在程式碼中生成一個IgniteConfiguration物件,然後進行配置。和server節點不同的是,如果需要啟動一個client節點,需要顯式的配置client mode為true(對應程式碼為cfg.setClientMode(true))。和程式碼裡等效的xml配置檔案如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="discoverySpi">
<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
<property name="ipFinder">
<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
<property name="multicastGroup" value="224.0.0.251"/>
</bean>
</property>
</bean>
</property>
<property name="clientMode" value="true"/>
</bean>
</beans>
在用Ignite.start()啟動節點後,client節點從Ignite叢集中獲取名為“TEST”的快取,然後試著從快取裡讀取不同城市對應的省份名字。
Server和client節點的啟動
啟動server和client時有兩點需要注意的:
- Client節點啟動時必須有可用的server節點在Ignite叢集中,所以啟動的順序是先server節點後client節點。當然,在某些情況下,如果需要client節點不管是否有可用的server節點都必須要成功啟動,則需要在client節點上配置強制服務端發現模式。
- 如果通過傳入xml配置檔案的方式啟動節點,則需要在CLASS_PATH中包含ignite-spring模組的jar檔案(如果你通過二級制包安裝了Ignite,ignite-spring模組就在IGNITE_HOME/lib/ignite-spring目錄下)。在maven成功編譯程式碼後,我用下面的命令啟動server節點:
$cd ignite-client-server-node-example/target
$java -cp ./ignite-client-server-node-example-1.0-SNAPSHOT.jar:$IGNITE_HOME/libs/*:$IGNITE_HOME/libs/ignite-spring/* IgniteServerNodeExample ../src/main/resources/ignite-server-config.xml
同理,用下面的命令啟動client節點:
$cd ignite-client-server-node-example/target
$java -cp ./ignite-client-server-node-example-1.0-SNAPSHOT.jar:$IGNITE_HOME/libs/*:$IGNITE_HOME/libs/ignite-spring/* IgniteClientNodeExample ../src/main/resources/ignite-client-config.xml
在啟動client節點前後,我們可以稍微留意下server節點關於Ignite叢集拓撲結構的相關日誌,在啟動client節點前:
[00:55:52] Ignite node started OK (id=42996817)
[00:55:52] Topology snapshot [ver=1, servers=1, clients=0, CPUs=2, offheap=1.6GB, heap=1.7GB]
[00:55:52] ^-- Node [id=42996817-925A-4FF5-8B5D-4B80D4774905, clusterState=ACTIVE]
[00:55:52] Data Regions Configured:
[00:55:52] ^-- default [initSize=256.0 MiB, maxSize=1.6 GiB, persistenceEnabled=false]
叢集的拓撲版本為1,叢集內有1個server節點,0個client節點。 在啟動client節點後:
[00:59:06] Topology snapshot [ver=2, servers=1, clients=1, CPUs=2, offheap=1.6GB, heap=3.5GB]
[00:59:06] ^-- Node [id=42996817-925A-4FF5-8B5D-4B80D4774905, clusterState=ACTIVE]
[00:59:06] Data Regions Configured:
[00:59:06] ^-- default [initSize=256.0 MiB, maxSize=1.6 GiB, persistenceEnabled=false]
叢集的拓撲版本為2,叢集內有1個server節點,1個client節點,這代表我們成功的啟動了一個server節點和client節點。
在client節點啟動後,它會試著讀取server節點寫入“TEST”快取的資料,所以我們應該可以在client節點日誌中看到以下的輸出:
Montreal is in Quebec
Edmonton is in Alberta
Markham is in Ontario
Toronto is in null
除了Toronto以外,其他的城市都能讀到對應的省份資訊。這也驗證了client節點讀取的就是server節點寫入的那份快取。
總結
我們介紹了Ignite叢集節點中兩個不同的角色--server和client,並比較了它們之間的不同。我們還展示瞭如何在java程式中啟動server和client節點。 完整的程式碼和maven工程可以在這裡找到。 Server和client對應的xml配置檔案在src/main/resources目錄下。
Ignite叢集的配置,節點發現以及叢集管理,感興趣的同學可以參考下官方文件。在後面會有專門的文章介紹細節和例子。從下一篇文章開始,讓我們先聚焦在Ignite的資料網格服務上,看看和其他key/value快取系統相比,Ignite提供了哪些不一樣的能力。