成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Kestrel中的Journal.scala類詳解

開發 后端
本文講述Kestrel中的PersistentQueue之下的Journal.scala類,這個類支撐了消息隊列的存儲問題,以避免避免服務重啟的時候,Kestrel的隊列丟失。

本文是Scala代碼實例之Kestrel的第六部分,講述PersistentQueue中的Journal.scala類。

在PersistentQueue之下,有一個Journal.scala的類,支撐了消息隊列的存儲問題。這是Kestrel提供的另外一個特性:通過文件系統保存消息隊列,避免服務重啟的時候,Kestrel的隊列丟失。

通過前面一段時間的閱讀,我們對Scala的語法已經有一個基本的把握,所以在閱讀Journal的時候,我們就更注重實現的方式,而不是語法細節了。當然Journal也沒有太多的語法細節需要講的了。當然出了還沒有詳細說過的case class和case object。

在Journal.scala的開始部分就定義了一個abstract class類JournalItem,并且定義了它的許多子類,這些子類是用來和PersistentQueue進行消息傳遞的。case class/case object是一種特殊的class/object,其功能是在對象里面增加了幾個功能

1. 把所有的建構函數的var變成val,也就是變成了不可變的常量

2.自動實現了equal, hashCode和toString三個方法

3.當對象出現在case之后的時候,會自動apply出一個對象,對象的值和創建的時候一樣,這個功能保證了可以和match…case語法可以寫得很簡練。

關于Case class的具體說明可以參考:CaseClasses和MatchingOnCaseClasses。關于第三條特性,還可以參考CompanionObjects。

簡單的理解,我們就把case object/case class當作消息傳遞中需要使用的對象類型就可以了。

Journal使用了noi的FileChannel,來處理文件的讀取和存儲。核心的算法,可以只看readJournalEntry和replay兩個方法。readJournalEntry的功能是從文件中讀取數據,并且根據格式組成各種case class/case object,并且同時返回字節數。而在上層的方法,比如replay,則根據得到的不同數據類型,調用更上層的函數f(case class/case object)。

我們回到PersistentQueue中看replayJournal的時候,發現它將調用replay后得到的一系列的case class轉義成為在PersistentQueue中需要執行的各種命令——所以這個方法的名字叫做replay!就是回放的意思。

當系統重啟的時候,打開每個queue之前都需要一段回放的時間,把文件系統中記錄的當時的整個存取過程重新回放一次,通過回放來重建內存中的隊列。回過來再看Journal.scala的時候,我們就更清晰的知道,文件存儲的不是當時的隊列狀態,而是每一次系統執行的軌跡。所以,Journal對整個Kestrel消息隊列的開銷才會很小。

但是另外一個問題隨之而來,如果記錄所有的操作過程,那么這個文件不是只會增大,不會縮小么?為了解決這個問題,Journal.scala實現了一個叫做roll的機制。從PersisitentQueue中的add方法中,我們可以看到這樣的代碼:

  1. if (keepJournal() && !journal.inReadBehind) {  
  2.      if (journal.size > maxJournalSize() * maxJournalOverflow() && queueSize < maxJournalSize()) {  
  3.        // force re-creation of the journal.  
  4.        log.info("Rolling journal file for '%s' (qsize=%d)", name, queueSize)  
  5.        journal.roll(xidCounter, openTransactionIds map { openTransactions(_) }, queue)  
  6.      }  
  7.      if (queueSize >= maxMemorySize()) {  
  8.        log.info("Dropping to read-behind for queue '%s' (%d bytes)", name, queueSize)  
  9.        journal.startReadBehind  
  10.      }  
  11.    }  

如果發生了Journal文件的尺寸太大,但是實際的Queue尺寸也沒有滿的時候,就啟動roll進程來重新建立一個Journal文件。處理的方法也很簡單,就是把當前內存中的隊列直接寫入到Journal對應的文件中,變成一連串的add。這么做,是不是一個很好的做法?只有一種意外的情況,那就是現存在消息隊列里面的數據很多,那么重建Journal的時間就需要很多。作者也考慮到了這個問題,所有要求queue實際的size必須小于Journal所能存儲的量的時候,才會做roll的操作,也就是說,當隊列里面有很多的事件沒有處理的時候,就算硬盤占用得再多,也不會啟動roll方法。而解決的方法是,當內存中的Queue太大,大到超過了***的內存使用限制的時候,啟動readBehind模式。

當readBehind模式啟動之后,會對文件增加一個read句柄,每次從內存里面remove掉消息的時候,就會嘗試從文件中讀取消息放到內存里面。在這樣的模式下,內存就一致保持著最滿的隊列。更多的消息就先直接存儲到文件中,直到文件中的read指針和write指針重合,也就是說所有在文件系統中的消息都已經被處理完畢了,系統就會重新切換回正常的模式。

在這種模式下,只要硬盤的數量足夠大,我們基本上可以把這個消息隊列理解為無限長……但是在readbehind模式下,是不會進行roll的操作的。所以——大家需要注意的是,在配置中,maxJournalSize必須要小于maxMemorySize,否則這兩個機制就會打架了。而maxJournalSize這個數值也不應該很大,這樣就能保證每次roll的效率會很快(因為roll的效率是取決于事件占用內存的數量,也就是maxJournalSize的),超過這個值,系統就不會roll。

決定是否roll。還有一個數值就是maxJournalOverflow,這是一個很好的設計,相當于Journal文件的利用率,比如說Overflow設置為5,表示現在有效的消息隊列數據,只有整個 Journal 文件大小的 1/5。

假設我們平均每個消息的數據占有1K,那么其他的指令信息基本可以被忽略(因為都只有幾個字節而已),所以Overflow的比例相當于總消息數量 / 還沒有處理過的消息數量。所以這個數值的上限取決于replay的效率。也就是讀取文件的速度,比如說,我們覺得啟動的時候,讀取100M的文件,大概需要10s,是我們可以接受的,而每個消息字節平均是1K,roll一次100個消息需要100ms,是可以接受的。那么 maxJournalOverflow = 100M / 100 * 1K = 1000。不過實際情況可能是roll的次數會更多一些,因為當內存中的消息隊列只有10個的時候,硬盤超過10M,就會觸發roll操作了。

但是設置1000的目的是,在最壞的情況可以接受,而不是在一半的情況下效率更高。這是需要注意的。

【相關閱讀】

  1. 從Java走進Scala(Scala經典讀物)
  2. A Scala Tutorial for Java programmers
  3. 專題:Scala編程語言
  4. 從Scala看canEqual與正確的的equals實現
  5. Scala快速入門:從下載安裝到定義方法
責任編輯:yangsai 來源: dingsding
相關推薦

2009-09-22 10:15:42

PersistentQScala

2009-09-22 09:59:40

QueueCollecScala

2009-09-28 11:25:17

PersistentQKestrelScala

2009-09-18 11:44:05

Scala實例教程Kestrel

2009-09-28 11:42:21

KestrelScala

2009-09-28 10:26:12

Scala代碼實例Kestrel

2009-09-22 09:42:24

Scala的核心

2009-07-22 07:53:00

Scala擴展類

2009-07-08 15:35:18

Case類Scala

2009-07-21 11:25:03

ScalaRational類

2009-06-16 17:54:38

Scala類語法語義

2009-07-22 09:31:59

Scala類類層級Java類

2009-09-09 11:37:08

Scala的模式匹配

2009-06-30 15:18:10

StringBuildJava

2009-07-21 08:54:35

Scala富包裝器

2009-07-22 07:45:00

Scala代碼重復

2009-07-20 16:56:51

Scala類的定義

2011-06-28 11:05:19

Qt QWidget Eventable

2025-02-07 08:47:38

C#派生類接口

2009-07-21 17:29:25

Scala第一類函數
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 成人免费观看男女羞羞视频 | 久久精品国产一区二区三区 | 免费国产一区二区 | 日韩毛片 | 国产欧美日韩视频 | 一区二区三区精品在线视频 | 色综合一区二区 | 美女日皮网站 | 日韩精品在线一区 | 一区二区三区不卡视频 | 91视视频在线观看入口直接观看 | 二区中文 | 青青草视频网 | 亚洲精品中文在线观看 | 国产精品久久久久久二区 | 日韩免费1区二区电影 | 日韩av第一页| 久久久久久久国产 | 免费视频99 | 精品免费国产一区二区三区四区 | 国产三级国产精品 | 巨大黑人极品videos精品 | 在线免费黄色小视频 | 久久男人天堂 | 国产成人在线观看免费 | 国产精品视频一区二区三区 | 国产综合网站 | 国产高清无av久久 | 国产专区在线 | 色综合国产 | 国产一区二 | 日韩二三区 | 蜜桃视频一区二区三区 | 日日干日日射 | 欧美性一区二区三区 | 精品国产乱码久久久久久中文 | 久久av影院 | 精品视频一区二区 | 国产精品爱久久久久久久 | 成人精品视频在线 | 久草精品视频 |