一、?Apache Ignite
1.簡介
Apache Ignite是一個分布式數據庫,支持以內存級的速度進行高性能計算。Ignite所支持的編程語言主要包括:Java、.NET、C#以及C++,其中Java版本的對應API是最豐富的。
2.應用場景
時下最主流的分布式數據庫應當是Redis,然而某些情況下我們的項目可能無法使用Redis進行開發。例如:由于Redis的底層是使用C語言實現的,而Ignite的底層則是使用Java語言實現,因此如果我們所在公司的云環境不支持C語言環境那么就無法對Redis進行部署。此時,我們可以考慮使用Ignite作為Redis的取代方案。
與Redis相比,Ignite由于也是內存數據庫因而同樣具有很高的計算效率,且也支持Redis這種Key-Value的存儲形式。Ignite中緩存的Key和Value都是Object類型的對象,相比Redis而言更加靈活,可以支持更多用戶自定義的數據類型,而Redis則受限于其所提供的String、Hash、Set等數據類型。
除了具有相似的K-V緩存結構,Ignite還有很多優于Redis的特性,例如:Ignite完全兼容JCache緩存規范而Redis不支持、Ignite完全支持ACID事務而Redis只能提供部分支持、Ignite支持緩存數據的全復制而Redis不支持。
二、Ignite的簡單部署
本章節以主流的Java Maven項目為例,對Ignite的簡單部署和使用進行示例說明。
1.引入
Maven項目當中,Ignite的部署十分簡單,不需要再單獨下載安裝包然后通過終端命令行的方式啟動節點。只需要在項目的pom.xml中添加Ignite的依賴坐標,即可成功對其實現引入。
值得注意的是,如果項目或子項目的pom.xml文件中引用了h2內存數據庫的相關依賴,那么必須將其版本覆蓋為2.14.197,否則Ignite會報啟動錯誤,這是因為Ignite的jar包中所引入的h2版本是2.14.197,因此如果不一致就會導致版本沖突,進而導致Ignite節點啟動失敗。
2.服務端代碼
首先,在創建Ignite節點之前,我們需要創建一個IgniteConfiguration類型的Ignite配置對象,IgniteConfiguration可以對我們所創建的Ignite節點進行一些自定義的配置。
其中,最基本的配置就是設置當前Ignite服務器節點(自己)所連接的IP地址。Ignite節點之間的網絡通信主要是通過TCP協議實現的,其默認端口是47500。
Ignite的服務發現機制(SPI)主要是通過 TcpDiscoverySpi這個類的對象實現的,我們通過調用其setIpFinder方法給TcpDiscoverySpi設置一個Ip發現器。
TcpDiscoveryVmIpFinder是靜態的IP發現器,可以指定一組IP地址和端口,IP發現器將檢查這些IP地址和端口以進行節點發現。一旦建立了與提供的任何IP地址的連接,Ignite就會自動發現所有其它節點。
Ignite節點的啟動是通過Ignition.start方法觸發的,在對Ignite的節點完成配置后就可以調用該方法啟動一個Ignite節點。在啟動時Ignite會將為節點分配為服務端節點或客戶端節點,如果不進行設置,Ignite節點將自動作為服務端節點啟動。
啟動后,IDEA輸出以下信息:
其中,“Ignite node started OK”表示Ignite節點成功啟動。“servers=1, clients=0”表示當前存在1個服務端節點以及0個客戶端節點。
3.客戶端代碼
Ignite客戶端節點的啟動和服務端節點的代碼幾乎完全一樣,由于Ignite節點默認以服務端模式啟動,因此只需要手動地將Ignite設置為客戶端節點即可。
上圖中,IgniteConfiguration的setClientMode(true)方法可以顯式地讓Ignite節點以客戶端的模式啟動。
上圖中,“servers=1, clients=1”表示當前存在1個服務端節點以及1個客戶端節點。
三、Ignite集群
在通過簡單的Java程序實例對Ignite服務端節點和客戶端節點的部署連接進行示例說明后,再簡要地對Ignite的集群特性進行介紹。
1.Ignite節點
Ignite的節點可以分為服務端節點和客戶端節點兩種類型。服務端節點是Ignite集群的主體,主要的作用是存儲數據、執行計算任務等,而客戶端節點只是作為常規節點加入集群,但并不對數據進行存儲。
Ignite節點間可以通過其配置的SPI(Service Provider Interface,服務發現機制)自動相互發現并組成集群。根據具體應用場景的不同,Ignite的SPI主要包括:TCP/IP發現以及ZooKeeper發現兩種類型。通常使用較多的是TCP/IP機制,節點間通過DiscoverySpi相互發現。DiscoverySpi的默認實現是TcpDiscoverySpi,具體可以配置為基于組播的IP發現或者基于靜態的IP發現模式(2.2和2.3節當中的TcpDiscoveryVmIpFinder)。
2.基于組播和靜態的IP發現
和TcpDiscoveryVmIpFinder不同的是,TcpDiscoveryMulticastIpFinder使用組播來發現每個節點,這也是默認的IP發現器。見下圖,兩種IP發現方式在編碼實現上幾乎沒有區別,只需要更改new的ipFinder類型。
TcpDiscoveryMulticastIpFinder還可以同時實現基于組播和靜態的IP發現,通過setMulticastGroup方法接收來自組播的IP地址,同時通過setAddress處理預定義的靜態IP地址。
3.基于JDBC的IP發現
通常情況下,本地開發時我們可以使用基于組播或靜態的IP發現,但公司項目一般部署在云環境,IP地址并不能保證固定不變,可能會由于容器故障重啟或其他不可控原因而動態變化,因此3.2節中的IP發現方式就會失效。Ignite為這種類似的應用場景提供了一種很便捷的SPI:基于JDBC數據庫的IP發現機制。
下面通過一個簡單的例子進行介紹,服務端程序和2.2、2.3節當中的服務端程序區別在于IpFinder的類型不再是TcpDiscoveryVmIpFinder(基于靜態IP)或TcpDiscoveryMulticastIpFinder(基于組播IP),而是TcpDiscoveryJdbcIpFinder。
上圖的Ignite服務端程序使用了基于JDBC的IP發現,此時ipFinder不再通過調用setAddress方法設置IP地址,而是通過setDataSource設置一個JDBC數據源。因此我們首先需要創建一個MysqlDataSource類的MySQL數據源對象,通過其setURL、setUser和setPassword方法分別設置數據源的URL地址、用戶名和密碼,再作為參數傳遞給TcpDiscoveryJdbcIpFinder.setDataSource。
客戶端程序和服務端幾乎是一模一樣的,2.3節所述,區別僅在于客戶端程序員需要顯式地調用IgniteConfiguration.setClientMode(true)方法讓Ignite節點以客戶端的模式啟動。
四、Ignite緩存
在對Ignite的簡單部署和Ignite集群的相關特性有了簡單了解后,我們通過一些簡單的實例來對Ignite的緩存進行示例說明。
1.IgniteCache
Ignite的所有緩存都是IgniteCache類型的,其實K是緩存的鍵,V是緩存的值,分別對應Redis中的key和value。IgniteCache繼承了javax包下的Cache接口,因此如前文所述,Ignite是支持JCache規范的。
2.創建緩存
前文中,由于只是簡單地啟動了Ignite節點,并未進行緩存操作,因此并未對Ignition.start的返回值進行獲取。當我們要進行緩存相關操作時,需要獲取start方法所返回的Ignite實例,通過對該實例對象的調用以實現緩存的相關操作。
如下圖所示,可以通過creatCache或getOrCreateCache兩種方式來獲取IgniteCache類型的緩存對象。如方法名所示,creatCache是直接創建緩存,getOrCreateCache是先獲取緩存,如果不存在則創建緩存。
調用createCache時,如果緩存已經存在則會創建失敗,具體判斷緩存是否存在是根據緩存的名字實現的,每個IgniteCache都有一個緩存名CacheName,我們所傳入的字符串s會被當作cacheName進行創建緩存實例。
除了字符串外,創建緩存時的參數也可以是CacheConfiguration類型的對象,其K和V表示的是緩存的Key和Value的類型。CacheConfiguration的setName方法可以設置Ignite緩存的名稱,效果等同于createCache(String s),因此如果像下圖這樣創建緩存就會創建失敗,因為兩個緩存的名稱都叫做“name”。
啟動Ignite客戶端程序,IDEA控制臺輸出如下錯誤,可見Ignite是通過緩存的name字段判斷緩存是否沖突的。
3.獲取緩存
獲取緩存主要有兩種方法:Ignite.cache和4.2節中的Ignite.getOrCreateCache。其中cache(String s)方法的參數是緩存的名稱,getOrCreateCache的參數可以是String類型的緩存名稱,也可以是CacheConfiguration的緩存配置。值得注意的是,必須保證緩存是已經存在的,否則會導致異常。
Java示例代碼:
IDEA控制臺輸出結果如下,圖中我們也可以得知,此時IgniteCache接口的具體實現類是GatewayProtectedCacheProxy類型的實例對象。
4.銷毀緩存
Ignite緩存的銷毀也有兩種方式,通過Ignite的destoryCache或IgniteCache的destory方法實現。
Java示例代碼:
IDEA控制臺輸出結果如下:
5.向緩存中寫數據
Ignite緩存的寫入主要通過put方法實現,鍵值均是Object類對象,既可以是Java原生對象,也可以是自定義的類對象。除此之外,也可以通過putAll一次性存入多個鍵值對。帶Async后綴的方法則是異步實現,帶IfAbsent的方法表示不存在時存入數據,getAndPut則會獲取所寫入的緩存數據。
6.從緩存中讀數據
Ignite緩存的讀取主要通過get方法實現,通過傳入key來獲取value。除此之外,也可以通過getAll傳入一個key的Set集合,一次性獲取Set集合中所有key多對應的多個key-value鍵值對。
Java示例代碼:
IDEA控制臺輸出如下:
五、基于Spring Cloud的實例教學
在對Ignite的部署、集群、緩存基本操作有了一定程度的了解后,我們通過Spring Cloud微服務來實現一個Ignite模擬Redis的小項目案例,加深讀者對Ignite的應用理解。
由于Ignite緩存是Object類型,因此我們通過定義一個常量類型作為緩存名來對
緩存進行分類,例如String類型的緩存所傳入的緩存名稱則為String,Hash類的
緩存所傳入的cacheName則為Hash。
1.Redis-String緩存的模擬
對于String類型的數據結構,Redis的主要方法和對應命令如下:
(1)添加/修改數據 set key value
(2)獲取數據get key
(3)刪除數據del key
(4)添加/修改多個數據mset key1 value1 key2 value2 ...
(5)獲取多個數據mget key1 key2 ...
(6)獲取數據字符個數(字符串長度)strlen key
(7)追加信息到尾部(不存在則新建)append key value
2.Redis-Hash緩存的模擬
對于Hash類型的數據結構,Redis的主要方法和對應命令如下:
(1)添加/修改數據 hset key field value
(2)獲取單個數據hget key field
(3)獲取全部數據hgetall key
(4)刪除數據hdel key field1 field2 ...
(5)添加/修改多個數據hmset key field1 value1 field2 value2 ...
(6)獲取多個數據hmget key field1 field2 ...
(7)獲取哈希表中字段的數量hlen key
(8)獲取哈希表中是否存在指定的字段hexists key field
3.Redis-List緩存的模擬
對于List類型的數據結構,Redis的主要方法和對應命令如下:
(1)添加數據lpush/rpush key value1 value2 ...
(2)獲取并移除數據lpop/rpop key
(3)獲取指定范圍的數據lrange key start end
(4)獲取指定位置的數據lindex key index
(5)獲取數據個數llen key
四、Redis-Set緩存的模擬
對于Set類型的數據結構,Redis的主要方法和對應命令如下:
(1)添加數據sadd key member1 member2 ...
(2)獲取全部數據smembers key
(3)刪除數據srem key member1 member2 ...
(4)獲取集合數據總量scard key
(5)判斷集合中是否包含指定數據sismember key member
5.服務端程序
不需要以微服務的注冊,只需要以普通Java類main方法調用的形式進行啟動。
6.客戶端程序
首先,我們需要在客戶端程序創建一個DataSource的配置Bean作為Ignite客戶端節點通過JDBC進行連接時所需的構造參數。
其次,創建一個Controller,并通過init方法用于初始化Ignite客戶端,在容器啟動時自動創建Ignite實例并作為一個Bean注入上述5.1-5.4節中的Ignite工具類Bean。
7.測試
最后,我們寫幾個簡單的測試方法進行測試。
(1)String類型的測試
啟動Ignite服務端程序、EurekaServer和EurekaConsumer后,在url輸入:localhost:8080/ignite/string進行測試,觀察瀏覽器輸出:
IDEA控制臺輸出:
(2)Hash類型的測試
在url輸入:localhost:8080/ignite/hash進行測試,觀察瀏覽器輸出:
IDEA控制臺輸出:
(3)List類型的測試
在url輸入:localhost:8080/ignite/list進行測試,觀察瀏覽器輸出:
IDEA控制臺輸出:
(4)Set類型的測試
在url輸入:localhost:8080/ignite/set進行測試,觀察瀏覽器輸出:
IDEA控制臺輸出:
以上為Apache Ignite的簡單入門案例,感謝閱讀。
作者介紹
孫俊輝,中國農業銀行股份有限公司研發中心軟件研發工程師,擅長Java開發領域。?