Apache Ignite 學習筆記(四): Ignite緩存冗餘備份策略

Ignite的數據網格是圍繞着基於內存的分佈式key/value存儲能力打造的。當初技術選型的時候,決定用Ignite也是由於雖然一樣是key/value存儲,它有着和其餘key/value存儲系統不一樣的特性。根據官網的介紹,Ignite在設計之初,就是爲了能方便的水平擴展而設計的。Ignite將數據分片,每一個節點只存儲數據的一部分,這樣每當有新節點加入時,整個集羣能夠存儲更多的數據。爲了提升可用性,Ignite也支持用不一樣的策略對數據分片進行冗餘備份,這樣保證數據不會由於集羣中一兩個節點失效而丟失。另外,和其餘key/value緩存系統最大的不一樣是,Ignite支持用SQL語句對緩存數據進行查詢。正是因爲有對SQL 99的支持,咱們甚至能夠把Ignite當作一個分佈式內存數據庫來使用。java

從這篇文章開始,咱們先聚焦在Ignite提供的數據網格服務上,看看一樣是基於key/value存儲,Ignite的key/value緩存又提供了哪些能力。node

消失的數據


在介紹Ignite不一樣的緩存冗餘備份模式以前,咱們先用上一篇文章的代碼來模擬一下在默認配置下,若是Ignite集羣中有節點失效,咱們的數據是否還完整有效。咱們在同一臺虛擬機按如下的順序分別啓動server和client實例:git

  1. 啓動一個server實例,該實例會建立一個「TEST」緩存並寫入三條緩存數據。
  2. 再啓動一個server實例,該實例會自動加入以前啓動的server節點,組成一個Ignite集羣。由於該實例建立的緩存名字和寫入的緩存數據都同樣,因此"TEST"緩存裏的數據保持不變。
  3. 啓動一個client實例,查詢「TEST」緩存裏的數據,此時該client應該能夠查詢到三條以前寫入的緩存數據:
Montreal is in Quebec   
Edmonton is in Alberta   
Markham is in Ontario   
Toronto is in null
  1. 關閉一個server實例,再啓動一個client實例作查詢,此時咱們會發現某些緩存數據消失了。好比在個人環境裏,就查不到Markham這條數據了:
Montreal is in Quebec   
Edmonton is in Alberta   
Markham is in null   
Toronto is in null

由於Ignite將緩存數據分片存儲的,即同一緩存中的不一樣數據存到不一樣的server節點上,Ignite經過一個哈希算法計算出某個數據分片所屬的節點。除了原生的哈希算法,用戶也可實現本身的哈希算法來決定數據分片對應的節點。在上面的步驟1中,緩存數據所有存在僅有的惟一一個server實例中。在步驟2中,當有新的server實例加入集羣,Ignite經過默認的哈希算法決定哪部分的數據分片應該存到新加入的server實例中,而後將數據在兩個實例間從新平衡分佈。因爲咱們採用的是默認的配置,因此每一個數據分片只有一份拷貝,這就是爲何當咱們關了一個server實例後會發生數據丟失的狀況。所以,爲了保證數據的高可用,咱們必須調整數據分片拷貝的數量。接下來,咱們就來看看Ignite提供了哪些對數據分片進行冗餘備份的策略,以便用戶根據實際需求在性能和數據高可用性之間作選擇。算法

Ignite緩存數據分片冗餘策略


Local模式

咱們先從簡單的模式提及,Local模式,顧名思義就是緩存的全部數據只保存在本地節點,數據不會分佈到其餘節點上,也就沒有數據分片和數據拷貝這麼一說。Local模式的最大好處是它的輕量化,由於沒有了數據分片和冗餘備份的負擔,其很是適合於數據只讀模式和須要按期刷新的場景,也適合於做爲一個read-through的緩存。除了數據分佈不一樣,採用local模式的緩存和分佈式緩存有着相同的功能,好比數據自動清除,過時失效,磁盤交換,數據查詢以及事務等特性。spring

Replicated模式

Replicated模式下,緩存數據雖然被均分爲多個數據分片,但每一個節點上都有該緩存的所有數據分片。下面這張官網圖很好的展現了replicated模式的數據分佈:
數據庫

在replicated模式下,緩存數據被平分爲4個數據分片A、B、C、D。在節點1(JVM1)上有分片A的primary拷貝和B、C、D的backup拷貝。在節點2(JVM2)上有分片C的primary拷貝和A、B、D的backup拷貝。節點3(JVM3)和節點4(JVM4)的狀況也相似。關於數據分片的primary和backup拷貝的概念咱們在下一篇介紹,這裏只要記住當primary拷貝失效了,Ignite能夠用backup拷貝恢復數據,保證了數據的高可靠性。因此在replicated模式下,每一個節點其實有緩存的全部數據分片拷貝,即使集羣裏其餘節點都失效,Ignite仍是能夠經過僅存的一個節點提供數據讀寫服務apache

Partitioned模式

Partition模式下,緩存數據被均分爲多個數據分片,數據分片的拷貝均等的分佈在集羣的某些節點上。換句話說,和replicated模式最大的不一樣就是,一個節點上沒有所有的緩存數據分片拷貝。讓咱們借用官網的圖來解釋一下partitioned模式:
緩存

如上圖所示,在partitioned模式下,緩存數據被平分爲4個數據分片A、B、C、D,每一個數據分片有一份primary拷貝和backup拷貝,因此每一個節點只保存兩個數據分片的拷貝,好比節點1(JVM1)有分片A的primary分片和分片B的backup分片,節點2(JVM2)有分片C的primary分片和分片A的backup分片。Backup拷貝的數量是用戶可配置的,若是配置爲0時,表明着一個數據分片沒有副本,一旦某個節點掛了,數據就會丟失。若是配置爲(集羣節點數量-1),表明着集羣的每一個節點上都有一份該數據分片的拷貝,這就至關於一種特殊的replicated模式。拷貝數量越多,表明數據約可靠,但也會帶來額外的開銷,因此咱們仍是要根據實際的場景和需求來調整拷貝數量。maven

Replicated V.S. Partitioned

讓咱們簡單的比較下兩種模式的優缺點以及它們適合的場景:tcp

  • 首先,從數據的可靠性來講固然是replicated模式佔優點,畢竟每一個節點都有緩存的全部數據分片,只要集羣中有一個節點還能工做,就能從該節點恢復數據。而partitioned模式下,數據的可靠性是和backup數量N相關的,在partitioned模式下,一旦有N+1個節點失效,集羣就有可能出現丟失數據的狀況。
  • 其次,從擴展性上看,是partitioned模式優於replicated模式。由於每一個節點須要有全部數據分片的拷貝,在replicated模式下,集羣所能容納的數據大小是受單個節點的內存和硬盤(若是啓用了Ignite原生的持久化功能)限制的,即使新增節點,也不能提升集羣的數據容量。反觀partitioned模式,新增長一個節點就能夠給集羣增長更多的存儲能力,容納更多的數據。
  • 再次,從讀寫性能上看,replicated模式適合多讀少寫的場景,由於每寫一份數據,就要同步到集羣中全部的節點上,若是節點數量多了,同步的開銷仍是很可觀的。對於讀數據,由於每一個節點上都有緩存數據的拷貝,因此在replicated模式下的讀能夠充分利用全部節點的帶寬,提供更好的讀性能。而Partitioned模式更適合多寫少讀的場景,由於寫數據時須要同步的節點數量要少,因此寫性能更好。對於讀場景,由於一份數據的拷貝只在集羣的幾臺節點上,因此讀性能勢必會受影響。

配置緩存Replicated/Partitioned模式


好了,在瞭解完Ignite緩存不一樣的數據分片冗餘策略後,讓咱們經過一個實際的例子看看如何在代碼或是xml配置文件中配置不一樣的數據分片冗餘策略。咱們在上一篇文章的server節點代碼上進行改造,大部分邏輯都保持不變,重點注意一下第26行~34行加入的新代碼:

public class IgniteCacheOpModeExample {
    public static void main(String[] args) {
        Ignite ignite;
        // 建立一個TEST緩存並寫入一些數據, key是城市的名字,value是省的名字
        IgniteCache<String, String> cityProvinceCache;

        if(args.length == 1 && !args[0].isEmpty())
        {
            //若是啓動時指定了配置文件,則用指定的配置文件
            System.out.println("Use " + args[0] + " to start.");
            ignite = Ignition.start(args[0]);
            //配置文件中,咱們將緩存設置爲partitioned模式,backup數量爲1
            cityProvinceCache = ignite.getOrCreateCache("TEST");
        }
        else
        {
            //若是啓動時沒指定配置文件,則生成一個配置文件
            System.out.println("Create an IgniteConfiguration to start.");
            TcpDiscoverySpi spi = new TcpDiscoverySpi();
            TcpDiscoveryMulticastIpFinder ipFinder = new TcpDiscoveryMulticastIpFinder();
            ipFinder.setMulticastGroup("224.0.0.251");
            spi.setIpFinder(ipFinder);
            IgniteConfiguration cfg = new IgniteConfiguration();
            cfg.setDiscoverySpi(spi);
            ignite = Ignition.start(cfg);
            CacheConfiguration<String, String> cacheCfg = new CacheConfiguration("TEST");
            // 若是不用配置文件啓動,緩存模式被設置爲replicated
            cacheCfg.setCacheMode(CacheMode.REPLICATED);
            /* 下面的配置將"TEST"緩存設爲partitioned模式,而且設置了backup數量爲1,這樣保證即便有一個node出現
                故障的狀況下,緩存數據仍是完整可用的
            cacheCfg.setCacheMode(CacheMode.PARTITIONED);
            cacheCfg.setBackups(1);
             */
            cityProvinceCache = ignite.getOrCreateCache(cacheCfg);
        }

        cityProvinceCache.put("Edmonton", "Alberta");
        cityProvinceCache.put("Markham", "Ontario");
        cityProvinceCache.put("Montreal", "Quebec");

    }
}

在調用ignite.getOrCreateCache()函數以前,咱們爲"TEST"先生成一個CacheConfiguration,而後調用setCacheMode()將其模式設置爲REPLICATED模式(在29~33行被註釋掉的代碼中,是如何設置PARTITIONED模式以及backups數量的代碼),最後再交由Ignite根據configuration生成"TEST"緩存。 固然,和上一篇同樣,也能夠經過XML文件來配置緩存模式:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
        <property name="discoverySpi">
            <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
                <property name="ipFinder">
                    <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
                        <property name="multicastGroup" value="224.0.0.251"/>
                    </bean>
                </property>
            </bean>
        </property>
        <property name="cacheConfiguration">
            <bean class="org.apache.ignite.configuration.CacheConfiguration">
                <!-- 設置緩存名字. -->
                <property name="name" value="TEST"/>
                <!-- 設置緩存模式. -->
                <property name="cacheMode" value="PARTITIONED"/>
                <property name="backups" value="1"/>
                <!-- 下面將緩存設置爲replicated模式 -->
                <!--property name="cacheMode" value="REPLICATED"/-->

            </bean>
        </property>
    </bean>
</beans>

在XML文件中,咱們加入了cacheConfiguration的配置,爲了和代碼裏建立的緩存名字保持一致,配置裏也使用了"TEST"做爲緩存名字,"cacheMode"設爲PARTITIONED,"backups"值設爲了1(每一個數據分片除了primay拷貝外,還有額外的一份backup拷貝,即緩存能夠容許有一個節點故障而保證緩存數據的完整性)。

更新了代碼和配置文件後,server節點若是制定了XML配置文件啓動,生成的緩存爲帶一個backup的PARTITIONED模式,若是不用XML配置文件,則生成的緩存爲REPLICATED模式。不管用哪一種方式啓動server節點,咱們再重複這篇文章開頭的那個實驗,就會發現即便在一個節點失效的狀況下,client節點仍是能夠訪問到緩存中的全部數據,不會再出現丟數據的狀況了。在實際使用過程當中,正確的配置緩存的冗餘模式直接影響到Ignite集羣數據的高可用性。

總結


這篇文章咱們介紹了Ignite集羣中數據分片的不一樣冗餘策略,在實際的使用過程當中,不一樣的策略會直接影響集羣中數據的高可用性和讀寫性能,因此理解不一樣的策略的優缺點,是使用好Ignite數據網格集羣的第一步。 這篇文章裏用到的例子的完整代碼和maven工程能夠在這裏找到。 Server對應的xml配置文件在src/main/resources目錄下。

下一篇,咱們將繼續瞭解一下Ignite針對不一樣的冗餘策略提供的功能,好比數據分片因爲節點失效出現丟失時的行爲,primary拷貝和backup拷貝以前的同步等。

相關文章
相關標籤/搜索