在运用大数据技术处理数据过程中涉及到如下几个方面的问题

  1. 在传输数据时怎么把数据完整的拿过来是首要解决的问题

这其中涉及:flume怎么保证断点续传,kafka在传输过程中发生数据积压怎么解决;

  1. 在存储数据时怎么使得数据能存的下是首要解决的问题

这其中涉及:如果hdfs上namenode节点挂掉怎么解决,以及挂掉后怎么快速恢复;

  1. 在处理数据时某台机器承担压力远大于其他机器,怎么使得计算效率最高这是我们首要解决的问题

这其中涉及:mapreduce以及spark怎么处理数据倾斜这个问题;

HDFS上传文件时是先把整个文件读到内存中,然后再分块,还是边读,边分块;HDFS如何判断一个文件的大小(他怎知道这个文件是100M还是200M)

hdfs的客户端在读取数据时会把数据按照预先设好的参数,分成一个块,这个块是边读边进行拆分的,如果加在内存中,那么机器很快就宕机了;

HDFS HA模式中jounalnode怎么确定哪台机器是namenode

在刚开始启动时,会有个预先设置好的namenode,启动时有个Active namenode ,Standby namenode

在HDFS上你是怎么处理大量的小文件的

hdfs在设计之初就决定了,它不擅长它管理大量的小文件,小文件过多首先导致namenode内存过大,其次找这个文件的时间大于传输这个文件的时间;因此如果根据业务逻辑本身来说,如果一直处理的是小文件那么可以考虑dfs.block.size调整块大小,但这是下下之策;
方法一:采用HAR(Hadoop Archives)的归档方式。HAR为构建在其它文件系统上用于文件存档的文件系统,通常将hdfs中的多个文件打包成一个存档文件,减少namenode内存的使用,可以直接使用hadoop archive命令创建HAR文件。创建HAR的过程是在运行一个mr作业。har在对小文件进行存档后,原文件不会被删除,且创建之后不能改变,文件名中也不能有空格存在,否则会报异常。
方法二:开启JVM重用;JVM重用可以使得JVM实例在同一个job中重新使用N次,N的值可以在hadoop的mapred-site.xml文件中进行配置,通常在10-20之间。如果没有小文件,不要开启JVM重用,因为会一直占用使用到的task卡槽,直到任务完成才释放
mapred-site.xml

<property>
  <name>mapreduce.job.jvm.numtasks</name>
  <value>10</value>
  <description>How many tasks to run per jvm,if set to -1 ,there is no limit</description>
</property>

Kafa的高吞吐量是怎么实现的(就单台机器本身来说)

  1. 顺序写入
    在硬盘上写一个文件的时需要寻道找出一个存储位置,如过写入文件较多,则需要频繁的通过刺头找到存储位置非常耗时,写入速度因此降低。Kafka会将数据顺序插入到文件末尾,消费者端通过控制偏移量来读取消息,这样做会导致数据无法删除,时间一长,磁盘空间会满。
    针对这种情况,kafka提供了2种策略来删除数据:基于时间删除和基于partition文件的大小删除。
  2. Memory Mapped Files
    映射磁盘的文件到内存:把一个文件映射到一个进程地址,然后通过操作内存来修改磁盘数据;
    有如下几种优势

– 用户进程把文件数据当内存数据,无需调用read()或write()
– 当用户进程接触到映射内存空间,会自动产生页错误,从而将文件数据从磁盘读到内存;若用户空间进程修改了内存页数据,相关页会自动标记并刷新到磁盘,文件被更新
– 操作系统的虚拟内存对内存页进行高速缓存,自动根据系统负载进行内存管理
– 用户空间和内核空间的数据总是一一对应,无需执行缓冲区拷贝
– 大数据的文件使用映射,无需消耗大量内存即可进行数据拷贝

创建一个内存映射文件

RandomAccessFile raf = new RandomAccessFile("test.txt", "rw");
FileChannel fc = raf.getChannel();
//将test.txt文件所有数据映射到虚拟内存,并只读
MappedByteBuffer mbuff = fc.map(MapMode.READ_ONLY, 0, fc.size());
  • 缺点及解决办法
    使用内存映射的话如果机器宕机,数据则会丢失,那么Kafka提供了produce.type参数来控制是否主动的进行刷新,如果kafka写入到mmp后立即flush再返回给生产者则为同步模式,反之为异步模式。
  1. 零拷贝

– 首先说下传统的数据传输形式
传输过程首先有这么几个部分,应用程序->cpu->DMA(Direct Memory Access)->Disk
以读数据举例
1. 应用程序读取数据首先调取read()函数从用户态转化内核态
2. DMA从磁盘缓冲区拷贝数据到内核缓冲区
3. CPU拷贝数据从内核缓冲区到用户缓冲区
4. 从内核态转化到用户态
因此可见传统模式下,涉及多次空间切换和数据冗余拷贝,效率并不高,接下来就该零拷贝技术出场了。

  • 零拷贝技术

降低冗余数据拷贝、解放CPU,这也就是零拷贝Zero-Copy技术;
零拷贝技术的几个实现手段包括:mmap+write、sendfile、sendfile+DMA收集、splice等。上面就是其中之一的技术

kafka在传输数据中难免碰到数据积压问题,你是怎么判断的,你是怎么解决的

  • 出现的情况
Auto offset commit failed for group 0: Commit cannot be completed since the group has already rebalanced and assigned the partitions to another member. 
This means that the time between subsequent calls to poll() was longer than the configured session.timeout.ms, which typically implies that the poll loop is spending too much time message processing. 
You can address this either by increasing the session timeout or by reducing the maximum size of batches returned in poll() with max.poll.records.

大概的意思是消费者的消费速度小于生产者的产生速度,所以导致了消息堆积,但是通过之前的测试可以知道.消费者的速度其实是远大于生产者的. 那么是什么原因呢? 真相只有一个:重复消费!

一个是增加session.timeout.ms的时间,

一个是设置不要自动提交(enable.auto.commit=false).

如果kafka中的某台机器挂掉,下次如果消费的不是同样的数据怎么办

The default partitioning strategy:

If a partition is specified in the record, use it
If no partition is specified but a key is present choose a partition based on a hash of the key
If no partition or key is present choose a partition in a round-robin fashion

默认的分区策略是:

如果在发消息的时候指定了分区,则消息投递到指定的分区
如果没有指定分区,但是消息的key不为空,则基于key的哈希值来选择一个分区
如果既没有指定分区,且消息的key也是空,则用轮询的方式选择一个分区

  1. range策略对应的实现类是org.apache.kafka.clients.consumer.RangeAssignor
    可以通过消费者配置中partition.assignment.strategy参数来指定分配策略,它的值是类的全路径,是一个数组
  • range分配策略针对的是主题(PS:也就是说,这里所说的分区指的某个主题的分区,消费者值的是订阅这个主题的消费者组中的消费者实例)

  • 首先,将分区按数字顺序排行序,消费者按消费者名称的字典序排好序

  • 然后,用分区总数除以消费者总数。如果能够除尽,则皆大欢喜,平均分配;若除不尽,则位于排序前面的消费者将多负责一个分区

  1. roundrobin(轮询)roundronbin分配策略的具体实现org.apache.kafka.clients.consumer.RoundRobinAssignor
轮询分配策略是基于所有可用的消费者和所有可用的分区的

与前面的range策略最大的不同就是它不再局限于某个主题

如果所有的消费者实例的订阅都是相同的,那么这样最好了,可用统一分配,均衡分配

例如,假设有两个消费者C0和C1,两个主题t0和t1,每个主题有3个分区,分别是t0p0,t0p1,t0p2,t1p0,t1p1,t1p2

那么,最终分配的结果是这样的:

C0: [t0p0, t0p2, t1p1]

C1: [t0p1, t1p0, t1p2]

flume传输中断,怎么保证下次继续从断开的位置传输
1. Flume基本组件

Event:数据消息的基本单位,有header(键值对)和body(字节数组)组成。

Agent:Flume 运行的核心是 Agent。Flume以agent为最小的独立运行单位。一个agent就是一个JVM。它是一个完整的数据收集工具,含有三个核心组件,分别是source、 channel、 sink。通过这些组件, Event 可以从一个地方流向另一个地方

lume 1.7.0 推出了 taildirSource 组件。tail 监控 目录下匹配上正则表达式的 的所有文件,实现断点续传。

hive中会导致数据倾斜的算子是啥

  1. group by,我使用Hive对数据做一些类型统计的时候遇到过某种类型的数据量特别多,而其他类型数据的数据量特别少。当按照类型进行group by的时候,会将相同的group by字段的reduce任务需要的数据拉取到同一个节点进行聚合,而当其中每一组的数据量过大时,会出现其他组的计算已经完成而这里还没计算完成,其他节点的一直等待这个节点的任务执行完成,所以会看到一直map 100% reduce 99%的情况。
解决方法:set hive.map.aggr=true

set hive.groupby.skewindata=true

原理:hive.map.aggr=true 这个配置项代表是否在map端进行聚合
  1. 当HiveQL中包含count(distinct)时如果数据量非常大,执行如select a,count(distinct b) from t group by a;类型的SQL时,会出现数据倾斜的问题。
解决方法:使用sum...group by代替。
如select a,sum(1) from (select a, b from t group by a,b) group by a;
  1. map和reduce优化
1.当出现小文件过多,需要合并小文件。可以通过set hive.merge.mapfiles=true来解决。

2.单个文件大小稍稍大于配置的block块的大写,此时需要适当增加map的个数。解决方法:set mapred.map.tasks个数

3.文件大小适中,但map端计算量非常大,如select id,count(*),sum(case when...),sum(case when...)...需要增加map个数。解决方法:set mapred.map.tasks个数,set mapred.reduce.tasks个数

map端能导致数据倾斜吗,如果能的话哪种情况能导致数据倾斜

同一个消费者组的不同线程能消费同一个数据吗,不能的话怎么做

消费者组是Kafka实现单播和广播两种消息模型的手段。同一个topic,每个消费者组都可以拿到相同的全部数据。
同一个消费者组的消费者不能消费同一个数据,可以将这个消费者放到不同的消费者组那么就可以消费这个消息,相同的数据会被不同组的消费者消费多次;

MySQL中的索引类型有哪些
Mysql目前主要有以下几种索引类型:FULLTEXT,HASH,BTREE,RTREE。

  1. FULLTEXT
    即为全文索引,目前只有MyISAM引擎支持。其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不过目前只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引。

全文索引并不是和MyISAM一起诞生的,它的出现是为了解决WHERE name LIKE “%word%”这类针对文本的模糊查询效率较低的问题。

  1. HASH
    由于HASH的唯一(几乎100%的唯一)及类似键值对的形式,很适合作为索引。

HASH索引可以一次定位,不需要像树形索引那样逐层查找,因此具有极高的效率。但是,这种高效是有条件的,即只在“=”和“in”条件下高效,对于范围查询、排序及组合索引仍然效率不高。

  1. BTREE
    BTREE索引就是一种将索引值按一定的算法,存入一个树形的数据结构中(二叉树),每次查询都是从树的入口root开始,依次遍历node,获取leaf。这是MySQL里默认和最常用的索引类型。

  2. RTREE
    RTREE在MySQL很少使用,仅支持geometry数据类型,支持该类型的存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive几种。

相对于BTREE,RTREE的优势在于范围查找。

ps. 此段详细内容见此片博文:Mysql几种索引类型的区别及适用情况

索引种类

索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。例如这样一个查询:select * from table1 where id=44。如果没有索引,必须遍历整个表,直到ID等于44的这一行被找到为止;有了索引之后(必须是在ID这一列上建立的索引),直接在索引里面找44(也就是在ID这一列找)

  • 普通索引:仅加速查询

  • 唯一索引:加速查询 + 列值唯一(可以有null)

  • 主键索引:加速查询 + 列值唯一(不可以有null)+ 表中只有一个

  • 组合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并

  • 全文索引:对文本的内容进行分词,进行搜索

Linux怎么查看占用CPU前10的进程

  • 找出占用内存资源最多的前 10 个进程
    ps -auxf | sort -nr -k 4 | head -10
[root@wq1 ~]# ps -auxf | sort -nr -k 4 | head -10
gdm        1613  0.2  9.1 3565508 138728 ?      Sl   00:45   1:56          \_ /usr/bin/gnome-shell
root       1202  0.0  1.6 314424 25392 tty1     Ssl+ 00:45   0:10  \_ /usr/bin/X :0 -background none -noreset -audit 4 -verbose -auth /run/gdm/auth-for-gdm-QNHBVw/database -seat seat0 -nolisten tcp vt1
root       1124  0.0  1.2 574304 19524 ?        Ssl  00:44   0:14 /usr/bin/python2 -Es /usr/sbin/tuned -l -P
gdm        1755  0.0  1.1 632032 16900 ?        Sl   00:46   0:01          \_ /usr/libexec/gsd-power
gdm        1741  0.0  1.1 1012404 17796 ?       Sl   00:46   0:00          \_ /usr/libexec/gsd-media-keys
gdm        1721  0.0  1.1 714352 16640 ?        Sl   00:46   0:10          \_ /usr/libexec/gsd-color
root       1131  0.0  1.0 1004992 16120 ?       Ssl  00:44   0:08 /usr/sbin/libvirtd
gdm        1720  0.0  1.0 464796 15584 ?        Sl   00:46   0:00          \_ /usr/libexec/gsd-clipboard
gdm        1682  0.0  1.0 465112 15812 ?        Sl   00:46   0:00 /usr/libexec/ibus-x11 --kill-daemon
gdm        1780  0.0  0.9 549632 14300 ?        Sl   00:46   0:00          \_ /usr/libexec/gsd-wacom
  • 找出占用 CPU 资源最多的前 10 个进程 ps -auxf | sort -nr -k 3 | head -10
[root@wq1 ~]# ps -auxf | sort -nr -k 3 | head -10
root        744  0.2  0.4 324784  7028 ?        Ssl  00:44   2:16 /usr/bin/vmtoolsd
gdm        1613  0.2  9.1 3565508 138728 ?      Sl   00:45   1:56          \_ /usr/bin/gnome-shell
root      10957  0.1  0.4 350508  6780 ?        Sl   14:11   0:00 /usr/sbin/abrt-dbus -t133
root      10931  0.1  0.4 163620  6132 ?        Ss   14:11   0:00  \_ sshd: root@pts/0
root      10701  0.1  0.0      0     0 ?        S    13:50   0:01  \_ [kworker/0:1]
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
rtkit       734  0.0  0.1 198808  1796 ?        SNsl 00:44   0:04 /usr/libexec/rtkit-daemon
rpc         732  0.0  0.0  69280  1008 ?        Ss   00:44   0:00 /sbin/rpcbind -w
root       9978  0.0  0.0      0     0 ?        S    12:53   0:00  \_ [kworker/3:0]
root          9  0.0  0.0      0     0 ?        S    00:44   0:20  \_ [rcu_sched]

Linux上内存的buff和cache都是什么含义

这是Linux一种非常优秀的设计,目的就是为了提升磁盘IO的性能,从低速的块设备上读取的数据会暂时保存在内存中,即使数据在当时已经不再需要了,但在应用程序下一次访问该数据时,它可以从内存中直接读取,绕开了低速的块设备,从而提高系统的整体性能。
为了提高系统性能和不浪费内存,linux把多的内存做了cache,以提高io速度.你的那些内存并没有被占用。对于内核来说,buffer 和 cache 其实都属于已经被使用的内存。但当应用程序申请内存时,如果 free 内存不够,内核就会回收 buffer 和 cache 的内存来满足应用程序的请求
buff:即写如磁盘时,先保存到磁盘缓冲区(buffer),然后再写入到磁盘。
cache:即读磁盘时,数据从磁盘读出后,暂留在缓冲区(cache),为后续程序的使用做准备。

df -lh 与free -lh中lh的含义是什么

[root@wq1 ~]# df --help
  -a, --all             include pseudo, duplicate, inaccessible file systems
  -B, --block-size=SIZE  scale sizes by SIZE before printing them; e.g.,
                           '-BM' prints sizes in units of 1,048,576 bytes;
                           see SIZE format below
      --direct          show statistics for a file instead of mount point
      --total           produce a grand total
  -h, --human-readable  print sizes in human readable format (e.g., 1K 234M 2G)
  -H, --si              likewise, but use powers of 1000 not 1024
  -i, --inodes          显示inode 信息而非块使用量
  -k                    即--block-size=1K
  -l, --local           只显示本机的文件系统
      --no-sync         取得使用量数据前不进行同步动作(默认)
      --output[=FIELD_LIST]  use the output format defined by FIELD_LIST,
                               or print all fields if FIELD_LIST is omitted.
  -P, --portability     use the POSIX output format
      --sync            invoke sync before getting usage info
  -t, --type=TYPE       limit listing to file systems of type TYPE
  -T, --print-type      print file system type
  -x, --exclude-type=TYPE   limit listing to file systems not of type TYPE
  -v                    (ignored)
      --help            显示此帮助信息并退出
      --version         显示版本信息并退出

free

[root@wq1 ~]# free --help

Usage:
 free [options]

Options:
 -b, --bytes         show output in bytes
 -k, --kilo          show output in kilobytes
 -m, --mega          show output in megabytes
 -g, --giga          show output in gigabytes
     --tera          show output in terabytes
     --peta          show output in petabytes
 -h, --human         show human-readable output
     --si            use powers of 1000 not 1024
 -l, --lohi          show detailed low and high memory statistics
 -t, --total         show total for RAM + swap
 -s N, --seconds N   repeat printing every N seconds
 -c N, --count N     repeat printing N times, then exit
 -w, --wide          wide output

     --help     display this help and exit
 -V, --version  output version information and exit

为什么被final修饰的常量不能被再修改
这就牵扯出一个问题:使用 final 关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?

//1) 对象相等则hashCode一定相等;
//2) hashCode相等对象未必相等。
  public static void main(String[] args) {
        final StringBuilder sb = new StringBuilder("haha");;
        //同一对象的hashCode值相同
        System.out.println("sb中的内容是:"+sb);
        sb.append("我变了");
        System.out.println("sb中的内容是:"+sb);
        System.out.println( sb.append("我变了")==sb);
        System.out.println( sb.append("我变了").equals(sb));
    }
sb中的内容是:haha
sb中的内容是:haha我变了
true
true

结论:使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。

多线程的实现方式

继承Thread类、实现Runnable接口、实现Callable接口通过FutureTask包装器来创建Thread线程、使用ExecutorService、Callable、Future实现有返回结果的多线程。

ArrayList与LinkedList的区别,以及应用场景

ArrayList是实现了基于动态数组的数据结构,LinkedList是基于链表结构。
对于随机访问的get和set方法,ArrayList要优于LinkedList,因为LinkedList要移动指针。
对于新增和删除操作add和remove,LinkedList比较占优势,因为ArrayList要移动数据。
ArrayList使用在查询比较多,但是插入和删除比较少的情况,而LinkedList用在查询比较少而插入删除比较多的情况

String stringbuffer stringbuilder三者之间的区别

String:不可变字符串;

StringBuffer:可变字符串、效率低、线程安全;

StringBuilder:可变字符序列、效率高、线程不安全;
初始化上的区别,String可以空赋值,后者不行,报错

(1)如果要操作少量的数据用 String;

(2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;

(3)单线程操作字符串缓冲区下操作大量数据 StringBuilder(推荐使用)。

说一说你在工作中遇到了什么问题,你是怎么判断这个问题的,以及是怎么解决的