前一篇文章,我們介紹了如何安裝部署Ignite集群,并且嘗試了用REST和SQL客戶端連接集群進行了緩存和數據庫的操作。現在我們就來寫點代碼,用Ignite的Java thin client來連接集群。 在開始介紹具體代碼之前,讓我們先簡單的了解一下Ignite的thin client,以及背后的binary client protocol(*原本打算把thin client翻譯為精簡客戶端,bianry client protocol翻譯為二進制客戶端協議,但總讀的不順口,就索性就不翻譯了吧-_-|||*)。
Ignite Thin Client和Binary Client Protocol介紹
為了緩存數據的高性能讀寫,Ignite是節點內部需要維護一套高效的數據結構來記錄一些元數據,所以如果在自己的應用程序中啟動一個Ignite的server/client節點是要占用一些應用程序的CPU/內存資源的。另外,Ignite是一個分布式系統,單個節點需要和集群里的其他節點通訊,又要消耗一些的網絡資源。 因此不同于server/client節點,thin client是一個Ignite輕量化的客戶端。為什么說它是輕量化的呢,因為thin client并不會加入到Ignite集群的拓撲中(即thin client的連接,斷開不會導致Ignite集群拓撲發生變化,也不會觸發相應的事件通知),不會存儲任何集群的數據或是被做為計算節點接收計算任務。Thin client就是一個純粹的客戶端,它純粹到通過最原始的socket連接到Ignite集群中的某一個節點進行所有的操作。
在Ignite集群成功啟動后,我們會在日志看到“Topology snapshot [ver=1, servers=1, clients=0, CPUs=2, offheap=1.6GB, heap=1.0GB]”信息。這條日志里的clients和thin client不是一回事。按照之前介紹,thin client是不會加入Ignite集群的拓撲中去,理應不會出現在和拓撲相關的日志中,所以這里不要把thin client和集群中的client節點搞混了。
這個鏈接詳細的介紹了Binary Client Protocol的數據格式(比如采用的是litter-endian,Ignite的二進制對象描述用戶數據),消息格式(定義了消息頭格式,響應消息的格式,以及連接時如何進行握手保證版本兼容等)和各種緩存操作所需的操作編碼和格式。 所以只要你按照Binary Client Protocol的要求,你可以用任何一種語言實現一個thin client。目前Ignite發布了兩種語言的thin client的實現,一個是基于Java實現,一個是基于.Net實現。
當然thin client雖然輕量化,也有它的問題。 Thin client寫數據時只能先把數據發給其連接的節點,再由該節點將數據發送給集群內的其他節點做存儲(同理,讀數據也需要通過該節點才能傳給thin client),這樣thin client和這個節點間的網絡很有可能就成為瓶頸。而server/client節點間可以互聯,利用數據分區,可以充分使用節點間的帶寬。另外,當前連接節點出故障后,thin client只能隨機選擇一個啟動時已知的節點進行重試,由于其不感知集群拓撲,即便有新節點加入,thin client也無法知道其存在,更不可能和其進行通訊了。 所以還是要根據自己應用的場景,看看到底是server/client節點還是thin client更合適。
Ignite Java Thin Client例子
上一篇文章中,我們用Dbeaver連接Ignite后,用SQL語句進行建表,插入數據和查詢數據。 在這個例子里,我們就來看看如何通過Ignite的thin client支持的JCache APIs進行相同的操作。
首先我們先用用maven命令創建一個新的project,然后在pom.xml文件中添加以下ignite-core的依賴:
<dependencies><dependency><groupId>org.apache.ignite</groupId><artifactId>ignite-core</artifactId><version>${ignite.version}</version></dependency>
</dependencies>
在看具體代碼之前,讓我們先來大概了解一下這個例子中我們要進行哪些操作以及步驟:
- 首先,我們通過thin client連接上我們已經啟動的Ignite集群。
- 然后,通過API創建兩個cache(cache的名字分別為province和city),一個用來存省份信息,一個用來存城市信息。 province緩存的key是省份的id,city緩存的key是城市的名稱。
- 我們分別往兩個cache里寫入一些數據。
- 啟動該程序時,可以從命令行傳入多個城市名稱,在終端我們會打印出該城市所在的省份信息。
下面是主程序的代碼:
import org.apache.ignite.Ignition;
import org.apache.ignite.client.ClientCache;
import org.apache.ignite.client.ClientException;
import org.apache.ignite.client.IgniteClient;
import org.apache.ignite.configuration.ClientConfiguration;public class IgniteThinClientExample {private static ClientCache<Integer, Province> provinceCache;private static ClientCache<String, City> cityCache;public static void main(String[] args) {System.out.println();System.out.println("Ignite thin client example started.");//連接到Ignite集群,默認端口號為10800ClientConfiguration cfg = new ClientConfiguration().setAddresses("192.168.0.110:10800");//用java的try-with-resource statement啟動clienttry (IgniteClient igniteClient = Ignition.startClient(cfg)){System.out.println();System.out.println("Begin create cache and insert data.");//創建兩個緩存,具體步驟見該函數creatCacheAndInsertData(igniteClient);System.out.println();System.out.println("Begin query cache.");//根據輸入開始查詢for(String city : args){//先用城市名字,查詢city緩存City c = cityCache.get(city);Province p = null;if (c != null){//在用城市數據中的province id查詢province緩存p = provinceCache.get(c.getProvinceId());}//輸出查詢結果if (c != null && p != null) {System.out.println("Find " + c.getName() + " in province " + p.getName());}else{System.out.println("Cannot find " + city + " in any province.");}}}catch (ClientException e) {System.err.println(e.getMessage());}catch (Exception e) {System.err.format("Unexpected failure: %s\n", e);}}private static void creatCacheAndInsertData(IgniteClient igniteClient){//創建province緩存,用來存放省份信息,該緩存以省的id為keyfinal String PROVINCE_CACHE_NAME = "province";provinceCache = igniteClient.getOrCreateCache(PROVINCE_CACHE_NAME);//往province緩存中寫入一些數據int provinceId = 1;final Province on = new Province(provinceId++, "Ontario");final Province ab = new Province(provinceId++, "Alberta");final Province qc = new Province(provinceId++, "Quebec");provinceCache.put(on.getId(), on);provinceCache.put(ab.getId(), ab);provinceCache.put(qc.getId(), qc);System.out.println("Successfully insert all provinces data.");//創建city緩存,用來存放城市信息,該緩存以城市的名字為keyfinal String CITY_CACHE_NAME = "city";cityCache = igniteClient.getOrCreateCache(CITY_CACHE_NAME);//往city緩存寫入一些數據int cityId = 1;final City toronto = new City(cityId++, "Toronto", on.getId());final City edmonton = new City(cityId++, "Edmonton", ab.getId());final City calgary = new City(cityId++, "Calgary", ab.getId());final City montreal = new City(cityId++, "Montreal", qc.getId());cityCache.put(toronto.getName(), toronto);cityCache.put(edmonton.getName(), edmonton);cityCache.put(calgary.getName(), calgary);cityCache.put(montreal.getName(), montreal);System.out.println("Successfully insert all city data.");}
}public class City {private int id;private String name;private int provinceId;...
}public class Province {private int id;private String name;...
}
成功的編譯project后,我們可以啟動這個client看看程序的輸出結果:
$java -cp $IGNITE_HOME/libs/*:./ignite-thin-client-example-1.0-SNAPSHOT.jar IgniteThinClientExample Toronto Markham Edmonton CalgaryIgnite thin client example started.Begin create cache and insert data.
Successfully insert all provinces data.
Successfully insert all city data.Begin query cache.
Find Toronto in province Ontario
Cannot find Markham in any province.
Find Edmonton in province Alberta
Find Calgary in province Alberta
因為我們的city緩存中,并沒有Markham的信息,所以查詢Markham的時候我們也找不到對應的省份信息。但是查詢Toronto,Edmonton和Calgary的時候,程序是能正確的返回其省份信息的。
在上面的例子中,有幾個需要注意的地方:
- 在我們連接Ignite集群的時候,用的端口號10800。默認配置下,Ignite會監聽該端口,等待thin client的連接。如果需要讓Ignite集群用不同的端口號,可以修改集群啟動時的配置文件,加入以下配置項(如果你是用上一篇文章的方法啟動的Ignite集群, 配置文件在$IGNITE_HOME/config/default-config.xml):
<bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration"><!-- Thin client connection configuration. --><property name="clientConnectorConfiguration"><bean class="org.apache.ignite.configuration.ClientConnectorConfiguration"><property name="host" value="192.168.0.100"/><property name="port" value="新的端口號"/><property name="portRange" value="30"/></bean></property>
</bean>
我們的插入和查詢數據的時候,只用到了最簡單緩存API--put和get。其實Ignite緩存的查詢API比其他緩存更豐富,支持scan/SQL/text方式進行查詢,這個我們會在后面的文章慢慢介紹。
我們用城市的名字查詢完city緩存后,再拿著province id去查詢province緩存。這兩步查詢其實是可以合并成一個SQL的join查詢,在后面介紹SQL查詢時,我們再來看看把兩個緩存當做兩張表做join操作。
總結
這篇文章我們介紹了Ignite的thin client,并用Ignite的Java think client實現了一個簡單的例子,解釋如何用thin client連接上Ignite集群,創建緩存,寫入數據以及查詢。 完整的代碼和maven工程文件戳這里。
下一篇文章,我們看看如何在自己的Java代碼里啟動Ignite集群及其相關配置。