Apache Ignite剖析

哥不是小蘿莉發表於2018-03-11

1.概述

  Apache Ignite和Apache Arrow很類似,屬於大資料範疇中的記憶體分散式管理系統。在《Apache Arrow 記憶體資料》中介紹了Arrow的相關內容,它統一了大資料領域各個生態系統的資料格式,避免了序列化和反序列化所帶來的資源開銷(能夠節省80%左右的CPU資源)。今天來給大家剖析下Apache Ignite的相關內容。

2.內容

  Apache Ignite是一個以記憶體為中心的資料平臺,具有強一致性、高可用、強大的SQL、K/V以及其所對應的應用介面(API)。結構分佈圖如下所示:

  在整個Ignite叢集中的多個節點中,Ignite記憶體中的資料模式有三種,分別是LOCAL、REPLICATED和PARTITIONED。這樣增加了Ignite的擴充套件性,Ignite可以自動化的控制資料如何分割槽,使用者也可以插入自定義的方法,或是為了提供效率將部分資料並存在一起。

  Ignite和其他關係型資料庫具有相似的行為,但是在處理約束和索引方面略有不同。Ignite支援一級和二級索引,但是隻有一級索引支援唯一性。在持久化方面,Ignite固化記憶體在記憶體和磁碟中都能良好的工作,但是持久化到磁碟是可以禁用的,一般將Ignite作為一個記憶體資料庫來使用。

  由於Ignite是一個全功能的資料網格,它既可以用於純記憶體模式,也可以帶有Ignite的原生持久化。同時,它還可以與任何第三方的資料庫整合,包含RDBMS和NoSQL。比如,在和Hadoop的HDFS、Kafka等,開發基於大資料平臺下的SQL引擎,來操作HDFS、Kafka這類的大資料儲存介質。

2.1 記憶體和磁碟

  Apache Ignite是基於固化記憶體架構的,當Ignite持久化儲存特性開啟時,它可以在記憶體和磁碟中儲存和處理資料和索引。在固化記憶體和Ignite持久化儲存同時開啟時,具有以下優勢:

2.1.1 記憶體優勢

  • 對外記憶體
  • 避免顯著的GC暫停現象
  • 自動化碎片清理
  • 可預估的記憶體消耗
  • 高SQL效能

2.1.2 磁碟優勢

  • 可選的持久化
  • 支援SSD介質
  • 分散式儲存
  • 支援事物
  • 叢集瞬時啟動

2.2 持久化過程

  Ignite的持久化儲存時一個分散式的、支援ACID、相容SQL的磁碟儲存。它作為一個可選的磁碟層,可以將資料和索引儲存到SSD這類磁碟介質,並且可以透明的與Ignite固化記憶體進行整合。Ignite的持久化儲存具有以下優勢:

  • 可以在資料中執行SQL操作,不管資料在記憶體還是在磁碟中,這意味著Ignite可以作為一個經過記憶體優化的分散式SQL資料庫
  • 可以不用講所有的資料和索引保持在記憶體中,持久化儲存可以在磁碟上儲存資料的大資料集合,然後只在記憶體中保持訪問頻繁的資料子集
  • 叢集是瞬時啟動,如果整個叢集當機,不需要通過預載入資料來對記憶體進行資料“預熱”,只需要將所有叢集的節點都連線到一起,整個叢集即可正常工作
  • 資料和索引在記憶體和磁碟中以相似的格式進行儲存,避免複雜的格式轉化,資料集只是在記憶體和磁碟之間進行移動

  持久化流程如下圖所示:

2.3 分散式SQL記憶體資料庫

  在Apache Ignite中提供了分散式SQL資料庫功能,這個記憶體資料庫可以水平擴充套件、容錯且相容標準的SQL語法,它支援所有的SQL及DML命令,包含SELECT、INSERT、DELETE等SQL命令。依賴於固化記憶體架構,資料集和索引可以同時在記憶體和磁碟中進行儲存,這樣可以跨越不同的儲存層執行分散式SQL操作,來獲得可以固化到磁碟的記憶體級效能。可以使用Java、Python、C++等原生的API來操作SQL與Ignite進行資料互動,也可以使用Ignite的JDBC或者ODBC驅動,這樣就具有了真正意義上的跨平臺連線性。具體架構體系,如下圖所示:

3.程式碼實踐

  瞭解Apache Ignite的作用後,下面我們可以通過模擬編寫一個大資料SQL引擎,來實現對Kafka的Topic的查詢。首先需要實現一個KafkaSqlFactory的類,具體實現程式碼如下所示:

/**
 * TODO
 * 
 * @author smartloli.
 *
 *         Created by Mar 9, 2018
 */
public class KafkaSqlFactory {

	private static final Logger LOG = LoggerFactory.getLogger(KafkaSqlFactory.class);

	private static Ignite ignite = null;

	private static void getInstance() {
		if (ignite == null) {
			ignite = Ignition.start();
		}
	}

	private static IgniteCache<Long, TopicX> processor(List<TopicX> collectors) {
		getInstance();
		CacheConfiguration<Long, TopicX> topicDataCacheCfg = new CacheConfiguration<Long, TopicX>();
		topicDataCacheCfg.setName(TopicCache.NAME);
		topicDataCacheCfg.setCacheMode(CacheMode.PARTITIONED);
		topicDataCacheCfg.setIndexedTypes(Long.class, TopicX.class);
		IgniteCache<Long, TopicX> topicDataCache = ignite.getOrCreateCache(topicDataCacheCfg);
		for (TopicX topic : collectors) {
			topicDataCache.put(topic.getOffsets(), topic);
		}
		return topicDataCache;
	}

	public static String sql(String sql, List<TopicX> collectors) {
		try {
			IgniteCache<Long, TopicX> topicDataCache = processor(collectors);
			SqlFieldsQuery qry = new SqlFieldsQuery(sql);
			QueryCursor<List<?>> cursor = topicDataCache.query(qry);
			for (List<?> row : cursor) {
				System.out.println(row.toString());
			}
		} catch (Exception ex) {
			LOG.error("Query kafka topic has error, msg is " + ex.getMessage());
		} finally {
			close();
		}
		return "";
	}

	private static void close() {
		try {
			if (ignite != null) {
				ignite.close();
			}
		} catch (Exception ex) {
			LOG.error("Close Ignite has error, msg is " + ex.getMessage());
		} finally {
			if (ignite != null) {
				ignite.close();
			}
		}
	}

}

  然後,模擬編寫一個生產者來生產資料,並查詢資料集,實現程式碼如下所示:

public static void ignite(){
		List<TopicX> collectors = new ArrayList<>();
		int count = 0;
		for (int i = 0; i < 10; i++) {
			TopicX td = new TopicX();
			if (count > 3) {
				count = 0;
			}
			td.setPartitionId(count);
			td.setOffsets(i);
			td.setMessage("hello_" + i);
			td.setTopicName("test");
			collectors.add(td);
			count++;
		}

		String sql = "select offsets,message from TopicX where offsets>6 and partitionId in (0,1) limit 1";
		long stime = System.currentTimeMillis();
		KafkaSqlFactory.sql(sql, collectors);
		System.out.println("Cost time [" + (System.currentTimeMillis() - stime) / 1000.0 + "]ms");
	}

  執行結果如下所示:

4.總結

  Apache Ignite整體來說,它基本把現在分散式的一些概念都整合了,包含分散式儲存、分散式計算、分散式服務、流式計算等等。而且,它對Java語言的支援,與JDK能夠很好的整合,能夠很友好的相容JDK的現有API,當你開啟一個執行緒池,你不需要關係是本地執行緒池還是分散式執行緒池,只管提交任務就行。Apache Ignite在與RDBMS、Hadoop、Spark、Kafka等傳統關係型資料庫和主流大資料套件的整合,提供了非常靈活好用的元件API。

5.結束語

  這篇部落格就和大家分享到這裡,如果大家在研究學習的過程當中有什麼問題,可以加群進行討論或傳送郵件給我,我會盡我所能為您解答,與君共勉!

相關文章