初步認識Apache Ignite
什麼是Apache Ignite?
Ignite是一個以記憶體為中心的分散式資料庫、快取和處理平臺,可以在PB級資料中,以記憶體級的速度進行事務性、分析性以及流式負載的處理。
上述引用了Ignite的官方介紹,通俗來講,Ignite就是一個記憶體資料庫,它包括了很多特性,它既是一個分散式快取,也是一個分散式資料庫,同時也支援一定程度的ACID事務。
關鍵字:固化記憶體、並置處理
固化記憶體
Ignite的固化記憶體元件不僅僅將記憶體作為一個快取層,還視為一個全功能的儲存層。這意味著可以按需將持久化開啟或者關閉。如果持久化關閉,那麼Ignite就可以作為一個分散式的記憶體資料庫或者記憶體資料網格,這完全取決於使用SQL和鍵-值API的喜好。如果持久化開啟,那麼Ignite就成為一個分散式的,可水平擴充套件的資料庫,它會保證完整的資料一致性以及叢集故障的可恢復能力。
並置處理
Ignite是一個分散式系統,因此,有能力將資料和資料以及資料和計算進行並置就變得非常重要,這會避免分散式資料噪聲。當執行分散式SQL關聯時資料的並置就變得非常的重要。Ignite還支援將使用者的邏輯(函式,lambda等)直接發到資料所在的節點然後在本地進行資料的運算。
Ingite和Spark有什麼區別?
Ignite 是一個基於記憶體的計算系統,也就是把記憶體做為主要的儲存裝置。Spark 則是在處理時使用記憶體。相比之下,Ingite的索引更快,提取時間減少,避免了序列/反序列等優點,使前者這種記憶體優先的方法更快。
Ignite提供了一個Spark RDD抽象的實現,他可以容易地在記憶體中跨越多個Spark作業共享狀態,在跨越不同Spark作業、工作節點或者應用時,IgniteRDD為記憶體中的相同資料提供了一個共享的、可變的檢視,而原生的SparkRDD無法在Spark作業或者應用之間進行共享。
1. 獲得真正的可擴充套件的記憶體級效能,避免資料來源和Spark工作節點和應用之間的資料移動
2. 提升DataFrame和SQL的效能
3. 在Spark作業之間更容易地共享狀態和資料
如何使用Ingite?
啟動Ingite叢集
從官網下載zip格式壓縮包
解壓到系統中的一個安裝資料夾,如apache-ignite-fabric-2.6.0-bin
配置IGNITE_HOME環境變數
linux執行命令:
bin/ignite.sh
此時將啟動Ingite,當最後輸出下面資訊時,則說明啟動成功:
[20:47:15] Ignite node started OK (id=60d15c51)
[20:47:15] Topology snapshot [ver=1, servers=1, clients=0, CPUs=4, offheap=3.2GB, heap=3.5GB]
使用maven啟動
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-core</artifactId>
<version>${ignite.version}</version>
</dependency>
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-spring</artifactId>
<version>${ignite.version}</version>
</dependency>
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-indexing</artifactId>
<version>${ignite.version}</version>
</dependency>
目前ignite最新版本為2.6
Ingite叢集知識
Ignite具有非常先進的叢集能力,包括邏輯叢集組和自動發現。
Ignite節點之間會自動發現對方,這有助於必要時擴充套件叢集,而不需要重啟整個叢集。開發者可以利用Ignite的混合雲支援,允許公有云(比如AWS)和私有云之間建立連線,向他們提供兩者的好處。
Ingite有兩種發現機制,分別是TCP/IP和Zookeeper。總的來說對於小叢集,使用預設的TCP/IP發現方式,對於成百上千的大叢集,則建議使用Zookeeper。
作為關係型資料庫使用
建立表
可以通過控制檯和jdbc兩種方式執行sql語句,支援H2的語法。
控制檯
1. 執行ignite.sh啟動叢集
2. 啟動sqlline
sqlline.sh --color=true --verbose=true -u jdbc:ignite:thin://127.0.0.1/
- 執行指令碼 用!sql +sql 語句即可
!sql CREATE TABLE City (id LONG PRIMARY KEY, name VARCHAR) WITH "template=replicated";
!sql CREATE TABLE Person (id LONG, name VARCHAR, city_id LONG, PRIMARY KEY (id, city_id)) WITH "backups=1, affinityKey=city_id";
!sql CREATE INDEX idx_city_name ON City (name);
!sql CREATE INDEX idx_person_name ON Person (name);
jdbc
// 註冊JDBC driver.
Class.forName("org.apache.ignite.IgniteJdbcThinDriver");
// 開啟 JDBC connection.
Connection conn = DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1/");
// 建立表
try (Statement stmt = conn.createStatement()) {
// 建立基於複製模式的City表
stmt.executeUpdate("CREATE TABLE City (" +
" id LONG PRIMARY KEY, name VARCHAR) " +
" WITH \"template=replicated\"");
// 建立基於分片模式,備份數為1的Person表
stmt.executeUpdate("CREATE TABLE Person (" +
" id LONG, name VARCHAR, city_id LONG, " +
" PRIMARY KEY (id, city_id)) " +
" WITH \"backups=1, affinityKey=city_id\"");
// 建立City表的索引
stmt.executeUpdate("CREATE INDEX idx_city_name ON City (name)");
// 建立Person表的索引
stmt.executeUpdate("CREATE INDEX idx_person_name ON Person (name)");
插入資料
控制檯
!sql INSERT INTO City (id, name) VALUES (1, 'Forest Hill');
!sql INSERT INTO City (id, name) VALUES (2, 'Denver');
!sql INSERT INTO City (id, name) VALUES (3, 'St. Petersburg');
!sql INSERT INTO Person (id, name, city_id) VALUES (1, 'John Doe', 3);
!sql INSERT INTO Person (id, name, city_id) VALUES (2, 'Jane Roe', 2);
!sql INSERT INTO Person (id, name, city_id) VALUES (3, 'Mary Major', 1);
!sql INSERT INTO Person (id, name, city_id) VALUES (4, 'Richard Miles', 2);
jdbc
Class.forName("org.apache.ignite.IgniteJdbcThinDriver");
Connection conn = DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1/");
try (PreparedStatement stmt =
conn.prepareStatement("INSERT INTO City (id, name) VALUES (?, ?)")) {
stmt.setLong(1, 1L);
stmt.setString(2, "Forest Hill");
stmt.executeUpdate();
stmt.setLong(1, 2L);
stmt.setString(2, "Denver");
stmt.executeUpdate();
stmt.setLong(1, 3L);
stmt.setString(2, "St. Petersburg");
stmt.executeUpdate();
}
try (PreparedStatement stmt =
conn.prepareStatement("INSERT INTO Person (id, name, city_id) VALUES (?, ?, ?)")) {
stmt.setLong(1, 1L);
stmt.setString(2, "John Doe");
stmt.setLong(3, 3L);
stmt.executeUpdate();
stmt.setLong(1, 2L);
stmt.setString(2, "Jane Roe");
stmt.setLong(3, 2L);
stmt.executeUpdate();
stmt.setLong(1, 3L);
stmt.setString(2, "Mary Major");
stmt.setLong(3, 1L);
stmt.executeUpdate();
stmt.setLong(1, 4L);
stmt.setString(2, "Richard Miles");
stmt.setLong(3, 2L);
stmt.executeUpdate();
}
查詢資料
控制檯
!sql SELECT p.name, c.name FROM Person p, City c WHERE p.city_id = c.id;
jdbc
Class.forName("org.apache.ignite.IgniteJdbcThinDriver");
Connection conn = DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1/");
// 使用標準的sql獲取資料
try (Statement stmt = conn.createStatement()) {
try (ResultSet rs =
stmt.executeQuery("SELECT p.name, c.name " +
" FROM Person p, City c " +
" WHERE p.city_id = c.id")) {
while (rs.next())
System.out.println(rs.getString(1) + ", " + rs.getString(2));
}
}
輸出結果
Mary Major, Forest Hill
Jane Roe, Denver
Richard Miles, Denver
John Doe, St. Petersburg
作為並置處理引擎
try (Ignite ignite = Ignition.start()) {
Collection<IgniteCallable<Integer>> calls = new ArrayList<>();
// 將這句字串按照空格分組,並將任務分派到各個節點中計算
for (final String word : "Count characters using callable".split(" "))
calls.add(word::length);
// 分派
Collection<Integer> res = ignite.compute().call(calls);
// 將各個節點統計後的結果彙總
int sum = res.stream().mapToInt(Integer::intValue).sum();
System.out.println("Total number of characters is '" + sum + "'.");
}
輸出
Total number of characters is '28'.
作為Data Grid(資料網格)應用
鍵值對存放及讀取
try (Ignite ignite = Ignition.start()) {
IgniteCache<Integer, String> cache = ignite.getOrCreateCache("myCacheName");
// Store keys in cache (values will end up on different cache nodes).
for (int i = 0; i < 10; i++)
cache.put(i, Integer.toString(i));
for (int i = 0; i < 10; i++)
System.out.println("Got [key=" + i + ", val=" + cache.get(i) + ']');
}
原子操作
// Put-if-absent which returns previous value.
Integer oldVal = cache.getAndPutIfAbsent("Hello", 11);
// Put-if-absent which returns boolean success flag.
boolean success = cache.putIfAbsent("World", 22);
// Replace-if-exists operation (opposite of getAndPutIfAbsent), returns previous value.
oldVal = cache.getAndReplace("Hello", 11);
// Replace-if-exists operation (opposite of putIfAbsent), returns boolean success flag.
success = cache.replace("World", 22);
// Replace-if-matches operation.
success = cache.replace("World", 2, 22);
// Remove-if-matches operation.
success = cache.remove("Hello", 1);
事務支援
try (Transaction tx = ignite.transactions().txStart()) {
Integer hello = cache.get("Hello");
if (hello == 1)
cache.put("Hello", 11);
cache.put("World", 22);
tx.commit();
}
分散式鎖
// Lock cache key "Hello".
Lock lock = cache.lock("Hello");
lock.lock();
try {
cache.put("Hello", 11);
cache.put("World", 22);
}
finally {
lock.unlock();
}
部署遠端微服務
Ignite的服務網格對於在叢集中部署微服務非常有用,Ignite會處理和部署的服務有關的任務的生命週期,並且提供了在應用中呼叫服務的簡單方式
下面的例子部署了一個Service,將從客戶端傳過來的資訊進行列印
1.宣告服務介面,擴充套件Ignite的service介面
import org.apache.ignite.services.Service;
public interface HelloService extends Service {
// 接受客戶端的資訊
String sayRepeat(String msg);
}
2.實現服務介面,除了實現自己定義的介面外,也可以覆蓋實現Ignite各個生命週期的工作
@Slf4j
public class HelloServiceImpl implements HelloService {
@Override
public String sayRepeat(String msg) {
log.info("I repeat your words : '{}'.", msg);
return msg;
}
@Override
public void cancel(ServiceContext serviceContext) {
log.info("{} cancel", serviceContext.name());
}
@Override
public void init(ServiceContext serviceContext) throws Exception {
log.info("{} init", serviceContext.name());
}
@Override
public void execute(ServiceContext serviceContext) throws Exception {
log.info("{} execute", serviceContext.name());
}
}
3.部署服務sayHello,此時服務應用常駐在記憶體中
@Slf4j
public class IgniteServiceDemo {
public static void main(String[] args) {
IgniteServiceDemo demo = new IgniteServiceDemo();
demo.deploy();
}
private void deploy() {
String serviceName = "sayHello";
log.info("ready to start service {}", serviceName);
Ignite ignite = Ignition.start();
ignite.services().deployClusterSingleton(serviceName, new HelloServiceImpl());
log.info("service {} have bean started", serviceName);
}
}
4.在另外一個應用中啟動客戶端,可通過控制檯輸入字串,呼叫服務sayHello
@Slf4j
public class IgniteClientDemo {
public static void main(String[] args) {
IgniteClientDemo demo = new IgniteClientDemo();
demo.call();
}
private void call() {
String serviceName = "sayHello";
try (Ignite ignite = Ignition.start()){
HelloService helloService = ignite.services().serviceProxy(serviceName, HelloService.class, false);
log.info("Speaking,please.");
Scanner in = new Scanner(System.in);
while(in.hasNext()){
helloService.sayRepeat(in.next());
}
}
}
}
5.結果
客戶端輸出
[INFO ] 22:41:16.860 [main] com.mumu.IgniteClientDemo - Speaking,please.
Hello!
My name is Ryan
服務端輸出
[INFO ] 22:41:05.481 [srvc-deploy-#43] c.mumu.service.impl.HelloServiceImpl - sayHello init
[INFO ] 22:41:05.481 [service-#46] c.mumu.service.impl.HelloServiceImpl - sayHello execute
[INFO ] 22:41:05.481 [main] com.mumu.IgniteServiceDemo - service sayHello have bean started
[22:41:16] Topology snapshot [ver=2, servers=2, clients=0, CPUs=4, offheap=6.4GB, heap=7.1GB]
[22:41:16] ^-- Node [id=610DAC7C-B087-405F-8549-8A7FE6012FD4, clusterState=ACTIVE]
[22:41:16] Data Regions Configured:
[22:41:16] ^-- default [initSize=256.0 MiB, maxSize=3.2 GiB, persistenceEnabled=false]
[INFO ] 22:41:23.086 [svc-#57] c.mumu.service.impl.HelloServiceImpl - I repeat your words : 'Hello!'.
[INFO ] 22:41:35.212 [svc-#59] c.mumu.service.impl.HelloServiceImpl - I repeat your words : 'My name is Ryan'.
後記
上述的例子只是Apache Ignite各種特性及功能中的一部分,作為一個記憶體為核心的框架,它的應用場景極多,既可像Redis一樣作為快取,也可像關係型資料庫那樣執行sql語句,同時還能與Spark整合,增強spark的擴充套件性及速度,還能作為Hibernate和MyBatis的二級快取,甚至還可以成為RPC框架提供微服務。而更可怕的是它具有分散式特性,可以根據應用規模水平擴充套件,並且還是執行在記憶體中,本身速度就佔有很大的優勢。
由於本人水平有限,加上Ignite屬於比較新的開源專案,在國內外還處於發展階段,很多特性仍在增加變化當中,最權威的介紹可參考官網:https://ignite.apache.org/
這篇文章對Ignite的特性描述得比較好,值得一讀:https://www.zybuluo.com/liyuj/note/1179662
By ryan.ou
相關文章
- Mybatis初步認識MyBatis
- 初步認識knockoutjsJS
- Apache Ignite剖析Apache
- Spring初步認識-(1)Spring
- GridGain 確認 Apache Ignite 效能是 Hazelcast 的 2 倍AIApacheAST
- Apache Ignite 與 Apache Spark比較ApacheSpark
- 初步認識 k8sK8S
- 初步認識ida軟體
- 網路報文初步認識
- 快速冪的初步認識(Java)Java
- OpenStack入門之初步認識
- 初步認識tomcat伺服器Tomcat伺服器
- 【XMPP】Smack原始碼之初步認識Mac原始碼
- Workerman學習筆記(一)初步認識筆記
- 低程式碼 —— 初步認識 AppsmithAPPMIT
- webpack 快速入門 系列 —— 初步認識 webpackWeb
- 01MySQL的 庫、表初步認識MySql
- Swift 網路請求 : Moya初步認識Swift
- tornado 原始碼閱讀-初步認識原始碼
- Apache Ignite 學習筆記(6): Ignite中Entry Processor使用Apache筆記
- mysql和apache不認識phpMySqlApachePHP
- 對vue原始碼的初步認識和理解Vue原始碼
- 關於瀏覽器外掛的初步認識瀏覽器
- 初步認識微前端(single-spa 和 qiankun)前端
- 前端學習 node 快速入門 系列 —— 初步認識 node前端
- 使用Apache Ignite實現無死鎖事務Apache
- Sql Server之旅——第十三站 對鎖的初步認識SQLServer
- 5分鐘內讓你瞭解Apache Ignite - softwaremillApacheREM
- 【人生苦短,我學 Python】基礎篇——初步認識(Day1)Python
- Python學習 —— 初步認知Python
- 在既有系統中打通Apache Ignite、MySQL和Node.jsApacheMySqlNode.js
- Mybatis學習-初步認知與使用MyBatis
- Struts入門初步知識
- 2017.04.26(MVVM的進一步學習初步對ReactiveCocoa認識)MVVMReact
- IgniteFAQ-8-org.apache.ignite.IgniteException: Failed to unmarshal discovery custom messageApacheExceptionAI
- SAP UI5 智慧控制元件 Smart Controls 的初步認識試讀版UI控制元件
- Angular 2 + 折騰記 :(2)初步認識angular2,不一樣的開發模式Angular模式
- 認識CopyOnWriteArrayList