大数据面试之遇见问题及思考

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

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