国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Spring Data Redis 讓 NoSQL 快如閃電(2)

lewif / 3344人閱讀

摘要:布隆過濾器布隆過濾器是一種空間利用率較高的概率數(shù)據(jù)結(jié)構(gòu),用來測試某元素是否某個集的一員。則利用布隆過濾器過濾掉不包含特殊行或列的塊磁盤讀取,使讀取速度得到明顯提升。搜索,就能發(fā)現(xiàn)很多布隆過濾器項目,其中一些還支持可調(diào)諧精度。

【編者按】本文作者為 Xinyu Liu,文章的第一部分重點概述了 Redis 方方面面的特性。在第二部分,將介紹詳細(xì)的用例。文章系國內(nèi) ITOM 管理平臺 OneAPM 編譯呈現(xiàn)。

把 Redis 當(dāng)作數(shù)據(jù)庫的用例

現(xiàn)在我們來看看在服務(wù)器端 Java 企業(yè)版系統(tǒng)中把 Redis 當(dāng)作數(shù)據(jù)庫的各種用法吧。無論用例的簡繁,Redis 都能幫助用戶優(yōu)化性能、處理能力和延遲,讓常規(guī) Java 企業(yè)版技術(shù)棧望而卻步。

1. 全局唯一增量計數(shù)器

我們先從一個相對簡單的用例開始吧:一個增量計數(shù)器,可顯示某網(wǎng)站受到多少次點擊。Spring Data Redis 有兩個適用于這一實用程序的類:RedisAtomicIntegerRedisAtomicLong。和 Java 并發(fā)包中的 AtomicIntegerAtomicLong 不同的是,這些 Spring 類能在多個 JVM 中發(fā)揮作用。

列表 3:全局唯一增量計數(shù)器

RedisAtomicLong counter = 
    new RedisAtomicLong("UNIQUE_COUNTER_NAME", redisTemplate.getConnectionFactory()); 
Long myCounter = counter.incrementAndGet();// return the incremented value

請注意整型溢出并謹(jǐn)記,在這兩個類上進(jìn)行操作需要付出相對較高的代價。

2. 全局悲觀鎖

時不時的,用戶就得應(yīng)對服務(wù)器集群的爭用。假設(shè)你從一個服務(wù)器集群運行一個預(yù)定作業(yè)。在沒有全局鎖的情況下,集群中的節(jié)點會發(fā)起冗余作業(yè)實例。假設(shè)某個聊天室分區(qū)可容納 50 人。如果聊天室已滿,就需要創(chuàng)建新的聊天室實例來容納另外 50 人。

如果檢測到聊天室已滿但沒有全局鎖,集群中的各個節(jié)點就會創(chuàng)建自有的聊天室實例,為整個系統(tǒng)帶來不可預(yù)知的因素。列表 4 介紹了應(yīng)當(dāng)如何充分利用 SETNX(SET if Not eXists:如果不存在,則設(shè)置)這一 Redis 命令來執(zhí)行全局悲觀鎖。

列表4:全局悲觀鎖

public String aquirePessimisticLockWithTimeout(String lockName,            int acquireTimeout, int lockTimeout) {        
  
  if (StringUtils.isBlank(lockName) || lockTimeout <= 0)            
      return null;        
      final String lockKey = lockName;
        String identifier = UUID.randomUUID().toString(); 
        Calendar atoCal = Calendar.getInstance();
        atoCal.add(Calendar.SECOND, acquireTimeout);
        Date atoTime = atoCal.getTime();        
        
        while (true) {            
           // try to acquire the lock            
           if (redisTemplate.execute(new RedisCallback() {                @Override                
           public Boolean doInRedis(RedisConnection connection)                        throws DataAccessException {                    
           return connection.setNX(
redisTemplate.getStringSerializer().serialize(lockKey), redisTemplate.getStringSerializer().serialize(identifier));
                }
            })) {   // successfully acquired the lock, set expiration of the lock
             redisTemplate.execute(new RedisCallback() {                      @Override                    
             public Boolean doInRedis(RedisConnection connection)                            throws DataAccessException {                        
              return connection.expire(redisTemplate
                                .getStringSerializer().serialize(lockKey),
                                lockTimeout);
                    }
                });                
                return identifier;
            } else { // fail to acquire the lock                
            // set expiration of the lock in case ttl is not set yet.                if (null == redisTemplate.execute(new RedisCallback() {                    @Override                    
            public Long 
      doInRedis(RedisConnection connection)                            
         throws DataAccessException 
         {                        
              return connection.ttl(redisTemplate
                                .getStringSerializer().serialize(lockKey));
                    }
                })) {                    // set expiration of the lock
                    redisTemplate.execute(new RedisCallback() 
                    {                        
                    @Override                        
                    public Boolean 
                    
           doInRedis(RedisConnection connection)                                        throws DataAccessException {                            
           return connection.expire(redisTemplate
                                .getStringSerializer().serialize(lockKey),
                                    lockTimeout);
                        }
                    }); 
}                if (acquireTimeout < 0) // no wait                    
                 return null;                
                 else {                    
                     try {
                        Thread.sleep(100l); // wait 100 milliseconds before retry
                    } catch (InterruptedException ex) {
                    }
                }                if (new Date().after(atoTime))                    break;
            }
        }        return null;
    }    
    
    
    public void 
releasePessimisticLockWithTimeout(String lockName, String identifier) {        if (StringUtils.isBlank(lockName) || StringUtils.isBlank(identifier))            return;        

     final String lockKey = lockName;

        redisTemplate.execute(new RedisCallback() {                          @Override                    
        public Void doInRedis(RedisConnection connection)                            throws DataAccessException {                        
        byte[] ctn = connection.get(redisTemplate
                                .getStringSerializer().serialize(lockKey));                        if(ctn!=null && identifier.equals(redisTemplate.getStringSerializer().deserialize(ctn)))
                            connection.del(redisTemplate.getStringSerializer().serialize(lockKey));                        return null;
                    }
                });
    }

如果使用關(guān)系數(shù)據(jù)庫,一旦最先生成鎖的程序意外退出,鎖就可能永遠(yuǎn)得不到釋放。Redis 的 EXPIRE 設(shè)置可確保在任何情況下釋放鎖。

3. 位屏蔽(Bit Mask)

假設(shè) web 客戶端需要輪詢一臺 web 服務(wù)器,針對某個數(shù)據(jù)庫中的多個表查詢客戶指定更新內(nèi)容。如果盲目地查詢所有相應(yīng)的表以尋找潛在更新,成本較高。為了避免這一做法,可以嘗試在 Redis 中給每個客戶端保存一個整型作為臟指標(biāo),整型的每個數(shù)位表示一個表。該表中存在客戶所需更新時,設(shè)置數(shù)位。輪詢期間,不會觸發(fā)對表的查詢,除非設(shè)置了相應(yīng)數(shù)位。就獲取并將這樣的位屏蔽設(shè)置為 STRING 而言,Redis 非常高效。

4. 排行榜(Leaderboard)

Redis 的 ZSET 數(shù)據(jù)結(jié)構(gòu)為游戲玩家排行榜提供了簡潔的解決方案。ZSET 的工作方式有些類似于 Java 中的 PriorityQueue,各個對象均為經(jīng)過排序的數(shù)據(jù)結(jié)構(gòu),井井有條??梢园凑辗?jǐn)?shù)排出游戲玩家在排行榜上的位置。Redis 的 ZSET 定義了一份內(nèi)容豐富的命令列表,支持靈活有效的查詢。例如,ZRANGE(包括 ZREVRANGE)可返回有序集內(nèi)的指定范圍要素。

你可以使用這一命令列出排行榜前 100 名玩家。ZRANGEBYSCORE 返回指定分?jǐn)?shù)范圍內(nèi)的要素(例如列出得分為 1000 至 2000 之間的玩家),ZRNK 則返回有序集內(nèi)的要素的排名,諸如此類。

5. 布隆(Bloom)過濾器

布隆過濾器 (Bloom filter) 是一種空間利用率較高的概率數(shù)據(jù)結(jié)構(gòu),用來測試某元素是否某個集的一員??赡軙霈F(xiàn)誤報匹配,但不會漏報。查詢可返回“可能在集內(nèi)”或“肯定不在集內(nèi)”。

就在線服務(wù)和離線服務(wù)包括大數(shù)據(jù)分析等方面,布隆過濾器數(shù)據(jù)結(jié)構(gòu)都能派上很多用場。Facebook 利用布隆過濾器進(jìn)行輸入提示搜索,為用戶輸入的查詢提取朋友和朋友的朋友。Apache HBase 則利用布隆過濾器過濾掉不包含特殊行或列的 HFile 塊磁盤讀取,使讀取速度得到明顯提升。Bitly 用布隆過濾器來避免將用戶重定向到惡意網(wǎng)站,而 Quara 則在訂閱后端執(zhí)行了一個切分的布隆過濾器,用來過濾掉之前查看過的內(nèi)容。在我自己的項目里,我用布隆過濾器追蹤用戶對各個主題的投票情況。

借助出色的速度和處理能力,Redis 極好地融合了布隆過濾器。搜索 GitHub,就能發(fā)現(xiàn)很多 Redis 布隆過濾器項目,其中一些還支持可調(diào)諧精度。

6. 高效的全局通知:發(fā)布/訂閱渠道

Redis 發(fā)布/訂閱渠道的工作方式類似于一個扇出消息傳遞系統(tǒng),或 JMS 語義中的一個主題。JMS 主題和 Redis 發(fā)布/訂閱渠道的一個區(qū)別是,通過 Redis 發(fā)布的消息并不持久。消息被推送給所有相連的客戶端后,Redis 上就會刪除這一消息。換句話說,訂閱者必須一直在線才能接收新消息。Redis 發(fā)布/訂閱渠道的典型用例包括實時配置分布、簡單的聊天服務(wù)器等。

在 web 服務(wù)器集群中,每個節(jié)點都可以是 Redis 發(fā)布/訂閱渠道的一個訂閱者。發(fā)布到渠道上的消息也會被即時推送到所有相連節(jié)點。這一消息可以是某種配置更改,也可以是針對所有在線用戶的全局通知。和恒定輪詢相比,這種推送溝通模式顯然極為高效。

Redis 性能優(yōu)化

Redis 非常強大,但也可以從整體上和根據(jù)特定編程場景做出進(jìn)一步優(yōu)化??梢钥紤]以下技巧。

存活時間

所有 Redis 數(shù)據(jù)結(jié)構(gòu)都具備存活時間 (TTL) 屬性。當(dāng)你設(shè)置這一屬性時,數(shù)據(jù)結(jié)構(gòu)會在過期后自動刪除。充分利用這一功能,可以讓 Redis 保持較低的內(nèi)存損耗。

管道技術(shù)

在一條請求中向 Redis 發(fā)送多個命令,這種方法叫做管道技術(shù)。這一技術(shù)節(jié)省了網(wǎng)絡(luò)往返的成本,這一點非常重要,因為網(wǎng)絡(luò)延遲可能比 Redis 延遲要高上好幾個量級。但這里存在一個陷阱:管道中的 Redis 命令列表必須預(yù)先確定,并且應(yīng)當(dāng)彼此獨立。如果一個命令的參數(shù)是由先前命令的結(jié)果計算得出,管道技術(shù)就不起作用。列表 5 給出了 Redis 管道技術(shù)的一個示例。

列表 5:管道技術(shù)

@Override
public List fetchLeaderboard(String key, String... playerIds) {    
   final List entries = new ArrayList<>();
    redisTemplate.executePipelined(new RedisCallback() {    // enable Redis Pipeline        
    @Override 
        public Object doInRedis(RedisConnection connection) throws DataAccessException { 
            for(String playerId : playerIds) {
                Long rank = connection.zRevRank(key.getBytes(), playerId.getBytes());
                Double score = connection.zScore(key.getBytes(), playerId.getBytes());
                LeaderboardEntry entry = new LeaderboardEntry(playerId, 
                score!=null?score.intValue():-1, rank!=null?rank.intValue():-1);
                entries.add(entry);
            }        
            return null; 
        }
    }); 
    return entries; 
}

副本集和切分

Redis 支持主從副本配置。和 MongoDB 一樣,副本集也是不對稱的,因為從節(jié)點是只讀的,以便共享讀取工作量。我在文章開頭提到過,也可以執(zhí)行切分來橫向擴(kuò)展 Redis 的處理能力和存儲容量。事實上,Redis 非常強大,據(jù)亞馬遜公司的內(nèi)部基準(zhǔn)顯示,類型 r3.4xlarge 的一個 EC2 實例每秒可輕松處理 100000 次請求。傳說還有把每秒 700000 次請求作為基準(zhǔn)的。對于中小型應(yīng)用程序,通常無需考慮 Redis 切分。(請參見這篇非常出色的文章《運行中的 Redis》,進(jìn)一步了解 Redis 的性能優(yōu)化和切分。)

Redis 中的事務(wù)

Redis 并不像關(guān)系數(shù)據(jù)庫管理系統(tǒng)那樣能支持全面的 ACID 事務(wù),但其自有的事務(wù)也非常有效。從本質(zhì)上來說,Redis 事務(wù)是管道、樂觀鎖、確定提交和回滾的結(jié)合。其思想是執(zhí)行一個管道中的一個命令列表,然后觀察某一關(guān)鍵記錄的潛在更新(樂觀鎖)。根據(jù)所觀察的記錄是否會被另一個進(jìn)程更新,該命令列表或整體確定提交,或完全回滾。

下面以某個拍賣網(wǎng)站上的賣方庫存為例。買方試圖從賣方處購買某件商品時,你負(fù)責(zé)觀察 Redis 事務(wù)內(nèi)的賣方庫存變化。同時,你要從同一個庫存中刪除此商品。事務(wù)關(guān)閉前,如果庫存被一個以上進(jìn)程觸及(例如,如果兩個買方同時購買了同一件商品),事務(wù)將回滾,否則事務(wù)會確定提交。回滾后可開始重試。

Spring Data Redis 中的事務(wù)陷阱

我在 Spring 的 RedisTemplateredisTemplate.setEnableTransactionSupport(true); 中啟用 Redis 事務(wù)時得到一個慘痛的教訓(xùn):Redis 會在運行幾天后開始返回垃圾數(shù)據(jù),導(dǎo)致數(shù)據(jù)嚴(yán)重?fù)p壞。StackOverflow 上也報道了類似情況。

在運行一個 monitor 命令后,我的團(tuán)隊發(fā)現(xiàn),在進(jìn)行 Redis 操作或 RedisCallback 后,Spring 并沒有自動關(guān)閉 Redis 連接,而事實上它是應(yīng)該關(guān)閉的。如果再次使用未關(guān)閉的連接,可能會從意想不到的 Redis 密鑰返回垃圾數(shù)據(jù)。有意思的是,如果在 RedisTemplate 中把事務(wù)支持設(shè)為 false,這一問題就不會出現(xiàn)了。

我們發(fā)現(xiàn),我們可以先在 Spring 語境里配置一個 PlatformTransactionManager(例如 DataSourceTransactionManager),然后再用 @Transactional 注釋來聲明 Redis 事務(wù)的范圍,讓 Spring 自動關(guān)閉 Redis 連接。

根據(jù)這一經(jīng)驗,我們相信,在 Spring 語境里配置兩個多帶帶的 RedisTemplate 是很好的做法:其中一個 RedisTemplates 的事務(wù)設(shè)為 false,用于大多數(shù) Redis 操作,另一個 RedisTemplates 的事務(wù)已激活,僅用于 Redis 事務(wù)。當(dāng)然必須要聲明 PlatformTransactionManager@Transactional,以防返回垃圾數(shù)值。

另外,我們還發(fā)現(xiàn)了 Redis 事務(wù)和關(guān)系數(shù)據(jù)庫事務(wù)(在本例中,即 JDBC)相結(jié)合的不利之處?;旌闲褪聞?wù)的表現(xiàn)和預(yù)想的不太一樣。

結(jié)論

我希望通過這篇文章向其他 Java 企業(yè)開發(fā)師介紹 Redis 的強大之處,尤其是將 Redis 用作遠(yuǎn)程數(shù)據(jù)緩存和用于易揮發(fā)數(shù)據(jù)時。在這里我介紹了 Redis 的六個有效用例,分享了一些性能優(yōu)化技巧,還說明了我的 Glu Mobile 團(tuán)隊怎樣解決了 Spring Data Redis 事務(wù)配置不當(dāng)造成的垃圾數(shù)據(jù)問題。我希望這篇文章能夠激發(fā)你對 Redis NoSQL 的好奇心,讓你能夠受到啟發(fā),在自己的 Java 企業(yè)版系統(tǒng)里創(chuàng)造出一番天地。

本文系 OneAPM 工程師編譯整理。OneAPM 能為您提供端到端的 Java 應(yīng)用性能解決方案,我們支持所有常見的 Java 框架及應(yīng)用服務(wù)器,助您快速發(fā)現(xiàn)系統(tǒng)瓶頸,定位異常根本原因。分鐘級部署,即刻體驗,Java 監(jiān)控從來沒有如此簡單。想閱讀更多技術(shù)文章,請訪問 OneAPM 官方技術(shù)博客。

本文轉(zhuǎn)自 OneAPM 官方博客

原文地址:http://www.javaworld.com/article/3062899/big-data/lightning-fast-nosql-with-spring-data-redis.html?page=2

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/64852.html

相關(guān)文章

  • Spring Data Redis NoSQL 快如閃電 (1)

    摘要:以遠(yuǎn)程緩存服務(wù)器見長,對易揮發(fā)數(shù)據(jù)來說是極快型數(shù)據(jù)庫。即使成功寫入數(shù)據(jù)庫,最后也可能會因為網(wǎng)絡(luò)故障而使得緩存服務(wù)器以失敗告終。 【編者按】本文作者為 Xinyu Liu,詳細(xì)介紹了 Redis 的特性,并輔之以豐富的用例。在本文的第一部分,將重點概述 Redis 的方方面面。文章系國內(nèi) ITOM 管理平臺 OneAPM 編譯呈現(xiàn)。 建立在 Java 企業(yè)版之上的多層體系結(jié)構(gòu)是強大的服務(wù)...

    JerryC 評論0 收藏0
  • 快如閃電,觸控優(yōu)先。新一代的純前端控件集 WijmoJS發(fā)布新版本了

    摘要:全球最大的控件提供商葡萄城宣布,新一代純前端控件發(fā)布版本,進(jìn)一步增強產(chǎn)品功能,并支持在上的安裝和發(fā)布,極大的提升了產(chǎn)品的易用性。葡萄城的控件和軟件產(chǎn)品在國內(nèi)外屢獲殊榮,在全球被數(shù)十萬家企業(yè)學(xué)校和政府機(jī)構(gòu)廣泛應(yīng)用。 全球最大的控件提供商葡萄城宣布,新一代純前端控件 WijmoJS 發(fā)布2018 v1 版本,進(jìn)一步增強產(chǎn)品功能,并支持在 Npm 上的安裝和發(fā)布,極大的提升了產(chǎn)品的易用性。 ...

    aikin 評論0 收藏0
  • 快如閃電,觸控優(yōu)先。新一代的純前端控件集 WijmoJS發(fā)布新版本了

    摘要:全球最大的控件提供商葡萄城宣布,新一代純前端控件發(fā)布版本,進(jìn)一步增強產(chǎn)品功能,并支持在上的安裝和發(fā)布,極大的提升了產(chǎn)品的易用性。葡萄城的控件和軟件產(chǎn)品在國內(nèi)外屢獲殊榮,在全球被數(shù)十萬家企業(yè)學(xué)校和政府機(jī)構(gòu)廣泛應(yīng)用。 全球最大的控件提供商葡萄城宣布,新一代純前端控件 WijmoJS 發(fā)布2018 v1 版本,進(jìn)一步增強產(chǎn)品功能,并支持在 Npm 上的安裝和發(fā)布,極大的提升了產(chǎn)品的易用性。 ...

    陳江龍 評論0 收藏0

發(fā)表評論

0條評論

lewif

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<