陜西整站關(guān)鍵詞自然排名優(yōu)化湖南網(wǎng)絡(luò)推廣機(jī)構(gòu)
配置內(nèi)存
#1.內(nèi)存架構(gòu)
#1.1.概述
Ignite內(nèi)存架構(gòu)通過(guò)可以同時(shí)在內(nèi)存和磁盤(pán)上存儲(chǔ)和處理數(shù)據(jù)及索引,得到了支持磁盤(pán)持久化的內(nèi)存級(jí)性能。
多層存儲(chǔ)的運(yùn)行方式類(lèi)似于操作系統(tǒng)(例如Linux)的虛擬內(nèi)存。但是這兩種類(lèi)型架構(gòu)之間的主要區(qū)別是,多層存儲(chǔ)始終將磁盤(pán)視為數(shù)據(jù)的超集(如果啟用了持久化),在故障或者重啟后仍然可以保留數(shù)據(jù),而傳統(tǒng)的虛擬內(nèi)存僅將磁盤(pán)作為交換擴(kuò)展,一旦進(jìn)程停止,數(shù)據(jù)就會(huì)被清除。
#1.2.內(nèi)存架構(gòu)
多層架構(gòu)是一種基于固定大小頁(yè)面的內(nèi)存架構(gòu),這些頁(yè)面存儲(chǔ)在內(nèi)存(Java堆外)的托管非堆區(qū)中,并按磁盤(pán)上的特定層次結(jié)構(gòu)進(jìn)行組織。
Ignite在內(nèi)存和磁盤(pán)上都維護(hù)相同的二進(jìn)制數(shù)據(jù)表示形式,這樣在內(nèi)存和磁盤(pán)之間移動(dòng)數(shù)據(jù)時(shí)就不需要進(jìn)行昂貴的序列化。
下圖說(shuō)明了多層存儲(chǔ)架構(gòu):
#1.2.1.內(nèi)存段
每個(gè)數(shù)據(jù)區(qū)均以初始大小開(kāi)始,并具有可以增長(zhǎng)到的最大大小。該區(qū)域通過(guò)分配連續(xù)的內(nèi)存段擴(kuò)展到其最大大小。
內(nèi)存段是從操作系統(tǒng)分配的物理內(nèi)存的連續(xù)字節(jié)數(shù)組,該數(shù)組被拆分為固定大小的頁(yè)面。該段中可以存在幾種類(lèi)型的頁(yè)面,如下圖所示。
#1.2.2.數(shù)據(jù)頁(yè)面
數(shù)據(jù)頁(yè)面存儲(chǔ)從應(yīng)用端寫(xiě)入緩存的條目。
通常每個(gè)數(shù)據(jù)頁(yè)面持有多個(gè)鍵值條目,以便盡可能高效地使用內(nèi)存并避免內(nèi)存碎片。將新條目添加到緩存后,Ignite會(huì)尋找一個(gè)適合整個(gè)鍵-值條目的最佳頁(yè)面。
但是如果一個(gè)條目的總大小超過(guò)了DataStorageConfiguration.setPageSize(..)
屬性配置的頁(yè)面大小,則該條目將占用多個(gè)數(shù)據(jù)頁(yè)面。
提示
如果有許多緩存條目無(wú)法容納在單個(gè)頁(yè)面中,那么增加頁(yè)面大小配置參數(shù)是有必要的。
如果在更新期間條目大小擴(kuò)大并超過(guò)了其數(shù)據(jù)頁(yè)面的剩余可用空間,則Ignite會(huì)搜索新的空間足夠的數(shù)據(jù)頁(yè)面,并將其移到那里。
#1.2.3.內(nèi)存碎片整理
Ignite自動(dòng)執(zhí)行內(nèi)存碎片整理,不需要用戶(hù)干預(yù)。
隨著時(shí)間的推移,每個(gè)數(shù)據(jù)頁(yè)面可能會(huì)通過(guò)不同的CRUD操作多次更新,這會(huì)導(dǎo)致頁(yè)面和整體內(nèi)存碎片化。為了最大程度地減少內(nèi)存碎片,只要頁(yè)面碎片過(guò)多,Ignite都會(huì)使用頁(yè)面壓縮。
壓縮的數(shù)據(jù)頁(yè)面如下圖所示:
頁(yè)面具有一個(gè)頭部,其存儲(chǔ)內(nèi)部使用所需的元信息。所有鍵-值條目總是從右到左添加。在上圖中,頁(yè)面中存儲(chǔ)了三個(gè)條目(分別為1、2和3)。這些條目可能具有不同的大小。
頁(yè)面內(nèi)條目位置的偏移量(或引用)從左到右存儲(chǔ),并且始終為固定大小。偏移量用于在頁(yè)面中查找鍵-值條目的指針。
中間的空間是可用空間,每當(dāng)將更多數(shù)據(jù)推入集群時(shí),該空間就會(huì)被填充。
接下來(lái),假設(shè)隨著時(shí)間的推移,條目2被刪除,這導(dǎo)致頁(yè)面中的非連續(xù)可用空間:
這就是碎片化頁(yè)面的樣子。
但是,當(dāng)需要頁(yè)面的整個(gè)可用空間或達(dá)到某個(gè)碎片閾值時(shí),壓縮過(guò)程會(huì)對(duì)頁(yè)面進(jìn)行碎片整理,使其變?yōu)樯厦娴谝粡垐D片中所示的狀態(tài),其中該連續(xù)空間是連續(xù)的。此過(guò)程是自動(dòng)的,不需要用戶(hù)干預(yù)。
#1.3.持久化
Ignite提供了許多功能,可以將數(shù)據(jù)持久化磁盤(pán)上,同時(shí)還保持一致性??梢栽诓粊G失數(shù)據(jù)的前提下重啟集群,可以應(yīng)對(duì)故障,并在內(nèi)存不足時(shí)為數(shù)據(jù)提供存儲(chǔ)。啟用原生持久化后,Ignite會(huì)將所有數(shù)據(jù)保存在磁盤(pán)上,并將盡可能多的數(shù)據(jù)加載到內(nèi)存中進(jìn)行處理。更多信息請(qǐng)參考Ignite持久化章節(jié)的內(nèi)容。
#2.配置數(shù)據(jù)區(qū)
#2.1.概述
Ignite使用數(shù)據(jù)區(qū)的概念來(lái)控制可用于緩存的內(nèi)存數(shù)量,數(shù)據(jù)區(qū)是緩存數(shù)據(jù)存儲(chǔ)在內(nèi)存中的邏輯可擴(kuò)展區(qū)域??梢钥刂茢?shù)據(jù)區(qū)的初始值及其可以占用的最大值,除了大小之外,數(shù)據(jù)區(qū)還控制緩存的持久化配置。
Ignite有一個(gè)默認(rèn)的數(shù)據(jù)區(qū)最多可占用該節(jié)點(diǎn)20%的內(nèi)存,并且創(chuàng)建的所有緩存均位于該數(shù)據(jù)區(qū)中,但是也可以添加任意多個(gè)數(shù)據(jù)區(qū),創(chuàng)建多個(gè)數(shù)據(jù)區(qū)的原因有:
- 可以通過(guò)不同數(shù)據(jù)區(qū)分別配置緩存對(duì)應(yīng)的可用內(nèi)存量;
- 持久化參數(shù)是按數(shù)據(jù)區(qū)配置的。如果要同時(shí)具有純內(nèi)存緩存和持久化緩存,則需要配置兩個(gè)(或多個(gè))具有不同持久化參數(shù)的數(shù)據(jù)區(qū):一個(gè)用于純內(nèi)存緩存,一個(gè)用于持久化緩存;
- 部分內(nèi)存參數(shù),比如退出策略,是按照數(shù)據(jù)區(qū)進(jìn)行配置的。
下面的章節(jié)會(huì)演示如何更改默認(rèn)數(shù)據(jù)區(qū)的參數(shù)或配置多個(gè)數(shù)據(jù)區(qū)。
#2.2.配置默認(rèn)數(shù)據(jù)區(qū)
新的緩存默認(rèn)會(huì)添加到默認(rèn)的數(shù)據(jù)區(qū)中,可以在數(shù)據(jù)區(qū)配置中更改默認(rèn)數(shù)據(jù)區(qū)的屬性:
- XML
- Java
- C#/.NET
DataStorageConfiguration storageCfg = new DataStorageConfiguration();DataRegionConfiguration defaultRegion = new DataRegionConfiguration();
defaultRegion.setName("Default_Region");
defaultRegion.setInitialSize(100 * 1024 * 1024);storageCfg.setDefaultDataRegionConfiguration(defaultRegion);IgniteConfiguration cfg = new IgniteConfiguration();cfg.setDataStorageConfiguration(storageCfg);// Start the node.
Ignite ignite = Ignition.start(cfg);
#2.3.添加自定義數(shù)據(jù)區(qū)
除了默認(rèn)的數(shù)據(jù)區(qū),還可以使用自定義配置定義更多個(gè)數(shù)據(jù)區(qū),在下面的示例中,配置了一個(gè)數(shù)據(jù)區(qū)占用40MB空間然后使用了Random-2-LRU退出策略,注意在進(jìn)一步的緩存配置中,在該數(shù)據(jù)區(qū)中創(chuàng)建了一個(gè)緩存。
- XML
- Java
- C#/.NET
DataStorageConfiguration storageCfg = new DataStorageConfiguration();DataRegionConfiguration defaultRegion = new DataRegionConfiguration();
defaultRegion.setName("Default_Region");
defaultRegion.setInitialSize(100 * 1024 * 1024);storageCfg.setDefaultDataRegionConfiguration(defaultRegion);
// 40MB memory region with eviction enabled.
DataRegionConfiguration regionWithEviction = new DataRegionConfiguration();
regionWithEviction.setName("40MB_Region_Eviction");
regionWithEviction.setInitialSize(20 * 1024 * 1024);
regionWithEviction.setMaxSize(40 * 1024 * 1024);
regionWithEviction.setPageEvictionMode(DataPageEvictionMode.RANDOM_2_LRU);storageCfg.setDataRegionConfigurations(regionWithEviction);IgniteConfiguration cfg = new IgniteConfiguration();cfg.setDataStorageConfiguration(storageCfg);CacheConfiguration cache1 = new CacheConfiguration("SampleCache");
//this cache will be hosted in the "40MB_Region_Eviction" data region
cache1.setDataRegionName("40MB_Region_Eviction");cfg.setCacheConfiguration(cache1);// Start the node.
Ignite ignite = Ignition.start(cfg);
#2.4.緩存預(yù)熱策略
集群?jiǎn)?dòng)組網(wǎng)成功之后,Ignite本身并不需要對(duì)內(nèi)存進(jìn)行預(yù)熱,應(yīng)用就可以在其上執(zhí)行計(jì)算和查詢(xún)。但是對(duì)于需要低延遲的系統(tǒng),還是希望在查詢(xún)數(shù)據(jù)之前先將數(shù)據(jù)加載到內(nèi)存中的。
當(dāng)前,Ignite的預(yù)熱策略是從索引開(kāi)始,將數(shù)據(jù)加載到所有或者指定的數(shù)據(jù)區(qū),直到用完可用空間為止??梢詾樗械臄?shù)據(jù)區(qū)進(jìn)行配置(默認(rèn)),也可以單獨(dú)為某個(gè)數(shù)據(jù)區(qū)進(jìn)行配置。
要預(yù)熱所有數(shù)據(jù)區(qū),需將配置參數(shù)LoadAllWarmUpStrategy
傳遞給DataStorageConfiguration#setDefaultWarmUpConfiguration
,如下所示:
- XML
- Java
IgniteConfiguration cfg = new IgniteConfiguration();DataStorageConfiguration storageCfg = new DataStorageConfiguration();//Changing the default warm-up strategy for all data regions
storageCfg.setDefaultWarmUpConfiguration(new LoadAllWarmUpConfiguration());cfg.setDataStorageConfiguration(storageCfg);
要預(yù)熱某個(gè)數(shù)據(jù)區(qū),需將配置參數(shù)LoadAllWarmUpStrategy
傳遞給DataStorageConfiguration#setWarmUpConfiguration
,如下所示:
- XML
- Java
IgniteConfiguration cfg = new IgniteConfiguration();DataStorageConfiguration storageCfg = new DataStorageConfiguration();//Setting another warm-up strategy for a custom data region
DataRegionConfiguration myNewDataRegion = new DataRegionConfiguration();myNewDataRegion.setName("NewDataRegion");//You can tweak the initial size as well as other settings
myNewDataRegion.setInitialSize(100 * 1024 * 1024);//Performing data loading from disk in DRAM on restarts.
myNewDataRegion.setWarmUpConfiguration(new LoadAllWarmUpConfiguration());//Enabling Ignite persistence. Ignite reads data from disk when queried for tables/caches from this region.
myNewDataRegion.setPersistenceEnabled(true);//Applying the configuration.
storageCfg.setDataRegionConfigurations(myNewDataRegion);cfg.setDataStorageConfiguration(storageCfg);
要停止預(yù)熱所有數(shù)據(jù)區(qū),請(qǐng)將配置參數(shù)NoOpWarmUpStrategy
傳遞給DataStorageConfiguration#setDefaultWarmUpConfiguration
,如下所示:
- XML
- Java
IgniteConfiguration cfg = new IgniteConfiguration();DataStorageConfiguration storageCfg = new DataStorageConfiguration();storageCfg.setDefaultWarmUpConfiguration(new NoOpWarmUpConfiguration());cfg.setDataStorageConfiguration(storageCfg);
要停止預(yù)熱某個(gè)數(shù)據(jù)區(qū),請(qǐng)將配置參數(shù)NoOpWarmUpStrategy
傳遞給DataStorageConfiguration#setWarmUpConfiguration
,如下所示:
- XML
- Java
IgniteConfiguration cfg = new IgniteConfiguration();DataStorageConfiguration storageCfg = new DataStorageConfiguration();//Setting another warm-up strategy for a custom data region
DataRegionConfiguration myNewDataRegion = new DataRegionConfiguration();myNewDataRegion.setName("NewDataRegion");//You can tweak the initial size as well as other settings
myNewDataRegion.setInitialSize(100 * 1024 * 1024);//Skip data loading from disk in DRAM on restarts.
myNewDataRegion.setWarmUpConfiguration(new NoOpWarmUpConfiguration());//Enabling Ignite persistence. Ignite reads data from disk when queried for tables/caches from this region.
myNewDataRegion.setPersistenceEnabled(true);//Applying the configuration.
storageCfg.setDataRegionConfigurations(myNewDataRegion);cfg.setDataStorageConfiguration(storageCfg);
還可以使用control.sh
和JMX停止緩存預(yù)熱過(guò)程。
要使用control.sh停止預(yù)熱:
- Linux
- Windows
control.sh --warm-up --stop --yes
要使用JMX停止預(yù)熱,可使用下面的方法:
org.apache.ignite.mxbean.WarmUpMXBean#stopWarmUp
#3.退出策略
如果關(guān)閉了Ignite原生持久化,Ignite會(huì)在堆外內(nèi)存中存儲(chǔ)所有的緩存條目,當(dāng)有新的數(shù)據(jù)注入,會(huì)進(jìn)行頁(yè)面的分配。如果達(dá)到了內(nèi)存的限制,Ignite無(wú)法分配頁(yè)面時(shí),部分?jǐn)?shù)據(jù)就必須從內(nèi)存中刪除以避免內(nèi)存溢出,這個(gè)過(guò)程叫做退出,退出保證系統(tǒng)不會(huì)內(nèi)存溢出,但是代價(jià)是內(nèi)存數(shù)據(jù)丟失以及如果需要數(shù)據(jù)還需要重新加載。
退出策略用于下面的場(chǎng)景:
- 關(guān)閉原生持久化之后的堆外內(nèi)存;
- 整合外部存儲(chǔ)后的堆外內(nèi)存;
- 堆內(nèi)緩存;
- 近緩存(如果啟用)。
如果開(kāi)啟了原生持久化,當(dāng)Ignite無(wú)法分配新的頁(yè)面時(shí),會(huì)有一個(gè)叫做頁(yè)面替換的簡(jiǎn)單過(guò)程來(lái)進(jìn)行堆外內(nèi)存的釋放,不同點(diǎn)在于數(shù)據(jù)并沒(méi)有丟失(因?yàn)槠浯鎯?chǔ)于持久化存儲(chǔ)),因此不用擔(dān)心數(shù)據(jù)丟失,而要關(guān)注效率。頁(yè)面替換由Ignite自動(dòng)處理,用戶(hù)無(wú)法進(jìn)行配置。
#3.1.堆外內(nèi)存退出
堆外內(nèi)存退出的實(shí)現(xiàn)方式如下:
當(dāng)內(nèi)存使用超過(guò)預(yù)設(shè)限制時(shí),Ignite使用預(yù)配置的算法之一來(lái)選擇最適合退出的內(nèi)存頁(yè)面。然后將頁(yè)面中的每個(gè)緩存條目從頁(yè)面中刪除,但是會(huì)保留被事務(wù)鎖定的條目。因此,整個(gè)頁(yè)面或大塊頁(yè)面都是空的,可以再次使用。
堆外內(nèi)存的退出默認(rèn)是關(guān)閉的,這意味著內(nèi)存使用量會(huì)一直增長(zhǎng)直到達(dá)到限值。如果要開(kāi)啟退出,需要在數(shù)據(jù)區(qū)配置中指定頁(yè)面退出模式。注意堆外內(nèi)存退出是數(shù)據(jù)區(qū)級(jí)的,如果沒(méi)使用數(shù)據(jù)區(qū),那么需要給默認(rèn)的數(shù)據(jù)區(qū)顯式地增加參數(shù)來(lái)配置退出。
默認(rèn)情況下,當(dāng)某個(gè)數(shù)據(jù)區(qū)的內(nèi)存消耗量達(dá)到90%時(shí),退出就開(kāi)始了,如果希望更早或者更晚地發(fā)起退出,可以配置DataRegionConfiguration.setEvictionThreshold(...)
參數(shù)。
Ignite支持兩種頁(yè)面選擇算法:
- Random-LRU
- Random-2-LRU
兩者的不同下面會(huì)說(shuō)明。
#3.1.1.Random-LRU
要啟用Random-LRU退出算法,配置方式如下所示;
- XML
- Java
- C#/.NET
// Node configuration.
IgniteConfiguration cfg = new IgniteConfiguration();// Memory configuration.
DataStorageConfiguration storageCfg = new DataStorageConfiguration();// Creating a new data region.
DataRegionConfiguration regionCfg = new DataRegionConfiguration();// Region name.
regionCfg.setName("20GB_Region");// 500 MB initial size (RAM).
regionCfg.setInitialSize(500L * 1024 * 1024);// 20 GB max size (RAM).
regionCfg.setMaxSize(20L * 1024 * 1024 * 1024);// Enabling RANDOM_LRU eviction for this region.
regionCfg.setPageEvictionMode(DataPageEvictionMode.RANDOM_LRU);// Setting the data region configuration.
storageCfg.setDataRegionConfigurations(regionCfg);// Applying the new configuration.
cfg.setDataStorageConfiguration(storageCfg);
Random-LRU算法工作方式如下:
- 當(dāng)一個(gè)數(shù)據(jù)區(qū)配置了內(nèi)存策略時(shí),就會(huì)分配一個(gè)堆外數(shù)組,它會(huì)跟蹤每個(gè)數(shù)據(jù)頁(yè)面的
最后使用
時(shí)間戳; - 當(dāng)數(shù)據(jù)頁(yè)面被訪問(wèn)時(shí),跟蹤數(shù)組的時(shí)間戳就會(huì)被更新;
- 當(dāng)?shù)搅送顺鲰?yè)面時(shí)間時(shí),算法會(huì)從跟蹤數(shù)組中隨機(jī)地選擇5個(gè)索引,然后退出最近的時(shí)間戳對(duì)應(yīng)的頁(yè)面,如果部分索引指向非數(shù)據(jù)頁(yè)面(索引或者系統(tǒng)頁(yè)面),算法會(huì)選擇其它的頁(yè)面。
#3.1.2.Random-2-LRU
Random-2-LRU退出算法是Random-LRU算法的抗掃描版,配置方式如下所示:
- XML
- Java
- C#/.NET
// Ignite configuration.
IgniteConfiguration cfg = new IgniteConfiguration();// Memory configuration.
DataStorageConfiguration storageCfg = new DataStorageConfiguration();// Creating a new data region.
DataRegionConfiguration regionCfg = new DataRegionConfiguration();// Region name.
regionCfg.setName("20GB_Region");// 500 MB initial size (RAM).
regionCfg.setInitialSize(500L * 1024 * 1024);// 20 GB max size (RAM).
regionCfg.setMaxSize(20L * 1024 * 1024 * 1024);// Enabling RANDOM_2_LRU eviction for this region.
regionCfg.setPageEvictionMode(DataPageEvictionMode.RANDOM_2_LRU);// Setting the data region configuration.
storageCfg.setDataRegionConfigurations(regionCfg);// Applying the new configuration.
cfg.setDataStorageConfiguration(storageCfg);
在Random-2-LRU算法中,每個(gè)數(shù)據(jù)頁(yè)面會(huì)存儲(chǔ)兩個(gè)最近訪問(wèn)時(shí)間戳,退出時(shí),算法會(huì)隨機(jī)地從跟蹤數(shù)組中選擇5個(gè)索引值,然后兩個(gè)最近時(shí)間戳中的最小值會(huì)被用來(lái)和另外4個(gè)候選頁(yè)面中的最小值進(jìn)行比較。
Random-2-LRU比Random-LRU要好,因?yàn)樗鉀Q了曇花一現(xiàn)
的問(wèn)題,即一個(gè)頁(yè)面很少被訪問(wèn),但是偶然地被訪問(wèn)了一次,然后就會(huì)被退出策略保護(hù)很長(zhǎng)時(shí)間。
#3.2.堆內(nèi)緩存退出
關(guān)于如何為堆內(nèi)緩存配置退出策略的介紹,請(qǐng)參見(jiàn)堆內(nèi)緩存配置退出策略章節(jié)的內(nèi)容。
配置持久化
#1.Ignite持久化
#1.1.概述
Ignite持久化,或者說(shuō)原生持久化,是旨在提供持久化存儲(chǔ)的一組功能。啟用后,Ignite會(huì)將所有數(shù)據(jù)存儲(chǔ)在磁盤(pán)上,并將盡可能多的數(shù)據(jù)加載到內(nèi)存中進(jìn)行處理。例如,如果有100個(gè)條目,而內(nèi)存僅能存儲(chǔ)20個(gè),則所有100個(gè)都存儲(chǔ)在磁盤(pán)上,而內(nèi)存中僅緩存20個(gè),以獲得更好的性能。
如果關(guān)閉原生持久化并且不使用任何外部存儲(chǔ)時(shí),Ignite就是一個(gè)純內(nèi)存存儲(chǔ)。
啟用持久化后,每個(gè)服務(wù)端節(jié)點(diǎn)只會(huì)存儲(chǔ)整個(gè)數(shù)據(jù)的一個(gè)子集,即只包含分配給該節(jié)點(diǎn)的分區(qū)(如果啟用了備份,也包括備份分區(qū))。
原生持久化基于以下特性:
- 在磁盤(pán)上存儲(chǔ)數(shù)據(jù)分區(qū);
- 預(yù)寫(xiě)日志;
- 檢查點(diǎn);
- 操作系統(tǒng)交換的使用。
啟用持久化后,Ignite會(huì)將每個(gè)分區(qū)存儲(chǔ)在磁盤(pán)上的單獨(dú)文件中,分區(qū)文件的數(shù)據(jù)格式與保存在內(nèi)存中的數(shù)據(jù)格式相同。如果啟用了分區(qū)備份,則也會(huì)保存在磁盤(pán)上,除了數(shù)據(jù)分區(qū),Ignite還存儲(chǔ)索引和元數(shù)據(jù)。
可以在配置中修改數(shù)據(jù)文件的默認(rèn)位置。
#1.2.啟用持久化存儲(chǔ)
原生持久化是配置在數(shù)據(jù)區(qū)上的。要啟用持久化存儲(chǔ),需要在數(shù)據(jù)區(qū)配置中將persistenceEnabled
屬性設(shè)置為true
,可以同時(shí)有純內(nèi)存數(shù)據(jù)區(qū)和持久化數(shù)據(jù)區(qū)。
以下是如何為默認(rèn)數(shù)據(jù)區(qū)啟用持久化存儲(chǔ)的示例:
- XML
- Java
- C#/.NET
IgniteConfiguration cfg = new IgniteConfiguration();//data storage configuration
DataStorageConfiguration storageCfg = new DataStorageConfiguration();storageCfg.getDefaultDataRegionConfiguration().setPersistenceEnabled(true);cfg.setDataStorageConfiguration(storageCfg);Ignite ignite = Ignition.start(cfg);
#1.3.配置持久化存儲(chǔ)目錄
啟用持久化之后,節(jié)點(diǎn)就會(huì)在{IGNITE_WORK_DIR}/db
目錄中存儲(chǔ)用戶(hù)的數(shù)據(jù)、索引和WAL文件,該目錄稱(chēng)為存儲(chǔ)目錄。通過(guò)配置DataStorageConfiguration
的storagePath
屬性可以修改存儲(chǔ)目錄。
每個(gè)節(jié)點(diǎn)都會(huì)在存儲(chǔ)目錄下維護(hù)一個(gè)子目錄樹(shù),來(lái)存儲(chǔ)緩存數(shù)據(jù)、WAL文件和WAL存檔文件。
子目錄名 | 描述 |
---|---|
{WORK_DIR}/db/{nodeId} | 該目錄中包括了緩存的數(shù)據(jù)和索引 |
{WORK_DIR}/db/wal/{nodeId} | 該目錄中包括了WAL文件 |
{WORK_DIR}/db/wal/archive/{nodeId} | 該目錄中包括了WAL存檔文件 |
這里的nodeId
要么是節(jié)點(diǎn)的一致性ID(如果在節(jié)點(diǎn)配置中定義)要么是自動(dòng)生成的節(jié)點(diǎn)ID,它用于確保節(jié)點(diǎn)目錄的唯一性。如果多個(gè)節(jié)點(diǎn)共享同一工作目錄,則它們將使用不同的子目錄。
如果工作目錄包含多個(gè)節(jié)點(diǎn)的持久化文件(存在多個(gè)具有不同nodeId
的{nodeId}
子目錄),則該節(jié)點(diǎn)將選擇第一個(gè)未使用的子目錄。為了確保節(jié)點(diǎn)即使重啟也始終使用固定的子目錄,即指定數(shù)據(jù)分區(qū),需要在節(jié)點(diǎn)配置中將IgniteConfiguration.setConsistentId
設(shè)置為集群范圍內(nèi)的唯一值。
修改存儲(chǔ)目錄的代碼如下所示:
- XML
- Java
- C#/.NET
IgniteConfiguration cfg = new IgniteConfiguration();//data storage configuration
DataStorageConfiguration storageCfg = new DataStorageConfiguration();storageCfg.getDefaultDataRegionConfiguration().setPersistenceEnabled(true);storageCfg.setStoragePath("/opt/storage");cfg.setDataStorageConfiguration(storageCfg);Ignite ignite = Ignition.start(cfg);
還可以將WAL和WAL存檔路徑指向存儲(chǔ)目錄之外的目錄。詳細(xì)信息后面章節(jié)會(huì)介紹。
#1.4.預(yù)寫(xiě)日志
預(yù)寫(xiě)日志是節(jié)點(diǎn)上發(fā)生的所有數(shù)據(jù)修改操作(包括刪除)的日志。在內(nèi)存中更新頁(yè)面時(shí),更新不會(huì)直接寫(xiě)入分區(qū)文件,而是會(huì)附加到WAL的末尾。
預(yù)寫(xiě)日志的目的是為單個(gè)節(jié)點(diǎn)或整個(gè)集群的故障提供一個(gè)恢復(fù)機(jī)制。如果發(fā)生故障或重啟,則可以依靠WAL的內(nèi)容將集群恢復(fù)到最近成功提交的事務(wù)。
WAL由幾個(gè)文件(稱(chēng)為活動(dòng)段)和一個(gè)存檔組成?;顒?dòng)段按順序填充,然后循環(huán)覆蓋。第一個(gè)段寫(xiě)滿后,其內(nèi)容將復(fù)制到WAL存檔中(請(qǐng)參見(jiàn)下面的WAL存檔章節(jié))。在復(fù)制第一段時(shí),第二段會(huì)被視為激活的WAL文件,并接受來(lái)自應(yīng)用端的所有更新,活動(dòng)段默認(rèn)有10個(gè)。
#1.4.1.WAL模式
WAL模式有幾種,每種模式對(duì)性能的影響方式不同,并提供不同的一致性保證:
WAL模式 | 描述 | 一致性保證 |
---|---|---|
FSYNC | 保證每個(gè)原子寫(xiě)或者事務(wù)性提交都會(huì)持久化到磁盤(pán)。 | 數(shù)據(jù)更新不會(huì)丟失,不管是任何的操作系統(tǒng)或者進(jìn)程故障,甚至是電源故障。 |
LOG_ONLY | 默認(rèn)模式,對(duì)于每個(gè)原子寫(xiě)或者事務(wù)性提交,保證會(huì)刷新到操作系統(tǒng)的緩沖區(qū)緩存或者內(nèi)存映射文件。默認(rèn)會(huì)使用內(nèi)存映射文件方式,并且可以通過(guò)將IGNITE_WAL_MMAP 系統(tǒng)屬性配置為false 將其關(guān)閉。 | 如果僅僅是進(jìn)程崩潰數(shù)據(jù)更新會(huì)保留。 |
BACKGROUND | 如果打開(kāi)了IGNITE_WAL_MMAP 屬性(默認(rèn)),該模式的行為類(lèi)似于LOG_ONLY 模式,如果關(guān)閉了內(nèi)存映射文件方式,變更會(huì)保持在節(jié)點(diǎn)的內(nèi)部緩沖區(qū),緩沖區(qū)刷新到磁盤(pán)的頻率由walFlushFrequency 參數(shù)定義。 | 如果打開(kāi)了IGNITE_WAL_MMAP 屬性(默認(rèn)),該模式提供了與LOG_ONLY 模式一樣的保證,否則如果進(jìn)程故障或者其它的故障發(fā)生時(shí),最近的數(shù)據(jù)更新可能丟失。 |
NONE | WAL被禁用,只有在節(jié)點(diǎn)優(yōu)雅地關(guān)閉時(shí),變更才會(huì)正常持久化,使用Ignite#active(false) 可以?xún)鼋Y(jié)集群然后停止節(jié)點(diǎn)。 | 可能出現(xiàn)數(shù)據(jù)丟失,如果節(jié)點(diǎn)在更新操作期間突然終止,則磁盤(pán)上存儲(chǔ)的數(shù)據(jù)很可能出現(xiàn)不同步或損壞。 |
#1.4.2.WAL存檔
WAL存檔用于保存故障后恢復(fù)節(jié)點(diǎn)所需的WAL段。存檔中保存的段的數(shù)量應(yīng)確保所有段的總大小不超過(guò)WAL存檔的既定大小。
WAL存檔的最大大小(在磁盤(pán)上占用的總空間)定義為檢查點(diǎn)緩沖區(qū)大小的4倍,可以在配置中更改該值。
警告
將WAL存檔大小配置為小于默認(rèn)值可能影響性能,用于生產(chǎn)之前需要進(jìn)行測(cè)試。
#1.4.3.修改WAL段大小
在高負(fù)載情況下,默認(rèn)的WAL段大小(64MB)可能效率不高,因?yàn)樗鼤?huì)導(dǎo)致WAL過(guò)于頻繁地在段之間切換,并且切換/輪轉(zhuǎn)是一項(xiàng)昂貴的操作。更大的WAL段大小有助于提高高負(fù)載下的性能,但代價(jià)是增加WAL文件和WAL存檔文件的總大小。
可以在數(shù)據(jù)存儲(chǔ)配置中更改WAL段文件的大小,該值必須介于512KB和2GB之間。
- XML
- Java
IgniteConfiguration cfg = new IgniteConfiguration();
DataStorageConfiguration storageCfg = new DataStorageConfiguration();
storageCfg.getDefaultDataRegionConfiguration().setPersistenceEnabled(true);storageCfg.setWalSegmentSize(128 * 1024 * 1024);cfg.setDataStorageConfiguration(storageCfg);Ignite ignite = Ignition.start(cfg);
#1.4.4.禁用WAL
警告
禁用或啟用WAL只能在穩(wěn)定的拓?fù)渖线M(jìn)行:即所有基線節(jié)點(diǎn)都應(yīng)該在線,在此操作期間不應(yīng)該有節(jié)點(diǎn)加入或離開(kāi)集群。否則,緩存可能會(huì)陷入不一致?tīng)顟B(tài)。如果發(fā)生這種情況,建議銷(xiāo)毀受影響的緩存。
在某些情況下,禁用WAL以獲得更好的性能是合理的做法。例如,在初始數(shù)據(jù)加載期間禁用WAL并在預(yù)加載完成后啟用WAL就是個(gè)好的做法。
- Java
- C#/.NET
- SQL
IgniteConfiguration cfg = new IgniteConfiguration();
DataStorageConfiguration storageCfg = new DataStorageConfiguration();
storageCfg.getDefaultDataRegionConfiguration().setPersistenceEnabled(true);cfg.setDataStorageConfiguration(storageCfg);Ignite ignite = Ignition.start(cfg);ignite.cluster().state(ClusterState.ACTIVE);String cacheName = "myCache";ignite.getOrCreateCache(cacheName);ignite.cluster().disableWal(cacheName);//load data
ignite.cluster().enableWal(cacheName);
警告
如果禁用WAL并重啟節(jié)點(diǎn),則將從該節(jié)點(diǎn)上的持久化存儲(chǔ)中刪除所有數(shù)據(jù)。之所以這樣實(shí)現(xiàn),是因?yàn)槿绻麤](méi)有WAL,則無(wú)法保證節(jié)點(diǎn)故障或重啟時(shí)的數(shù)據(jù)一致性。
#1.4.5.WAL存檔壓縮
可以啟用WAL存檔壓縮以減少WAL存檔占用的空間。WAL存檔默認(rèn)包含最后20個(gè)檢查點(diǎn)的段(此數(shù)字是可配置的)。啟用壓縮后,則將所有1個(gè)檢查點(diǎn)之前的已存檔段壓縮為ZIP格式,如果需要這些段(例如在節(jié)點(diǎn)之間再平衡數(shù)據(jù)),則會(huì)將其解壓縮為原始格式。
關(guān)于如何啟用WAL存檔壓縮,請(qǐng)參見(jiàn)下面的配置屬性章節(jié)。
#1.4.6.WAL記錄壓縮
如設(shè)計(jì)文檔中所述,在確認(rèn)用戶(hù)操作之前,代表數(shù)據(jù)更新的物理和邏輯記錄已寫(xiě)入WAL文件,Ignite可以先將WAL記錄壓縮到內(nèi)存中,然后再寫(xiě)入磁盤(pán)以節(jié)省空間。
WAL記錄壓縮要求引入ignite-compress
模塊,具體請(qǐng)參見(jiàn)啟用模塊。
WAL記錄壓縮默認(rèn)是禁用的,如果要啟用,需要在數(shù)據(jù)存儲(chǔ)配置中設(shè)置壓縮算法和壓縮級(jí)別:
IgniteConfiguration cfg = new IgniteConfiguration();DataStorageConfiguration dsCfg = new DataStorageConfiguration();
dsCfg.getDefaultDataRegionConfiguration().setPersistenceEnabled(true);//WAL page compression parameters
dsCfg.setWalPageCompression(DiskPageCompression.LZ4);
dsCfg.setWalPageCompressionLevel(8);cfg.setDataStorageConfiguration(dsCfg);
Ignite ignite = Ignition.start(cfg);
DiskPageCompression中列出了支持的壓縮算法。
#1.4.7.禁用WAL存檔
有時(shí)可能想要禁用WAL存檔,比如減少與將WAL段復(fù)制到存檔文件有關(guān)的開(kāi)銷(xiāo),當(dāng)Ignite將數(shù)據(jù)寫(xiě)入WAL段的速度快于將段復(fù)制到存檔文件的速度時(shí),這樣做就有用,因?yàn)檫@樣會(huì)導(dǎo)致I/O瓶頸,從而凍結(jié)節(jié)點(diǎn)的操作,如果遇到了這樣的問(wèn)題,就可以嘗試關(guān)閉WAL存檔。
通過(guò)將WAL路徑和WAL存檔路徑配置為同一個(gè)值,可以關(guān)閉存檔。這時(shí)Ignite就不會(huì)將段復(fù)制到存檔文件,而是只是在WAL文件夾中創(chuàng)建新的段。根據(jù)WAL存檔大小設(shè)置,舊段將隨著WAL的增長(zhǎng)而刪除。
#1.5.檢查點(diǎn)
檢查點(diǎn)是一個(gè)將臟頁(yè)面從內(nèi)存復(fù)制到磁盤(pán)上的分區(qū)文件的過(guò)程,臟頁(yè)面是指頁(yè)面已經(jīng)在內(nèi)存中進(jìn)行了更新但是還沒(méi)有寫(xiě)入對(duì)應(yīng)的分區(qū)文件(只是添加到了WAL中)。
創(chuàng)建檢查點(diǎn)后,所有更改都將保存到磁盤(pán),并且在節(jié)點(diǎn)故障并重啟后將生效。
檢查點(diǎn)和預(yù)寫(xiě)日志旨在確保數(shù)據(jù)的持久化和節(jié)點(diǎn)故障時(shí)的恢復(fù)能力。
這個(gè)過(guò)程通過(guò)在磁盤(pán)上保持頁(yè)面的最新?tīng)顟B(tài)而節(jié)省更多的磁盤(pán)空間,檢查點(diǎn)完成后,就可以在WAL存檔中刪除檢查點(diǎn)執(zhí)行前創(chuàng)建的WAL段。
具體請(qǐng)參見(jiàn)相關(guān)的文檔:
- 檢查點(diǎn)操作監(jiān)控;
- 調(diào)整檢查點(diǎn)緩沖區(qū)大小。
#1.6.配置屬性
下表列出了DataStorageConfiguration
的主要參數(shù):
屬性名 | 描述 | 默認(rèn)值 |
---|---|---|
persistenceEnabled | 將該屬性配置為true 可以開(kāi)啟原生持久化。 | false |
storagePath | 數(shù)據(jù)存儲(chǔ)路徑。 | ${IGNITE_HOME}/work/db/node{IDX}-{UUID} |
walPath | WAL活動(dòng)段存儲(chǔ)路徑。 | ${IGNITE_HOME}/work/db/wal/ |
walArchivePath | WAL存檔路徑。 | ${IGNITE_HOME}/work/db/wal/archive/ |
walCompactionEnabled | 將該屬性配置為true 可以開(kāi)啟WAL存檔壓縮。 | false |
walSegmentSize | WAL段文件大小(字節(jié))。 | 64MB |
walMode | 預(yù)寫(xiě)日志模式。 | LOG_ONLY |
walCompactionLevel | WAL壓縮級(jí)別,1 表示速度最快,9 表示最高的壓縮率。 | 1 |
maxWalArchiveSize | WAL存檔占用空間最大值(字節(jié))。 | 檢查點(diǎn)緩沖區(qū)大小的4倍 |
#2.外部存儲(chǔ)
#2.1.概述
Ignite可以做為已有數(shù)據(jù)庫(kù)之上的一個(gè)緩存層,包括RDBMS或者NoSQL數(shù)據(jù)庫(kù),比如Apache Cassandra或者M(jìn)ongoDB等,該場(chǎng)景通過(guò)內(nèi)存計(jì)算來(lái)對(duì)底層數(shù)據(jù)庫(kù)進(jìn)行加速。
Ignite可以與Apache Cassandra直接集成,但是暫時(shí)還不支持其他NoSQL數(shù)據(jù)庫(kù),但是開(kāi)發(fā)自己的CacheStore接口實(shí)現(xiàn)。
使用外部存儲(chǔ)的兩個(gè)主要場(chǎng)景是:
- 作為已有數(shù)據(jù)庫(kù)的緩存層,這時(shí)可以通過(guò)將數(shù)據(jù)加載到內(nèi)存來(lái)優(yōu)化處理速度,還可以為不支持SQL的數(shù)據(jù)庫(kù)帶來(lái)SQL支持能力(數(shù)據(jù)全部加載到內(nèi)存);
- 希望將數(shù)據(jù)持久化到外部數(shù)據(jù)庫(kù)(而不是單一的原生持久化)。
CacheStore
接口同時(shí)擴(kuò)展了javax.cache.integration.CacheLoader
和javax.cache.integration.CacheWriter
,相對(duì)應(yīng)的分別用于通讀和通寫(xiě)。也可以單獨(dú)實(shí)現(xiàn)每個(gè)接口,然后在緩存配置中單獨(dú)配置。
提示
除了鍵-值操作,Ignite的通寫(xiě)也支持SQL的INSERT、UPDATE和MERGE,但是SELECT查詢(xún)語(yǔ)句不會(huì)從外部數(shù)據(jù)庫(kù)通讀數(shù)據(jù)。
#2.1.1.通讀和通寫(xiě)
通讀是指如果緩存中不存在,則從底層持久化存儲(chǔ)中讀取數(shù)據(jù)。注意這僅適用于通過(guò)鍵-值A(chǔ)PI進(jìn)行的get
操作,SELECT
查詢(xún)不會(huì)從外部數(shù)據(jù)庫(kù)查詢(xún)數(shù)據(jù)。要執(zhí)行SELECT
查詢(xún),必須通過(guò)調(diào)用loadCache()
方法將數(shù)據(jù)從數(shù)據(jù)庫(kù)預(yù)加載到緩存中。
通寫(xiě)是指數(shù)據(jù)在緩存中更新后會(huì)自動(dòng)持久化。所有的通讀和通寫(xiě)操作都參與緩存事務(wù),然后作為整體提交或回滾。
#2.1.2.后寫(xiě)緩存
在一個(gè)簡(jiǎn)單的通寫(xiě)模式中每個(gè)緩存的put
和remove
操作都會(huì)涉及一個(gè)持久化存儲(chǔ)的請(qǐng)求,因此整個(gè)緩存更新的持續(xù)時(shí)間可能是相對(duì)比較長(zhǎng)的。另外,密集的緩存更新頻率也會(huì)導(dǎo)致非常高的存儲(chǔ)負(fù)載。
對(duì)于這種情況,可以啟用后寫(xiě)模式,它會(huì)以異步的方式執(zhí)行更新操作。這個(gè)方式的主要概念是累積更新操作然后作為一個(gè)批量異步刷入持久化存儲(chǔ)。數(shù)據(jù)的刷新可以基于時(shí)間的事件(數(shù)據(jù)條目駐留在隊(duì)列中的時(shí)間是有限的)來(lái)觸發(fā),也可以基于隊(duì)列大小的事件(如果隊(duì)列大小達(dá)到限值,會(huì)被刷新)觸發(fā),或者兩者(先發(fā)生者優(yōu)先)。
性能和一致性
啟用后寫(xiě)緩存可以通過(guò)異步更新來(lái)提高性能,但這可能會(huì)導(dǎo)致一致性下降,因?yàn)槟承└驴赡苡捎诠?jié)點(diǎn)故障或崩潰而丟失。
對(duì)于后寫(xiě)的方式只有數(shù)據(jù)的最后一次更新會(huì)被寫(xiě)入底層存儲(chǔ)。如果鍵為key1
的緩存數(shù)據(jù)分別被依次更新為值value1
、value2
和value3
,那么只有(key1,value3)
對(duì)這一個(gè)存儲(chǔ)請(qǐng)求會(huì)被傳播到持久化存儲(chǔ)。
更新性能
批量的存儲(chǔ)操作通常比按順序的單一操作更有效率,因此可以通過(guò)開(kāi)啟后寫(xiě)模式的批量操作來(lái)利用這個(gè)特性。簡(jiǎn)單類(lèi)型(put
和remove
)的簡(jiǎn)單順序更新操作可以被組合成一個(gè)批量操作。比如,連續(xù)地往緩存中寫(xiě)入(key1,value1)
、(key2,value2)
、(key3,value3)
可以通過(guò)一個(gè)單一的CacheStore.putAll(...)
操作批量處理。
#2.2.RDBMS集成
要將RDBMS作為底層存儲(chǔ),可以使用下面的CacheStore
實(shí)現(xiàn)之一:
CacheJdbcPojoStore
:使用反射將對(duì)象存儲(chǔ)為一組字段,如果在現(xiàn)有數(shù)據(jù)庫(kù)之上添加Ignite并希望使用底層表中的部分字段或所有字段,請(qǐng)使用此實(shí)現(xiàn);CacheJdbcBlobStore
:將對(duì)象以Blob格式存儲(chǔ)在底層數(shù)據(jù)庫(kù)中,當(dāng)將外部數(shù)據(jù)庫(kù)作為持久化存儲(chǔ)并希望以簡(jiǎn)單格式存儲(chǔ)數(shù)據(jù)時(shí),可以用此實(shí)現(xiàn)。
下面是CacheStore
兩種實(shí)現(xiàn)的配置示例:
#2.2.1.CacheJdbcPojoStore
使用CacheJdbcPojoStore
,可以將對(duì)象存儲(chǔ)為一組字段,并可以配置表列和對(duì)象字段之間的映射。
-
將
CacheConfiguration.cacheStoreFactory
屬性設(shè)置為org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory
并提供以下屬性:dataSourceBean
:數(shù)據(jù)庫(kù)連接憑據(jù):URL、用戶(hù)、密碼;dialect
:實(shí)現(xiàn)與數(shù)據(jù)庫(kù)兼容的SQL方言的類(lèi)。Ignite為MySQL、Oracle、H2、SQLServer和DB2數(shù)據(jù)庫(kù)提供了現(xiàn)成的實(shí)現(xiàn)。這些方言位于org.apache.ignite.cache.store.jdbc.dialect
包中;types
:此屬性用于定義數(shù)據(jù)庫(kù)表和相應(yīng)的POJO之間的映射(請(qǐng)參見(jiàn)下面的POJO配置示例)。
-
(可選)如果要在緩存上執(zhí)行SQL查詢(xún),請(qǐng)配置查詢(xún)實(shí)體。
以下示例演示了如何在MySQL表之上配置Ignite緩存。該映射到Person
類(lèi)對(duì)象的表有2列:id(INTEGER)
和name(VARCHAR)
。
可以通過(guò)XML或Java代碼配置CacheJdbcPojoStore
。
- XML
- Java
IgniteConfiguration igniteCfg = new IgniteConfiguration();CacheConfiguration<Integer, Person> personCacheCfg = new CacheConfiguration<>();personCacheCfg.setName("PersonCache");
personCacheCfg.setCacheMode(CacheMode.PARTITIONED);
personCacheCfg.setAtomicityMode(CacheAtomicityMode.ATOMIC);personCacheCfg.setReadThrough(true);
personCacheCfg.setWriteThrough(true);CacheJdbcPojoStoreFactory<Integer, Person> factory = new CacheJdbcPojoStoreFactory<>();
factory.setDialect(new MySQLDialect());
factory.setDataSourceFactory((Factory<DataSource>)() -> {MysqlDataSource mysqlDataSrc = new MysqlDataSource();mysqlDataSrc.setURL("jdbc:mysql://[host]:[port]/[database]");mysqlDataSrc.setUser("YOUR_USER_NAME");mysqlDataSrc.setPassword("YOUR_PASSWORD");return mysqlDataSrc;
});JdbcType personType = new JdbcType();
personType.setCacheName("PersonCache");
personType.setKeyType(Integer.class);
personType.setValueType(Person.class);
// Specify the schema if applicable
// personType.setDatabaseSchema("MY_DB_SCHEMA");
personType.setDatabaseTable("PERSON");personType.setKeyFields(new JdbcTypeField(java.sql.Types.INTEGER, "id", Integer.class, "id"));personType.setValueFields(new JdbcTypeField(java.sql.Types.INTEGER, "id", Integer.class, "id")),new JdbcTypeField(java.sql.Types.VARCHAR, "name", String.class, "name"));factory.setTypes(personType);personCacheCfg.setCacheStoreFactory(factory);QueryEntity qryEntity = new QueryEntity();qryEntity.setKeyType(Integer.class.getName());
qryEntity.setValueType(Person.class.getName());
qryEntity.setKeyFieldName("id");Set<String> keyFields = new HashSet<>();
keyFields.add("id");
qryEntity.setKeyFields(keyFields);LinkedHashMap<String, String> fields = new LinkedHashMap<>();
fields.put("id", "java.lang.Integer");
fields.put("name", "java.lang.String");qryEntity.setFields(fields);personCacheCfg.setQueryEntities(Collections.singletonList(qryEntity));igniteCfg.setCacheConfiguration(personCacheCfg);
Person類(lèi):
class Person implements Serializable {private static final long serialVersionUID = 0L;private int id;private String name;public Person() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}
}
#2.2.2.CacheJdbcBlobStore
CacheJdbcBlobStore
將對(duì)象以Blob格式存儲(chǔ)于底層數(shù)據(jù)庫(kù)中,它會(huì)創(chuàng)建一張表名為ENTRIES
,有名為key
和val
的列(類(lèi)型都為binary
)。
可以通過(guò)提供自定義的建表語(yǔ)句和DML語(yǔ)句,分別用于加載、更新、刪除數(shù)據(jù)來(lái)修改默認(rèn)的定義,具體請(qǐng)參見(jiàn)CacheJdbcBlobStore的javadoc。
在下面的示例中,Person類(lèi)的對(duì)象存儲(chǔ)于單一列的字節(jié)數(shù)組中。
- XML
- Java
IgniteConfiguration igniteCfg = new IgniteConfiguration();CacheConfiguration<Integer, Person> personCacheCfg = new CacheConfiguration<>();
personCacheCfg.setName("PersonCache");CacheJdbcBlobStoreFactory<Integer, Person> cacheStoreFactory = new CacheJdbcBlobStoreFactory<>();cacheStoreFactory.setUser("USER_NAME");MysqlDataSource mysqlDataSrc = new MysqlDataSource();
mysqlDataSrc.setURL("jdbc:mysql://[host]:[port]/[database]");
mysqlDataSrc.setUser("USER_NAME");
mysqlDataSrc.setPassword("PASSWORD");cacheStoreFactory.setDataSource(mysqlDataSrc);personCacheCfg.setCacheStoreFactory(cacheStoreFactory);personCacheCfg.setWriteThrough(true);
personCacheCfg.setReadThrough(true);igniteCfg.setCacheConfiguration(personCacheCfg);
#2.3.加載數(shù)據(jù)
緩存存儲(chǔ)配置完成并啟動(dòng)集群后,就可以使用下面的代碼從數(shù)據(jù)庫(kù)加載數(shù)據(jù)了:
// Load data from person table into PersonCache.
IgniteCache<Integer, Person> personCache = ignite.cache("PersonCache");personCache.loadCache(null);
#2.4.NoSQL數(shù)據(jù)庫(kù)集成
通過(guò)實(shí)現(xiàn)CacheStore
接口,可以將Ignite與任何NoSQL數(shù)據(jù)庫(kù)集成。
警告
雖然Ignite支持分布式事務(wù),但是并不會(huì)使NoSQL數(shù)據(jù)庫(kù)具有事務(wù)性,除非數(shù)據(jù)庫(kù)本身直接支持事務(wù)。
#2.4.1.Cassandra集成
Ignite通過(guò)CacheStore實(shí)現(xiàn),直接支持將Apache Cassandra用作持久化存儲(chǔ)。其利用Cassandra的異步查詢(xún)來(lái)提供loadAll()
、writeAll()
和deleteAll()
等高性能批處理操作,并自動(dòng)在Cassandra中創(chuàng)建所有必要的表和命名空間。
具體請(qǐng)參見(jiàn)Cassandra集成章節(jié)的介紹。
#3.交換空間
#3.1.概述
如果使用純內(nèi)存存儲(chǔ),隨著數(shù)據(jù)量的大小逐步達(dá)到物理內(nèi)存大小,可能導(dǎo)致內(nèi)存溢出。如果不想使用原生持久化或者外部存儲(chǔ),還可以開(kāi)啟交換,這時(shí)Ignite會(huì)將內(nèi)存中的數(shù)據(jù)移動(dòng)到磁盤(pán)上的交換空間,注意Ignite不會(huì)提供自己的交換空間實(shí)現(xiàn),而是利用了操作系統(tǒng)(OS)提供的交換功能。
打開(kāi)交換空間之后,Ignite會(huì)將數(shù)據(jù)存儲(chǔ)在內(nèi)存映射文件(MMF)中,操作系統(tǒng)會(huì)根據(jù)內(nèi)存使用情況,將其內(nèi)容交換到磁盤(pán),但是這時(shí)數(shù)據(jù)訪問(wèn)的性能會(huì)下降。另外,還沒(méi)有數(shù)據(jù)持久性保證,這意味著交換空間中的數(shù)據(jù)只在節(jié)點(diǎn)在線期間才可用。一旦存在交換空間的節(jié)點(diǎn)停止,所有數(shù)據(jù)都會(huì)丟失。因此,應(yīng)該將交換空間作為內(nèi)存的擴(kuò)展,以留出足夠的時(shí)間向集群中添加更多的節(jié)點(diǎn)讓數(shù)據(jù)重新分布,并避免集群未及時(shí)擴(kuò)容導(dǎo)致內(nèi)存溢出的錯(cuò)誤(OOM)發(fā)生。
注意
雖然交換空間位于磁盤(pán)上,但是其不能替代原生持久化。交換空間中的數(shù)據(jù)只有在節(jié)點(diǎn)在線時(shí)才有效,一旦節(jié)點(diǎn)關(guān)閉,數(shù)據(jù)將丟失。為了確保數(shù)據(jù)一直可用,應(yīng)該啟用原生持久化或使用外部存儲(chǔ)。
#3.2.啟用交換
數(shù)據(jù)區(qū)的maxSize
定義了區(qū)域的整體最大值,如果數(shù)據(jù)量達(dá)到了maxSize
,然后既沒(méi)有使用原生持久化,也沒(méi)有使用外部存儲(chǔ),那么就會(huì)拋出內(nèi)存溢出異常。使用交換可以避免這種情況的發(fā)生,做法是:
- 配置
maxSize
的值大于內(nèi)存大小,這時(shí)操作系統(tǒng)就會(huì)使用交換; - 啟用數(shù)據(jù)區(qū)的交換,如下所示。
- XML
- Java
- C#/.NET
// Node configuration.
IgniteConfiguration cfg = new IgniteConfiguration();// Durable Memory configuration.
DataStorageConfiguration storageCfg = new DataStorageConfiguration();// Creating a new data region.
DataRegionConfiguration regionCfg = new DataRegionConfiguration();// Region name.
regionCfg.setName("500MB_Region");// Setting initial RAM size.
regionCfg.setInitialSize(100L * 1024 * 1024);// Setting region max size equal to physical RAM size(5 GB)
regionCfg.setMaxSize(5L * 1024 * 1024 * 1024);// Enable swap space.
regionCfg.setSwapPath("/path/to/some/directory");// Setting the data region configuration.
storageCfg.setDataRegionConfigurations(regionCfg);// Applying the new configuration.
cfg.setDataStorageConfiguration(storageCfg);
#4.實(shí)現(xiàn)自定義CacheStore
可以實(shí)現(xiàn)自己的自定義CacheStore
并將其作為緩存的底層數(shù)據(jù)存儲(chǔ),IgniteCache
中讀寫(xiě)數(shù)據(jù)的方法將會(huì)調(diào)用CacheStore
實(shí)現(xiàn)中相應(yīng)的方法。
下表描述了CacheStore
接口中的方法:
方法 | 描述 |
---|---|
loadCache() | 調(diào)用IgniteCache.loadCache(…?) 時(shí),就會(huì)調(diào)用該方法,通常用于從數(shù)據(jù)庫(kù)預(yù)加載數(shù)據(jù)。此方法在駐有緩存的所有節(jié)點(diǎn)上執(zhí)行,要加載單個(gè)節(jié)點(diǎn)的數(shù)據(jù),需要在該節(jié)點(diǎn)上調(diào)用IgniteCache.localLoadCache() 方法。 |
load() 、write() 、delete() | 當(dāng)調(diào)用IgniteCache 接口的get() 、put() 、remove() 方法時(shí),會(huì)分別調(diào)用這3個(gè)方法,這些方法用于單條數(shù)據(jù)的通讀和通寫(xiě)。 |
loadAll() 、writeAll() 、deleteAll() | 當(dāng)調(diào)用IgniteCache 接口的getAll() 、putAll() 、removeAll() 方法時(shí),會(huì)分別調(diào)用這3個(gè)方法,這些方法用于處理多條數(shù)據(jù)的通讀和通寫(xiě),通常以批量的形式實(shí)現(xiàn)以提高性能。 |
#4.1.CacheStoreAdapter
CacheStoreAdapter
是CacheStore
的擴(kuò)展,提供了批量操作的默認(rèn)實(shí)現(xiàn),如loadAll(Iterable)
、writeAll(Collection)
和deleteAll(Collection)
,其會(huì)迭代所有條目并在每個(gè)條目上調(diào)用對(duì)應(yīng)的load()
、write()
和delete()
方法。
#4.2.CacheStoreSession
CacheStoreSession
用于持有多個(gè)操作之間的上下文,主要用于提供事務(wù)支持。一個(gè)事務(wù)中的多個(gè)操作是在同一個(gè)數(shù)據(jù)庫(kù)連接中執(zhí)行的,并在事務(wù)提交時(shí)提交該連接。通過(guò)@GridCacheStoreSessionResource
注解可以將其注入CacheStore
實(shí)現(xiàn)中。
關(guān)于如何實(shí)現(xiàn)事務(wù)化的CacheStore
,可以參見(jiàn)GitHub上的示例。
#4.3.示例
下面是一個(gè)CacheStore
的非事務(wù)化實(shí)現(xiàn)的示例:
public class CacheJdbcPersonStore extends CacheStoreAdapter<Long, Person> {// This method is called whenever the "get(...)" methods are called on IgniteCache.@Overridepublic Person load(Long key) {try (Connection conn = connection()) {try (PreparedStatement st = conn.prepareStatement("select * from PERSON where id=?")) {st.setLong(1, key);ResultSet rs = st.executeQuery();return rs.next() ? new Person(rs.getInt(1), rs.getString(2)) : null;}} catch (SQLException e) {throw new CacheLoaderException("Failed to load: " + key, e);}}@Overridepublic void write(Entry<? extends Long, ? extends Person> entry) throws CacheWriterException {try (Connection conn = connection()) {// Syntax of MERGE statement is database specific and should be adopted for your database.// If your database does not support MERGE statement then use sequentially// update, insert statements.try (PreparedStatement st = conn.prepareStatement("merge into PERSON (id, name) key (id) VALUES (?, ?)")) {Person val = entry.getValue();st.setLong(1, entry.getKey());st.setString(2, val.getName());st.executeUpdate();}} catch (SQLException e) {throw new CacheWriterException("Failed to write entry (" + entry + ")", e);}}// This method is called whenever the "remove(...)" method are called on IgniteCache.@Overridepublic void delete(Object key) {try (Connection conn = connection()) {try (PreparedStatement st = conn.prepareStatement("delete from PERSON where id=?")) {st.setLong(1, (Long) key);st.executeUpdate();}} catch (SQLException e) {throw new CacheWriterException("Failed to delete: " + key, e);}}// This method is called whenever the "loadCache()" and "localLoadCache()"// methods are called on IgniteCache. It is used for bulk-loading the cache.// If you don't need to bulk-load the cache, skip this method.@Overridepublic void loadCache(IgniteBiInClosure<Long, Person> clo, Object... args) {if (args == null || args.length == 0 || args[0] == null)throw new CacheLoaderException("Expected entry count parameter is not provided.");final int entryCnt = (Integer) args[0];try (Connection conn = connection()) {try (PreparedStatement st = conn.prepareStatement("select * from PERSON")) {try (ResultSet rs = st.executeQuery()) {int cnt = 0;while (cnt < entryCnt && rs.next()) {Person person = new Person(rs.getInt(1), rs.getString(2));clo.apply(person.getId(), person);cnt++;}}}} catch (SQLException e) {throw new CacheLoaderException("Failed to load values from cache store.", e);}}// Open JDBC connection.private Connection connection() throws SQLException {// Open connection to your RDBMS systems (Oracle, MySQL, Postgres, DB2, Microsoft SQL, etc.)Connection conn = DriverManager.getConnection("jdbc:mysql://[host]:[port]/[database]", "YOUR_USER_NAME", "YOUR_PASSWORD");conn.setAutoCommit(true);return conn;}
}
#5.集群快照
#5.1.概述
對(duì)于開(kāi)啟了原生持久化的集群,Ignite提供了創(chuàng)建集群完整快照的功能。一個(gè)Ignite快照包括了整個(gè)集群中所有存盤(pán)數(shù)據(jù)的完整一致副本,以及用于恢復(fù)過(guò)程必需的其他一些文件。
快照的結(jié)構(gòu)除了一些例外,類(lèi)似于Ignite原生持久化存儲(chǔ)目錄的布局,以下面的快照為例,看一下結(jié)構(gòu):
work
└── snapshots└── backup23012020└── db├── binary_meta│ ├── node1│ ├── node2│ └── node3├── marshaller│ ├── node1│ ├── node2│ └── node3├── node1│ └── my-sample-cache│ ├── cache_data.dat│ ├── part-3.bin│ ├── part-4.bin│ └── part-6.bin├── node2│ └── my-sample-cache│ ├── cache_data.dat│ ├── part-1.bin│ ├── part-5.bin│ └── part-7.bin└── node3└── my-sample-cache├── cache_data.dat├── part-0.bin└── part-2.bin
- 快照位于
work\snapshots
目錄下,名為backup23012020
,這里work
是Ignite的工作目錄; - 創(chuàng)建快照的集群有3個(gè)節(jié)點(diǎn),所有節(jié)點(diǎn)都在同一臺(tái)主機(jī)上運(yùn)行。在此示例中,節(jié)點(diǎn)分別名為
node1
、node2
和node3
,而實(shí)際上,它們的名字是節(jié)點(diǎn)的一致性ID; - 快照保留了
my-sample-cache
緩存的副本; db
文件夾在part-N.bin
和cache_data.dat
文件中保留數(shù)據(jù)記錄的副本。預(yù)寫(xiě)日志和檢查點(diǎn)不在快照中,因?yàn)檫@些在當(dāng)前的恢復(fù)過(guò)程中并不需要;binary_meta
和marshaller
目錄存儲(chǔ)了和元數(shù)據(jù)和編組器有關(guān)的信息。
通??煺辗植加谡麄€(gè)集群
上面的示例顯示為同一個(gè)集群創(chuàng)建的快照運(yùn)行于同一臺(tái)物理機(jī),因此整個(gè)快照位于一個(gè)位置上。實(shí)際上,集群中不同主機(jī)的所有節(jié)點(diǎn)上都會(huì)有快照數(shù)據(jù)。每個(gè)節(jié)點(diǎn)都持有快照的一段,即歸屬于該節(jié)點(diǎn)的數(shù)據(jù)快照,恢復(fù)過(guò)程會(huì)說(shuō)明恢復(fù)時(shí)如何將所有段合并在一起。
#5.2.配置快照目錄
快照默認(rèn)存儲(chǔ)在相應(yīng)Ignite節(jié)點(diǎn)的工作目錄中,并和Ignite持久化保存數(shù)據(jù)、索引、WAL和其他文件使用相同的存儲(chǔ)介質(zhì)。因?yàn)榭煺障牧撕统志没喈?dāng)?shù)目臻g,然后和Ignite持久化進(jìn)程共享磁盤(pán)IO,從而會(huì)影響應(yīng)用的性能,因此建議將快照和持久化文件存儲(chǔ)在不同的存儲(chǔ)介質(zhì)上。
可以通過(guò)更改持久化文件的存儲(chǔ)目錄或覆蓋快照的默認(rèn)位置來(lái)避免Ignite原生持久化和快照之間的這種干擾,如下所示:
- XML
- Java
IgniteConfiguration cfg = new IgniteConfiguration();File exSnpDir = U.resolveWorkDirectory(U.defaultWorkDirectory(), "ex_snapshots", true);cfg.setSnapshotPath(exSnpDir.getAbsolutePath());
#5.3.創(chuàng)建快照
Ignite提供了幾個(gè)API來(lái)進(jìn)行快照的創(chuàng)建,下面看下所有的選項(xiàng):
#5.3.1.使用控制腳本
Ignite自帶的控制腳本支持和快照有關(guān)的操作,如下所示:
#Create a cluster snapshot:
control.(sh|bat) --snapshot create snapshot_name#Cancel a running snapshot:
control.(sh|bat) --snapshot cancel snapshot_name#Kill a running snapshot:
control.(sh|bat) --kill SNAPSHOT snapshot_name
#5.3.2.使用JMX
使用SnapshotMXBean
接口,可以通過(guò)JMX執(zhí)行和快照有關(guān)的過(guò)程:
方法 | 描述 |
---|---|
createSnapshot(String snpName) | 創(chuàng)建快照 |
createSnapshot(String snpName) | 在創(chuàng)建快照的發(fā)起節(jié)點(diǎn)取消快照 |
#5.3.3.使用Java API
也可以通過(guò)Java API通過(guò)編程式創(chuàng)建快照:
CacheConfiguration<Long, String> ccfg = new CacheConfiguration<Long, String>("snapshot-cache");try (IgniteCache<Long, String> cache = ignite.getOrCreateCache(ccfg)) {cache.put(1, "Maxim");// Start snapshot operation.ignite.snapshot().createSnapshot("snapshot_02092020").get();
}
finally {ignite.destroyCache(ccfg);
}
#5.4.從快照恢復(fù)
當(dāng)前,數(shù)據(jù)恢復(fù)過(guò)程必須手動(dòng)執(zhí)行。簡(jiǎn)而言之,需要停止集群,用快照中的數(shù)據(jù)替換持久化數(shù)據(jù)和其他文件,然后重啟節(jié)點(diǎn)。
詳細(xì)過(guò)程如下:
- 停止要恢復(fù)的集群;
- 從檢查點(diǎn)目錄
$IGNITE_HOME/work/cp
中刪除所有文件; - 在每個(gè)節(jié)點(diǎn)上執(zhí)行以下操作,單獨(dú)清理
db/{node_id}
目錄,如果他不在Ignite的work
目錄下:- 從
$IGNITE_HOME/work/db/binary_meta
目錄中刪除和{nodeId}
有關(guān)的文件; - 從
$IGNITE_HOME/work/db/marshaller
目錄中刪除和{nodeId}
有關(guān)的文件; - 從
$IGNITE_HOME/work/db
目錄中刪除和{nodeId}
有關(guān)的文件和子目錄; - 將快照中屬于
{node_id}
節(jié)點(diǎn)的文件復(fù)制到$IGNITE_HOME/work/
目錄中。如果db/{node_id}
目錄不在Ignite的工作目錄下,則應(yīng)在對(duì)應(yīng)目錄復(fù)制數(shù)據(jù)文件。
- 從
- 重啟集群。
在不同拓?fù)涞募荷匣謴?fù)
有時(shí)可能在N個(gè)節(jié)點(diǎn)的集群上創(chuàng)建快照,但是需要在有M個(gè)節(jié)點(diǎn)的集群上進(jìn)行恢復(fù),下表說(shuō)明了支持的選項(xiàng):
條件 | 描述 |
---|---|
N==M | 建議方案,在拓?fù)湟恢碌募荷蟿?chuàng)建和使用快照。 |
N<M | 在M個(gè)節(jié)點(diǎn)的集群上首先啟動(dòng)N個(gè)節(jié)點(diǎn),應(yīng)用快照,然后將剩余的M-N 個(gè)集群節(jié)點(diǎn)加入拓?fù)?#xff0c;然后等待數(shù)據(jù)再平衡和索引重建。 |
N>M | 不支持。 |
#5.5.一致性保證
在Ignite的持久化文件、索引、模式、二進(jìn)制元數(shù)據(jù)、編組器以及節(jié)點(diǎn)的其他文件上的并發(fā)操作以及正在進(jìn)行的修改,所有的快照都是完全一致的。
集群范圍的快照一致性是通過(guò)觸發(fā)分區(qū)映射交換過(guò)程實(shí)現(xiàn)的,通過(guò)這樣做,集群最終達(dá)到的狀態(tài)是所有之前發(fā)起的事務(wù)全部完成,新的事務(wù)全部暫停,這個(gè)過(guò)程結(jié)束之后,集群就會(huì)發(fā)起快照創(chuàng)建過(guò)程,PME過(guò)程會(huì)確??煺找砸恢碌臓顟B(tài)包括了主快照和備份快照。
Ignite持久化文件與其快照副本之間的一致性是通過(guò)將原始文件復(fù)制到目標(biāo)快照目錄并跟蹤所有正在進(jìn)行的更改來(lái)實(shí)現(xiàn)的,跟蹤更改可能需要額外的空間。
#5.6.當(dāng)前的限制
快照過(guò)程有若干限制,如果要用于生產(chǎn)環(huán)境需要事先了解:
- 不支持某個(gè)表/緩存的快照,只能創(chuàng)建整個(gè)集群的快照;
- 未開(kāi)啟原生持久化的表/緩存,不支持快照;
- 加密的緩存不包括在快照中;
- 同時(shí)只能執(zhí)行一個(gè)快照操作;
- 如果一個(gè)服務(wù)端節(jié)點(diǎn)離開(kāi)集群,快照過(guò)程會(huì)被中斷;
- 快照只能在具有相同節(jié)點(diǎn)ID的同一集群拓?fù)渲谢謴?fù);
- 目前還不支持自動(dòng)化的恢復(fù)過(guò)程,只能手工執(zhí)行。
#6.磁盤(pán)壓縮
磁盤(pán)壓縮是指將數(shù)據(jù)頁(yè)面寫(xiě)入磁盤(pán)時(shí)對(duì)其進(jìn)行壓縮的過(guò)程,以減小磁盤(pán)空間占用。這些頁(yè)面在內(nèi)存中是不壓縮的,但是當(dāng)將數(shù)據(jù)刷新到磁盤(pán)時(shí),將使用配置的算法對(duì)其進(jìn)行壓縮。這僅適用于開(kāi)啟原生持久化的數(shù)據(jù)頁(yè)面并且不會(huì)壓縮索引或WAL記錄的數(shù)據(jù)頁(yè),WAL記錄壓縮是可以單獨(dú)啟用的。
磁盤(pán)頁(yè)面壓縮是在每個(gè)緩存的配置中設(shè)定的,緩存必須在持久化的數(shù)據(jù)區(qū)中。目前沒(méi)有選項(xiàng)可全局啟用磁盤(pán)頁(yè)面壓縮,此外,還必須必須滿足以下的條件:
- 將持久化配置中的
pageSize
屬性設(shè)置為文件系統(tǒng)頁(yè)面大小的至少2倍,這意味著頁(yè)面大小必須為8K或16K; - 啟用
ignite-compress
模塊。
要為某個(gè)緩存啟用磁盤(pán)頁(yè)面壓縮,需要在緩存配置中提供一種可用的壓縮算法,如下所示:
- XML
- Java
DataStorageConfiguration dsCfg = new DataStorageConfiguration();//set the page size to 2 types of the disk page size
dsCfg.setPageSize(4096 * 2);//enable persistence for the default data region
dsCfg.setDefaultDataRegionConfiguration(new DataRegionConfiguration().setPersistenceEnabled(true));IgniteConfiguration cfg = new IgniteConfiguration();
cfg.setDataStorageConfiguration(dsCfg);CacheConfiguration cacheCfg = new CacheConfiguration("myCache");
//enable disk page compression for this cache
cacheCfg.setDiskPageCompression(DiskPageCompression.LZ4);
//optionally set the compression level
cacheCfg.setDiskPageCompressionLevel(10);cfg.setCacheConfiguration(cacheCfg);Ignite ignite = Ignition.start(cfg);
#6.1.支持的算法
支持的壓縮算法包括:
ZSTD
:支持從-131072到22的壓縮級(jí)別(默認(rèn)值:3);LZ4
:支持從0到17的壓縮級(jí)別(默認(rèn)值:0);SNAPPY
SKIP_GARBAGE
:該算法僅從半填充頁(yè)面中提取有用的數(shù)據(jù),而不壓縮數(shù)據(jù)。
#7.持久化調(diào)優(yōu)
本章節(jié)總結(jié)了Ignite原生持久化調(diào)優(yōu)的最佳實(shí)踐。
#7.1.調(diào)整頁(yè)面大小
Ignite的頁(yè)面大小(DataStorageConfiguration.pageSize
)不要小于存儲(chǔ)設(shè)備(SSD、閃存、HDD等)的頁(yè)面大小以及操作系統(tǒng)緩存頁(yè)面的大小,默認(rèn)值為4KB。
操作系統(tǒng)的緩存頁(yè)面大小很容易就可以通過(guò)系統(tǒng)工具和參數(shù)獲取到。
存儲(chǔ)設(shè)備比如SSD的頁(yè)面大小可以在設(shè)備的說(shuō)明上找到,如果廠商未提供這些信息,可以運(yùn)行SSD的基準(zhǔn)測(cè)試來(lái)算出這個(gè)數(shù)值,如果還是難以拿到這個(gè)數(shù)值,可以使用4KB作為Ignite的頁(yè)面大小。很多廠商為了適應(yīng)4KB的隨機(jī)寫(xiě)工作負(fù)載不得不調(diào)整驅(qū)動(dòng),因?yàn)楹芏鄻?biāo)準(zhǔn)基準(zhǔn)測(cè)試都是默認(rèn)使用4KB,來(lái)自英特爾的白皮書(shū)也確認(rèn)4KB足夠了。
選定最優(yōu)值之后,可以將其用于集群的配置:
- XML
- Java
- C#/.NET
IgniteConfiguration cfg = new IgniteConfiguration();// Durable memory configuration.
DataStorageConfiguration storageCfg = new DataStorageConfiguration();// Changing the page size to 8 KB.
storageCfg.setPageSize(8192);cfg.setDataStorageConfiguration(storageCfg);
#7.2.單獨(dú)保存WAL
考慮為數(shù)據(jù)文件以及預(yù)寫(xiě)日志(WAL)使用單獨(dú)的磁盤(pán)設(shè)備。Ignite會(huì)主動(dòng)地寫(xiě)入數(shù)據(jù)文件以及WAL文件,下面的示例會(huì)顯示如何為數(shù)據(jù)存儲(chǔ)、WAL以及WAL存檔配置單獨(dú)的路徑:
- XML
- Java
- C#/.NET
IgniteConfiguration cfg = new IgniteConfiguration();// Configuring Native Persistence.
DataStorageConfiguration storeCfg = new DataStorageConfiguration();// Sets a path to the root directory where data and indexes are to be persisted.
// It's assumed the directory is on a separated SSD.
storeCfg.setStoragePath("/ssd/storage");// Sets a path to the directory where WAL is stored.
// It's assumed the directory is on a separated HDD.
storeCfg.setWalPath("/wal");// Sets a path to the directory where WAL archive is stored.
// The directory is on the same HDD as the WAL.
storeCfg.setWalArchivePath("/wal/archive");cfg.setDataStorageConfiguration(storeCfg);// Starting the node.
Ignite ignite = Ignition.start(cfg);
#7.3.增加WAL段大小
WAL段的默認(rèn)大小(64MB)在高負(fù)載情況下可能是低效的,因?yàn)樗鼘?dǎo)致WAL在段之間頻繁切換,并且切換/輪轉(zhuǎn)是昂貴的操作。將段大小設(shè)置為較大的值(最多2GB)可能有助于減少切換操作的次數(shù),不過(guò)這將增加預(yù)寫(xiě)日志的占用空間。
具體請(qǐng)參見(jiàn)修改WAL段大小。
#7.4.調(diào)整WAL模式
考慮其它WAL模式替代默認(rèn)模式。每種模式在節(jié)點(diǎn)故障時(shí)提供不同程度的可靠性,并且可靠性與速度成反比,即,WAL模式越可靠,則速度越慢。因此,如果具體業(yè)務(wù)不需要高可靠性,那么可以切換到可靠性較低的模式。
具體可以看WAL模式的相關(guān)內(nèi)容。
#7.5.禁用WAL
有時(shí)禁用WAL也會(huì)改進(jìn)性能。
#7.6.頁(yè)面寫(xiě)入限流
Ignite會(huì)定期地啟動(dòng)檢查點(diǎn)進(jìn)程,以在內(nèi)存和磁盤(pán)間同步臟頁(yè)面。臟頁(yè)面是已在內(nèi)存中更新但是還未寫(xiě)入對(duì)應(yīng)的分區(qū)文件的頁(yè)面(更新只是添加到了WAL)。這個(gè)進(jìn)程在后臺(tái)進(jìn)行,對(duì)應(yīng)用沒(méi)有影響。
但是,如果計(jì)劃進(jìn)行檢查點(diǎn)的臟頁(yè)面在寫(xiě)入磁盤(pán)前被更新,它之前的狀態(tài)會(huì)被復(fù)制進(jìn)某個(gè)區(qū)域,叫做檢查點(diǎn)緩沖區(qū)。如果這個(gè)緩沖區(qū)溢出,那么在檢查點(diǎn)處理過(guò)程中,Ignite會(huì)停止所有的更新。因此,寫(xiě)入性能可能降為0,直至檢查點(diǎn)過(guò)程完成,如下圖所示:
當(dāng)檢查點(diǎn)處理正在進(jìn)行中時(shí),如果臟頁(yè)面數(shù)達(dá)到閾值,同樣的情況也會(huì)發(fā)生,這會(huì)使Ignite強(qiáng)制安排一個(gè)新的檢查點(diǎn)執(zhí)行,并停止所有的更新操作直到第一個(gè)檢查點(diǎn)執(zhí)行完成。
當(dāng)磁盤(pán)較慢或者更新過(guò)于頻繁時(shí),這兩種情況都會(huì)發(fā)生,要減少或者防止這樣的性能下降,可以考慮啟用頁(yè)面寫(xiě)入限流算法。這個(gè)算法會(huì)在檢查點(diǎn)緩沖區(qū)填充過(guò)快或者臟頁(yè)面占比過(guò)高時(shí),將更新操作的性能降低到磁盤(pán)的速度。
頁(yè)面寫(xiě)入限流剖析
要了解更多的信息,可以看相關(guān)的Wiki頁(yè)面。
下面的示例顯示了如何開(kāi)啟頁(yè)面寫(xiě)入限流:
- XML
- Java
- C#/.NET
IgniteConfiguration cfg = new IgniteConfiguration();// Configuring Native Persistence.
DataStorageConfiguration storeCfg = new DataStorageConfiguration();// Enabling the writes throttling.
storeCfg.setWriteThrottlingEnabled(true);cfg.setDataStorageConfiguration(storeCfg);
// Starting the node.
Ignite ignite = Ignition.start(cfg);
#7.7.調(diào)整檢查點(diǎn)緩沖區(qū)大小
前述章節(jié)中描述的檢查點(diǎn)緩沖區(qū)大小,是檢查點(diǎn)處理的觸發(fā)器之一。
緩沖區(qū)的默認(rèn)大小是根據(jù)數(shù)據(jù)區(qū)大小計(jì)算的。
數(shù)據(jù)區(qū)大小 | 默認(rèn)檢查點(diǎn)緩沖區(qū)大小 |
---|---|
< 1GB | MIN (256 MB, 數(shù)據(jù)區(qū)大小) |
1GB ~ 8GB | 數(shù)據(jù)區(qū)大小/4 |
> 8GB | 2GB |
默認(rèn)的緩沖區(qū)大小并沒(méi)有為寫(xiě)密集型應(yīng)用進(jìn)行優(yōu)化,因?yàn)樵诖笮〗咏鼧?biāo)稱(chēng)值時(shí),頁(yè)面寫(xiě)入限流算法會(huì)降低寫(xiě)入的性能,因此在正在進(jìn)行檢查點(diǎn)處理時(shí)還希望保持寫(xiě)入性能,可以考慮增加DataRegionConfiguration.checkpointPageBufferSize
,并且開(kāi)啟寫(xiě)入限流來(lái)阻止性能的下降:
- XML
- Java
- C#/.NET
IgniteConfiguration cfg = new IgniteConfiguration();// Configuring Native Persistence.
DataStorageConfiguration storeCfg = new DataStorageConfiguration();// Enabling the writes throttling.
storeCfg.setWriteThrottlingEnabled(true);// Increasing the buffer size to 1 GB.
storeCfg.getDefaultDataRegionConfiguration().setCheckpointPageBufferSize(1024L * 1024 * 1024);cfg.setDataStorageConfiguration(storeCfg);// Starting the node.
Ignite ignite = Ignition.start(cfg);
在上例中,默認(rèn)數(shù)據(jù)區(qū)的檢查點(diǎn)緩沖區(qū)大小配置為1GB。
#7.8.啟用直接I/O
通常當(dāng)應(yīng)用訪問(wèn)磁盤(pán)上的數(shù)據(jù)時(shí),操作系統(tǒng)拿到數(shù)據(jù)后會(huì)將其寫(xiě)入一個(gè)文件緩沖區(qū)緩存,寫(xiě)操作也是同樣,操作系統(tǒng)首先將數(shù)據(jù)寫(xiě)入緩存,然后才會(huì)傳輸?shù)酱疟P(pán),要消除這個(gè)過(guò)程,可以打開(kāi)直接IO,這時(shí)數(shù)據(jù)會(huì)忽略文件緩沖區(qū)緩存,直接從磁盤(pán)進(jìn)行讀寫(xiě)。
Ignite中的直接I/O插件用于加速檢查點(diǎn)進(jìn)程,它的作用是將內(nèi)存中的臟頁(yè)面寫(xiě)入磁盤(pán),建議將直接IO插件用于寫(xiě)密集型負(fù)載環(huán)境中。
注意
注意,無(wú)法專(zhuān)門(mén)為WAL文件開(kāi)啟直接I/O,但是開(kāi)啟直接I/O可以為WAL文件帶來(lái)一點(diǎn)好處,就是WAL數(shù)據(jù)不會(huì)在操作系統(tǒng)的緩沖區(qū)緩存中存儲(chǔ)過(guò)長(zhǎng)時(shí)間,它會(huì)在下一次頁(yè)面緩存掃描中被刷新(依賴(lài)于WAL模式),然后從頁(yè)面緩存中刪除。
要啟用直接I/O插件,需要在二進(jìn)制包中將{IGNITE_HOME}/libs/optional/ignite-direct-io
文件夾上移一層至libs/optional/ignite-direct-io
文件夾,或者也可以作為一個(gè)Maven構(gòu)件引入,具體請(qǐng)參見(jiàn)這里的介紹。
通過(guò)IGNITE_DIRECT_IO_ENABLED
系統(tǒng)屬性,也可以在運(yùn)行時(shí)啟用/禁用該插件。
相關(guān)的Wiki頁(yè)面有更多的細(xì)節(jié)。
#7.9.購(gòu)買(mǎi)產(chǎn)品級(jí)SSD
限于SSD的操作特性,在經(jīng)歷幾個(gè)小時(shí)的高強(qiáng)度寫(xiě)入負(fù)載之后,Ignite原生持久化的性能可能會(huì)下降,因此需要考慮購(gòu)買(mǎi)快速的產(chǎn)品級(jí)SSD來(lái)保證高性能,或者切換到非易失性?xún)?nèi)存設(shè)備比如Intel Optane持久化內(nèi)存。
#7.10.SSD預(yù)留空間
由于SSD預(yù)留空間的原因,50%使用率的磁盤(pán)的隨機(jī)寫(xiě)性能要好于90%使用率的磁盤(pán),因此需要考慮購(gòu)買(mǎi)高預(yù)留空間比率的SSD,然后還要確保廠商能提供工具來(lái)進(jìn)行相關(guān)的調(diào)整。
Intel 3D XPoint
考慮使用3D XPoint驅(qū)動(dòng)器代替常規(guī)SSD,以避免由SSD級(jí)別上的低預(yù)留空間設(shè)置和恒定垃圾收集造成的瓶頸。具體可以看這里。
配置緩存
#1.緩存配置
本章節(jié)介紹如何設(shè)定緩存的配置參數(shù),緩存創(chuàng)建之后,這些參數(shù)將無(wú)法修改。
Ignite中的緩存和表
緩存驅(qū)動(dòng)的配置方式是配置選項(xiàng)之一,還可以使用CREATE TABLE
這樣的標(biāo)準(zhǔn)SQL命令來(lái)配置緩存/表,具體請(qǐng)參見(jiàn)鍵-值緩存與SQL表章節(jié)的內(nèi)容以了解Ignite中緩存和表的關(guān)系。
#1.1.配置示例
下面是緩存配置的示例:
- XML
- Java
- C#/.NET
- SQL
CacheConfiguration cacheCfg = new CacheConfiguration("myCache");cacheCfg.setCacheMode(CacheMode.PARTITIONED);
cacheCfg.setBackups(2);
cacheCfg.setRebalanceMode(CacheRebalanceMode.SYNC);
cacheCfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
cacheCfg.setPartitionLossPolicy(PartitionLossPolicy.READ_ONLY_SAFE);IgniteConfiguration cfg = new IgniteConfiguration();
cfg.setCacheConfiguration(cacheCfg);// Start a node.
Ignition.start(cfg);
完整的參數(shù)列表,請(qǐng)參見(jiàn)CacheConfiguration的javadoc。
參數(shù) | 描述 | 默認(rèn)值 |
---|---|---|
name | 緩存名 | |
cacheMode | 該參數(shù)定義了數(shù)據(jù)在集群中的分布方式。在默認(rèn)的PARTITIONED 模式中,整體數(shù)據(jù)集被拆分為分區(qū),然后所有的分區(qū)再以平衡的方式分布于相關(guān)的節(jié)點(diǎn)上。而在REPLICATED 模式中,所有的數(shù)據(jù)在所有的節(jié)點(diǎn)上都復(fù)制一份,具體請(qǐng)參見(jiàn)分區(qū)/復(fù)制模式章節(jié)的介紹。 | PARTITIONED |
writeSynchronizationMode | 寫(xiě)同步模式,具體請(qǐng)參見(jiàn)配置分區(qū)備份章節(jié)的內(nèi)容。 | PRIMARY_SYNC |
rebalanceMode | 該參數(shù)控制再平衡過(guò)程的執(zhí)行方式??蛇x值包括:SYNC :所有緩存操作都會(huì)被阻塞直到再平衡結(jié)束;ASYNC :再平衡在后臺(tái)執(zhí)行;NONE :再平衡不會(huì)被觸發(fā)。 | ASYNC |
backups | 緩存的備份分區(qū)數(shù)量。 | 0 |
partitionLossPolicy | 分區(qū)丟失策略 | IGNORE |
readFromBackup | 如果本地的備份分區(qū)可用,則從備份分區(qū)讀取數(shù)據(jù),而不是向主分區(qū)請(qǐng)求數(shù)據(jù)(可能位于遠(yuǎn)程節(jié)點(diǎn))。 | true |
queryPrallelism | 單節(jié)點(diǎn)在緩存上執(zhí)行SQL查詢(xún)的線程數(shù),具體請(qǐng)參見(jiàn)性能優(yōu)化的查詢(xún)并行度相關(guān)章節(jié)的內(nèi)容。 | 1 |
#1.2.緩存模板
緩存模板是在集群中注冊(cè)的CacheConfiguration
實(shí)例,然后用作后續(xù)創(chuàng)建新緩存或SQL表的基礎(chǔ),一個(gè)從模板創(chuàng)建的緩存或表會(huì)繼承該模板的所有屬性。
當(dāng)使用CREATE TABLE命令建表時(shí),模板非常有用,因?yàn)樵撁畈⒉恢С炙械木彺鎱?shù)。
提示
當(dāng)前,CREATE TABLE和REST命令支持模板。
創(chuàng)建模板時(shí),需要定義一個(gè)緩存配置然后將其加入Ignite
實(shí)例中,如下所示。如果希望在XML配置文件中定義緩存模板,需要在模板名后面加一個(gè)*
號(hào),這個(gè)是用于標(biāo)示該配置是一個(gè)模板而不是實(shí)際的緩存。
- XML
- Java
- C#/.NET
IgniteConfiguration igniteCfg = new IgniteConfiguration();try (Ignite ignite = Ignition.start(igniteCfg)) {CacheConfiguration cacheCfg = new CacheConfiguration("myCacheTemplate");cacheCfg.setBackups(2);cacheCfg.setCacheMode(CacheMode.PARTITIONED);// Register the cache templateignite.addCacheConfiguration(cacheCfg);
}
緩存模板在集群中注冊(cè)之后,就可以用相同的配置創(chuàng)建其他緩存了。
#2.配置分區(qū)備份
Ignite默認(rèn)為每個(gè)分區(qū)持有一個(gè)副本(整個(gè)數(shù)據(jù)集的一個(gè)副本),這時(shí)如果一個(gè)或者多個(gè)節(jié)點(diǎn)故障,存儲(chǔ)于這些節(jié)點(diǎn)上的分區(qū)就會(huì)丟失,為了避免這種情況,可以配置Ignite維護(hù)分區(qū)的備份副本。
提示
備份默認(rèn)是禁用的。
備份副本是緩存(表)級(jí)的配置,如果配置了2個(gè)備份副本,集群會(huì)為每個(gè)分區(qū)維護(hù)3個(gè)副本。其中一個(gè)分區(qū)稱(chēng)為主分區(qū),其他2個(gè)稱(chēng)為備份分區(qū)。擴(kuò)展來(lái)說(shuō),具有主分區(qū)的節(jié)點(diǎn)稱(chēng)為該分區(qū)中存儲(chǔ)的數(shù)據(jù)的主節(jié)點(diǎn),備份分區(qū)對(duì)應(yīng)的節(jié)點(diǎn)稱(chēng)為備份節(jié)點(diǎn)。
當(dāng)某些數(shù)據(jù)對(duì)應(yīng)的主分區(qū)所在的節(jié)點(diǎn)離開(kāi)集群,Ignite會(huì)觸發(fā)分區(qū)映射交換(PME)過(guò)程,PME會(huì)標(biāo)記這些數(shù)據(jù)對(duì)應(yīng)的某個(gè)已配置的備份分區(qū)為主分區(qū)。
備份分區(qū)增加了數(shù)據(jù)的可用性和某些場(chǎng)景的數(shù)據(jù)讀取速度,因?yàn)槿绻镜毓?jié)點(diǎn)的備份分區(qū)可用,Ignite會(huì)從備份分區(qū)讀取數(shù)據(jù)(這是默認(rèn)的行為,但是可以禁用)。但是增加了內(nèi)存的消耗或者持久化存儲(chǔ)的大小(如果開(kāi)啟)。
#2.1.配置備份
在緩存配置中配置backups
屬性,可以配置備份副本的數(shù)量。
- XML
- Java
- C#/.NET
CacheConfiguration cacheCfg = new CacheConfiguration();cacheCfg.setName("cacheName");
cacheCfg.setCacheMode(CacheMode.PARTITIONED);
cacheCfg.setBackups(1);IgniteConfiguration cfg = new IgniteConfiguration();cfg.setCacheConfiguration(cacheCfg);// Start the node.
Ignite ignite = Ignition.start(cfg);
#2.2.同步和異步備份
通過(guò)指定寫(xiě)同步模式,可以配置更新在主備副本之間是同步模式還是異步模式,如下所示:
- XML
- Java
- C#/.NET
CacheConfiguration cacheCfg = new CacheConfiguration();cacheCfg.setName("cacheName");
cacheCfg.setBackups(1);
cacheCfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
IgniteConfiguration cfg = new IgniteConfiguration();cfg.setCacheConfiguration(cacheCfg);// Start the node.
Ignition.start(cfg);
寫(xiě)同步模式有如下的可選值:
值 | 描述 |
---|---|
FULL_SYNC | 客戶(hù)端節(jié)點(diǎn)會(huì)等待所有相關(guān)的遠(yuǎn)程節(jié)點(diǎn)(主和備)寫(xiě)入或者提交完成。 |
FULL_ASYNC | 客戶(hù)端節(jié)點(diǎn)不會(huì)等待來(lái)自相關(guān)節(jié)點(diǎn)的響應(yīng),這時(shí)遠(yuǎn)程節(jié)點(diǎn)會(huì)在緩存寫(xiě)入或者事務(wù)提交方法完成之后稍晚些收到狀態(tài)更新。 |
PRIMARY_SYNC | 默認(rèn)模式,客戶(hù)端節(jié)點(diǎn)會(huì)等待主節(jié)點(diǎn)的寫(xiě)入或者提交完成,但是不會(huì)等待備份的更新。 |
#3.分區(qū)丟失策略
在整個(gè)集群的生命周期中,由于分區(qū)的主節(jié)點(diǎn)和備份節(jié)點(diǎn)的故障可能出現(xiàn)分區(qū)丟失的情況,這會(huì)導(dǎo)致部分?jǐn)?shù)據(jù)丟失,需要根據(jù)場(chǎng)景進(jìn)行處理。
當(dāng)一個(gè)分區(qū)的主副本和所有備份副本均不在線,即該分區(qū)的主節(jié)點(diǎn)和備份節(jié)點(diǎn)全部故障時(shí),該分區(qū)將丟失。這意味著對(duì)于給定的緩存,能承受的節(jié)點(diǎn)故障數(shù)不能超過(guò)緩存?zhèn)浞輸?shù)。
當(dāng)集群拓?fù)浒l(fā)生變更時(shí),Ignite會(huì)檢查變更是否導(dǎo)致分區(qū)丟失,并根據(jù)配置的分區(qū)丟失策略和基線自動(dòng)調(diào)整設(shè)置,允許或禁止對(duì)緩存進(jìn)行操作,具體請(qǐng)參見(jiàn)下一章節(jié)的介紹。
對(duì)于純內(nèi)存緩存,當(dāng)分區(qū)丟失時(shí),除非數(shù)據(jù)重新加載,否則分區(qū)中的數(shù)據(jù)將無(wú)法恢復(fù)。對(duì)于持久化緩存,數(shù)據(jù)不會(huì)物理丟失,因?yàn)樗驯怀志没酱疟P(pán)上。當(dāng)發(fā)生故障或斷開(kāi)連接的節(jié)點(diǎn)回到集群時(shí)(重啟后),將從磁盤(pán)上加載數(shù)據(jù)。這時(shí)需要重置丟失的分區(qū)的狀態(tài)才能繼續(xù)使用數(shù)據(jù),具體請(qǐng)參見(jiàn)處理分區(qū)丟失章節(jié)的介紹。
#3.1.配置分區(qū)丟失策略
Ignite支持以下的分區(qū)丟失策略:
策略 | 描述 |
---|---|
IGNORE | 分區(qū)丟失將被忽略。集群將丟失的分區(qū)視為空分區(qū)。當(dāng)請(qǐng)求該分區(qū)的數(shù)據(jù)時(shí),將返回空值,就好像數(shù)據(jù)從不存在一樣。此策略只能在純內(nèi)存集群中使用且是默認(rèn)值,這個(gè)模式中啟用了基線自動(dòng)調(diào)整且超時(shí)為0。在所有其他配置(集群中只要有一個(gè)數(shù)據(jù)區(qū)開(kāi)啟了持久化)中,IGNORE 策略都會(huì)被READ_WRITE_SAFE 替代,即使在緩存配置中顯式指定也不行。 |
READ_WRITE_SAFE | 緩存丟失分區(qū)的讀寫(xiě)嘗試都會(huì)拋出異常,但是在線分區(qū)的讀寫(xiě)是正常的。 |
READ_ONLY_SAFE | 緩存處于只讀狀態(tài),緩存的寫(xiě)操作會(huì)拋出異常,丟失分區(qū)的讀操作也會(huì)拋出異常,具體請(qǐng)參見(jiàn)處理分區(qū)丟失章節(jié)的介紹。 |
分區(qū)丟失策略是緩存級(jí)的配置。
- XML
- Java
CacheConfiguration cacheCfg = new CacheConfiguration("myCache");cacheCfg.setPartitionLossPolicy(PartitionLossPolicy.READ_ONLY_SAFE);
#3.2.監(jiān)聽(tīng)分區(qū)丟失事件
當(dāng)發(fā)生分區(qū)丟失時(shí),可以監(jiān)聽(tīng)EVT_CACHE_REBALANCE_PART_DATA_LOST
事件的通知。每個(gè)丟失的分區(qū)都會(huì)觸發(fā)該事件,其包含了丟失的分區(qū)號(hào)以及持有該分區(qū)的節(jié)點(diǎn)ID。只有使用READ_WRITE_SAFE
或READ_ONLY_SAFE
策略時(shí),才會(huì)觸發(fā)分區(qū)丟失事件。
首先需要在集群的配置中啟用事件,具體參見(jiàn)啟用事件的介紹。
Ignite ignite = Ignition.start();IgnitePredicate<Event> locLsnr = evt -> {CacheRebalancingEvent cacheEvt = (CacheRebalancingEvent) evt;int lostPart = cacheEvt.partition();ClusterNode node = cacheEvt.discoveryNode();System.out.println(lostPart);return true; // Continue listening.
};ignite.events().localListen(locLsnr, EventType.EVT_CACHE_REBALANCE_PART_DATA_LOST);
關(guān)于其他和分區(qū)再平衡有關(guān)的事件,可以參見(jiàn)分區(qū)再平衡事件章節(jié)的介紹。
#3.3.處理分區(qū)丟失
如果數(shù)據(jù)沒(méi)有物理丟失,可以將該節(jié)點(diǎn)恢復(fù)然后重置丟失分區(qū)的狀態(tài),這樣就可以繼續(xù)處理該數(shù)據(jù),通過(guò)控制腳本,或者在特定的緩存上調(diào)用Ignite.resetLostPartitions(cacheNames)
,可以重置分區(qū)的狀態(tài)。
ignite.resetLostPartitions(Arrays.asList("myCache"));
控制腳本命令為:
control.sh --cache reset_lost_partitions myCache
如果不重置丟失的分區(qū),根據(jù)緩存策略的配置,從丟失分區(qū)的讀寫(xiě)操作可能會(huì)拋出CacheException
,通過(guò)分析上層的觸發(fā)原因,可以檢查該異常是否由分區(qū)狀態(tài)導(dǎo)致:
IgniteCache<Integer, Integer> cache = ignite.cache("myCache");try {Integer value = cache.get(3);System.out.println(value);
} catch (CacheException e) {if (e.getCause() instanceof CacheInvalidStateException) {System.out.println(e.getCause().getMessage());} else {e.printStackTrace();}
}
通過(guò)IgniteCache.lostPartitions()
,可以拿到緩存丟失分區(qū)的列表:
IgniteCache<Integer, String> cache = ignite.cache("myCache");cache.lostPartitions();
#3.4.從丟失分區(qū)中恢復(fù)
下面的章節(jié)會(huì)介紹根據(jù)集群的不同配置,如何從分區(qū)丟失中恢復(fù)。
#3.4.1.IGNORE策略的純內(nèi)存集群
在此配置中,該IGNORE
策略?xún)H適用于啟用基線自動(dòng)調(diào)整且超時(shí)為0的場(chǎng)景,這也是純內(nèi)存集群的默認(rèn)設(shè)置。這時(shí)將忽略分區(qū)丟失,緩存仍然可以操作,丟失的分區(qū)會(huì)被視為空分區(qū)。
當(dāng)禁用基線自動(dòng)調(diào)整或超時(shí)時(shí)間大于0時(shí),IGNORE
策略會(huì)被替換為READ_WRITE_SAFE
。
#3.4.2.READ_WRITE_SAFE或READ_ONLY_SAFE策略的純內(nèi)存集群
重置丟失的分區(qū)之前,對(duì)緩存的操作將被阻止。重置后,緩存可以繼續(xù)使用,但是數(shù)據(jù)將丟失。
禁用基線自動(dòng)調(diào)整或超時(shí)大于0時(shí),必須在重置丟失的分區(qū)之前將節(jié)點(diǎn)(每個(gè)分區(qū)至少一個(gè)分區(qū)所有者)恢復(fù)到基線拓?fù)?。否則,Ignite.resetLostPartitions(cacheNames)
會(huì)拋出一個(gè)消息為Cannot reset lost partitions because no baseline nodes are online [cache=someCahe, partition=someLostPart]
的ClusterTopologyCheckedException
,表明無(wú)法安全恢復(fù)。如果由于某種原因(例如硬件故障)而無(wú)法恢復(fù)節(jié)點(diǎn),需要在重置丟失的分區(qū)之前將它們從基線拓?fù)渲惺謩?dòng)刪除。
#3.4.3.開(kāi)啟持久化的集群
如果所有的數(shù)據(jù)區(qū)都開(kāi)啟了持久化(沒(méi)有純內(nèi)存數(shù)據(jù)區(qū)),那么有兩種從丟失分區(qū)中恢復(fù)的方式(只要數(shù)據(jù)沒(méi)有物理?yè)p壞):
- 讓所有的節(jié)點(diǎn)返回到基線;
- 重置丟失的分區(qū)(所有的緩存調(diào)用
Ignite.resetLostPartitions(…?)
)。
或者:
- 停止所有的節(jié)點(diǎn);
- 啟動(dòng)包括故障節(jié)點(diǎn)在內(nèi)的所有節(jié)點(diǎn),然后激活集群。
如果某些節(jié)點(diǎn)無(wú)法返回,在嘗試重置丟失分區(qū)狀態(tài)前,需要將他們從基線拓?fù)渲袆h除。
#3.4.4.同時(shí)有純內(nèi)存和持久化緩存的集群
如果集群同時(shí)有純內(nèi)存的數(shù)據(jù)區(qū)和持久化的數(shù)據(jù)區(qū),那么純內(nèi)存的緩存會(huì)和配置為READ_WRITE_SAFE
的純內(nèi)存集群的處理方式一致,而持久化的緩存會(huì)和持久化的集群的處理方式一致。
#4.原子化模式
緩存默認(rèn)僅支持原子操作,而批量操作(例如putAll()
或removeAll()
)則按順序單獨(dú)執(zhí)行寫(xiě)入和刪除。但是也可以啟用事務(wù)支持并將一個(gè)或多個(gè)緩存操作,可能對(duì)應(yīng)一個(gè)或者多個(gè)鍵,分組為單個(gè)原子事務(wù)。這些操作在沒(méi)有任何其他交叉操作的情況下執(zhí)行,或全部成功或全部失敗,沒(méi)有部分成功的狀態(tài)。
要啟用緩存的事務(wù)支持,需要將緩存配置中的atomicityMode
參數(shù)設(shè)置為TRANSACTIONAL
。
警告
如果在一個(gè)緩存組中配置了多個(gè)緩存,這些緩存的原子化模式應(yīng)全部相同,不能有的是TRANSACTIONAL
,有的是ATOMIC
。
Ignite支持3種原子化模式,如下表所示:
原子化模式 | 描述 |
---|---|
ATOMIC | 默認(rèn)模式,所有操作都會(huì)原子化地執(zhí)行,一次一個(gè),不支持事務(wù)。ATOMIC 模式通過(guò)避免事務(wù)鎖,提供了最好的性能,同時(shí)為每個(gè)單個(gè)操作提供了數(shù)據(jù)原子性和一致性。比如putAll(…?) 以及removeAll(…?) 方法這樣的批量操作,并不以事務(wù)方式執(zhí)行,可能部分失敗,如果發(fā)生了這種情況,會(huì)拋出CachePartialUpdateException 異常,其中包含了更新失敗的鍵列表。 |
TRANSACTIONAL | 在鍵-值A(chǔ)PI層面開(kāi)啟了符合ACID的事務(wù)支持,但是SQL不支持事務(wù)。該模式的事務(wù)支持不同的并發(fā)模型和隔離級(jí)別。如果確實(shí)需要符合ACID操作才建議開(kāi)啟這個(gè)模式,因?yàn)槭聞?wù)會(huì)導(dǎo)致性能下降。具體請(qǐng)參見(jiàn)執(zhí)行事務(wù)。 |
TRANSACTIONAL_SNAPSHOT | 多版本并發(fā)控制(MVCC)的試驗(yàn)性實(shí)現(xiàn)。其同時(shí)支持鍵-值事務(wù)和SQL事務(wù),更多的信息以及限制,請(qǐng)參見(jiàn)多版本并發(fā)控制。**注意:**MVCC實(shí)現(xiàn)目前還處于測(cè)試階段,不建議用于生產(chǎn)。 |
可以在緩存配置中為緩存開(kāi)啟事務(wù)支持:
- XML
- Java
- C#/.NET
CacheConfiguration cacheCfg = new CacheConfiguration();cacheCfg.setName("cacheName");cacheCfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);IgniteConfiguration cfg = new IgniteConfiguration();cfg.setCacheConfiguration(cacheCfg);// Optional transaction configuration. Configure TM lookup here.
TransactionConfiguration txCfg = new TransactionConfiguration();cfg.setTransactionConfiguration(txCfg);// Start a node
Ignition.start(cfg);
#5.過(guò)期策略
#5.1.概述
過(guò)期策略指定了在緩存條目過(guò)期之前必須經(jīng)過(guò)的時(shí)間量,時(shí)間可以從創(chuàng)建、最后訪問(wèn)或者修改時(shí)間開(kāi)始計(jì)算。
根據(jù)內(nèi)存配置,過(guò)期策略將從內(nèi)存或磁盤(pán)上刪除條目:
- 內(nèi)存模式:數(shù)據(jù)僅保存在內(nèi)存中,過(guò)期的條目會(huì)完全從內(nèi)存中清除;
- 內(nèi)存+Ignite持久化:過(guò)期的條目會(huì)完全從內(nèi)存和磁盤(pán)上刪除,注意過(guò)期策略會(huì)從磁盤(pán)上的分區(qū)文件中刪除數(shù)據(jù),但是不會(huì)釋放空間,該空間會(huì)在后續(xù)的數(shù)據(jù)寫(xiě)入中重用;
- 內(nèi)存+外部存儲(chǔ):過(guò)期的條目?jī)H僅從內(nèi)存(Ignite)中刪除,外部存儲(chǔ)(RDBMS、NoSQL以及其它數(shù)據(jù)庫(kù))中的數(shù)據(jù)會(huì)保持不變;
- 內(nèi)存+交換空間:過(guò)期的條目會(huì)同時(shí)從內(nèi)存和交換空間中刪除。
過(guò)期策略可以通過(guò)任何標(biāo)準(zhǔn)的javax.cache.expiry.ExpiryPolicy
實(shí)現(xiàn)或自定義實(shí)現(xiàn)進(jìn)行設(shè)置:
#5.2.配置
下面是過(guò)期策略的配置示例:
- XML
- Java
- C#/.NET
CacheConfiguration<Integer, String> cfg = new CacheConfiguration<Integer, String>();
cfg.setName("myCache");
cfg.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.FIVE_MINUTES));
也可以為單獨(dú)的緩存操作配置或者修改過(guò)期策略,該策略會(huì)影響返回的緩存實(shí)例上調(diào)用的每個(gè)操作:
CacheConfiguration<Integer, String> cacheCfg = new CacheConfiguration<Integer, String>("myCache");ignite.createCache(cacheCfg);IgniteCache cache = ignite.cache("myCache").withExpiryPolicy(new CreatedExpiryPolicy(new Duration(TimeUnit.MINUTES, 5)));// if the cache does not contain key 1, the entry will expire after 5 minutes
cache.put(1, "first value");
#5.3.Eager TTL(熱生存時(shí)間)
過(guò)期的條目從緩存中刪除,既可以馬上刪除,也可以在緩存操作對(duì)其訪問(wèn)時(shí)再刪除。只要有一個(gè)緩存啟用了熱生存時(shí)間,Ignite就會(huì)創(chuàng)建一個(gè)線程在后臺(tái)清理過(guò)期的數(shù)據(jù)。
如果該屬性配置為false
,過(guò)期的條目不會(huì)被馬上刪除,而是在執(zhí)行緩存操作時(shí)由執(zhí)行該操作的線程將其刪除。
熱生存時(shí)間可以通過(guò)CacheConfiguration.eagerTtl
屬性啟用或者禁用(默認(rèn)值是true
)。
- XML
- Java
- C#/.NET
CacheConfiguration<Integer, String> cfg = new CacheConfiguration<Integer, String>();
cfg.setName("myCache");cfg.setEagerTtl(true);
#6.堆內(nèi)緩存
Ignite在Java堆外部使用堆外內(nèi)存來(lái)分配數(shù)據(jù)區(qū),但是可以通過(guò)配置CacheConfiguration.setOnheapCacheEnabled(true)
來(lái)開(kāi)啟堆內(nèi)緩存。
對(duì)于在使用二進(jìn)制形式的緩存條目或調(diào)用緩存條目的反序列化的服務(wù)器節(jié)點(diǎn)上進(jìn)行大量緩存讀取的場(chǎng)景,堆內(nèi)緩存很有用。例如,當(dāng)分布式計(jì)算或部署的服務(wù)從緩存中獲取數(shù)據(jù)進(jìn)行進(jìn)一步處理時(shí),可能會(huì)發(fā)生這種情況。
- XML
- Java
- C#/.NET
CacheConfiguration cfg = new CacheConfiguration();
cfg.setName("myCache");
cfg.setOnheapCacheEnabled(true);
#6.1.配置退出策略
啟用堆內(nèi)緩存后,可以使用堆內(nèi)緩存退出策略來(lái)管理不斷增長(zhǎng)的堆內(nèi)緩存。
退出策略控制緩存的堆內(nèi)存中可以存儲(chǔ)的最大數(shù)據(jù)量,當(dāng)?shù)竭_(dá)最大值后,條目會(huì)從Java堆中退出。
提示
堆內(nèi)退出策略只會(huì)從Java堆中刪除緩存條目,堆外數(shù)據(jù)區(qū)中存儲(chǔ)的數(shù)據(jù)不受影響。
退出策略支持基于批次的退出和基于內(nèi)存大小限制的退出。如果開(kāi)啟了基于批次的退出,那么當(dāng)緩存的數(shù)量比緩存最大值多出batchSize
個(gè)條目時(shí),退出就開(kāi)始了,這時(shí)batchSize
個(gè)條目就會(huì)被退出。如果開(kāi)啟了基于內(nèi)存大小限制的退出,那么當(dāng)緩存條目的大小(字節(jié)數(shù))大于最大值時(shí),退出就會(huì)被觸發(fā)。
注意
只有未配置最大內(nèi)存限制時(shí),才會(huì)支持基于批次的退出。
Ignite中退出策略是可插拔的,可以通過(guò)EvictionPolicy
接口進(jìn)行控制,退出策略的實(shí)現(xiàn)定義了從堆內(nèi)緩存選擇待退出條目的算法,然后當(dāng)緩存發(fā)生改變時(shí)就會(huì)收到通知。
#6.1.1.最近最少使用(LRU)
LRU退出策略基于最近最少使用算法,它會(huì)確保最近最少使用的數(shù)據(jù)(即最久沒(méi)有被訪問(wèn)的數(shù)據(jù))會(huì)被首先退出。
注意
LRU退出策略適用于堆內(nèi)緩存的大多數(shù)使用場(chǎng)景,不確定時(shí)可以?xún)?yōu)先使用。
這個(gè)退出策略通過(guò)CacheConfiguration
進(jìn)行配置,支持基于批次的退出以及基于內(nèi)存大小限制的退出,如下所示:
- XML
- Java
- C#/.NET
CacheConfiguration cacheCfg = new CacheConfiguration();cacheCfg.setName("cacheName");// Enabling on-heap caching for this distributed cache.
cacheCfg.setOnheapCacheEnabled(true);// Set the maximum cache size to 1 million (default is 100,000).
cacheCfg.setEvictionPolicyFactory(() -> new LruEvictionPolicy(1000000));IgniteConfiguration cfg = new IgniteConfiguration();cfg.setCacheConfiguration(cacheCfg);
#6.1.2.先進(jìn)先出(FIFO)
FIFO退出策略基于先進(jìn)先出(FIFO)算法,它確保緩存中保存時(shí)間最久的數(shù)據(jù)會(huì)被首先退出,它與LruEvictionPolicy
不同,因?yàn)樗雎粤藬?shù)據(jù)的訪問(wèn)順序。
這個(gè)策略通過(guò)CacheConfiguration
進(jìn)行配置,支持基于批次的退出以及基于內(nèi)存大小限制的退出。
- XML
- Java
- C#/.NET
CacheConfiguration cacheCfg = new CacheConfiguration();cacheCfg.setName("cacheName");// Enabling on-heap caching for this distributed cache.
cacheCfg.setOnheapCacheEnabled(true);// Set the maximum cache size to 1 million (default is 100,000).
cacheCfg.setEvictionPolicyFactory(() -> new FifoEvictionPolicy(1000000));IgniteConfiguration cfg = new IgniteConfiguration();cfg.setCacheConfiguration(cacheCfg);
#6.1.3.有序
有序退出策略和FIFO退出策略很像,不同點(diǎn)在于通過(guò)默認(rèn)或者用戶(hù)定義的比較器定義了數(shù)據(jù)的順序,然后確保最小的數(shù)據(jù)(即排序數(shù)值最小的數(shù)據(jù))會(huì)被退出。
默認(rèn)的比較器用緩存條目的鍵作為比較器,它要求鍵必須實(shí)現(xiàn)Comparable
接口。也可以提供自定義的比較器實(shí)現(xiàn),可以通過(guò)鍵,值或者兩者都用來(lái)進(jìn)行條目的比較。
這個(gè)策略通過(guò)CacheConfiguration
進(jìn)行配置,支持基于批次的退出以及基于內(nèi)存大小限制的退出。
- XML
- Java
CacheConfiguration cacheCfg = new CacheConfiguration();cacheCfg.setName("cacheName");// Enabling on-heap caching for this distributed cache.
cacheCfg.setOnheapCacheEnabled(true);// Set the maximum cache size to 1 million (default is 100,000).
cacheCfg.setEvictionPolicyFactory(() -> new SortedEvictionPolicy(1000000));IgniteConfiguration cfg = new IgniteConfiguration();cfg.setCacheConfiguration(cacheCfg);
#7.緩存組
對(duì)于集群中的緩存來(lái)說(shuō),總有一個(gè)開(kāi)銷(xiāo),即緩存被拆分為分區(qū)后其狀態(tài)必須在每個(gè)集群節(jié)點(diǎn)上進(jìn)行跟蹤以滿足系統(tǒng)的需要。
如果開(kāi)啟了Ignite的原生持久化,那么對(duì)于每個(gè)分區(qū)來(lái)說(shuō),都會(huì)在磁盤(pán)上打開(kāi)一個(gè)文件進(jìn)行讀寫(xiě),因此,如果有更多的緩存和分區(qū):
- 分區(qū)映射就會(huì)占用更多的Java堆,每個(gè)緩存都有自己的分區(qū)映射;
- 新節(jié)點(diǎn)加入集群就會(huì)花費(fèi)更多的時(shí)間;
- 節(jié)點(diǎn)離開(kāi)集群也會(huì)因?yàn)樵倨胶饣ㄙM(fèi)更多的時(shí)間;
- 打開(kāi)中的分區(qū)文件就會(huì)更多從而影響檢查點(diǎn)的性能。
通常,如果只有幾十甚至幾百個(gè)緩存時(shí),不用擔(dān)心這些問(wèn)題,但是如果增長(zhǎng)到上千時(shí),這類(lèi)問(wèn)題就會(huì)凸顯。
要避免這個(gè)影響,可以考慮使用緩存組,一個(gè)組內(nèi)的緩存會(huì)共享各種內(nèi)部數(shù)據(jù)結(jié)構(gòu)比如上面提到的分區(qū)映射,這樣,會(huì)提高拓?fù)涫录幚淼男室约敖档驼w的內(nèi)存使用量。注意,從API上來(lái)看,緩存是不是組的一部分并沒(méi)有什么區(qū)別。
通過(guò)配置CacheConfiguration
的groupName
屬性可以創(chuàng)建一個(gè)緩存組,示例如下:
- XML
- Java
- C#/.NET
// Defining cluster configuration.
IgniteConfiguration cfg = new IgniteConfiguration();// Defining Person cache configuration.
CacheConfiguration<Integer, Person> personCfg = new CacheConfiguration<Integer, Person>("Person");personCfg.setBackups(1);// Group the cache belongs to.
personCfg.setGroupName("group1");// Defining Organization cache configuration.
CacheConfiguration orgCfg = new CacheConfiguration("Organization");orgCfg.setBackups(1);// Group the cache belongs to.
orgCfg.setGroupName("group1");cfg.setCacheConfiguration(personCfg, orgCfg);// Starting the node.
Ignition.start(cfg);
在上面的示例中,Person
和Organization
緩存都屬于group1
。
如何區(qū)分鍵-值對(duì)
如果將緩存分配給一個(gè)緩存組,則其數(shù)據(jù)存儲(chǔ)在共享分區(qū)的內(nèi)部結(jié)構(gòu)中。寫(xiě)入緩存的每個(gè)鍵都會(huì)附加其所屬的緩存的唯一ID。該ID是從緩存名派生的。這些都是透明的,并允許將不同緩存的數(shù)據(jù)存儲(chǔ)在相同的分區(qū)和B+樹(shù)結(jié)構(gòu)中。
對(duì)緩存進(jìn)行分組的原因很簡(jiǎn)單,如果決定對(duì)1000個(gè)緩存進(jìn)行分組,則存儲(chǔ)分區(qū)數(shù)據(jù)、分區(qū)映射和打開(kāi)分區(qū)文件的結(jié)構(gòu)將減少為原來(lái)的千分之一。
緩存組是否應(yīng)一直使用?
雖然有這么多的好處,但是它可能影響讀操作和索引的性能,這是由于所有的數(shù)據(jù)和索引都混合在一個(gè)共享的數(shù)據(jù)結(jié)構(gòu)(分區(qū)映射、B+樹(shù))中,查詢(xún)的時(shí)間變長(zhǎng)導(dǎo)致的。 因此,如果集群有數(shù)十個(gè)和數(shù)百個(gè)節(jié)點(diǎn)和緩存,并且由于內(nèi)部結(jié)構(gòu)、檢查點(diǎn)性能下降和/或節(jié)點(diǎn)到集群的連接速度較慢而遇到Java堆使用增加的情況,可以考慮使用緩存組。
#8.近緩存
近緩存是一種本地緩存,用于在本地節(jié)點(diǎn)上存儲(chǔ)最近或最常訪問(wèn)的數(shù)據(jù)。假設(shè)應(yīng)用啟動(dòng)了一個(gè)客戶(hù)端節(jié)點(diǎn)并定期查詢(xún)數(shù)據(jù),例如國(guó)家/地區(qū)代碼。因?yàn)榭蛻?hù)端節(jié)點(diǎn)不存儲(chǔ)數(shù)據(jù),所以這些查詢(xún)總是從遠(yuǎn)程節(jié)點(diǎn)獲取數(shù)據(jù)。這時(shí)可以配置近緩存,以在應(yīng)用運(yùn)行時(shí)將國(guó)家/地區(qū)代碼保留在本地節(jié)點(diǎn)上,這樣可以提高性能。
近緩存為特定的常規(guī)緩存配置,并且僅保留該緩存的數(shù)據(jù)。
近緩存將數(shù)據(jù)存儲(chǔ)在堆內(nèi)存中,可以為近緩存條目配置緩存的最大值和退出策略。
提示
近緩存是完全事務(wù)性的,并且每當(dāng)服務(wù)端節(jié)點(diǎn)上的數(shù)據(jù)更改時(shí),它們都會(huì)自動(dòng)更新或失效。
#8.1.配置近緩存
可以在緩存配置中為某個(gè)緩存配置近緩存:
- XML
- Java
- C#/.NET
// Create a near-cache configuration for "myCache".
NearCacheConfiguration<Integer, Integer> nearCfg = new NearCacheConfiguration<>();// Use LRU eviction policy to automatically evict entries
// from near-cache whenever it reaches 100_000 entries
nearCfg.setNearEvictionPolicyFactory(new LruEvictionPolicyFactory<>(100_000));CacheConfiguration<Integer, Integer> cacheCfg = new CacheConfiguration<Integer, Integer>("myCache");cacheCfg.setNearConfiguration(nearCfg);// Create a distributed cache on server nodes
IgniteCache<Integer, Integer> cache = ignite.getOrCreateCache(cacheCfg);
以這種方式配置后,就在從底層緩存請(qǐng)求數(shù)據(jù)的任何節(jié)點(diǎn)(包括服務(wù)端節(jié)點(diǎn)和客戶(hù)端節(jié)點(diǎn))上創(chuàng)建近緩存。如以下示例所示,當(dāng)拿到緩存的實(shí)例時(shí),數(shù)據(jù)將通過(guò)近緩存獲得:
IgniteCache<Integer, Integer> cache = ignite.cache("myCache");int value = cache.get(1);
CacheConfiguration
中與近緩存有關(guān)的大部分參數(shù)都會(huì)繼承于底層緩存的配置,比如,如果底層緩存有一個(gè)ExpiryPolicy
配置,近緩存中的條目也會(huì)基于同樣的策略。
下表中列出的參數(shù)是不會(huì)從底層配置中繼承的:
參數(shù) | 描述 | 默認(rèn)值 |
---|---|---|
nearEvictionPolicy | 近緩存退出策略 | 無(wú) |
nearStartSize | 近緩存初始大小(可持有的條目數(shù)) | 375,000 |
#8.2.客戶(hù)端節(jié)點(diǎn)動(dòng)態(tài)創(chuàng)建近緩存
從客戶(hù)端節(jié)點(diǎn)向尚未配置近緩存的緩存發(fā)出請(qǐng)求時(shí),可以為該緩存動(dòng)態(tài)創(chuàng)建近緩存,通過(guò)在客戶(hù)端本地存儲(chǔ)“熱”數(shù)據(jù)來(lái)提高性能。此緩存僅在創(chuàng)建它的節(jié)點(diǎn)上生效。
為此,創(chuàng)建一個(gè)近緩存配置并將其作為參數(shù)傳遞給獲取緩存實(shí)例的方法:
- Java
- C#/.NET
// Create a near-cache configuration
NearCacheConfiguration<Integer, String> nearCfg = new NearCacheConfiguration<>();// Use LRU eviction policy to automatically evict entries
// from near-cache, whenever it reaches 100_000 in size.
nearCfg.setNearEvictionPolicyFactory(new LruEvictionPolicyFactory<>(100_000));// get the cache named "myCache" and create a near cache for it
IgniteCache<Integer, String> cache = ignite.getOrCreateNearCache("myCache", nearCfg);String value = cache.get(1);
數(shù)據(jù)再平衡
#1.數(shù)據(jù)再平衡
#1.1.概述
當(dāng)一個(gè)新節(jié)點(diǎn)加入集群時(shí),部分分區(qū)會(huì)被分配至新的節(jié)點(diǎn),以使整個(gè)集群的數(shù)據(jù)保持平均分布,這個(gè)過(guò)程稱(chēng)為數(shù)據(jù)再平衡。
如果現(xiàn)有節(jié)點(diǎn)永久離開(kāi)集群,并且未配置備份,則會(huì)丟失此節(jié)點(diǎn)上存儲(chǔ)的分區(qū)。配置備份后,丟失分區(qū)的備份副本之一將成為主分區(qū),并開(kāi)始再平衡過(guò)程。
警告
數(shù)據(jù)再平衡由基線拓?fù)涞淖兓|發(fā)。在純內(nèi)存集群中,默認(rèn)行為是在節(jié)點(diǎn)離開(kāi)或加入集群時(shí)(基線拓?fù)渥詣?dòng)更改)立即開(kāi)始再平衡。在開(kāi)啟持久化的集群中,默認(rèn)必須手動(dòng)更改基線拓?fù)?#xff0c;或者在啟用基線自動(dòng)調(diào)整后可以自動(dòng)更基線拓?fù)洹?/p>
再平衡是緩存級(jí)的配置。
#1.2.配置再平衡模式
Ignite支持同步和異步的再平衡,在同步模式中,再平衡結(jié)束前緩存的任何操作都會(huì)被阻塞。在異步模式中,再平衡過(guò)程以異步的模式執(zhí)行,也可以為某個(gè)緩存禁用再平衡。
如果要修改再平衡模式,可以在緩存配置中配置如下的值:
SYNC
:同步再平衡模式,再平衡結(jié)束前緩存的任何操作都會(huì)被阻塞;ASYNC
:異步再平衡模式,緩存直接可用,然后在后臺(tái)會(huì)從其它節(jié)點(diǎn)加載所有必要的數(shù)據(jù);NONE
:該模式下不會(huì)發(fā)生再平衡,這意味著要么在訪問(wèn)數(shù)據(jù)時(shí)從持久化存儲(chǔ)載入,要么數(shù)據(jù)被顯式地填充。
- XML
- Java
- C#/.NET
IgniteConfiguration cfg = new IgniteConfiguration();CacheConfiguration cacheCfg = new CacheConfiguration("mycache");cacheCfg.setRebalanceMode(CacheRebalanceMode.SYNC);cfg.setCacheConfiguration(cacheCfg);// Start a node.
Ignite ignite = Ignition.start(cfg);
#1.3.配置再平衡線程池
默認(rèn)一個(gè)節(jié)點(diǎn)只會(huì)有一個(gè)線程用于再平衡,這意味著在一個(gè)特定的時(shí)間點(diǎn)只有一個(gè)線程用于從一個(gè)節(jié)點(diǎn)到另一節(jié)點(diǎn)傳輸批量數(shù)據(jù),或者處理來(lái)自遠(yuǎn)端的批量數(shù)據(jù)。
可以從系統(tǒng)線程池中拿到更多的線程數(shù)用于再平衡。每當(dāng)節(jié)點(diǎn)需要將一批數(shù)據(jù)發(fā)送到遠(yuǎn)端節(jié)點(diǎn)或需要處理來(lái)自遠(yuǎn)端節(jié)點(diǎn)的一批數(shù)據(jù)時(shí),都會(huì)從池中獲取系統(tǒng)線程,批次處理完成后,該線程會(huì)被釋放。
- XML
- Java
IgniteConfiguration cfg = new IgniteConfiguration();cfg.setRebalanceThreadPoolSize(4);CacheConfiguration cacheCfg = new CacheConfiguration("mycache");
cfg.setCacheConfiguration(cacheCfg);// Start a node.
Ignite ignite = Ignition.start(cfg);
警告
在內(nèi)部,系統(tǒng)線程池廣泛用于和緩存有關(guān)的所有操作(put,get等),SQL引擎和其它模塊,因此將再平衡線程池設(shè)置為一個(gè)很大的值會(huì)顯著提高再平衡的性能,但是會(huì)影響應(yīng)用的吞吐量。
#1.4.再平衡消息限流
當(dāng)數(shù)據(jù)從一個(gè)節(jié)點(diǎn)傳輸?shù)搅硪粋€(gè)節(jié)點(diǎn)時(shí),整個(gè)數(shù)據(jù)集會(huì)被拆分為多個(gè)批次然后將每一個(gè)批次作為一個(gè)單獨(dú)的消息進(jìn)行發(fā)送,批次的大小和節(jié)點(diǎn)在消息之間的等待時(shí)間,都是可以配置的。
- XML
- Java
- C#/.NET
IgniteConfiguration cfg = new IgniteConfiguration();CacheConfiguration cacheCfg = new CacheConfiguration("mycache");cfg.setRebalanceBatchSize(2 * 1024 * 1024);
cfg.setRebalanceThrottle(100);cfg.setCacheConfiguration(cacheCfg);// Start a node.
Ignite ignite = Ignition.start(cfg);
#1.5.其他配置
下表列出了CacheConfiguration
中和再平衡有關(guān)的屬性:
屬性 | 描述 | 默認(rèn)值 |
---|---|---|
rebalanceBatchSize | 單個(gè)再平衡消息的大小(字節(jié)),在每個(gè)節(jié)點(diǎn)再平衡算法會(huì)將數(shù)據(jù)拆分為多個(gè)批次,然后再將其發(fā)送給其他節(jié)點(diǎn)。 | 512KB |
rebalanceDelay | 當(dāng)節(jié)點(diǎn)加入或者離開(kāi)集群時(shí),再平衡過(guò)程啟動(dòng)的延遲時(shí)間(毫秒),如果打算在節(jié)點(diǎn)離開(kāi)拓?fù)浜笾貑⒐?jié)點(diǎn),或者打算在同時(shí)/一個(gè)個(gè)啟動(dòng)多個(gè)節(jié)點(diǎn)的過(guò)程中,所有節(jié)點(diǎn)都啟動(dòng)完成之前不進(jìn)行重新分區(qū)或者再平衡,也可以推遲。 | 0,無(wú)延遲 |
rebalanceOrder | 完成再平衡的順序,只有SYNC 和ASYNC 再平衡模式的緩存才可以將再平衡順序設(shè)置為非0值,具有更小值的緩存再平衡會(huì)被首先完成,再平衡默認(rèn)是無(wú)序的。 | 0 |
rebalanceThrottle | 請(qǐng)參見(jiàn)再平衡消息限流 | 0(限流禁用) |
rebalanceTimeout | 節(jié)點(diǎn)間交換再平衡消息的掛起超時(shí)。 | 10秒 |
#1.6.再平衡過(guò)程監(jiān)控
通過(guò)JMX可以監(jiān)控緩存的再平衡過(guò)程。