大數據面試之遇見問題及思考

1.hadoop存儲一億數據

考慮:大文件和小文件肯定是要預先設計的,這樣就可以調整默認數據塊大小,以及可以考慮CombineFile文件壓縮,或者歸檔存儲的方式。如果真是上億個文件信息,一定會導致許多問題,比如性能方面。以及內存中維護目錄樹能否存儲下。推斷有可能會有以下情況:a.內存直接溢出,系統報錯。2.內存數據,使用虛存。不管是哪種方式,都是不合理的,最合理的應該考慮是都需要分多個集羣,或者是hdfs聯盟。hadoop3.0中可以使用多個namenode。

1.1 添加硬盤,或者數據目錄

關閉datanode進程
修改hdfs-site.xml文件dfs.data.dir值,多個路徑以“,”分割
啓動datanode進程
注意:關閉datanode進程後,如果namenode長時間未接收到datanode心跳會認爲datanode掛了,然後會複製此datanode上的數據到其他主機上。timeout = 10 * 心跳間隔時間(默認3s) + 2 * 檢查一次消耗的時間(默認5min)

1.2 添加數據節點

a.新節點環境準備,java,hadoop,ssh,hosts等
b.編輯主節點slaves文件,添加新節點 >hdfs dfsadmin -refreshNodes
c.啓動新的數據節點 >hadoop-daemon.sh start datanode 以及 >yarn-daemon.sh start nodemanager

1.3 容量監控

cdh/ambari中可以添加預警郵箱(部署過ambari集羣,由於筆記本硬件沒部署過cdh集羣,一般連接測試使用的原生的,版本號根據cdh提供組件版本)
原生的hadoop集羣如果想實現預警的話,可以定時(5-10s,這樣也不至於佔用太多的帶寬)發送get請求,然後xpath解析獲取到的頁面,獲取hdfs利用率,然後在linux下安裝一個簡單的郵件服務,就可以發送服務情況到某個郵箱,當然這個功能默認肯定是需要關閉的。否者可能會被判斷爲安全隱患。
另外對於各個主機的運行狀態之前項目中使用java開發過一個系統監控的功能,基於snmp協議,獲取cpu,內存,網絡,磁盤等一系列信息。

2.rowkey原則

a.一般10-100byte,定長
b.開頭建議使用散列,避免熱key,regionServer負載均衡
c.一般使用散列+時間戳+關鍵字段

3.hadoop幽靈進程

這個問題我沒遇見過,倒是遇見過一次,namenode進程啓動之後,進程自動結束了的問題。當時是查找的hdfs的日誌,提示的是數據塊異常,我本地的環境,默認副本數是1,就直接格式化了。

3.java基本操作kafka

public class ProducerDemo {
private static final String topic = “my-topic”;

public static void main(String[] args) {
    Properties properties = new Properties();
    properties.put("metadata.broker.list","master:9092,slave1:9092,slave2:9092"); 
    properties.put("serializer.class","kafka.serializer.StringEncoder");
    ProducerConfig producerConfig = new ProducerConfig(properties);
    Producer<String, String> producer = new Producer<>(producerConfig);
    for (int i = 0; i < 1000; i++) {
        producer.send(new KeyedMessage<String,String>(topic,"gugu"+i));
    }
}

}
// 多線程消費同一個組的數據
public class ConsumerDemo {

private static final String topic = "my-topic";
private static final Integer threads = 2;

public static void main(String[] args) {
    Properties properties = new Properties();
    properties.put("zookeeper.connect","master:2181,slave1:2181,slave2:2181");
    properties.put("group.id","gugu");
    //smallest重最開始消費,largest代表重消費者啓動後產生的數據才消費
    //--from-beginning
    properties.put("auto.offset.reset","smallest");
    ConsumerConfig config = new ConsumerConfig(properties);
    ConsumerConnector consumer = Consumer.createJavaConsumerConnector(config);

    Map<String,Integer> topicCountMap = new HashMap<>();
    topicCountMap.put(topic,threads);
    Map<String, List<KafkaStream<byte[], byte[]>>> messageStreams = consumer.createMessageStreams(topicCountMap);
    List<KafkaStream<byte[], byte[]>> kafkaStreams = messageStreams.get(topic);
    for (KafkaStream<byte[], byte[]> kafkaStream:kafkaStreams){
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (MessageAndMetadata<byte[], byte[]> mm:kafkaStream){
                    String msg = new String(mm.message());
                    System.out.println(msg);
                }
            }
        }).start();
    }
}

}

kafka的一個topic可以有多個分區,可以通過多個分區將一個topic的數據打散到多個broker上,實現負載均衡,以提高吞吐量。
經過查閱資料,確實發現了與kafka的兩個offset,一個是存儲在zookeeper中的和另外一個存儲在kafka中的。如果是使用javaapi來消費的,需要配置zookeeper.connect,這個時候使用的是zookeeper中的offset。如果使用kafka默認api,需要配置bootstrap.servers參數,這個時候使用kafka中存儲的offset。

4.spark讀取數據

kafkaUtils.createStream
較頂層,但是如果要保證保證數據可靠性(job出錯的時候可能會丟失),需要開啓WAL和checkpiont,因此會影響效率
kafkaUtils.createDirectStream
底層方法會根據kafka分區創建rdd,因此效率比較高,如果需要保證可靠性,需要開啓checkpiont

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章