KafkaSpout分析:配置

devos發表於2015-03-13
public KafkaSpout(SpoutConfig spoutConf) {
        _spoutConfig = spoutConf;
}

基於0.93版本的Storm

SpoutConfig繼承自KafkaConfig。由於SpoutConfig和KafkaConfig所有的instance field全是public, 因此在使用構造方法後,可以直接設定各個域的值。

public class SpoutConfig extends KafkaConfig implements Serializable {
    public List<String> zkServers = null; //記錄Spout讀取進度所用的zookeeper的host
    public Integer zkPort = null;//記錄進度用的zookeeper的埠
    public String zkRoot = null;//進度資訊記錄於zookeeper的哪個路徑下
    public String id = null;//進度記錄的id,想要一個新的Spout讀取之前的記錄,應把它的id設為跟之前的一樣。
    public long stateUpdateIntervalMs = 2000;//多久往Zookeeper記錄一次進度

    public SpoutConfig(BrokerHosts hosts, String topic, String zkRoot, String id) {
        super(hosts, topic);
        this.zkRoot = zkRoot;
        this.id = id;
    }
}
public class KafkaConfig implements Serializable {

    public final BrokerHosts hosts; //用以獲取Kafka broker和partition的資訊
    public final String topic;//從哪個topic讀取訊息
    public final String clientId; // SimpleConsumer所用的client id

    public int fetchSizeBytes = 1024 * 1024; //發給Kafka的每個FetchRequest中,用此指定想要的response中總的訊息的大小
    public int socketTimeoutMs = 10000;//與Kafka broker的連線的socket超時時間
    public int fetchMaxWait = 10000;   //當伺服器沒有新訊息時,消費者會等待這些時間
    public int bufferSizeBytes = 1024 * 1024;//SimpleConsumer所使用的SocketChannel的讀緩衝區大小
    public MultiScheme scheme = new RawMultiScheme();//從Kafka中取出的byte[],該如何反序列化
    public boolean forceFromStart = false;//是否強制從Kafka中offset最小的開始讀起
    public long startOffsetTime = kafka.api.OffsetRequest.EarliestTime();//從何時的offset時間開始讀,預設為最舊的offset
    public long maxOffsetBehind = Long.MAX_VALUE;//KafkaSpout讀取的進度與目標進度相差多少,相差太多,Spout會丟棄中間的訊息 
   public boolean useStartOffsetTimeIfOffsetOutOfRange = true;//如果所請求的offset對應的訊息在Kafka中不存在,是否使用startOffsetTime
   public int metricsTimeBucketSizeInSecs = 60;//多長時間統計一次metrics
   public KafkaConfig(BrokerHosts hosts, String topic) {
    this(hosts, topic, kafka.api.OffsetRequest.DefaultClientId());
  }
  
public KafkaConfig(BrokerHosts hosts, String topic, String clientId) {
    this.hosts = hosts;
    
this.topic = topic;
    
this.clientId = clientId;
   }
}

 對Zookeeper的使用

KafkaSpout的配置中有兩個地方可以用到Zookeeper

  1. 用Zookeeper來記錄KafkaSpout的處理進度,在topology重新提交或者task重啟後繼續之前的處理進度。在SpoutConfig中的zkServers, zkPort和zkRoot與此相關。如果zkServer和zkPort沒有設定,那麼KafkaSpout會使用Storm叢集所用的Zookeeper記錄這些資訊。
  2. 用Zookeeper來獲取Kafka中一個topic的所有partition,和每個partition的leader。這需要實現BrokerHosts的子類ZkHosts.但是,這個Zookeepr是可選的。如果使用BrokerHosts的另一個子類StaticHosts,把partition和leader的對應關係硬編碼,則不需要Zookeeper來提供此功能。KafkaSpout會從Kafka叢集使用的Zookeeper中提取partition和leader的對應關係。而且:
  • 如果使用StatisHosts,那麼KafkaSpout會使用StaticCoordinator,這個coordinator不能響應partition leader的變化。
  • 如果使用ZkHosts,那麼KafkaSpout會使用ZkCoordinator, 當其refresh()方法被呼叫後,這個cooridnator會檢查發生leader變更的partition,併為之生成新的PartitionManager.從而能夠在leader變更後,繼續讀取訊息。

影響初始讀取進度的配置項

在一個topology上線後,它從哪個offset開始讀取訊息呢?有一些配置項對此有影響:

  1. SpoutConfig中的id欄位。如果想要一個topology從另一個topology之前的處理進度繼續處理,它們需要有相同的id。
  2. KafkaConfig的forceFromStart欄位。如果此欄位設為true, 那麼它一個topology上線後,它會忽略之前相同id的topology的進度,並且從Kafka中最早的訊息開始處理。
  3. KafkaConfig的startOffsetTime欄位。預設為kafka.api.OffsetRequest.EarliestTime()開始讀,也就是從Kafka中最早的訊息開始處理。也可以設成kafka.api.OffsetRequest.LatestOffset,也就是最早的訊息開始讀。也可以自己指定具體的值。
  4. KafkaConfig的maxOffsetBehind欄位。這個欄位對於KafkaSpout的多個處理流程都有影響。當提交一個新topology時,如果沒有forceFromStart, 當KafkaSpout對某個partition的處理進度落後startOffsetTime對應的offset多於此值時,KafkaSpout會丟棄中間的訊息,從而強制趕上目標進度.比如,如果startOffsetTime設成了lastestTime,那麼如果進度落後超過maxOffsetBehind,KafkaSpout會直接從latestTime對應的offset開始處理。如果設成了froceFromStart,則在提交新任務時,始終會從EarliestTime開始讀。
  5. KafkaSpout的userStartOffsetTimeIfOffsetOutOfRange欄位。如果設成true,那麼當fetch訊息時出錯,且FetchResponse顯示的出錯原因是OFFSET_OUT_OF_RANGE,那麼就會嘗試從KafkaSpout指定的startOffsetTime對應的訊息開始讀。例如,如果有一批訊息因為超過了儲存期限被Kafka刪除,並且zk裡記錄的訊息在這批被刪除的訊息裡。如果KafkaSpout試圖從zk的記錄繼續讀,那麼就會出現OFFSET_OUT_OF_RANGE的錯誤,從而觸發這個配置。

實際上maxOffsetBehind有時候有點名不符實。當startOffsetTime為A, zk裡的進度為B, A - B > maxOffsetBehind時,應該從A - maxOffsetBehind除開始讀或許更好一些,而不是直接跳到startOffsetTime。此處的邏輯參見PartitionManager的實現。

附:其中KafkaConfig的maxWait的意義請參見這篇文章 《卡夫卡的煉獄》

實際上,KafkaSpout的一些行為可能會比較詭異,特別是與maxOffsetBehind有關的部分。這些行為由PartitionManager決定,參見對PartitionManager的分析這篇文章。

相關文章