数据分析大数据面试题大杂烩01

互联网:通过埋点实时计算用户浏览频次用优惠券等措施吸引用户,通过历史信息用非智能学习的title方式构造用户画像(抖音,京东)
电信,银行统计营收和针对用户的个人画像:处理大量非实时数据
政府:健康码,扫码之后确诊,找出与确诊对象有关联的人
订单 订单表(除商品以外所有信息),商品详情表,通过搜集用户title进行定制化推荐
点击流数据 通过埋点进行用户点击行为分析
FLINK一般用来做实时
SPARK一般用来做离线
原理胜过代码

List 与set 的区别?
List特点:元素有放入顺序,元素可重复 ,Set特点:元素无放入顺序,元素不可重复 . 
数据库的三大范式
ACID,是指在可靠数据库管理系统(DBMS)中,事务(transaction)所应该具有的四个特性:原子性(Atomicity) 一致性(Consistency) 隔离性(Isolation) 持久性(Durability)
原子性是指事务是一个不可再分割的工作单位,事务中的操作要么都发生,要么都不发生 . 
在事务中的扣款和加款两条语句,要么都执行,要么就都不执行 . 否则如果只执行了扣款语句,就提交了,此时如果突然断电,A账号已经发生了扣款,B账号却没收到加款,在生活中就会引起纠纷 . 

一致性是指在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏 . 这是说数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性 . 
对银行转帐事务,不管事务成功还是失败,应该保证事务结束后ACCOUNT表中aaa和bbb的存款总额为2000元 . 

事务之间的相互影响分为几种,分别为:脏读,不可重复读,幻读,丢失更新
脏读意味着一个事务读取了另一个事务未提交的数据,而这个数据是有可能回滚的;如下案例,此时如果事务1回滚,则B账户必将有损失 . 

幻读,是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行 . 同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据 . 那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样.

丢失更新就是两个不同的事务(或者Java程序线程)在某一时刻对同一数据进行读取后,先后进行修改 . 导致第一次操作数据丢失 . 
两个事务同时读取同一条记录,A先修改记录,B也修改记录(B是不知道A修改过),B提交数据后B的修改结果覆盖了A的修改结果 . 

并发事务处理隔离性级别带来的问题
更新丢失(Lost Update)
当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题——最后的更新覆盖了由其他事务所作的更新.
例如:两个程序员修改同一文件,每个程序员独立地更改其副本,然后保存更改后地副本,这样就覆盖了原始文档.最后保存其更改副本的编辑人员覆盖前一个程序员所作的更改.
如果在一个程序员完成并提交事务之前,另一个程序员不能访问同一文件,则可避免此问题.
脏读(Dirty Reads)
一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也就读取同一条记录,如果不加控制,第二个事务读取了这些"脏"数据,并据此做进一步的处理,就会产生未提交的数据依赖关系.这种现象被形象地叫做"脏读"
一句话:事务A读取到了事务B 已修改但尚未提交 的数据,还在这个数据基础上做了操作.此时,如果B事务回滚,A读取的数据无效,不符合一致性要求.
不可重复读(Non-Repeatable Reads)
一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变.或某些记录已经被删除了!这种现象就叫做"不可重复读".
一句话:事务A读取到了事务B已经提交的修改数据,不符合隔离性.
幻读(Phantom Reads)
一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象被称为"幻读".
一句话:事务A读取到了事务B提交的新增数据,不符合隔离性.
不可重复读:A事务在执行过程中,B事务对数据进行了修改或删除,导致A两次读取的数据不一致;
重点在于update和delete(锁行即可解决),
幻读:A事务在执行过程中,B事务新增了符合A事务要查询的数据,导致A两次读取的数据不一致;
重点在于insert(需要锁表解决).

01:Read uncommitted(读未提交):最低级别,任何情况都会发生 . 
02:Read Committed(读已提交):可避免脏读的发生 . 
03:Repeatable read(可重复读):可避免脏读 不可重复读的发生 . 
04:Serializable(串行化):避免脏读 不可重复读,幻读的发生 . 

       未提交读:在读数据时不会检查或使用任何锁 . 因此,在这种隔离级别中可能读取到没有提交的数据 .   

       已提交读:只读取提交的数据并等待其他事务释放排他锁 . 读数据的共享锁在读操作完成后立即释放 .  .  

       可重复读:像已提交读级别那样读数据,但会保持共享锁直到事务结束 .   

       可串行读:工作方式类似于可重复读 . 但它不仅会锁定受影响的数据,还会锁定这个范围 . 这就阻止了新数据插入查询所涉及的范围 . 

事务的(ACID)特性是由关系数据库管理系统(RDBMS,数据库系统)来实现的 . 数据库管理系统采用日志来保证事务的原子性 一致性和持久性 . 日志记录了事务对数据库所做的更新,如果某个事务在执行过程中发生错误,就可以根据日志,撤销事务对数据库已做的更新,使数据库退回到执行事务前的初始状态 . 

数据库管理系统采用锁机制来实现事务的隔离性 . 当多个事务同时更新数据库中相同的数据时,只允许持有锁的事务能更新该数据,其他事务必须等待,直到前一个事务释放了锁,其他事务才有机会更新该数据 . 

四种隔离级别最高:Seralizable级别,最低的是Read uncommitted级别; 级别越高,执行效率就越低; 隔离级别的设置只对当前链接有效,对JDBC操作数据库来说,一个Connection对象相当于一个链接,只对该Connection对象设置的隔离级别只对该connection对象有效,与其它链接connection对象无关 . 

01:Mysql的默认隔离级别是:可重复读:Repeatable read;

02:oracle数据库中,只支持seralizable(串行化)级别和Read committed();默认的是Read committed级别;

03:Read committed()是SQL Server的默认隔离级别 . 

隔离事务之间的影响是通过锁来实现的,通过阻塞来阻止上述影响 . 不同的隔离级别是通过加不同的锁,造成阻塞来实现的,所以会以付出性能作为代价;安全级别越高,处理效率越低;安全级别越低,效率高 . 
Read Commited符合了多数的实际需求.

Serializabale:最高的事务隔离级别,代价花费最高,性能很低,很少使用,在此级别下,事务顺序执行,避免上述产生的情况 . 

反射有三种获取的方式,分别是:forName  / getClass / 直接使用class方式 使用反射可以获取类的实例

设计方式有工厂法,懒加载,观察者模式,静态工厂,迭代器模式,外观模式    

Rpc分为同步调用和异部调用,异步与同步的区别在于是否等待服务器端的返回值 . Rpc的组件有RpcServer,RpcClick,RpcProxy,RpcConnection,RpcChannel,RpcProtocol,RpcInvoker等组件

ArrayList 和 Vector 是采用数组方式存储数据的,是根据索引来访问元素的,都可以根据需要自动扩展内部数据长度,以便增加和插入元素,都允许直接序号索引元素,但是插入数据要涉及到数组元素移动等内存操作,所以索引数据快插入数据慢,他们最大的区别就是 synchronized 同步的使用 . 
LinkedList 使用双向链表实现存储,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入数度较快!如果只是查找特定位置的元素或只在集合的末端增加 移除元素,那么使用 Vector
或 ArrayList 都可以 . 如果是对其它指定位置的插入 删除操作,最好选择 LinkedList

HashMap HashTable 的区别及其优缺点:
HashTable 中的方法是同步的(有锁) HashMap 的方法在缺省情况下是非同步的 因此在多线程环境下需要做额外的同步机制 . 
HashTable 不允许有 null 值 key 和 value 都不允许,而 HashMap 允许有 null 值 key和 value 都允许 因此 HashMap 使用 containKey()来判断是否存在某个键 . HashTable 使用 Enumeration ,而 HashMap 使用 iterator . 
Hashtable 是 Dictionary 的子类,HashMap 是 Map 接口的一个实现类 . 

当需要对字符串进行操作时,使用 StringBuffer 而不是 String,String 是 read-only 的,如果对它进行修改,会产生临时对象,而 StringBuffer 是可修改的,不会产生临时对象 . 

 hashmap hashtable 的区别在于hashtable 是线程安全的,而hashmap 不是线程安全的,currentHashMap也是线程安全的 . 
     ConcurrentHashMap是使用了锁分段技术技术来保证线程安全的 . 所分段的技术是:讲数据分成一段一段的储存,给每一段的数据添加一把锁,当线程访问一个数据时,其他的数据可以被访问 . 

1 程序在运行时会产生很多的对象的信息,当这些对象的信息没有用时,则会被gc回收

2 调优的方式主要是调节年轻代与老年代的内存的大小

OOM是OutOfMemory的缩写(搞得跟多高大上似的)就是线程创建的多了,没有及时的回收过来所产生的


2-4)修改 linux 内核参数
[root@hadoop1 /]# vi /etc/sysctl.conf
net.core.somaxconn = 32768
表示物理内存使用到 90%(100-10=90)的时候才使用 swap 交换区

2-5)关闭 noatime
在最后追加一下内容
/dev/sda2 /data ext3 noatime,nodiratime 0 0

2-6)请用shell命令把某一个文件下的所有的文件分发到其他的机器上
Scp  -r  /user/local   hadoop2:/user/local

[root@hadoop1 test]# find  .|  grep -ri "a"

1 客户端向 nameNode 发送要上传文件的请求

2 nameNode 返回给用户是否能上传数据的状态

3 加入用户端需要上传一个 1024M 的文件,客户端会通过 Rpc 请求 NameNode,并返回需要上传给那些DataNode(分配机器的距离以及空间的大小等),namonode会选择就近原则分配机器 . 

4 客户端请求建立 block 传输管道 chnnel 上传数据

5 在上传是 datanode 会与其他的机器建立连接并把数据块传送到其他的机器上

6 dataNode 向 namenode 汇报自己的储存情况以及自己的信息

当第一个快上传完后再去执行其他的复制的传送

只需要在IF[ -f ] 括号中加上-f参数即可判断文件是否存在

fsimage是保存最新的元数据的信息,当fsimage数据到一定的大小事会去生成一个新的文件来保存元数据的信息,这个新的文件就是edit,edit会回滚最新的数据 . 

不管是hadoop1.x 还是hadoop2.x 都是默认的保存三份,可以通过参数dfs.replication就行修改

Core-site.xml 文件的优化

fs.trash.interval
默认值:0
说明:这个是开启hdfs文件删除自动转移到垃圾箱的选项,值为垃圾箱文件清除时间 . 一般开启这个会比较好,以防错误删除重要文件 . 单位是分钟 . 

dfs.namenode.handler.count
默认值:10
说明:hadoop系统里启动的任务线程数,这里改为40,同样可以尝试该值大小对效率的影响变化进行最合适的值的设定 . 

mapreduce.tasktracker.http.threads
默认值:40
说明:map和reduce是通过http进行数据传输的,这个是设置传输的并行线程数 . 

数据的倾斜主要是两个的数据相差的数量不在一个级别上,在只想任务时就造成了数据的倾斜,可以通过分区的方法减少reduce数据倾斜性能的方法,例如;抽样和范围的分区 自定义分区 数据大小倾斜的自定义侧略

1.创建 hadoop 帐户 . 

2.setup.改 IP . 

3.安装 java,并修改/etc/profile 文件,配置 java 的环境变量 . 

4.修改 Host 文件域名 . 

5.安装 SSH,配置无密钥通信 . 

6.解压 hadoop . 

7.配置 conf 文件下 hadoop-env.sh core-site.sh mapre-site.sh hdfs-site.sh . 

8.配置 hadoop 的环境变量 . 

9.Hadoop namenode -format

Start-all.sh

怎样快速的杀死一个job
1 执行hadoop  job -list  拿到job-id
2 Hadoop job kill hadoop-id

Hadoop-daemon.sh start datanode

Hadoop 常用的jion有reduce side join  , map side  join ,  SemiJoin 不过reduce side join 与 map side join 比较常用,不过都是比较耗时的 . 

Hadoop 的压缩算法有很多,其中比较常用的就是gzip算法与bzip2算法,都可以可通过CompressionCodec来实现

Hadoop 的调度有三种其中fifo的调度hadoop的默认的,这种方式是按照作业的优先级的高低与到达时间的先后执行的,还有公平调度器:名字见起意就是分配用户的公平获取共享集群呗!容量调度器:让程序都能货到执行的能力,在队列中获得资源 . 

hadoop flush 的过程?
Flush 就是把数据落到磁盘,把数据保存起来

队列的实现是链表,消费的顺序是先进先出 . 

Cloudera 提供哪几种安装 CDH 的方法
· Cloudera manager
· Tarball
· Yum
· Rpm

文件大小默认为 64M,改为 128M 有啥影响?
这样减少了namenode的处理量,数据的元数据保存在namenode上,如果在网络不好的情况下会增到datanode的储存时间 . 可以根据自己的网络来设置大小 . 

datanode 首次加入 cluster 的时候,如果 log 报告不兼容文件版本,那需要namenode 执行格式化操作,这样处理的原因是?
这样处理是不合理的,因为那么 namenode 格式化操作,是对文件系统进行格式化,namenode 格式化时清空 dfs/name 下空两个目录下的所有文件,之后,会在目录 dfs.name.dir 下创建文件 . 文本不兼容,有可能时 namenode 与 datanode 的 数据里的 namespaceID clusterID 不一致,找到两个 ID 位置,修改为一样即可解决 . 

1 首先,hadoop streaming是一种编程工具,它是由hadoop提供的 . 
2 为什么要用hadoop streaming呢?
hadoop框架是用java语言写的,也就是说,hadoop框架中运行的所有应用程序都要用java语言来写才能正常地在hadoop集群中运行 . 那么问题来了,如果有些开发者就是不会java语言,但是又想使用mapreduce这个并行计算模型的话,那该怎么办?
就是基于这样的考虑,所以hadoop提供了hadoop streaming这个编程工具,它支持用任何编程语言来编写mapreduce的map函数和reduce函数 . 

一个 MapReduce 作业由 Map 阶段和 Reduce 阶段两部分组成,这两阶段会对数据排序,从这个意义上说MapReduce 框架本质就是一个 Distributed Sort . 在 Map阶段,在 Map 阶段,Map Task 会在本地磁盘输出一个按照 key 排序(采用的是快速排序)的文件(中间可能产生多个文件,但最终会合并成一个),在 Reduce 阶段,每个 Reduce Task 会对收到的数据排序,这样,数据便按照 Key 分成了若干组,之后以组为单位交给 reduce处理 . 很多人的误解在 Map 阶段,如果不使用 Combiner便不会排序,这是错误的,不管你用不用 Combiner,Map Task 均会对产生的数据排序(如果没有 Reduce Task,则不会排序,实际上 Map 阶段的排序就是为了减轻 Reduce端排序负载) . 由于这些排序是 MapReduce 自动完成的,用户无法控制,因此,在hadoop 1.x 中无法避免,也不可以关闭,但 hadoop2.x 是可以关闭的 . 

交换排序
两两比较待排序的关键字,并交换不满足次序要求的那对数,直到整个表都满足次序要求为止 . 

冒泡排序 
交换排序的一种
1 比较相邻的元素 . 如果第一个比第二个大(小),就交换他们两个 . 
2 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对 . 这步做完后,最后的元素会是最大(小)的数 . 
3 针对所有的元素重复以上的步骤,除了最后已经选出的元素(有序) . 
4 持续每次对越来越少的元素(无序元素)重复上面的步骤,直到没有任何一对数字需要比较,则序列最终有序 . 

快速排序(Quicksort)是对冒泡排序的一种改进,通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列 . 

归并排序


选择排序
选择法的原理是先将第一个数与后面的每一个数依次比较,不断将将小的赋给第一个数,从而找出最小的,然后第二个数与后面的每一个数依次比较,从而找出第二小的,然后第三个数与后面的

比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序 . 
非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序 . 

Shuffle是一个过程,是在map端到reduce在调reduce数据之前都叫shuffle,主要是分区与排序,也就是内部的缓存分区以及分发(是reduce来拉数据的)和传输

1 优化的思路可以从配置文件和系统以及代码的设计思路来优化
2 配置文件的优化:调节适当的参数,在调参数时要进行测试
3 代码的优化:combiner的个数尽量与reduce的个数相同,数据的类型保持一致,可以减少拆包与封包的进度
4 系统的优化:可以设置linux系统打开最大的文件数预计网络的带宽MTU的配置
5 为 job 添加一个 Combiner,可以大大的减少shuffle阶段的map Task拷贝过来给远程的   reduce task的数据量,一般而言combiner与reduce相同 . 
6 在开发中尽量使用stringBuffer而不是string,string的模式是read-only的,如果对它进行修改,会产生临时的对象,二stringBuffer是可修改的,不会产生临时对象 . 
7 修改一下配置:
一下是修改 mapred-site.xml 文件
修改最大槽位数
槽位数是在各个 tasktracker 上的 mapred-site.xml 上设置的,默认都是 2
<property>
<name>mapred.tasktracker.map.tasks.maximum</name>
maptask 的最大数
<value>2</value>
</property>
<property>
<name>mapred.tasktracker.reduce.tasks.maximum</name>
rducetask 的最大数
<value>2</value>
</property>
调整心跳间隔
集群规模小于 300 时,心跳间隔为 300 毫秒
mapreduce.jobtracker.heartbeat.interval.min 心跳时间
mapred.heartbeats.in.second 集群每增加多少节点,时间增加下面的值
mapreduce.jobtracker.heartbeat.scaling.factor 集群每增加上面的个数,心跳增多少
启动带外心跳
mapreduce.tasktracker.outofband.heartbeat 默认是 false
配置多块磁盘
mapreduce.local.dir
配置 RPC hander 数目
mapred.job.tracker.handler.count 默认是 10,可以改成 50,根据机器的能力
配置 HTTP 线程数目
tasktracker.http.threads 默认是 40,可以改成 100 根据机器的能力
选择合适的压缩方式
以 snappy 为例:
<property>
<name>mapred.compress.map.output</name>
<value>true</value>
</property>
<property>
<name>mapred.map.output.compression.codec</name>
<value>org.apache.hadoop.io.compress.SnappyCodec</value>
</property>

hadoop2最主要的两个变化是:namenode可以集群的部署了,hadoop2中的mapreduce中的jobTracker中的资源调度器与生命周期管理是YARN(管理全部资源的ResourceManager以及管理每个应用的ApplicationMaster)
Hadoop1时代中MapReduce可以说是啥事都干,而Hadoop2中的MapReduce的话则是专门处理数据分析,而YARN则做为资源管理器而存在 . 
该架构将JobTracker中的资源管理及任务生命周期管理(包括定时触发及监控),拆分成两个独立的服务,用于管理全部资源的ResourceManager以及管理每个应用的ApplicationMaster,ResourceManager用于管理向应用程序分配计算资源,每个ApplicationMaster用于管理应用程序 调度以及协调 . 一个应用程序可以是经典的MapReduce架构中的一个单独的Job任务,也可以是这些任务的一个DAG(有向无环图)任务 . ResourceManager及每台机上的NodeManager服务,用于管理那台主机的用户进程,形成计算架构 . 每个应用程序的ApplicationMaster实际上是一个框架具体库,并负责从ResourceManager中协调资源及与NodeManager(s)协作执行并监控任务 . 
(1)ResourceManager包含两个主要的组件:定时调用器(Scheduler)以及应用管理器(ApplicationManager) . 
  ①定时调度器(Scheduler):
  定时调度器负责向应用程序分配资源,它不做监控以及应用程序的状态跟踪,并且它不保证会重启由于应用程序本身或硬件出错而执行失败的应用程序 . 
  ②应用管理器(ApplicationsManager ASM):
  应用程序管理器负责接收新任务,协调并提供在ApplicationMaster容器失败时的重启功能 . 
(2)ApplicationMaster(yarn核心组件):每个应用程序的ApplicationMaster负责从Scheduler申请资源,以及跟踪这些资源的使用情况以及任务进度的监控 . 
(3)NodeManager:NodeManager是ResourceManager在每台机器的上代理,负责容器的管理,并监控他们的资源使用情况(cpu,内存,磁盘及网络等),以及向 ResourceManager/Scheduler提供这些资源使用报告

实现两个表的join首先在map端需要把表标识一下,把其中的一个表打标签,到reduce端再进行笛卡尔积的运算,就是reduce进行的实际的链接操作 . 

当map端一个文件非常大另外一个文件非常小时就会产生资源的分配不均匀,既可以使用setPartitionerClass来设置分区,即形成了二次分区 . 

hadoop的mapreduce的排序发生在几个阶段?
发生在两个阶段即使map与reduce阶段

Mapreduce中的Combiner就是为了避免map任务和reduce任务之间的数据传输而设置的,Hadoop允许用户针对map task的输出指定一个合并函数 . 即为了减少传输到Reduce中的数据量 . 它主要是为了削减Mapper的输出从而减少网络带宽和Reducer之上的负载 . 
在数据量较少时不宜使用 . 

随着大数据的快速发展,多机器的协调工作,避免主要机器单点故障的问题,于是就引入管理机器的一个软件,他就是zookeeper来协助机器正常的运行 . 
Zookeeper有三个角色分别是leader与follower和obsrvr,其中leader是主节点,其他的是副节点,在安装配置上一定要注意配置奇数个的机器上,便于zookeeper快速切换选举其他的机器 . 
在其他的软件执行任务时在zookeeper注册时会在zookeeper下生成相对应的目录,以便zookeeper去管理机器 . 

主要是配置文件zoo.cfg 配置dataDir 的路径,dataLogDir 的路径以及myid的配置以及server的配置,心跳端口与选举端口

hive是怎样保存元数据的
保存元数据的方式有:内存数据库derby,本地mysql数据库,远程mysql数据库,但是本地的mysql数据用的比较多,因为本地读写速度都比较快

hive保存元数据的方式以及各有什么特点?
Hive有内存数据库derby数据库,特点是保存数据小,不稳定
使用derby数据库存储元数据 . 
这种方式是最简单的存储方式,只需要在hive-default.xml或hive-site.xml做如下配置便可 . 
使用derby存储方式时,运行hive会在当前目录生成一个derby文件和一个metastore_db目录 . 这种存储方式的弊端是在同一个目录下同时只能有一个hive客户端能使用数据库,否则会提示如下错误(这是一个很常见的错误) . 
2 mysql数据库,储存方式可以自己设定,持久化好,一般企业开发都用mysql做支撑
使用本机mysql服务器存储元数据 . 这种存储方式需要在本地运行一个mysql服务器,并作如下配置(需要将mysql的jar包拷贝到$HIVE_HOME/lib目录下) . 
使用远端mysql服务器存储元数据 . 这种存储方式需要在远端服务器运行一个mysql服务器,并且需要在Hive服务器启动meta服务 . 
默认监听的端口是9083

先来说下Hive中内部表与外部表的区别:
Hive 创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变 . 
在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据 . 这样外部表相对来说更加安全些,数据组织也更加灵活,方便共享源数据 . 

对于 hive,你写过哪些 UDF 函数,作用是什么
UDF:user  defined  function  的缩写,编写hive udf的两种方式extends UDF 重写evaluate第二种extends GenericUDF重写initialize getDisplayString evaluate方法

Hive 的 sort by 和 order by 的区别
order by 会对输入做全局排序,因此只有一个reducer(多个reducer无法保证全局有序)只有一个reducer,会导致当输入规模较大时,需要较长的计算时间 . 
sort by不是全局排序,其在数据进入reducer前完成排序.
因此,如果用sort by进行排序,并且设置mapred.reduce.tasks>1, 则sortby只保证每个reducer的输出有序,不保证全局有序 . 
sort by 不受 hive.mapred.mode 是否为strict ,nostrict 的影响
sort by 的数据只能保证在同一reduce中的数据可以按指定字段排序 . 
使用sort by 你可以指定执行的reduce 个数 (set mapred.reduce.tasks=<number>),对输出的数据再执行归并排序,即可以得到全部结果 . 
注意:可以用limit子句大大减少数据量 . 使用limit n后,传输到reduce端(单机)的数据记录数就减少到n (map个数) . 否则由于数据过大可能出不了结果 . 
distribute by
按照指定的字段对数据进行划分到不同的输出reduce  / 文件中 . 
此方法会根据name的长度划分到不同的reduce中,最终输出到不同的文件中 .   
length 是内建函数,也可以指定其他的函数或这使用自定义函数 . 
Cluster By
cluster by 除了具有 distribute by 的功能外还兼具 sort by 的功能 .  
但是排序只能是asc,不能指定排序规则为asc 或者desc . 

当对数据库进行复杂操作时(如对多个表进行Update,Insert,Query,Delete时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用
存储过程可以重复使用,可减少数据库开发人员的工作量
响应时间上来说有优势:如果你在前台处理的话 . 可能会涉及到多次数据库连接 . 但如果你用存储过程的话,就只有一次 . 存储过程可以给我们带来执行效率提高的好处
更好的安全机制,对于没有权限执行存储过程的用户,也可授权他们执行存储过程

可以提高运算的速度,大量的运算都可以在服务器端运行,比如报表等可以在服务器上用存储过程定时来生成(选择不忙的时候)


(1)hive 是基于 Hadoop 的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供完整的 sql 查询功能,可以将 sql 语句转换为 MapReduce 任务进行运行 . 其优点是学习成本低,可以通过类 SQL 语句快速实现简单的 MapReduce 统计,不必开发专门的 MapReduce 应用,十分适合数据仓库的统计分析 . 
(2)Hive 是建立在 Hadoop 上的数据仓库基础构架 . 它提供了一系列的工具,可以用来进行数据提取转化加载(ETL),这是一种可以存储 查询和分析存储在 Hadoop 中的大规模数据的机制 . Hive 定义了简单的类 SQL 查询语言,称为 HQL,它允许熟悉 SQL 的用户查询数据 . 同时,这个语言也允许熟悉 MapReduce 开发者的开发自定义的 mapper 和 reducer 来处理内建的 mapper 和 reducer 无法完成的复杂的分析工作 . 

Sqoop是一个在结构化数据与Hadoop Hive丶HDFS中之间进行批量数据迁移的工具,结构化数据可以是Mysql Oracle等RDBMS . Sqoop底层用MapReduce程序实现抽取 转换 加载,MapReduce天生的特性保证了并行化和高容错率,而且相比Kettle等传统ETL工具,任务跑在Hadoop集群上,减少了ETL服务器资源的使用情况 . 在特定场景下,抽取过程会有很大的性能提升 . 
对于某些NoSQL数据库它也提供了连接器 . Sqoop,类似于其他ETL工具,使用元数据模型来判断数据类型并在数据从数据源转移到Hadoop时确保类型安全的数据处理 . Sqoop专为大数据批量传输设计,能够分割数据集并创建Hadoop任务来处理每个区块 . 

hive partition 分区
分区表,动态分区
他和mr不是一个概念

insert into 和 override write 区别?
insert into:将某一张表中的数据写到另一张表中
override write:覆盖之前的内容 . 

Hbase 的 rowkey 怎么创建比较好?列族怎么创建比较好?
Rowkey是一个二进制码流,Rowkey的长度被很多开发者建议说设计在10~100个字节,不过建议是越短越好,不要超过16个字节 . 在查找时有索引会加快速度 . 
Rowkey散列原则   Rowkey唯一原则   针对事务数据Rowkey设计   针对统计数据的Rowkey设计   针对通用数据的Rowkey设计  支持多条件查询的RowKey设计 .  
总结设计列族:
1 一般不建议设计多个列族
2 数据块的缓存的设计
3 激进缓存设计
4 布隆过滤器的设计(可以提高随机读取的速度)
5 生产日期的设计
6 列族压缩
7 单元时间版本

Hbase 的实现原理
Hbase  的实现原理是rpc Protocol 

Hbase的过滤器有:RowFilter PrefixFilter KeyOnlyFilter RandomRowFilter InclusiveStopFilter FirstKeyOnlyFilter ColumnPrefixFilter ValueFilter ColumnCountGetFilter SingleColumnValueFilter SingleColumnValueExcludeFilter WhileMatchFilter FilterList 
比较常用的过滤器有:RowFilter 一看就知道是行的过滤器,来过滤行的信息 . PrefixFilter前缀的过滤器,就是把前缀作为参数来查找数据

hbase 主要的配置文件有hbase.env.sh 主要配置的是JDK的路径以及是否使用外部的ZK,hbase-site.xml 主要配置的是与HDFS的链接的路径以及zk的信息,修改regionservers的链接其他机器的配置 . 

Hive的权限需要在hive-site.xml文件中设置才会起作用,配置默认的是false,需要把hive.security.authorization.enabled设置为true,并对不同的用户设置不同的权限,例如select ,drop等的操作 . 

hbase 写数据的原理
1. 首先,client通过访问ZK来请求目标数据的地址 . 
2. ZK中保存了-ROOT-表的地址,所以ZK通过访问-ROOT-表来请求数据地址 . 
3. 同样,-ROOT-表中保存的是.META.的信息,通过访问.META.表来获取具体的RS . 
4. .META.表查询到具体RS信息后返回具体RS地址给client . 
5. client端获取到目标地址后,然后直接向该地址发送数据请求 . 

hbase宕机了如何处理?
HBase的RegionServer宕机超过一定时间后,HMaster会将其所管理的region重新分布到其他活动的RegionServer上,由于数据和日志都持久在HDFS中,
该操作不会导致数据丢失 . 所以数据的一致性和安全性是有保障的 . 
但是重新分配的region需要根据日志恢复原RegionServer中的内存MemoryStore表,这会导致宕机的region在这段时间内无法对外提供服务 . 
而一旦重分布,宕机的节点重新启动后就相当于一个新的RegionServer加入集群,为了平衡,需要再次将某些region分布到该server .  
因此,Region Server的内存表memstore如何在节点间做到更高的可用,是HBase的一个较大的挑战 . 

hbase客户端在客户端怎样优化?
Hbase使用JAVA来运算的,索引Java的优化也适用于hbase,在使用过滤器事记得开启bloomfilter可以是性能提高3-4倍,设置HBASE_HEAPSIZE设置大一些


Hbase是基于Hadoop的项目,所以一般情况下我们使用的直接就是HDFS文件系统
只需要知道虽然Hbase中有多个RegionServer的概念,并不意味着数据是持久化在RegionServer上的,
事实上,RegionServer是 调度者,管理Regions,但是数据是持久化在HDFS上的 . 
Hbase是一个分布式的数据库,
使用Zookeeper来管理集群 . 
在架构层面上分为Master(Zookeeper选举)和多个RegionServer,
RegionServer对应于集群中的一个节点,而一个RegionServer负责管理多个Region . 
一个Region代 表一张表的一部分数据,所以在Hbase中的一张表可能会需要很多个Region来存储其数据,
但是每个Region中的数据并不是杂乱无章 的,Hbase在管理Region的时候会给每个Region定义一个Rowkey的范围,落在特定范围内的数据将交给特定的Region,从而将负载分 摊到多个节点上,充分利用分布式的优点 . 
另外,Hbase会自动的调节Region处在的位置,如果一个RegionServer变得Hot(大量的请求 落在这个Server管理的Region上),Hbase就会把Region移动到相对空闲的节点,依次保证集群环境被充分利用

Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务 . 它被当作一个远程过程调用(RPC)框架来使用,是由Facebook为"大规模跨语言服务开发"而开发的 . 它通过一个代码生成引擎联合了一个软件栈,来创建不同程度的 无缝的跨平台高效服务,可以使用C# C++(基于POSIX兼容系统) Cappuccino Cocoa Delphi Erlang Go Haskell Java Node.js OCaml Perl PHP Python Ruby和Smalltalk . 
REST是设计风格而不是标准
REST 指的是一组架构约束条件和原则 . 满足这些约束条件和原则的应用程序或设计就是 RESTful . 
客户端和服务器之间的交互在请求之间是无状态的 . 从客户端到服务器的每个请求都必须包含理解请求所必需的信息 . 如果服务器在请求之间的任何时间点重启,客户端不会得到通知 . 此外,无状态请求可以由任何可用服务器回答,这十分适合云计算之类的环境 . 客户端可以缓存数据以改进性能 . 
另一个重要的 REST 原则是分层系统,这表示组件无法了解它与之交互的中间层以外的组件 . 
无状态服务器是指一种把每个请求作为与之前任何请求都无关的独立的事务的服务器 . 
无状态通信要求在网络通信过程中,任意一个Web请求必须与其他请求隔离,当请求端提出请求时,
请求本身包含了响应端为响应这一请求所需的全部信息 . 
HTTP 服务器就是一个例子 . 以 URL 形式提交的客户端请求可能包含 cookies 等带状态的数据,这些数据完全指定了所需的文档,而不需要其他之前请求的上下文或内存 . 
    举例子:
    状态记录在服务端设计:
    a, 用户user登陆后,user的上下文信息例如记录该user已登陆的标识保存在服务器端session中,当用户发生下一次的请求,服务端会根据userId查找该session是否标记了该用户已登录的状态 
    b, 用户浏览书签页,当前用户浏览的页面是第3页,这个第3页的信息保存在服务器端session中,当用户请求下一页nextPage,服务端从session拿出当前阅读状态为第3页,基于此状态计算出下一页是第4页
    RESTful的设计:
    a, 用户user登陆后,服务器生成验证信息token,该token标记该用户已经登陆的状态,服务端不保存该token信息,而是token返回给客户端, 
    当用户发生下一次的请求,客户端把该token重新发送给服务端,于是服务端就根据该token知道用户已经登陆的状态(具体实现是:第一次登陆,token信息在数据库端缓存下来,第二次请求时候从数据库缓存查询该用户token . 这样用户状态的信息就不需要保存在服务器端,保存了在数据库端,数据库端一般采用redis类型的缓存数据库) 
    b, 用户浏览书签页,当前用户浏览的页面是第3页,服务器返回当前页第3页这个状态给客户端,服务端不保存当前阅读页数的状态,当用户发生下一页的请求,客户端把当前页第3页和下一页操作给服务端,服务端基于客户端的状态信息计算出下一页是第4页
    由此可以看出, 
    REST 风格应用可以实现交互,但它却天然地具有服务器无状态的特征 . 在状态迁移的过程中,服务器不需要记录任何 Session,所有的状态都通过 URI 的形式记录在了客户端 . 更准确地说,这里的无状态服务器,是指服务器不保存会话状态(Session);而资源本身则是天然的状态,通常是需要被保存的;这里所指无状态服务器均指无会话状态服务器 . 
补充一点:
REST表述性状态转移,可以简单理解为把服务端的状态迁移到客户端保存或者数据库端保存,从而应用服务器就可以设计成无状态 . 严格来说应该是"准确理解REST在应用服务端的无状态设计" . 


REST中的资源所指的不是数据,而是数据和表现形式的组合,比如"最新访问的10位会员"和"最活跃的10位会员"在数据上可能有重叠或者完全相同,而由于他们的表现形式不同,所以被归为不同的资源,这也就是为什么REST的全名是Representational State Transfer的原因 . 
资源标识符就是URI(Uniform Resource Identifier),不管是图片,Word还是视频文件,甚至只是一种虚拟的服务,也不管你是XML(标准通用标记语言下的一个子集)格式 txt文件格式还是其它文件格式,全部通过 URI对资源进行唯一的标识 . 
Rest API,无论它的名字多么高大上,它本质还是一个HTTP请求,POST也好,GET也罢,都是不同的数据提交方式 . 所以,能够决定一个Rest API的也就:URI 参数 请求方式 请求头等

hbase是怎样预分区的?
如何去进行预分区,可以采用下面三步:
  1.取样,先随机生成一定数量的rowkey,将取样数据按升序排序放到一个集合里
  2.根据预分区的region个数,对整个集合平均分割,即是相关的splitKeys.
  3.HBaseAdmin.createTable(HTableDescriptor tableDescriptor,byte[][] splitkeys)可以指定预分区的splitKey,即是指定region间的rowkey临界值

怎样将 mysql 的数据导入到 hbase 中?
不能使用 sqoop,速度太慢了,提示如下:
A 一种可以加快批量写入速度的方法是通过预先创建一些空的 regions,这样当
数据写入 HBase 时,会按照 region 分区情况,在集群内做数据的负载均衡 . 
B hbase 里面有这样一个 hfileoutputformat 类,他的实现可以将数据转换成 hfile
格式,通过 new 一个这个类,进行相关配置,这样会在 hdfs 下面产生一个文件,这个
时候利用 hbase 提供的 jruby 的 loadtable.rb 脚本就可以进行批量导入

谈谈 HBase 集群安装注意事项?
     需要注意的地方是 ZooKeeper 的配置 . 这与 hbase-env.sh 文件相关,文件中
HBASE_MANAGES_ZK 环境变量用来设置是使用 hbase 默认自带的 Zookeeper 还
是使用独立的 ZooKeeper . HBASE_MANAGES_ZK=false 时使用独立的,为 true 时
使用默认自带的 . 
    某个节点的 HRegionServer 启动失败,这是由于这 3 个节点的系统时间不一致相
差超过集群的检查时间 30s . 

简述 HBase 的瓶颈
Hbase主要的瓶颈就是传输问题,在操作时大部分的操作都是需要对磁盘操作的

cpu架构最重要,其次工艺 核心数量 超线程 频率 缓存 指令集等(超频另算) . 会影响或者说提升cpu性能的方面,高频内存条(含超频) cpu或者主板是否支持多通道内存,比如双通道 三通道 四通道等 . 

Redis, 传统数据库,hbase,hive  每个之间的区别
Redis 是基于内存的数据库,注重使用内存的计算,hbase是列式数据库,无法创建主键,是基于HDFS的,每一行可以保存很多的列,hive是数据的仓库,是为了减轻mapreduce复写而设计的

HBase的查询实现只提供两种方式:
1 按指定RowKey获取唯一一条记录,get方法(org.apache.hadoop.hbase.client.Get)
2 按指定的条件获取一批记录,scan方法(org.apache.hadoop.hbase.client.Scan) 实现条件查询功能使用的就是scan方式

可以通过setCaching与setBatch方法提高速度(以空间换时间),
setCaching设置的值为每次rpc的请求记录数,默认是1;cache大可以优化性能,但是太大了会花费很长的时间进行一次传输 . 
setBatch设置每次取的column size;有些row特别大,所以需要分开传给client,就是一次传一个row的几个column . 

hbase 中cell的结构
cell中的数据是没有类型的,全部是字节码形式存贮 . 

Hbase的region会自动split,当region太时,regio太大时分布会不均衡,同时对于大批量的代入数据建议如下:
1 还是必须让业务方对rowkey进行预分片,对业务数据rowkey进行md5或者其他的hash策略,让数据尽量随机分布而不是顺序写入 . 
2 随时观察region的大小,是否出现大region的情况 . 

nginx采集日志时无法获取session的信息,然而logger4j则可以获取session的信息,logger4j比较稳定,不会宕机 . 缺点:不够灵活,logger4j和项目结合过于紧密,flume比较灵活,便于插拔,不会影响项目的性能 . 

Flume 采集日志是通过流的方式直接将日志收集到存储层,而 kafka 将日志缓存在 kafka
集群,待后期可以采集到存储层 . Flume 采集中间停了,可以采用文件的方式记录之前的日志,而 kafka 是采用offset(偏移量) 的方式记录之前的日志 . 


Mr 是文件方式的分布式计算框架,是将中间结果和最终结果记录在文件中,map 和 reduce的数据分发也是在文件中 . 
spark 是内存迭代式的计算框架,计算的中间结果可以缓存内存,也可以缓存硬盘,但是不是每一步计算都需要缓存的 . 
Spark-rdd 是一个数据的分区记录集合,是利用内存来计算的

简单描述spark的wordCount的执行过程
scala>sc.textFile("/usr/local/words.txt").flatMap(_.split("")).map((_,1)).reduceByKey(_+_).collect

res6:Array[(String,Int)]=Array((dageda,1),(xiaoli,1),(hellow,4),(xisdsd,1),(xiaozhang,1))

sqoop在导入到MySql数据库是怎样保证数据不重复
在导入时在语句的后面加上一下命令作为节点:
--incremental append \
--check-column id \
--last-value 1208

在执行任务时发现副本的个数不对,经过一番的查找发现是超时的原因,修改了配置文件hdfs-site.xml:中修改了超时时间 . 


采集nginx产生的日志,日志的格式为user  ip   time  url   htmlId  每天产生的文件的数据量上亿条,请设计方案把数据保存到HDFS上,并提供一下实时查询的功能(响应时间小于3s)
A 某个用户某天访问某个URL的次数
B 某个URL某天被访问的总次数
实时思路是:使用Logstash + Kafka + Spark-streaming + Redis + 报表展示平台
离线的思路是:Logstash + Kafka + Elasticsearch +  Spark-streaming + 关系型数据库
A B 数据在进入到Spark-streaming 中进行过滤,把符合要求的数据保存到Redis(nosql)或rdb中

client 向 NameNode 发起文件写入的请求 . 
NameNode 根据文件大小和文件块配置情况,返回给 client 它所管理部分 DataNode 的信息 . 
client 将文件划分为多个 Block,根据 DataNode 的地址信息,按顺序写入到每一个 DataNode 块中 . 

集群的最主要瓶颈磁盘 IO  

SecondaryNameNode帮助 NameNode 合并编辑日志,减少 NameNode 启动时间

HBase 来源于BigTable博文
HBase是开源的面向列的分布式的NoSQL 数据库
HBase 依靠HDFS存储底层数据 
HBase 只是nosql数据库依赖MapReduce提供强大的计算能力
HBase 依赖Zookeeper提供消息通信机制

Hive是建立在Hadoop之上为了减少MapReduce jobs编写工作的批处理系统,HBase是为了支持弥补Hadoop对实时操作的缺陷的项目  . 
想象你在操作RMDB数据库,如果是全表扫描,就用Hive+Hadoop,如果是索引访问,就用HBase+Hadoop  . 
Hive query就是MapReduce jobs可以从5分钟到数小时不止,HBase是非常高效的
Hbase主要解决实时数据查询问题,Hive主要解决数据处理和计算问题,一般是配合使用 . 
区别:
Hbase:Hadoop database 的简称,也就是基于Hadoop数据库,是一种NoSQL数据库,主要适用于海量明细数据(十亿 百亿)的随机实时查询,如日志明细 交易清单 轨迹行为等 . 
Hive:Hive是Hadoop数据仓库,主要是让开发人员能够通过SQL来计算和处理HDFS上的结构化数据,适用于离线的批量数据计算 . 
协作:
通过ETL工具将数据源抽取到HDFS存储;
通过Hive清洗 处理和计算原始数据;
HIve ETL后的结果,如果是面向海量数据随机查询场景的可存入Hbase
数据应用从HBase查询数据;

On-Line Transaction Processing联机事务处理过程(OLTP)
On-Line Analysis Processing联机分析处理过程(OLAP)

 MapReduce 与 HBase 的关系
两者不是强关联关系,没有 MapReduce,HBase 可以正常运行
MapReduce 可以直接访问 HBase

LSM 含义是日志结构合并树
顺序存储
需要将数据 Flush 到磁盘
更能保证写的性能
LSM 的读操作和写操作是独立的 
LSM 结构的数据首先存储在闪存中
HFile 数据格式中的 Data 字段用于存储实际的 KeyValue 数据(是 byte[]数组,有固定的结构, Value 部分是 二进制数据)
HFile 数据格式中的 MetaIndex 字段用于Meta 块的起始点
HFile 数据格式中的 Magic 字段用于存储随机数,防止数据损坏

HBase 中的批量加载底层使用MapReduce实现
HBase 性能优化包含:读优化,写优化,配置优化,JVM 优化
Rowkey 设计的原则:尽量保证越短越好,可以使用汉字,可以使用字符串,本身是有序的
HBase 构建二级索引( 核心是倒排表, 二级索引概念是对应 Rowkey 这个"一级"索引)的实现方式有:MapReduce,Coprocessor
Bloom Filter 是一个很长的二进制向量和一系列随机映射函数,有一定的误算率
HBase 官方版本可以安装在CentOS,Ubuntu,RedHat上
HBase 伪分布式需要1个节点,分布式模式最好需要3个节点
安装 HBase 前必须安装:操作系统,JDK
Zookeeper 类似的框架 Chubby
NameNode 不需要从磁盘读取 metadata,所有数据都在内存中,硬盘上的只是序列化的结果,只有每次namenode 启动的时候才会读取 . 
1)文件写入
client 向 NameNode 发起文件写入的请求 . 
NameNode 根据文件大小和文件块配置情况,返回给 client 它所管理部分 DataNode 的信息 . 
client 将文件划分为多个 Block,根据 DataNode 的地址信息,按顺序写入到每一个 DataNode 块中 . 
2)文件读取
client 向 NameNode 发起文件读取的请求 . 
NameNode 返回文件存储的 DataNode 的信息 . 
client 读取文件信息 . 

DataNode 是文件存储的基本单元,它将 Block 存储在本地文件系统中,保存了 Block Meta-data,同时周期性地将所有存在的 Block 信息发送给 NameNode . 

DataNode 通过心跳机制(短连接) NameNode 保持通信 . 
(1).长连接
client 方与 Server 方先建立通讯连接,连接建立后不断开,然后再进行报文发送和接收 . 这种方式下由于通讯连接一直存在,此种方式常用于点对点通讯 . 
(2).短连接
client 方与 Server 每进行一次报文收发交易时才进行通讯连接,交易完毕后立即断开连接 . 此种方式常用于一点对多点通讯,比如多个 client 连接一个 Server.

hadoop dfsadmin -report
用这个命令可以快速定位出哪些节点 down 掉了,HDFS 的容量以及使用了多少,以及每个节点的硬盘使用情况 . 
当然 NameNode 有个 http 页面也可以查询,但是这个命令的输出更适合我们的脚本监控 dfs 的使用状况

Hadoop 默认调度器策略为 FIFO(按照到达时间顺序,先来先服务)
Hadoop中常见的调度器有三种,分别为:
FIFO调度器 公平调度器Fair Scheduler 容量调度器Capacity Scheduler(计算能力调度器)
它的作用是将系统中空闲的资源按一定策略分配给作业 . 在Hadoop中,调度器是一个可插拔的模块,用户可以根据自己的实际应用要求设计调度器 . 

RAID:磁盘阵列(Redundant Arrays of Independent Disks,RAID),有"独立磁盘构成的具有冗余能力的阵列"
因为 hadoop 本身就具有冗余能力,所以如果不是很严格不需要都配备 RAID . 

hadoop 为各个守护进程(namenode,secondarynamenode,jobtracker,datanode,tasktracker)统一分配的内存在 hadoop-env.sh 中设置,参数为 HADOOP_HEAPSIZE,默认为 1000M . 

DataNode 首次加入 cluster 的时候,如果 log 中报告不兼容文件版本,说明 DataNode 所装的 Hadoop 版本和其它节点不一致,应该检查 DataNode 的 Hadoop 版本

Block Size 是可以修改的
Hadoop 的基础配置文件是 hadoop-default.xml,默认建立一个 Job 的时候会建立 Job 的 Config,Config
首先读入hadoop-default.xml的配置,然后再读入hadoop-site.xml的配置(这个文件初始的时候配置为空),
hadoop-site.xml 中主要配置需要覆盖的 hadoop-default.xml 的系统级配置 . 具体配置可以参考下:
<property>
  <name>dfs.block.size</name>//block 的大小,单位字节,后面会提到用处,必须是 512 的倍数,因
为采用 crc 作文件完整性校验,默认配置 512 是 checksum 的最小单元 . 
  <value>5120000</value>
  <description>The default block size for new files.</description>
</property>

lucene 是支持随机读写的,而 hdfs 只支持随机读 . 但是 HBase 可以来补救 . 
HBase 提供随机读写,来解决 Hadoop 不能处理的问题 . HBase 自底层设计开始即聚焦于各种可伸缩性问题:表可以很―高‖,有数十亿个数据行;也可以很―宽‖,有数百万个列;水平分区并在上千个普通商用机节点上自动复制 . 表的模式是物理存储的直接反映,使系统有可能提高高效的数据结构的序列化 存储和检索 . 

MR 一个task对应一个线程
分析:首先我们知道什么是 map 槽,map 槽->map slot,map slot 只是一个逻辑值 ( org.apache.hadoop.mapred.TaskTracker.TaskLauncher.numFreeSlots ),而不是对应着一个线程或者进程

Mapreduce 的 input split 就是一个block数组
InputSplit也是一个interface,具体返回什么样的implement,这是由具体的InputFormat来决定的 . InputSplit也只有两个接口函数:
long getLength() throws IOException;
String[] getLocations() throws IOException;
这个interface仅仅描述了Split有多长,以及存放这个Split的Location信息(也就是这个Split在HDFS上存放的机器 . 它可能有多个replication,存在于多台机器上) . 除此之外,就再没有任何直接描述Split的信息了 . 比如:Split对应于哪个文件?在文件中的起始和结束位置是什么?等等重要的特征都没有描述到 . 
为什么会这样呢?因为关于Split的那些描述信息,对于MapReduce框架来说是不需要关心的 . 框架只关心Split的长度(主要用于一些统计信息)和Split的Location(主要用于Split的调度,后面会细说) . 
而Split中真正重要的描述信息还是只有InputFormat会关心 . 在需要读取一个Split的时候,其对应的InputSplit会被传递到InputFormat的第二个接口函数getRecordReader,然后被用于初始化一个RecordReader,以解析输入数据 . 也就是说,描述Split的重要信息都被隐藏了,只有具体的InputFormat自己知道 . 它只需要保证getSplits返回的InputSplit和getRecordReader所关心的InputSplit是同样的implement就行了 . 这就给InputFormat的实现提供了巨大的灵活性 . 

hdfs有namenode secondraynamenode datanode组成 . 
namenode负责管理datanode和记录元数据
secondraynamenode负责合并日志
datanode负责存储数据

如何安装配置一个apache开源本hadoop
1.创建hadoop用户
2.修改IP
3.安装JDK,并配置环境变量
4.修改host文件IP映射
5.安装SSH,配置无秘钥通信
6.上传解压hadoop安装包
7.配置conf文件夹下的hadoop-env.sh core-site.xml mapred-site.xml hdfs-site.xml(Hadoop的核心配置)
8.配置hadoop的环境变量
9.Hadoop namenode -format
10.start-all

hadoop job -list 记录job-id hadoop job -kill job-id
hadoop fs -rmr /tmp/aaa
hadoop -daemon.sh start datanode
更新namenode相关属性:bin/hadoop dfsadmin –-refreshnodes

1.FIFO schedular:默认,先进先出的原则
2.Capacity schedular:计算能力调度器,选择占用最小,优先级高的先执行,以此类推 . 
3.Fair schedular:公平调度,所有的job具有相同的资源 . 

hadoop框架中怎么来优化
解答:
(1)从应用程序角度进行优化 . 由于mapreduce是迭代(反复执行子程序)逐行解析数据文件的,怎样在迭代的情况下,编写高效率的应用程序,是一种优化思路 . 
(2)对Hadoop参数进行调优 . 当前hadoop系统有190多个配置参数,怎样调整这些参数,使hadoop作业运行尽可能的快,也是一种优化思路 . 
(3)从系统实现角度进行优化 . 这种优化难度是最大的,它是从hadoop实现机制角度,发现当前Hadoop设计和实现上的缺点,然后进行源码级地修改 . 该方法虽难度大,但往往效果明显 . 
(4)linux内核参数调整
1. 使用自定义Writable
自带的Text很好用,但是字符串转换开销较大,故根据实际需要自定义Writable,注意作为Key时要实现WritableComparable接口
避免output.collect(new Text( ),new Text())
提倡key.set( ) value.set( ) output.collect(key,value)
前者会产生大量的Text对象,使用完后Java垃圾回收器会花费大量的时间去收集这些对象
2. 使用StringBuilder
不要使用Formatter StringBuffer(线程安全)
StringBuffer尽量少使用多个append方法,适当使用+
3. 使用DistributedCache加载文件
比如配置文件,词典,共享文件,避免使用static变量 
4. 充分使用Combiner Parttitioner Comparator . 
Combiner :对map任务进行本地聚合
Parttitioner :合适的Parttitioner避免reduce端负载不均
Comparator :二次排序
比如求每天的最大气温,map结果为日期:气温,若气温是降序的,直接取列表首元素即可
5. 使用自定义InputFormat和OutputFormat
6. MR应避免
静态变量:不能用于计数,应使用Counter
大对象:Map List
递归:避免递归深度过大
超长正则表达式:消耗性能,要在map或reduce函数外编译正则表达式
不要创建本地文件:变向的把HDFS里面的数据转移到TaskTracker,占用网络带宽
不要大量创建目录和文件
不要大量使用System.out.println,而使用Logger
不要自定义过多的Counter,最好不要超过100个
不要配置过大内存,mapred.child.java.opts -Xmx2000m是用来设置mapreduce任务使用的最大heap量
7.关于map的数目
map数目过大[创建和初始化map的开销],一般是由大量小文件造成的,或者dfs.block.size设置的太小,对于小文件可以archive文件或者Hadoop fs -merge合并成一个大文件.
map数目过少,造成单个map任务执行时间过长,频繁推测执行,且容易内存溢出,并行性优势不能体现出来 . dfs.block.size一般为256M-512M
压缩的Text 文件是不能被分割的,所以尽量使用SequenceFile,可以切分
8.关于reduce的数目
reduce数目过大,产生大量的小文件,消耗大量不必要的资源,reduce数目过低呢,造成数据倾斜问题,且通常不能通过修改参数改变 . 
可选方案:mapred.reduce.tasks设为-1变成AutoReduce . 
Key的分布,也在某种程度上决定了Reduce数目,所以要根据Key的特点设计相对应的Parttitioner 避免数据倾斜
9.Map-side相关参数优化
io.sort.mb(100MB):通常k个map tasks会对应一个buffer,buffer主要用来缓存map部分计算结果,并做一些预排序提高map性能,若map输出结果较大,可以调高这个参数,减少map任务进行spill任务个数,降低 I/O的操作次数 . 若map任务的瓶颈在I/O的话,那么将会大大提高map性能 . 如何判断map任务的瓶颈?
io.sort.spill.percent(0.8):spill操作就是当内存buffer超过一定阈值(这里通常是百分比)的时候,会将buffer中得数据写到Disk中 . 而不是等buffer满后在spill,否则会造成map的计算任务等待buffer的释放 . 一般来说,调整 io.sort.mb而不是这个参数 . 
io.sort.factor(10):map任务会产生很多的spill文件,而map任务在正常退出之前会将这些spill文件合并成一个文件,即merger过程,缺省是一次合并10个参数,调大io.sort.factor,减少merge的次数,减少Disk I/O操作,提高map性能 . 
min.num.spill.for.combine:通常为了减少map和reduce数据传输量,我们会制定一个combiner,将map结果进行本地聚集 . 这里combiner可能在merger之前,也可能在其之后 . 那么什么时候在其之前呢?当spill个数至少为min.num.spill.for.combine指定的数目时同时程序指定了Combiner,Combiner会在其之前运行,减少写入到Disk的数据量,减少I/O次数 . 
10.压缩(时间换空间)
MR中的数据无论是中间数据还是输入输出结果都是巨大的,若不使用压缩不仅浪费磁盘空间且会消耗大量网络带宽 . 同样在spill,merge(reduce也对有一个merge)亦可以使用压缩 . 若想在cpu时间和压缩比之间寻找一个平衡,LzoCodec比较适合 . 通常MR任务的瓶颈不在CPU而在于I/O,所以大部分的MR任务都适合使用压缩 . 
11. reduce-side相关参数优化
reduce:copy->sort->reduce,也称shuffle
mapred.reduce.parellel.copies(5):任一个map任务可能包含一个或者多个reduce所需要数据,故一个map任务完成后,相应的reduce就会立即启动线程下载自己所需要的数据 . 调大这个参数比较适合map任务比较多且完成时间比较短的Job . 
mapred.reduce.copy.backoff:reduce端从map端下载数据也有可能由于网络故障,map端机器故障而失败 . 那么reduce下载线程肯定不会无限等待,当等待时间超过mapred.reduce.copy.backoff时,便放弃,尝试从其他地方下载 . 需注意:在网络情况比较差的环境,我们需要调大这个参数,避免reduce下载线程被误判为失败 . 
io.sort.factor:recude将map结果下载到本地时,亦需要merge,如果reduce的瓶颈在于I/O,可尝试调高增加merge的并发吞吐,提高reduce性能 
mapred.job.shuffle.input.buffer.percent(0.7):reduce从map下载的数据不会立刻就写到Disk中,而是先缓存在内存中,mapred.job.shuffle.input.buffer.percent指定内存的多少比例用于缓存数据,内存大小可通过mapred.child.java.opts来设置 . 和map类似,buffer不是等到写满才往磁盘中写,也是到达阈值就写,阈值由mapred.job,shuffle.merge.percent来指定 . 若Reduce下载速度很快,容易内存溢出,适当增大这个参数对增加reduce性能有些帮助 . 
mapred.job.reduce.input.buffer.percent (0):当Reduce下载map数据完成之后,就会开始真正的reduce的计算,reduce的计算必然也是要消耗内存的,那么在读物reduce所需要的数据时,同样需要内存作为buffer,这个参数是决定多少的内存百分比作为buffer . 默认为0,也就是说reduce全部从磁盘读数据 . 若redcue计算任务消耗内存很小,那么可以设置这个参数大于0,使一部分内存用来缓存数据 . 

大数据的本质:从数据中挖掘价值
云计算的本质:共享服务

序列化 Writable接口 comparable WritableComparable代码讲解
序列化
将对象(文件)的状态信息转换成可存储的字节序列的过程 . 反过来就是反序列化 . hadoop中的所有key/value都必须实现以下接口 . 
Writable 接口
public interface Writable{
      //将对象状态信息写入二进制的DataOutput流(序列化)
      void write(DataOutput out) throws IOException;
      //从二进制的DataInput流中读取对象状态(反序列化)
      void readFields(DataInput in) throws IOException;
}
对特定的Writable可以进行赋值和取值操作(以IntWritable为例)
IntWritable value = new IntWritable();
value.set(5567);//用set()方法赋值
/

IntWritable value = new IntWritable(5567);//或者用构造方法赋值

/
int result = value.get();//通过get()方法取值
Comparable接口
实现了Comparable的对象可以和自身相同类型的对象比较大小
public interface Comparable{
   //将T对象和对象o进行比较,约定:返回负数为小于,零为大于,整数为大于
    public int compareTo(T O);
}
WritableComparable
所有的key必须实现Comparable接口,value只用实现Writable接口 . 在MapReduce过程中需要对Key/Value对进行反复的排序 . 默认情况下依据Key进行排序的,要实现comparaTo()方法 . 所以通过Key既要实现Writable接口又要实现Comparable接口,把两个接口合为一个公共接口WritableComparable . 
自定义一个WritableCpmparable类型的Example
public class TextPair implements WritableComparable {
    private Text first;//Text 类型的实例对象
    private Text second;
    public TextPair() {
        set(newText(),newText());
    }
    public TextPair(String first, String second) {
        set(new Text(first),new Text(second));
    }
    public TextPair(Text first, Text second) {
        set(first, second);
    }
    public void set(Text first, Text second) {
        this.first = first;
        this.second = second;
    }
    public Text getFirst() {
        return first;
    }
    public Text getSecond() {
        return second;
    }
    //序列化
    @Override
    public void write(DataOutput out)throwsIOException {
        first.write(out);
        second.write(out);
    }
    /
     在排序之前,需要先从磁盘中读取数据进行反序列化成对象,然后在内存中对反序列化的对象进行比较 . 
     /
    //反序列化
    @Override
    public void readFields(DataInput in)throwsIOException {
        first.readFields(in);
        second.readFields(in);
    }
    //返回哈希值
    @Override
    public int hashCode() {
        return first.hashCode() 163+ second.hashCode();
    }
    @Override
    public boolean equals(Object o) {
        //判定o是否与TextPair同等类型
        if(o instanceof TextPair) {
            TextPair tp = (TextPair) o;
            return first.equals(tp.first) && second.equals(tp.second);
        }
            return false;
    }
    @Override
    publicString toString() {
        return first +"\t"+ second;
    }
    //排序
    @Override
    public int compareTo(TextPair tp) {
        int cmp = first.compareTo(tp.first); 
        if(cmp !=0) {
            return cmp;
        }
        return second.compareTo(tp.second);
    }
}

从应用程序角度进行优化
解答:
(1) 避免不必要的reduce任务
如果mapreduce程序中reduce是不必要的,那么我们可以在map中处理数据, Reducer设置为0 . 这样避免了多余的reduce任务 . 
(2) 为job添加一个Combiner
为job添加一个combiner可以大大减少shuffle阶段从map task拷贝给远程reduce task的数据量 . 一般而言,combiner与reducer相同 . 
(3) 根据处理数据特征使用最适合和简洁的Writable类型
Text对象使用起来很方便,但它在由数值转换到文本或是由UTF8字符串转换到文本时都是低效的,且会消耗大量的CPU时间 . 当处理那些非文本的数据时,可以使用二进制的Writable类型,如IntWritable, FloatWritable等 . 二进制writable好处:避免文件转换的消耗;使map task中间结果占用更少的空间 . 
(4) 重用Writable类型
很多MapReduce用户常犯的一个错误是,在一个map/reduce方法中为每个输出都创建Writable对象 . 例如,你的Wordcout mapper方法可能这样写: 
public void map(...) {
  …
  for (String word :words) {
    output.collect(new Text(word), new IntWritable(1));
  }
}
这样会导致程序分配出成千上万个短周期的对象 . Java垃圾收集器就要为此做很多的工作 . 更有效的写法是:
class MyMapper … {
  Text wordText = new Text();
  IntWritable one = new IntWritable(1);
  public void map(...) {
    for (String word:words) {
      wordText.set(word);
      output.collect(wordText, one);
    }
  }
}
(5) 使用StringBuffer而不是String
当需要对字符串进行操作时,使用StringBuffer而不是String,String是read-only的,如果对它进行修改,会产生临时对象,而StringBuffer是可修改的,不会产生临时对象 . 

ACK 是否三个备份都写成功之后再确认成功操作?
不是的,只要成功写入的节点数量达到dfs.replication.min(默认为1),那么就任务是写成功的
正常情况下:
① 在进行写操作的时候(以默认备份3份为例),DataNode_1接受数据后,首先将数据写入buffer,再将数据写入DatNode_2,写入成功后将 buffer 中的数据写入本地磁盘,并等待ACK信息
② 重复上一个步骤,DataNode_2写入本地磁盘后,等待ACK信息
③ 如果ACK都成功返回后,发送给client,本次写入成功
如果一个节点或多个节点写入失败:
只要成功写入的节点数量达到dfs.replication.min(默认为1),那么就任务是写成功的 . 然后NameNode会通过异步的方式将block复制到其他节点,使数据副本达到dfs.replication参数配置的个数

combiner出现在map阶段的map方法后

3个datanode中有一个datanode出现错误会怎样?
这个datanode的数据会在其他的datanode上重新做备份 . 

hadoop 的 namenode 宕机,怎么解决
解答:
先分析宕机后的损失,宕机后直接导致client无法访问,内存中的元数据丢失,但是硬盘中的元数据应该还存在,如果只是节点挂了,重启即可,如果是机器挂了,重启机器后看节点是否能重启,不能重启就要找到原因修复了 . 但是最终的解决方案应该是在设计集群的初期就考虑到这个问题,做namenode的HA . 

一个datanode 宕机,怎么一个流程恢复
Datanode宕机了后,如果是短暂的宕机,可以实现写好脚本监控,将它启动起来 . 如果是长时间宕机了,那么datanode上的数据应该已经被备份到其他机器了,那这台datanode就是一台新的datanode了,删除他的所有数据文件和状态文件,重新启动 . 

请简述 hadoop 怎么样实现二级排序?
解答:
在Reduce阶段,先对Key排序,再对Value排序
最常用的方法是将Value放到Key中,实现一个组合Key,然后自定义Key排序规则(为Key实现一个WritableComparable) . 

如何使用MapReduce实现两个表join,可以考虑一下几种情况:(1)一个表大,一个表小(可放到内存中);(2)两个表都是大表?
解答:
第一种情况比较简单,只需将小表放到DistributedCache中即可;
第二种情况常用的方法有:map-side join(要求输入数据有序,通常用户Hbase中的数据表连接),reduce-side join,semi join(半连接)

reduce side join
在map阶段,map函数同时读取两个文件File1和File2,为了区分两种来源的key/value数据对,对每条数据打一个标签(tag),比如:tag=0表示来自文件File1,tag=2表示来自文件File2 . 即:map阶段的主要任务是对不同文件中的数据打标签 . 
在reduce阶段,reduce函数获取key相同的来自File1和File2文件的value list, 然后对于同一个key,对File1和File2中的数据进行join(笛卡尔乘积) . 即:reduce阶段进行实际的连接操作 . 
假设集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)} . 

map side join
Map side join是针对以下场景进行的优化:两个待连接表中,有一个表非常大,而另一个表非常小,以至于小表可以直接存放到内存中 . 这样,我们可以将小表复制多份,让每个map task内存中存在一份(比如存放到hash table中),然后只扫描大表:对于大表中的每一条记录key/value,在hash table中查找是否有相同的key的记录,如果有,则连接后输出即可 . 
为了支持文件的复制,Hadoop提供了一个类DistributedCache,使用该类的方法如下:
用户使用静态方法DistributedCache.addCacheFile()指定要复制的文件,它的参数是文件的URI(如果是HDFS上的文件,可以这样:hdfs://namenode:9000/home/XXX/file,其中9000是自己配置的NameNode端口号) . JobTracker在作业启动之前会获取这个URI列表,并将相应的文件拷贝到各个TaskTracker的本地磁盘上 . 
用户使用DistributedCache.getLocalCacheFiles()方法获取文件目录,并使用标准的文件读写API读取相应的文件

Semi Join
也叫半连接,是从分布式数据库中借鉴过来的方法 . 它的产生动机是:对于reduce side join,跨机器的数据传输量非常大,这成了join操作的一个瓶颈,如果能够在map端过滤掉不会参加join操作的数据,则可以大大节省网络IO . 
实现方法很简单:选取一个小表,假设是File1,将其参与join的key抽取出来,保存到文件File3中,File3文件一般很小,可以放到内存中 . 在map阶段,使用DistributedCache将File3复制到各个TaskTracker上,然后将File2中不在File3中的key对应的记录过滤掉,剩下的reduce阶段的工作与reduce side join相同(重点这里就是和mapsidejoin区别) . 


reduce side join + BloomFilter
在某些情况下,SemiJoin抽取出来的小表的key集合在内存中仍然存放不下,这时候可以使用BloomFiler以节省空间 . 
BloomFilter最常见的作用是:判断某个元素是否在一个集合里面 . 它最重要的两个方法是:add() 和contains() . 最大的特点是不会存在 false negative,即:如果contains()返回false,则该元素一定不在集合中,但会存在一定的 false positive,即:如果contains()返回true,则该元素一定可能在集合中 . 
因而可将小表中的key保存到BloomFilter中,在map阶段过滤大表,可能有一些不在小表中的记录没有过滤掉(但是在小表中的记录一定不会过滤掉),这没关系,只不过增加了少量的网络IO而已 . 

MapReduce中排序发生在哪几个阶段?这些排序是否可以避免?为什么?
解答:
一个MapReduce作业由Map阶段和Reduce阶段两部分组成,这两阶段会对数据排序,从这个意义上说,MapReduce框架本质就是一个Distributed Sort . 在Map阶段,在Map阶段,Map Task会在本地磁盘输出一个按照key排序(采用的是快速排序)的文件(中间可能产生多个文件,但最终会合并成一个),在Reduce阶段,每个Reduce Task会对收到的数据排序,这样,数据便按照Key分成了若干组,之后以组为单位交给reduce()处理 . 很多人的误解在Map阶段,如果不使用Combiner便不会排序,这是错误的,不管你用不用Combiner,Map Task均会对产生的数据排序(如果没有Reduce Task,则不会排序, 实际上Map阶段的排序就是为了减轻Reduce端排序负载) . 由于这些排序是MapReduce自动完成的,用户无法控制,因此,在hadoop 1.x中无法避免,也不可以关闭,但hadoop2.x是可以关闭的 . 

请简述 mapreduce 中,combiner,partition 作用?
解答:
combiner是reduce的实现,在map端运行计算任务,减少map端的输出数据 . 
作用就是优化 . 
但是combiner的使用场景是mapreduce的map输出结果和reduce输入输出一样 . 
partition的默认实现是hashpartition,是map端将数据按照reduce个数取余,进行分区,不同的reduce来copy自己的数据 . 
partition的作用是将数据分到不同的reduce进行计算,加快计算效果 . 
1 combiner最基本是实现本地key的聚合,对map输出的key排序,value进行迭代 . 如下所示:
  map:(K1, V1) → list(K2, V2)
  combine:(K2, list(V2)) → list(K2, V2)
  reduce:(K2, list(V2)) → list(K3, V3)
2 combiner还具有类似本地的reduce功能.
  例如hadoop自带的wordcount的例子和找出value的最大值的程序,combiner和reduce完全一致 . 如下所示:
  map:(K1, V1) → list(K2, V2)
  combine:(K2, list(V2)) → list(K3, V3)
  reduce:(K3, list(V3)) → list(K4, V4)
  3 如果不用combiner,那么,所有的结果都是reduce完成,效率会相对低下 . 使用combiner,先完成的map会在本地聚合,提升速度 . 
  4 对于hadoop自带的wordcount的例子,value就是一个叠加的数字,所以map一结束就可以进行reduce的value叠加,而不必要等到所有的map结束再去进行reduce的value叠加 . 
  combiner使用的合适,可以在满足业务的情况下提升job的速度,如果不合适,则将导致输出的结果不正确 . 

mr 的工作原理
Map—combiner—partition—sort—copy—sort—grouping—reduce

用mapreduce怎么处理数据倾斜问题?
解答:
数据倾斜:map /reduce程序执行时,reduce节点大部分执行完毕,但是有一个或者几个reduce节点运行很慢,导致整个程序的处理时间很长,这是因为某一个key的条数比其他key多很多(有时是百倍或者千倍之多),这条key所在的reduce节点所处理的数据量比其他节点就大很多,从而导致某几个节点迟迟运行不完,此称之为数据倾斜 . 
用hadoop程序进行数据关联时,常碰到数据倾斜的情况,这里提供一种解决方法 . 
自己实现partition类,用key和value相加取hash值:
方式1:
源代码:
public int getPartition(K key, V value,int numReduceTasks) {
    return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
}
修改后
public int getPartition(K key, V value,int numReduceTasks) {
    return (((key).hashCode()+value.hashCode()) & Integer.MAX_VALUE) % numReduceTasks;

方式2:
public class HashPartitioner<K, V> extends Partitioner<K, V> {
private int aa= 0;
/ Use {@link Object#hashCode()} to partition. /
public int getPartition(K key, V value,int numReduceTasks) {
 return (key.hashCode()+(aa++) & Integer.MAX_VALUE) % numReduceTasks;
}
}

map的数量由数据块决定,reduce数量随便配置 . 

在hadoop中文件的压缩带来了两大好处:
(1)它减少了存储文件所需的空间;
(2)加快了数据在网络上或者从磁盘上或到磁盘上的传输速度;


hdfs写流程
流程:
1.client链接namenode存数据(client向NameNode申请上传…/xxx.txt文件)
2.namenode记录一条数据位置信息(元数据),告诉client存哪 . 
3.client用hdfs的api将数据块(默认是128M)存储到datanode上(client向DN1,DN2,DN3申请建立文件传输通道,DN3,DN2,DN1依次响应连接,client向DN1上传一个block,DN1向DN2,DN3冗余文件)
4.datanode将数据水平备份 . 并且备份完将反馈client . 
5.client通知namenode存储块完毕 . 
6.namenode将元数据同步到内存中 . 
7.另一块循环上面的过程 . 

hdfs读流程
流程:
1.client链接namenode,查看元数据,找到数据的存储位置 . (client向NN请求下载…/xxx.txt文件)
2.client通过hdfs的api并发读取数据(Client向DN1请求访问读数据blk_1,DN1向Client传输数据,Client向DN2请求访问读数据blk_2,DN2向Client传输数据)
3.关闭连接 . 

举一个简单的例子说明mapreduce是怎么来运行的 ?
解答:
Word count例子接口
一个MapReduce作业(job)通常会把输入的数据集切分为若干独立的数据块,由map任务(task)以完全并行的方式处理它们 . 框架会对map的输出先进行排序,然后把结果输入给reduce任务 . 通常作业的输入和输出都会被存储在文件系统中 . 整个框架负责任务的调度和监控,以及重新执行已经失败的任务 . 
  通常,MapReduce框架和分布式文件系统是运行在一组相同的节点上的,也就是说,计算节点和存储节点通常在一起 . 这种配置允许框架在那些已经存好数据的节点上高效地调度任务,这可以使整个集群的网络带宽被非常高效地利用 . 
  master负责调度构成一个作业的所有任务,这些任务分布在不同的slave上,master监控它们的执行,重新执行已经失败的任务 . 而slave仅负责执行由master指派的任务

yarn流程
解答:
1)用户向YARN 中提交应用程序, 其中包括ApplicationMaster 程序 启动ApplicationMaster 的命令 用户程序等 . 
2)ResourceManager 为该应用程序分配第一个Container, 并与对应的NodeManager 通信,要求它在这个Container 中启动应用程序的ApplicationMaster . 
3) ApplicationMaster 首先向ResourceManager 注册, 这样用户可以直接通过ResourceManage 查看应用程序的运行状态,然后它将为各个任务申请资源,并监控它的运行状态,直到运行结束,即重复步骤4~7 . 
4)ApplicationMaster 采用轮询(轮流着查询,在一个周期内,对远端设备挨个进行请求应答,得到回应称为轮询成功,未得到回应的称为轮询不成功)的方式通过RPC 协议向ResourceManager 申请和领取资源 . 
5)一旦ApplicationMaster 申请到资源后,便与对应的NodeManager 通信,要求它启动任务 . 
6) NodeManager 为任务设置好运行环境(包括环境变量 JAR 包 二进制程序等)后,将任务启动命令写到一个脚本中,并通过运行该脚本启动任务 . 
7)各个任务通过某个RPC 协议向ApplicationMaster 汇报自己的状态和进度,以让ApplicationMaster 随时掌握各个任务的运行状态,从而可以在任务失败时重新启动任务 . 在应用程序运行过程中,用户可随时通过RPC 向ApplicationMaster 查询应用程序的当前运行状态 . 
8)应用程序运行完成后,ApplicationMaster 向ResourceManager 注销并关闭自己 . 

hive内部表和外部表的区别
解答:
内部表:加载数据到hive所在的hdfs目录,删除时,元数据和数据文件都删除
外部表:不加载数据到hive所在的hdfs目录,删除时,只删除表结构 . 

你们数据库怎么导入hive 的,有没有出现问题
在导入hive的时候,如果数据库中有blob或者text字段,会报错,解决方案在sqoop笔记中 . 在将数据由Oracle数据库导入到Hive时,发现带有clob字段的表的数据会错乱,出现一些字段全为NULL的空行 .  由于在项目中CLOB字段没有实际的分析用途,因此考虑将CLOB字段去掉 . 同时,为了防止CLOB字段产生一些问题,因此将HIVE中CLOB字段禁用,禁用的方式如下:[Hadoop@master sqoop-1.4.5]$ cd $SQOOP_HOME/conf[hadoop@master conf]$ vi oraoop-site.xml 将以下属性的注释去掉,并且将value改为true <property> <name>oraoop.import.omit.lobs.and.long</name> <value>true</value> <deion>If true, OraOop will omit BLOB, CLOB, NCLOB and LONG columns during an Import. </deion> </property>有些表中虽然有clob字段,但是不能排除掉,因为其他字段使我们所需要,因此在导入的时候采用指定--columns的方式来进行导入sqoop import --hive-import --hive-database test --create-hive-table --connect jdbc --username user--password user --bindir //scratch --outdir /Java --table aaa --columns "ID,NAME" -m 1 --null-string '\\N' --null-non-string '\\N'

简述Hive中的虚拟列作用是什么,使用它的注意事项
解答:
Hive提供了三个虚拟列:
INPUT__FILE__NAME
BLOCK__OFFSET__INSIDE__FILE
ROW__OFFSET__INSIDE__BLOCK
但ROW__OFFSET__INSIDE__BLOCK默认是不可用的,需要设置hive.exec.rowoffset为true才可以 . 可以用来排查有问题的输入数据 . 
INPUT__FILE__NAME, mapper任务的输出文件名 . 
BLOCK__OFFSET__INSIDE__FILE, 当前全局文件的偏移量 . 对于块压缩文件,就是当前块的文件偏移量,即当前块的第一个字节在文件中的偏移量 . 
hive> SELECT INPUT__FILE__NAME, BLOCK__OFFSET__INSIDE__FILE, line 
> FROM hive_text WHERE line LIKE '%hive%' LIMIT 2;
har://file/user/hive/warehouse/hive_text/folder=docs/
data.har/user/hive/warehouse/hive_text/folder=docs/README.txt  2243
har://file/user/hive/warehouse/hive_text/folder=docs/
data.har/user/hive/warehouse/hive_text/folder=docs/README.txt  3646

hive partition分区
分区表,动态分区

hive中支持两种类型的分区:
静态分区SP(static partition)
动态分区DP(dynamic partition)
静态分区与动态分区的主要区别在于静态分区是手动指定,而动态分区是通过数据来进行判断 . 详细来说,静态分区的列是在编译时期,通过用户传递来决定的;动态分区只有在SQL执行时才能决定 . 

insert into 和 override write区别?
insert into:将某一张表中的数据写到另一张表中
override write:覆盖之前的内容 . 

alter table ptable drop partition (daytime='20140911',city='bj');
元数据,数据文件都删除,但目录daytime= 20140911还在

Hive里面用什么代替in查询
Hive中的left semi join替换sql中的in操作

hbase 过滤器


简述Hbase filter的实现原理是什么?结合实际项目经验,写出几个使用filter的场景 . 
解答:
hbase的filter是通过scan设置的,所以是基于scan的查询结果进行过滤 . 
1.在进行订单开发的时候,我们使用rowkeyfilter过滤出某个用户的所有订单
2.在进行云笔记开发时,我们使用rowkey过滤器进行redis数据的恢复 . 

hbase的rowkey怎么创建好?列族怎么创建比较好?
解答:
hbase存储时,数据按照Row key的字典序(byte order)排序存储 . 设计key时,要充分利用排序存储这个特性,将经常一起读取的行存储放到一起 . (位置相关性(相对位置偏移量))
一个列族在数据底层是一个文件,所以将经常一起查询的列放到一个列族中,列族尽量少,减少文件的寻址时间 . 
因为hbase是列式数据库,列非表schema的一部分,所以在设计初期只需要考虑rowkey 和 columnFamily即可,rowkey有位置相关性,所以如果数据是连续查询((continuous queries):只提交一次,而对不断到达的数据 连续不断执行的查询;次查询与连续查询 与传统数据库管理系统中的一次查询不同,对于持续到达的数据流,人 们提出了连续查询(ContinuousQuery,CQ)的概念 . 一次查询,是对数据集在 某个时间点上的一次计算,再把结果返回给用户),最好对同类数据加一个前缀,而每个columnFamily实际上在底层是一个文件,那么文件越小,查询越快,所以讲经常一起查询的列设计到一个列簇,但是列簇不宜过多 .  
Rowkey长度原则
Rowkey是一个二进制码流,Rowkey的长度被很多开发者建议说设计在10~100个字节,不过建议是越短越好,不要超过16个字节 . 
原因如下:
(1)数据的持久化文件HFile中是按照KeyValue存储的,如果Rowkey过长比如100个字节,1000万列数据光Rowkey就要占用1001000万=10亿个字节,将近1G数据,这会极大影响HFile的存储效率;
(2)MemStore将缓存部分数据到内存,如果Rowkey字段过长内存的有效利用率会降低,系统将无法缓存更多的数据,这会降低检索效率 . 因此Rowkey的字节长度越短越好 . 
(3)目前操作系统是是64位系统,内存8字节对齐 . 控制在16个字节,8字节的整数倍利用操作系统的最佳特性 . 
Rowkey散列原则
如果Rowkey是按时间戳的方式递增,不要将时间放在二进制码的前面,建议将Rowkey的高位作为散列字段,由程序循环生成,低位放时间字段,这样将提高数据均衡分布在每个Regionserver实现负载均衡的几率 . 如果没有散列字段,首字段直接是时间信息将产生所有新数据都在一个 RegionServer上堆积的热点现象,这样在做数据检索的时候负载将会集中在个别RegionServer,降低查询效率 . 
Rowkey唯一原则
必须在设计上保证其唯一性 . 

简述Hbase性能优化的思路
解答:
1 在库表设计的时候,尽量考虑rowkey和columnfamily的特性
2 进行hbase集群的调优

HBase的检索支持3种方式:
解答:
(1) 通过单个Rowkey访问,即按照某个Rowkey键值进行get操作,这样获取唯一一条记录;
(2) 通过Rowkey的range进行scan,即通过设置startRowKey和endRowKey,在这个范围内进行扫描 . 这样可以按指定的条件获取一批记录;
(3) 全表扫描,即直接扫描整张表中所有行记录 . 

简述HBase的瓶颈
解答:
HBase的瓶颈就是硬盘传输速度 . HBase的操作,它可以往数据里面insert,也可以update一些数据,但update的实际上也是insert,只是插入一个新的时间戳的一行 . Delete数据,也是insert,只是insert一行带有delete标记的一行 . Hbase的所有操作都是追加插入操作 . Hbase是一种日志集数据库 . 它的存储方式,像是日志文件一样 . 它是批量大量的往硬盘中写,通常都是以文件形式的读写 . 这个读写速度,就取决于硬盘与机器之间的传输有多快 . 而Oracle的瓶颈是硬盘寻道时间 . 它经常的操作时随机读写 . 要update一个数据,先要在硬盘中找到这个block,然后把它读入内存,在内存中的缓存中修改,过段时间再回写回去 . 由于你寻找的block不同,这就存在一个随机的读 . 硬盘的寻道时间主要由转速来决定的 . 而寻道时间,技术基本没有改变,这就形成了寻道时间瓶颈 . 

1.1 Hbase适合大量插入同时又有读的情况
1.2  Hbase的瓶颈是硬盘传输速度,Oracle的瓶颈是硬盘寻道时间 . 
Hbase本质上只有一种操作,就是插入,其更新操作是插入一个带有新的时间戳的行,而删除是插入一个带有插入标记的行 . 其主要操作是收集内存中一批数据,然后批量的写入硬盘,所以其写入的速度主要取决于硬盘传输的速度 . Oracle则不同,因为他经常要随机读写,这样硬盘磁头需要不断的寻找数据所在,所以瓶颈在于硬盘寻道时间 . 
1.3 Hbase很适合寻找按照时间排序top n的场景
1.4 索引不同造成行为的差异 . 
1.5 Oracle 既可以做OLTP又可以做OLAP,但在某种极端的情况下(负荷十分之大),就不适合了 . 

hive和hbase本质区别——hbase本质是OLTP的nosql DB,而hive是OLAP 底层是hdfs,需从已有数据库同步数据到hdfs;hive可以用hbase中的数据,通过hive表映射到hbase表
对于hbase当前noSql数据库的一种,最常见的应用场景就是采集的网页数据的存储,由于是key-value型数据库,可以再扩展到各种key-value应用场景,如日志信息的存储,对于内容信息不需要完全结构化出来的类CMS应用等 . 注意hbase针对的仍然是OLTP应用为主 . 
对于hive主要针对的是OLAP应用,注意其底层不是hbase,而是hdfs分布式文件系统,重点是基于一个统一的查询分析层,支撑OLAP应用中的各种关联,分组,聚合类SQL语句 . hive一般只用于查询分析统计,而不能是常见的CUD操作(CURD代表创建(Create) 更新(Update) 读取(Read)和删除(Delete)操作),要知道HIVE是需要从已有的数据库或日志进行同步最终入到hdfs文件系统中,当前要做到增量实时同步都相当困难 . 
和mysql,oracle完全不是相同的应用场景 . 这个是结构化数据库,针对的更多的是结构化,事务一致性要求高,业务规则逻辑复杂,数据模型复杂的企业信息化类应用等 . 包括互联网应用中的很多业务系统也需要通过结构化数据库来实现 . 所以和hbase,hive不是一个层面的东西 . 

1. Hive中的表是纯逻辑表,就只是表的定义等,即表的元数据 . Hive本身不存储数据,它完全依赖HDFS和MapReduce . 这样就可以将结构化的数据文件映射为为一张数据库表,并提供完整的SQL查询功能,并将SQL语句最终转换为MapReduce任务进行运行 .  而HBase表是物理表,适合存放非结构化的数据 . 
2. Hive是基于MapReduce来处理数据,而MapReduce处理数据是基于行的模式;HBase处理数据是基于列的而不是基于行的模式,适合海量数据的随机访问 . 
3. HBase的表是疏松的存储的,因此用户可以给行定义各种不同的列;而Hive表是稠密型,即定义多少列,每一行有存储固定列数的数据 . 
4. Hive使用Hadoop来分析处理数据,而Hadoop系统是批处理系统,因此不能保证处理的低迟延问题;而HBase是近实时系统,支持实时查询 . 
5. Hive不提供row-level的更新,它适用于大量append-only数据集(如日志)的批任务处理 . 而基于HBase的查询,支持和row-level的更新 . 
6. Hive提供完整的SQL实现,通常被用来做一些基于历史数据的挖掘 分析 . 而HBase不适用与有join,多级索引,表关系复杂的应用场景 . 
HBase是个基于HDFS的数据库 . Hive是用SQL替代写MR的编程框架,做Hadoop上会把用户提交的SQL语句做语法分析,执行计划等一堆乱七八糟的事后变成MR job提交去跑,返回结果给用户 . 不然每次都写MR很麻烦的,有这个写个SQL就可以拿到等效的结果,很适合运营童鞋用 . 当然Hive也有HBase的Connector,用这个Connnector后可以写SQL查询HBase的数据而不是HDFS,不过一般不这么搞 . 

Hbase的局限:
1 只能做简单的Key value查询,复杂的sql统计做不到 . 
2 只能在row key上做快速查询 . 

传统数据库的行式存储

在数据分析的场景里面,我们经常是以某个列作为查询条件,返回的结果经常也只是某些列,不是全部的列 . 行式数据库在这种情况下的I/O性能会很差,以Oracle为例,Oracle会有一个很大的数据文件,在这个数据文件中,划分了很多block,然后在每个block中放入行,行是一行一行放进去,挤在一起,然后把block塞满,当然也会预留一些空间,用于将来update . 这种结构的缺点是:当我们读某个列的时候,比如我们只需要读红色标记的列的时候,不能只读这部分数据,我必须把整个block读取到内存中,然后再把这些列的数据取出来,换句话说,我为了读表中某些列的数据,我必须把整个列的行读完,才可以读到这些列 . 如果这些列的数据很少,比如1T的数据中只占了100M, 为了读100M数据却要读取1TB的数据到内存中去,则显然是不划算 . 
Oracle中采用的数据访问技术主要是B树索引:

从树的跟节点出发,可以找到叶子节点,其记录了key值对应的那行的位置 . 
对B树的操作:
B树插入——分裂节点
B数删除——合并节点

列式存储

同一个列的数据会挤在一起,比如挤在block里,当我需要读某个列的时候,值需要把相关的文件或块读到内存中去,整个列就会被读出来,这样I/O会少很多 . 
同一个列的数据的格式比较类似,这样可以做大幅度的压缩 . 这样节省了存储空间,也节省了I/O,因为数据被压缩了,这样读的数据量随之也少了 .  
行式数据库适合OLTP,反倒列式数据库不适合OLTP . 

BigTable的LSM(Log Struct Merge 日志结构合并)索引

在Hbase中日志即数据,数据就是日志,他们是一体化的 . 为什么这么说了,因为Hbase的更新时插入一行,删除也是插入一行,然后打上删除标记,则不就是日志吗?
在Hbase中,有Memory Store,还有Store File,其实每个Memory Store和每个Store File就是对每个列族附加上一个B+树(有点像Oracle的索引组织表,数据和索引是一体化的), 也就是图的下面是列族,上面是B+树,当进行数据的查询时,首先会在内存中memory store的B+树中查找,如果找不到,再到Store File中去找 . 
如果找的行的数据分散在好几个列族中,那怎么把行的数据找全呢?那就需要找好几个B+树,这样效率就比较低了 . 所以尽量让每次insert的一行的列族都是稀疏的,只在某一个列族上有值,其他列族没有值,
一,索引不同造成行为的差异
Hbase只能建立一个主键索引,而且之后的数据查询也只能基于该索引进行简单的key-value查询;
但是Oracle可以建立任意索引,也可以按照任意列进行数据查询 . 
二,Hbase适合大量插入同时又有读的情况,读一般为key-value查询
大数据 高并发正合Hbase的胃口
三,Hbase的瓶颈是硬盘传输速度,Oracle的瓶颈是硬盘寻道时间
Hbase都是大量往硬盘上写数据(没有delete update,都是insert),即使是读数据,也是优先MemStore,所以硬盘传输速度成为其瓶颈;
而Oracle由于具有随机访问特性(select update等),所以硬盘寻道时间成为其瓶颈,而寻道时间主要由转速决定 . 
四,Hbase很适合寻找按照时间排序top n的场景
因为Hbase的数据都具有时间戳(Hbase默认就有时间戳)
行式存储:
数据存放在数据文件内
数据文件的基本组成单位:块/页(一行接一行存在block中,当然block不会填满,预留空间进行行的操作,譬如:update)
块内结构:块头 数据区
为了select橘红色的列,行式数据库会把整个block加在到内存,然后筛选出所需列 . 
而对于Hbase而言,由于数据存储特性,数据以列族为单位进行存储,一个文件块存储的都是同一个列族的数据),
这样,查询会比行式数据库优化很多 . 
另外,由于在Hbase中,同一个列里面数据格式比较接近,或者长度相近,从而可以对数据进行大幅度的压缩,
结果就是节省了硬盘空间,也减少了IO

Hbase内部是什么机制?
在HMaster RegionServer内部,创建了RpcServer实例,并与client三者之间实现了Rpc调用,HBase0.95内部引入了Google-Protobuf作为中间数据组织方式,并在Protobuf提供的Rpc接口之上,实现了基于服务的Rpc实现,本文详细阐述了HBase-Rpc实现细节 . 
HBase的RPC Protocol
 在HMaster RegionServer内部,实现了rpc 多个protocol来完成管理和应用逻辑,具体如下protocol如下:
HMaster支持的Rpc协议:
MasterMonitorProtocol,client与Master之间的通信,Master是RpcServer端,主要实现HBase集群监控的目的 . 
MasterAdminProtocol,client与Master之间的通信,Master是RpcServer端,主要实现HBase表格的管理 . 例如TableSchema的更改,Table-Region的迁移 合并 下线(Offline) 上线(Online)以及负载平衡,以及Table的删除 快照等相关功能 . 
RegionServerStatusProtoco,RegionServer与Master之间的通信,Master是RpcServer端,负责提供RegionServer向HMaster状态汇报的服务 . 
RegionServer支持的Rpc协议:
clientProtocol,client与RegionServer之间的通信,RegionServer是RpcServer端,主要实现用户的读写请求 . 例如get multiGet mutate scan bulkLoadHFile 执行Coprocessor等 . 
AdminProtocols,client与RegionServer之间的通信,RegionServer是RpcServer端,主要实现Region 服务 文件的管理 . 例如storefile信息 Region的操作 WAL操作 Server的开关等 . 
(备注:以上提到的client可以是用户Api 也可以是RegionServer或者HMaster)
HBase-RPC实现机制分析
RpcServer配置三个队列:
1)普通队列callQueue,绝大部分Call请求存在该队列中:callQueue上maxQueueLength为${ipc.server.max.callqueue.length},默认是${hbase.master.handler.count}DEFAULT_MAX_CALLQUEUE_LENGTH_PER_HANDLER,目前0.95.1中,每个Handler上CallQueue的最大个数默认值(DEFAULT_MAX_CALLQUEUE_LENGTH_PER_HANDLER)为10 . 
2)优先级队列:PriorityQueue . 如果设置priorityHandlerCount的个数,会创建与callQueue相当容量的queue存储Call,该优先级队列对应的Handler的个数由rpcServer实例化时传入 . 
3)拷贝队列:replicationQueue . 由于RpcServer由HMaster和RegionServer共用,该功能仅为RegionServer提供,queue的大小为${ipc.server.max.callqueue.size}指定,默认为102410241024,handler的个数为hbase.regionserver.replication.handler.count . 
RpcServer由三个模块组成:
Listener ===Queue=== Responder
这里以HBaseAdmin.listTables为例,     分析一个Rpc请求的函数调用过程:
1) Rpcclient创建一个BlockingRpcChannel . 
2)以channel为参数创建执行RPC请求需要的stub,此时的stub已经被封装在具体Service下,stub下定义了可执行的rpc接口 . 
3)stub调用对应的接口,实际内部channel调用callBlockingMethod方法 . 
Rpcclient内实现了protobuf提供的BlockingRpcChannel接口方法callBlockingMethod,  @OverridepublicMessage callBlockingMethod(MethodDescriptor md, RpcController controller,Message param, Message returnType)throwsServiceException {returnthis.rpcclient.callBlockingMethod(md, controller, param, returnType, this.ticket,this.isa, this.rpcTimeout);}
通过以上的实现细节,最终转换成rpcclient的调用,使用MethodDescriptor封装了不同rpc函数,使用Message基类可以接收基于Message的不同的Request和Response对象 . 
4)Rpcclient创建Call对象,查找或者创建合适的Connection,并唤醒Connection . 
5)Connection等待Call的Response,同时rpcclient调用函数中,会使用connection.writeRequest(Call call)将请求写入到RpcServer网络流中 . 
6)等待Call的Response,然后层层返回给更上层接口,从而完成此次RPC调用 . 
RPCServer收到的Rpc报文的内部组织如下:


从功能上讲,RpcServer上包含了三个模块,
1)Listener . 包含了多个Reader线程,通过Selector获取ServerSocketChannel接收来自Rpcclient发送来的Connection,并从中重构Call实例,添加到CallQueue队列中 . 
 "IPC Server listener on 60021″ daemon prio=10 tid=0x00007f7210a97800 nid=0x14c6 runnable [0x00007f720e8d0000]
java.lang.Thread.State:RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:210)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:65)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:69)
- locked <0x00000000c43cae68> (a sun.nio.ch.Util$2)
- locked <0x00000000c43cae50> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000000c4322ca8> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:80)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:84)
at org.apache.hadoop.hbase.ipc.RpcServer$Listener.run(RpcServer.java:646)
2)Handler . 负责执行Call,调用Service的方法,然后返回Pair<Message,CellScanner>
"IPC Server handler 0 on 60021″ daemon prio=10 tid=0x00007f7210eab000 nid=0x14c7 waiting on condition [0x00007f720e7cf000]
java.lang.Thread.State:WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for  <0x00000000c43cad90> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:399)
at org.apache.hadoop.hbase.ipc.RpcServer$Handler.run(RpcServer.java:1804)
3) Responder . 负责把Call的结果返回给Rpcclient . 
 "IPC Server Responder" daemon prio=10 tid=0x00007f7210a97000 nid=0x14c5 runnable [0x00007f720e9d1000]
java.lang.Thread.State:RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:210)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:65)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:69)
- locked <0x00000000c4407078> (a sun.nio.ch.Util$2)
- locked <0x00000000c4407060> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000000c4345b68> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:80)
at org.apache.hadoop.hbase.ipc.RpcServer$Responder.doRunLoop(RpcServer.java:833)
at org.apache.hadoop.hbase.ipc.RpcServer$Responder.run(RpcServer.java:816)
Rpcclient为Rpc请求建立Connection,通过Connection将Call发送RpcServer,然后Rpcclient等待结果的返回 . 

storm 如果碰上了复杂逻辑,需要算很长的时间,你怎么去优化
解答:
拆分复杂的业务到多个bolt中,这样可以利用bolt的tree将速度提升
提高并行度

开发流程,容错机制
解答:
开发流程:
写主类(设计spout和bolt的分发机制)
写spout收集数据
写bolt处理数据,根据数据量和业务的复杂程度,设计并行度 . 
容错机制:
采用ack和fail进行容错,失败的数据重新发送 . 

flume管道内存,flume宕机了数据丢失怎么解决
解答:
1 Flume的channel分为很多种,可以将数据写入到文件
2 防止非首个agent宕机的方法数可以做集群或者主备

flume配置方式,flume集群(问的很详细)
解答:
Flume的配置围绕着source channel sink叙述,flume的集群是做在agent上的,而非机器上 . 

flume和kafka采集日志区别,采集日志时中间停了,怎么记录之前的日志 . 
解答:
Flume采集日志是通过流的方式直接将日志收集到存储层,而kafka是将日志缓存在kafka集群(硬盘),待后期可以采集到存储层 . 
Flume采集中间停了,可以采用文件的方式记录之前的日志,而kafka是采用offset的方式记录之前的日志 . 

Kafka容错机制
解答:
分区备份,存在主备partition

 kafka+spark-streaming结合丢数据怎么解决?
解答:
spark streaming从1.2开始提供了数据的零丢失,想享受这个特性,需要满足如下条件:
数据输入需要可靠的sources和可靠的receivers
应用metadata必须通过应用driver checkpoint
WAL(write ahead log)
可靠的sources和receivers
spark streaming可以通过多种方式作为数据sources(包括kafka),输入数据通过receivers接收,通过replication存储于spark中(为了faultolerance,默认复制到两个spark executors),如果数据复制完成,receivers可以知道(例如kafka中更新offsets到zookeeper中) . 这样当receivers在接收数据过程中crash掉,不会有数据丢失,receivers没有复制的数据,当receiver恢复后重新接收 . 
metadata checkpoint
可靠的sources和receivers,可以使数据在receivers失败后恢复,然而在driver失败后恢复是比较复杂的,一种方法是通过checkpoint metadata到HDFS或者S3 . metadata包括:
configuration
code
一些排队等待处理但没有完成的RDD(仅仅是metadata,而不是data)
这样当driver失败时,可以通过metadata checkpoint,重构应用程序并知道执行到那个地方 . 
数据可能丢失的场景
可靠的sources和receivers,以及metadata checkpoint也不可以保证数据的不丢失,例如:
两个executor得到计算数据,并保存在他们的内存中
receivers知道数据已经输入
executors开始计算数据
driver突然失败
driver失败,那么executors都会被kill掉
因为executor被kill掉,那么他们内存中得数据都会丢失,但是这些数据不再被处理
executor中的数据不可恢复
WAL(WAL:Write-Ahead Logging [1]  预写日志系统,数据库中一种高效的日志算法,对于非内存数据库而言,磁盘I/O操作是数据库效率的一大瓶颈 . 在相同的数据量下,采用WAL日志的数据库系统在事务提交时,磁盘写操作只有传统的回滚日志的一半左右,大大提高了数据库磁盘I/O操作的效率,从而提高了数据库的性能 . )
为了避免上面情景的出现,spark streaming 1.2引入了WAL . 所有接收的数据通过receivers写入HDFS或者S3中checkpoint目录,这样当driver失败后,executor中数据丢失后,可以通过checkpoint恢复 . 
At-Least-Once
尽管WAL可以保证数据零丢失,但是不能保证exactly-once,例如下面场景:
Receivers接收完数据并保存到HDFS或S3
在更新offset前,receivers失败了
Spark Streaming以为数据接收成功,但是Kafka以为数据没有接收成功,因为offset没有更新到zookeeper
随后receiver恢复了
从WAL可以读取的数据重新消费一次,因为使用的kafka High-Level消费API,从zookeeper中保存的offsets开始消费
WAL的缺点
通过上面描述,WAL有两个缺点:
降低了receivers的性能,因为数据还要存储到HDFS等分布式文件系统
对于一些resources,可能存在重复的数据,比如Kafka,在Kafka中存在一份数据,在Spark Streaming也存在一份(以WAL的形式存储在hadoop API兼容的文件系统中)
Kafka direct API
为了WAL的性能损失和exactly-once,spark streaming1.3中使用Kafka direct API . 非常巧妙,Spark driver计算下个batch的offsets,指导executor消费对应的topics和partitions . 消费Kafka消息,就像消费文件系统文件一样 . 
不再需要kafka receivers,executor直接通过Kafka API消费数据
WAL不再需要,如果从失败恢复,可以重新消费
exactly-once得到了保证,不会再从WAL中重复读取数据
总结
主要说的是spark streaming通过各种方式来保证数据不丢失,并保证exactly-once,每个版本都是spark streaming越来越稳定,越来越向生产环境使用发展 . 

kafka中存储目录data/dir.....topic1和topic2怎么存储的,存储结构,data.....目录下有多少个分区,每个分区的存储格式是什么样的?
解答:
1 topic是按照"主题名-分区"存储的
2 分区个数由配置文件决定
3 每个分区下最重要的两个文件是0000000000.log和000000.index,0000000.log以默认1G大小回滚 . 

mr和spark区别,怎么理解spark-rdd
解答:
Mr是文件方式的分布式计算框架,是将中间结果和最终结果记录在文件中,map和reduce的数据分发也是在文件中 . 
spark是内存迭代式的计算框架,计算的中间结果可以缓存内存,也可以缓存硬盘,但是不是每一步计算都需要缓存的 . 
Spark-rdd是一个数据的分区记录集合………………

 Spark应用转换流程
解答:
1 spark应用提交后,经历了一系列的转换,最后成为task在每个节点上执行
2 RDD的Action算子触发Job的提交,生成RDD DAG
3 由DAGScheduler将RDD DAG转化为Stage DAG,每个Stage中产生相应的Task集合
4 TaskScheduler将任务分发到Executor执行
5 每个任务对应相应的一个数据块,只用用户定义的函数处理数据块

 Driver运行在客户端
解答:
作业执行流程描述:
1 客户端启动后直接运行用户程序,启动Driver相关的工作:DAGScheduler和BlockManagerMaster等 . 
2 客户端的Driver向Master注册 . 
3 Master还会让Worker启动Exeuctor . Worker创建一个ExecutorRunner线程,ExecutorRunner会启动ExecutorBackend进程 . 
4 ExecutorBackend启动后会向Driver的SchedulerBackend注册 . Driver的DAGScheduler解析作业并生成相应的Stage,每个Stage包含的Task通过TaskScheduler分配给Executor执行 . 
5 所有stage都完成后作业结束 . 

Driver运行在Worker上
解答:
通过org.apache.spark.deploy.client类执行作业,作业运行命令如下:
作业执行流程描述:
1 客户端提交作业给Master
2 Master让一个Worker启动Driver,即SchedulerBackend . Worker创建一个DriverRunner线程,DriverRunner启动SchedulerBackend进程 . 
3 另外Master还会让其余Worker启动Exeuctor,即ExecutorBackend . Worker创建一个ExecutorRunner线程,ExecutorRunner会启动ExecutorBackend进程 . 
4 ExecutorBackend启动后会向Driver的SchedulerBackend注册 . SchedulerBackend进程中包含DAGScheduler,它会根据用户程序,生成执行计划,并调度执行 . 对于每个stage的task,都会被存放到TaskScheduler中,ExecutorBackend向SchedulerBackend汇报的时候把TaskScheduler中的task调度到ExecutorBackend执行 . 
5 所有stage都完成后作业结束 . 

Sqoop
1.      命令:
sqoop import --connect jdbc:mysql://192.168.56.204:3306/sqoop --username hive --password hive --table jobinfo --target-dir /sqoop/test7 --inline-lob-limit 16777216 --fields-terminated-by '\t' -m 2

sqoop create-hive-table --connect jdbc:mysql://192.168.56.204:3306/sqoop --table jobinfo --username hive --password hive --hive-table sqtest --fields-terminated-by "\t" --lines-terminated-by "\n";

sqoop在导入数据到mysql中,如何让数据不重复导入?如果存在数据问题sqoop如何处理?
解答:
Sqoop是一个用来将Hadoop和关系型数据库中的数据相互转移的工具,可以将一个关系型数据库(例如 :MySQL ,Oracle ,Postgres等)中的数据导进到Hadoop的HDFS中,也可以将HDFS的数据导进到关系型数据库中 . 
首先需以下要准备:
第一:hadoop的NameNode节点下lib文件夹中要有相应数据库驱动的jar包和sqoop的jar包 . 
第二:预先在相应的数据库创建Table,注:在HDFS的某个目录上的数据格式要和相应的表中的字段数量一致 . 
由于我这里使用的是Oracle数据库并且是使用Java来操作的 . 所以下面的代码以及截图都是以Java的例子:
Java代码如下:
Configuration conf = new Configuration();
conf.set("fs.default.name", "hdfs://192.168.115.5:9000");
conf.set("hadoop.job.ugi", "hadooper,hadoopgroup");
conf.set("mapred.job.tracker", "192.168.115.5:9001");
ArrayList<String> list = new ArrayList<String>(); // 定义一个list
list.add("--table");
list.add("A_BAAT_client"); // Oracle中的表 . 将来数据要导入到这个表中 . 
list.add("--export-dir");
list.add("/home/hadoop/traffic/capuse/near7date/activeUser/capuse_near7_activeUser_2013-02-06.log"); // hdfs上的目录 . 这个目录下的数据要导入到a_baat_client这个表中 . 
list.add("--connect");
list.add("jdbc:oracle:thin:@10.18.96.107:1521:life"); // Oracle的链接
list.add("--username");
list.add("TRAFFIC"); // Oracle的用户名
list.add("--password");
list.add("TRAFFIC"); // Oracle的密码
list.add("--input-fields-terminated-by");
list.add("|"); // 数据分隔符号
list.add("-m");
list.add("1");// 定义mapreduce的数量 . 
String[] arg = new String[1];
ExportTool exporter = new ExportTool();
Sqoop sqoop = new Sqoop(exporter);
sqoop.setConf(conf);
arg = list.toArray(new String[0]);
int result = Sqoop.runSqoop(sqoop, arg);
System.out.println("res:" + result); // 打印执行结果 . 
最后再在Main方法中运行即可
通过上面的操作以及代码即可在Java中实现把HDFS数据生成对应的表数据;23666
不过除了可以用Java来实现,使用基本的命令也是可以的,命令如下:
在Hadoop bin目录中:
sqoop export --connect jdbc:oracle:thin:@10.18.96.107:1521:life \
--table A_BAAT_client --username TRAFFIC --password TRAFFIC \
--input-fields-terminated-by '|' \
--export-dir /home/hadoop/traffic/capuse/near7date/activeUser/test.log  -m 1
意思和上面Java中代码一样 . 
注意:
1 数据库表名 用户名 密码使用大写(这有可能会出现问题,因为我在测试过程中,使用小写时出现错误,出现No Columns这个经典错误 . 所以推荐大写,当然这不是必须);
2 预先建好相应的Table;

Redis,传统数据库,hbase,hive 每个之间的区别
解答:
redis:分布式缓存,强调缓存,内存中数据
传统数据库:注重关系
hbase:列式数据库,无法做关系数据库的主外键,用于存储海量数据,底层基于hdfs
hive:数据仓库工具,底层是mapreduce . 不是数据库,不能用来做用户的交互存储

数据库
1.      反向索引
解答:
倒排索引(Inverted index)
适用范围:搜索引擎,关键字查询
基本原理及要点:为何叫倒排索引?一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射 . 
以英文为例,下面是要被索引的文本:
T0 = "it is what it is" 
T1 = "what is it"
T2 = "it is a banana"
我们就能得到下面的反向文件索引:
"a":{2}
"banana":{2}
"is":{0, 1, 2}
"it":{0, 1, 2}
"what":{0, 1}
检索的条件"what","is"和"it"将对应集合的交集 . 
正向索引开发出来用来存储每个文档的单词的列表 . 正向索引的查询往往满足每个文档有序 频繁的全文查询和每个单词在校验文档中的验证这样的查询 . 在正向索引中,文档占据了中心的位置,每个文档指向了一个它所包含的索引项的序列 . 也就是说文档指向了它包含的那些单词,而反向索引则是单词指向了包含它的文档,很容易看到这个反向的关系

搜索引擎就使用倒排索引的 . 
如果数据库使用全文搜索,一般就要用倒排索引的 . 
Oracle的索引对数据库管理员是透明的,数据库管理是不用知道索引的细节的 . 


数据库的三大范式?
解答:
数据库范式1NF 2NF 3NF BCNF(实例)
    设计范式(范式,数据库设计范式,数据库的设计范式)是符合某一种级别的关系模式的集合 . 构造数据库必须遵循一定的规则 . 在关系数据库中,这种规则就是范式 . 关系数据库中的关系必须满足一定的要求,即满足不同的范式 . 目前关系数据库有六种范式:第一范式(1NF) 第二范式(2NF) 第三范式(3NF) 第四范式(4NF) 第五范式(5NF)和第六范式(6NF) . 满足最低要求的范式是第一范式(1NF) . 在第一范式的基础上进一步满足更多要求的称为第二范式(2NF),其余范式以次类推 . 一般说来,数据库只需满足第三范式(3NF)就行了 . 下面我们举例介绍第一范式(1NF) 第二范式(2NF)和第三范式(3NF) .  
    在创建一个数据库的过程中,范化是将其转化为一些表的过程,这种方法可以使从数据库得到的结果更加明确 . 这样可能使数据库产生重复数据,从而导致创建多余的表 . 范化是在识别数据库中的数据元素 关系,以及定义所需的表和各表中的项目这些初始工作之后的一个细化的过程 .  
    下面是范化的一个例子 Customer Item purchased Purchase price Thomas Shirt $40 Maria Tennis shoes $35 Evelyn Shirt $40 Pajaro Trousers $25 
如果上面这个表用于保存物品的价格,而你想要删除其中的一个顾客,这时你就必须同时删除一个价格 . 范化就是要解决这个问题,你可以将这个表化为两个表,一个用于存储每个顾客和他所买物品的信息,另一个用于存储每件产品和其价格的信息,这样对其中一个表做添加或删除操作就不会影响另一个表 . 
关系数据库的几种设计范式介绍
1 第一范式(1NF)
    在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库 .  
    所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性 . 如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系 . 在第一范式(1NF)中表的每一行只包含一个实例的信息 . 例如,对于图3-2 中的员工信息表,不能将员工信息都放在一列中显示,也不能将其中的两列或多列在一列中显示;员工信息表的每一行只表示一个员工的信息,一个员工的信息在表中只出现一次 . 简而言之,第一范式就是无重复的列 . 
2 第二范式(2NF)
    第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF) . 第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分 . 为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识 . 如图3-2 员工信息表中加上了员工编号(emp_id)列,因为每个员工的员工编号是惟一的,因此每个员工可以被惟一区分 . 这个惟一属性列被称为主关键字或主键 主码 .  
第二范式(2NF)要求实体的属性完全依赖于主关键字 . 所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系 . 为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识 . 简而言之,第二范式就是非主属性非部分依赖于主关键字 . 
3 第三范式(3NF) 
    满足第三范式(3NF)必须先满足第二范式(2NF) . 简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息 . 例如,存在一个部门信息表,其中每个部门有部门编号(dept_id) 部门名称 部门简介等信息 . 那么在图3-2的员工信息表中列出部门编号后就不能再将部门名称 部门简介等与部门有关的信息再加入员工信息表中 . 如果不存在部门信息表,则根据第三范式(3NF)也应该构建它,否则就会有大量的数据冗余 . 简而言之,第三范式就是属性不依赖于其它非主属性 . 
数据库设计三大范式应用实例剖析 
     数据库的设计范式是数据库设计所需要满足的规范,满足这些规范的数据库是简洁的 结构明晰的,同时,不会发生插入(insert) 删除(delete)和更新(update)操作异常 . 反之则是乱七八糟,不仅给数据库的编程人员制造麻烦,而且面目可憎,可能存储了大量不需要的冗余信息 .  
    设计范式是不是很难懂呢?非也,大学教材上给我们一堆数学公式我们当然看不懂,也记不住 . 所以我们很多人就根本不按照范式来设计数据库 .  
实质上,设计范式用很形象 很简洁的话语就能说清楚,道明白 . 本文将对范式进行通俗地说明,并以笔者曾经设计的一个简单论坛的数据库为例来讲解怎样将这些范式应用于实际工程 . 
范式说明 
    第一范式(1NF):数据库表中的字段都是单一属性的,不可再分 . 这个单一属性由基本类型构成,包括整型 实数 字符型 逻辑型 日期型等 . 
    例如,如下的数据库表是符合第一范式的:
    字段1 字段2 字段3 字段4
    而这样的数据库表是不符合第一范式的:
    字段1 字段2 字段3 字段4 
    字段3.1 字段3.2 
    很显然,在当前的任何关系数据库管理系统(DBMS)中,傻瓜也不可能做出不符合第一范式的数据库,因为这些DBMS不允许你把数据库表的一列再分成二列或多列 . 因此,你想在现有的DBMS中设计出不符合第一范式的数据库都是不可能的 .  
    第二范式(2NF):数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖(部分函数依赖指的是存在组合关键字中的某些字段决定非关键字段的情况),也即所有非关键字段都完全依赖于任意一组候选关键字 . 
    假定选课关系表为SelectCourse(学号, 姓名, 年龄, 课程名称, 成绩, 学分),关键字为组合关键字(学号, 课程名称),因为存在如下决定关系:
    (学号, 课程名称) → (姓名, 年龄, 成绩, 学分) 
    这个数据库表不满足第二范式,因为存在如下决定关系:
    (课程名称) → (学分) 
    (学号) → (姓名, 年龄) 
    即存在组合关键字中的字段决定非关键字的情况 .  
    由于不符合2NF,这个选课关系表会存在如下问题:
    (1) 数据冗余:
    同一门课程由n个学生选修,"学分"就重复n-1次;同一个学生选修了m门课程,姓名和年龄就重复了m-1次 .  
    (2) 更新异常:
    若调整了某门课程的学分,数据表中所有行的"学分"值都要更新,否则会出现同一门课程学分不同的情况 .  
    (3) 插入异常:
    假设要开设一门新的课程,暂时还没有人选修 . 这样,由于还没有"学号"关键字,课程名称和学分也无法记录入数据库 .  
    (4) 删除异常:
    假设一批学生已经完成课程的选修,这些选修记录就应该从数据库表中删除 . 但是,与此同时,课程名称和学分信息也被删除了 . 很显然,这也会导致插入异常 .  
    把选课关系表SelectCourse改为如下三个表:
    学生:Student(学号, 姓名, 年龄); 
    课程:Course(课程名称, 学分); 
    选课关系:SelectCourse(学号, 课程名称, 成绩) .  
    这样的数据库表是符合第二范式的, 消除了数据冗余 更新异常 插入异常和删除异常 .  
    另外,所有单关键字的数据库表都符合第二范式,因为不可能存在组合关键字 . 
    第三范式(3NF):在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式 . 所谓传递函数依赖,指的是如果存在"A → B → C"的决定关系,则C传递函数依赖于A . 因此,满足第三范式的数据库表应该不存在如下依赖关系:
    关键字段 → 非关键字段x → 非关键字段y 
    假定学生关系表为Student(学号, 姓名, 年龄, 所在学院, 学院地点, 学院电话),关键字为单一关键字"学号",因为存在如下决定关系:
    (学号) → (姓名, 年龄, 所在学院, 学院地点, 学院电话) 
    这个数据库是符合2NF的,但是不符合3NF,因为存在如下决定关系:
    (学号) → (所在学院) → (学院地点, 学院电话) 
    即存在非关键字段"学院地点" "学院电话"对关键字段"学号"的传递函数依赖 .     
    它也会存在数据冗余 更新异常 插入异常和删除异常的情况,读者可自行分析得知 .  
    把学生关系表分为如下两个表:
    学生:(学号, 姓名, 年龄, 所在学院); 
   学院:(学院, 地点, 电话) .  
    这样的数据库表是符合第三范式的,消除了数据冗余 更新异常 插入异常和删除异常 .  
鲍依斯-科得范式(BCNF):在第三范式的基础上,数据库表中如果不存在任何字段对任一候选关键字段的传递函数依赖则符合第三范式 .  
    假设仓库管理关系表为StorehouseManage(仓库ID, 存储物品ID, 管理员ID, 数量),且有一个管理员只在一个仓库工作;一个仓库可以存储多种物品 . 这个数据库表中存在如下决定关系:
    (仓库ID, 存储物品ID) →(管理员ID, 数量) 
    (管理员ID, 存储物品ID) → (仓库ID, 数量) 
    所以,(仓库ID, 存储物品ID)和(管理员ID, 存储物品ID)都是StorehouseManage的候选关键字,表中的唯一非关键字段为数量,它是符合第三范式的 . 但是,由于存在如下决定关系:
    (仓库ID) → (管理员ID) 
    (管理员ID) → (仓库ID) 
    即存在关键字段决定关键字段的情况,所以其不符合BCNF范式 . 它会出现如下异常情况:
    (1) 删除异常:
    当仓库被清空后,所有"存储物品ID"和"数量"信息被删除的同时,"仓库ID"和"管理员ID"信息也被删除了 .  
    (2) 插入异常:
    当仓库没有存储任何物品时,无法给仓库分配管理员 .  
    (3) 更新异常:
    如果仓库换了管理员,则表中所有行的管理员ID都要修改 .  
    把仓库管理关系表分解为二个关系表:
    仓库管理:StorehouseManage(仓库ID, 管理员ID); 
    仓库:Storehouse(仓库ID, 存储物品ID, 数量) .  
    这样的数据库表是符合BCNF范式的,消除了删除异常 插入异常和更新异常 .  
范式应用 
    我们来逐步搞定一个论坛的数据库,有如下信息:
    (1) 用户:用户名,email,主页,电话,联系地址 
    (2) 帖子:发帖标题,发帖内容,回复标题,回复内容 
    第一次我们将数据库设计为仅仅存在表:
    用户名 email 主页 电话 联系地址 发帖标题 发帖内容 回复标题 回复内容 
    这个数据库表符合第一范式,但是没有任何一组候选关键字能决定数据库表的整行,唯一的关键字段用户名也不能完全决定整个元组 . 我们需要增加"发帖ID" "回复ID"字段,即将表修改为:
    用户名 email 主页 电话 联系地址 发帖ID 发帖标题 发帖内容 回复ID 回复标题 回复内容 
    这样数据表中的关键字(用户名,发帖ID,回复ID)能决定整行:
    (用户名,发帖ID,回复ID) → (email,主页,电话,联系地址,发帖标题,发帖内容,回复标题,回复内容) 
    但是,这样的设计不符合第二范式,因为存在如下决定关系:
    (用户名) → (email,主页,电话,联系地址) 
    (发帖ID) → (发帖标题,发帖内容) 
    (回复ID) → (回复标题,回复内容) 
    即非关键字段部分函数依赖于候选关键字段,很明显,这个设计会导致大量的数据冗余和操作异常 .  
我们将数据库表分解为(带下划线的为关键字):
(1) 用户信息:用户名,email,主页,电话,联系地址 
(2) 帖子信息:发帖ID,标题,内容 
(3) 回复信息:回复ID,标题,内容 
(4) 发贴:用户名,发帖ID 
(5) 回复:发帖ID,回复ID 
    这样的设计是满足第1 2 3范式和BCNF范式要求的,但是这样的设计是不是最好的呢? 
不一定 .  
    观察可知,第4项"发帖"中的"用户名"和"发帖ID"之间是1:N的关系,因此我们可以把"发帖"合并到第2项的"帖子信息"中;第5项"回复"中的"发帖ID"和"回复ID"之间也是1:N的关系,因此我们可以把"回复"合并到第3项的"回复信息"中 . 这样可以一定量地减少数据冗余,新的设计为:
(1) 用户信息:用户名,email,主页,电话,联系地址 
(2) 帖子信息:用户名,发帖ID,标题,内容 
(3) 回复信息:发帖ID,回复ID,标题,内容 
    数据库表1显然满足所有范式的要求; 
    数据库表2中存在非关键字"标题" "内容"对关键字段"发帖ID"的部分函数依赖,即不满足第二范式的要求,但是这一设计并不会导致数据冗余和操作异常; 
    数据库表3中也存在非关键字段"标题" "内容"对关键字段"回复ID"的部分函数依赖,也不满足第二范式的要求,但是与数据库表2相似,这一设计也不会导致数据冗余和操作异常 .  
    由此可以看出,并不一定要强行满足范式的要求,对于1:N关系,当1的一边合并到N的那边后,N的那边就不再满足第二范式了,但是这种设计反而比较好! 
    对于M:N的关系,不能将M一边或N一边合并到另一边去,这样会导致不符合范式要求,同时导致操作异常和数据冗余 .  
对于1:1的关系,我们可以将左边的1或者右边的1合并到另一边去,设计导致不符合范式要求,但是并不会导致操作异常和数据冗余 . 

有 10 个文件,每个文件 1G,每个文件的每一行存放的都是用户的 query,每个文件的 query 都可能重复 . 要求你按照query 的频度排序 . 
解答:
方案 1:
1. hash映射:顺序读取10个文件,按照hash(query)%10的结果将query写入到另外10个文件中 . 这样新生成的文件每个的大小大约也1G(假设hash函数是随机的) . 
2. hash统计:找一台内存在2G左右的机器,依次对用hash_map(query, query_count)来统计每个query出现的次数 . 注:hash_map(query,query_count)是用来统计每个query的出现次数,不是存储他们的值,出现一次,则count+1 . 
3. 堆/快速/归并排序:利用快速/堆/归并排序按照出现次数进行排序 . 将排序好的query和对应的query_cout输出到文件中 . 这样得到了10个排好序的文件 . 对这10个文件进行归并排序(内排序与外排序相结合) . 
方案 2:
一般 query 的总量是有限的,只是重复的次数比较多而已,可能对于所有的 query,一次性就可以加入到内存了 . 这样,我们就可以采用 trie 树(字典树)/hash_map 等直接来统计每个 query 出现的次数,然后按出现次数做快速/堆/归并排序就可以了 . 
方案 3:
与方案 1 类似,但在做完 hash,分成多个文件后,可以交给多个文件来处理,采用分布式的架构来处理(比如 MapReduce),最后再进行合并 . 
//一般在大文件中找出出现频率高的,先把大文件映射成小文件,模 1000,在小文件中找到高频的

一般情况下,快速排序效率要高于堆排序 . 因为堆排序的常数较大(不过也是1~2之间吧) . 
快速排序的平均时间复杂度是O(1.39nlogn) . 一般来说,除非有需要绝对保证不能出现O(n^2)的要求,不使用堆排 . 
堆排序需要有效的随机存取 . 

共享内存是System V版本的最后一个进程间通信方式 . 共享内存,顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式 . 不同进程之间共享的内存通常为同一段物理内存 . 进程可以将同一段物理内存连接到他们自己的地址空间中,所有的进程都可以访问共享内存中的地址 . 如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程 . 
特别提醒:共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取,所以我们通常需要用其他的机制来同步对共享内存的访问,例如信号量 . 
共享内存指 (shared memory)在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存 . 由于多个CPU需要快速访问存储器,这样就要对存储器进行缓存(Cache) . 任何一个缓存的数据被更新后,由于其他处理器也可能要存取,共享内存就需要立即更新,否则不同的处理器可能用到不同的数据 . 共享内存是 Unix下的多进程之间的通信方法 ,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息 . 

一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前 10 个词,请给出思想,给出时间复杂度分析 . 
解答:
方案 1:这题是考虑时间效率 . 用 trie 树统计每个词出现的次数,时间复杂度是 O(nle)(le 表示单词的平准长 度) . 然后是找出出现最频繁的前 10 个词,可以用堆来实现,前面的题中已经讲到了,时间复杂度是 O(nlg10) . 所以总的时间复杂度,是 O(nle)与 O(nlg10)中较大的哪一个 . 

密匙 分而治之/Hash映射 + Hash统计 + 堆/快速/归并排序

海量日志数据,提取出某日访问百度次数最多的那个IP . 
1.       先根据日期在日志文件中提取出ip,根据ip哈希进行分写N个文件 . 
2.       采用mapreduce的word cont
    既然是海量数据处理,那么可想而知,给我们的数据那就一定是海量的 . 针对这个数据的海量,我们如何着手呢?对的,无非就是分而治之/hash映射 + hash统计 + 堆/快速/归并排序,说白了,就是先映射,而后统计,最后排序:
1. 分而治之/hash映射:针对数据太大,内存受限,只能是:把大文件化成(取模映射)小文件,即16字方针:大而化小,各个击破,缩小规模,逐个解决
2. hash统计:当大文件转化了小文件,那么我们便可以采用常规的hash_map(ip,value)来进行频率统计 . 
3. 堆/快速排序:统计完了之后,便进行排序(可采取堆排序),得到次数最多的IP . 
   具体而论,则是: "首先是这一天,并且是访问百度的日志中的IP取出来,逐个写入到一个大文件中 . 注意到IP是32位的,最多有2^32个IP . 同样可以采用映射的方 法,比如模1000,把整个大文件映射为1000个小文件,再找出每个小文中出现频率最大的IP(可以采用hash_map进行频率统计,然后再找出频率 最大的几个)及相应的频率 . 然后再在这1000个最大的IP中,找出那个频率最大的IP,即为所求 . " . 
    注:Hash取模是一种等价映射,不会存在同一个元素分散到不同小文件中去的情况,即这里采用的是mod1000算法,那么相同的IP在hash后,只可能落在同一个文件中,不可能被分散的 . 
那到底什么是hash映射呢?我换个角度举个浅显直白的例子,如本文的URL是:http://blog.csdn.net/v_july_v/article/details/7382693,当我把这个URL发表在微博上,便被映射成了:http://t.cn/zOixljh,于此,我们发现URL本身的长度被缩短了,但这两个URL对应的文章的是同一篇即本文 . OK,有兴趣的,还可以再了解下一致性hash算法,见此文第五部分:http://blog.csdn.net/v_july_v/article/details/6879101 . 

搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节 . 
    假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个 . 一个查询串的重复度越高,说明查询它的用户越多,也就是越热门),请你统计最热门的10个查询串,要求使用的内存不能超过1G . 
    由上面第1题,我们知道,数据大则划为小的,但如果数据规模比较小,能一次性装入内存呢?比如这第2题,虽然有一千万个Query,但是由于重复度比较 高,因此事实上只有300万的Query,每个Query255Byte,因此我们可以考虑把他们都放进内存中去,而现在只是需要一个合适的数据结构,在 这里,Hash Table绝对是我们优先的选择 . 所以我们摒弃分而治之/hash映射的方法,直接上hash统计,然后排序 . So,
1. hash 统计:先对这批海量数据预处理(维护一个Key为Query字串,Value为该Query出现次数的HashTable,即 hash_map(Query,Value),每次读取一个Query,如果该字串不在Table中,那么加入该字串,并且将Value值设为1;如果该 字串在Table中,那么将该字串的计数加一即可 . 最终我们在O(N)的时间复杂度内用Hash表完成了统计;
2. 堆排序:第二步 借助堆 这个数据结构,找出Top K,时间复杂度为N‘logK . 即借助堆结构,我们可以在log量级的时间内查找和调整/移动 . 因此,维护一个K(该题目中是10)大小的小根堆,然后遍 历300万的Query,分别和根元素进行对比所以,我们最终的时间复杂度是:O(N) + N'O(logK),(N为1000万,N’为300万) . 
    别忘了这篇文章中所述的堆排序思路:"维 护k个元素的最小堆,即用容量为k的最小堆存储最先遍历到的k个数,并假设它们即是最大的k个数,建堆费时O(k),并调整堆(费时O(logk))后, 有k1>k2>...kmin(kmin设为小顶堆中最小元素) . 继续遍历数列,每次遍历一个元素x,与堆顶元素比较,若 x>kmin,则更新堆(用时logk),否则不更新堆 . 这样下来,总费时O(klogk+(n-k)logk)=O(nlogk) . 此方法 得益于在堆中,查找等各项操作时间复杂度均为logk . "--第三章续 Top K算法问题的实现 . 
当然,你也可以采用trie树,关键字域存该查询串出现的次数,没有出现为0 . 最后用10个元素的最小推来对出现频率进行排序 . 

有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M . 返回频数最高的100个词 . 
       由上面那两个例题,分而治之 + hash统计 + 堆/快速排序这个套路,我们已经开始有了屡试不爽的感觉 . 下面,再拿几道再多多验证下 . 请看此第3题:又是文件很大,又是内存受限,咋办?还能怎么办呢?无非还是:
1. 分 而治之/hash映射:顺序读文件中,对于每个词x,取hash(x)%5000,然后按照该值存到5000个小文件(记为 x0,x1,...x4999)中 . 这样每个文件大概是200k左右 . 如果其中的有的文件超过了1M大小,还可以按照类似的方法继续往下分,直到分解得到 的小文件的大小都不超过1M . 
2. hash统计:对每个小文件,采用trie树/hash_map等统计每个文件中出现的词以及相应的频率 . 
3. 堆/归并排序:取出出现频率最大的100个词(可以用含100个结点的最小堆),并把100个词及相应的频率存入文件,这样又得到了5000个文件 . 最后就是把这5000个文件进行归并(类似于归并排序)的过程了 . 


给定a b两个文件,各存放50亿个url,每个url各占用64字节,内存限制是4G,如何找出a b文件共同的url?
    主要的思想是把文件分开进行计算,在对每个文件进行对比,得出相同的URL,因为以上说是含有相同的URL所以不用考虑数据倾斜的问题 . 详细的解题思路为:
可以估计每个文件的大小为5G64=300G,远大于4G . 所以不可能将其完全加载到内存中处理 . 考虑采取分而治之的方法 .  
    遍历文件a,对每个url求取hash(url)%1000,然后根据所得值将url分别存储到1000个小文件(设为a0,a1,...a999)当中 . 这样每个小文件的大小约为300M . 遍历文件b,采取和a相同的方法将url分别存储到1000个小文件(b0,b1....b999)中 . 这样处理后,所有可能相同的url都在对应的小文件(a0 vs b0, a1 vs b1....a999 vs b999)当中,不对应的小文件(比如a0 vs b99)不可能有相同的url . 然后我们只要求出1000对小文件中相同的url即可 .  
    比如对于a0 vs b0,我们可以遍历a0,将其中的url存储到hash_map当中 . 然后遍历b0,如果url在hash_map中,则说明此url在a和b中同时存在,保存到文件中即可 .  
如果分成的小文件不均匀,导致有些小文件太大(比如大于2G),可以考虑将这些太大的小文件再按类似的方法分成小小文件即可
方案 1:将大文件分成能够被内存加载的小文件 . 
可以估计每个文件安的大小为 50G×64=320G,远远大于内存限制的 4G . 所以不可能将其完全加载到内存中处理 . 考虑采取分而治之的方法 . 
1分而治之/hash映射:遍历文件 a,对每个 url 求取 ,然后根据所取得的值将 url 分别存储到 1000 个小文件中 . 
这样每个小文件的大约为 300M . 
2遍历文件 b,采取和 a 相同的方式将 url 分别存储到 1000 各小文件 . 这样处理后,所有可能相同的 url 都在对应的小文件中,不对应的小文件不可能有相同的 url . 然后我们只要求出 1000 对小文件中相同的 url 即可 . 
3 hash统计:求每对小文件中相同的 url 时,可以把其中一个小文件的 url 存储到 hash_set 中 . 然后遍历另一个小文件的每个 url,看其是否在刚才构建的 hash_set 中,如果是,那么就是共同的 url,存到文件里面就可以了 . 
方案 2:内存映射成 BIT 最小存储单元 . 
如果允许有一定的错误率,可以使用 Bloom filter,4G 内存大概可以表示 340 亿 bit . 将其中一个文件中的url使用Bloom filter映射为这340亿bit,然后挨个读取另外一个文件的url,检查是否与Bloom filter相同,如果是,那么该 url 应该是共同的 url(注意会有一定的错误率) . 
1比特(bit)=0.125字节(b)
1B=8 Bit
1B就是1个字节 . 

上千万或上亿数据(有重复),统计其中出现次数最多的钱N个数据 . 
方案1:上千万或上亿的数据,现在的机器的内存应该能存下 . 所以考虑采用hash_map/搜索二叉树/红黑树等来进行统计次数 . 然后就是取出前N个出现次数最多的数据了,可以用第2题提到的堆机制完成 . 

一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词,请给出思想,给出时间复杂度分析 . 
     方案1:这题是考虑时间效率 . 用trie树统计每个词出现的次数,时间复杂度是O(nle)(le表示单词的平准长度) . 然后是找出出现最频繁的前 10个词,可以用堆来实现,前面的题中已经讲到了,时间复杂度是O(nlg10) . 所以总的时间复杂度,是O(nle)与O(nlg10)中较大的 哪一个 . 
接下来,咱们来看第二种方法,双层捅划分 . 
双层桶划分----其实本质上还是分而治之的思想,重在"分"的技巧上!
  适用范围:第k大,中位数,不重复或重复的数字
  基本原理及要点:因为元素范围很大,不能利用直接寻址表,所以通过多次划分,逐步确定范围,然后最后在一个可以接受的范围内进行 . 可以通过多次缩小,双层只是一个例子 . 

2.5亿个整数中找出不重复的整数的个数,内存空间不足以容纳这2.5亿个整数 . 
有点像鸽巢原理,整数个数为2^32,也就是,我们可以将这2^32个数,划分为2^8个区域(比如用单个文件代表一个区域),然后将数据分离到不同的区域,然后不同的区域在利用bitmap就可以直接解决了 . 也就是说只要有足够的磁盘空间,就可以很方便的解决 . 
方案1:采用2-Bitmap(每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义)进行,共需内存2^32  2 bit=1 GB内存,还可以接受 . 然后扫描这2.5亿个整数,查看Bitmap中相对应位,如果是00变01,01变10,10保持不变 . 所描完事后,查看 bitmap,把对应位是01的整数输出即可 . 
方案2:也可采用与第1题类似的方法,进行划分小文件的方法 . 然后在小文件中找出不重复的整数,并排序 . 然后再进行归并,注意去除重复的元素 . 
方案3:
1.       将2.5亿个整数重写到一个文件里,内个整数占一行 . 
2.       进行对半排序重写到新的文件里,这样最后2.5亿个整数在文件里便是有序的了
3.       读取文本,将不重复的写到一个新的文件里即可 . 

5亿个int找它们的中位数 . 
   这个例子比上面那个更明显 . 首先我们将int划分为2^16个区域,然后读取数据统计落到各个区域里的数的个数,之后我们根据统计结果就可以判断中位数 落到那个区域,同时知道这个区域中的第几大数刚好是中位数 . 然后第二次扫描我们只统计落在这个区域中的那些数就可以了 . 
  实际上,如果不是 int是int64,我们可以经过3次这样的划分即可降低到可以接受的程度 . 即可以先将int64分成2^24个区域,然后确定区域的第几大数,在将该区 域分成2^20个子区域,然后确定是子区域的第几大数,然后子区域里的数的个数只有2^20,就可以直接利用direct addr table进行统计了 . 

Bloom filter
  适用范围:可以用来实现数据字典,进行数据的判重,或者集合求交集
  基本原理及要点:
   对于原理来说很简单,m位数组+k个独立hash函数 . 将hash函数对应的值的位数组置1,查找时如果发现所有hash函数对应位都是1说明存在,很明 显这个过程并不保证查找的结果是100%正确的 . 同时也不支持删除一个已经插入的关键字,因为该关键字对应的位会牵动到其他的关键字 . 所以一个简单的改进 就是 counting Bloom filter,用一个counter数组代替位数组,就可以支持删除了 . 
  还有一个比较重要的问题,如何 根据输入元素个数n,确定位数组m的大小及hash函数个数 . 当hash函数个数k=(ln2)(m/n)时错误率最小 . 在错误率不大于E的情况下,m 至少要等于nlg(1/E)才能表示任意n个元素的集合 . 但m还应该更大些,因为还要保证bit数组里至少一半为0,则m应该>=nlg(1 /E)lge 大概就是nlg(1/E)1.44倍(lg表示以2为底的对数) . 
  举个例子我们假设错误率为0.01,则此时m应大概是n的13倍 . 这样k大概是8个 . 
  注意这里m与n的单位不同,m是bit为单位,而n则是以元素个数为单位(准确的说是不同元素的个数) . 通常单个元素的长度都是有很多bit的 . 所以使用bloom filter内存上通常都是节省的 . 
  扩展:
   Bloom filter将集合中的元素映射到位数组中,用k(k为哈希函数个数)个映射位是否全1表示元素在不在这个集合中 . Counting bloom filter(CBF)将位数组中的每一位扩展为一个counter,从而支持了元素的删除操作 . Spectral Bloom Filter(SBF)将其与集合元素的出现次数关联 . SBF采用counter中的最小值来近似表示元素的出现频率 . 

腾讯面试题:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?
方案1:用位图/Bitmap的方法,申请512M的内存,一个bit位代表一个unsigned int值 . 读入40亿个数,设置相应的bit位,读入要查询的数,查看相应bit位是否为1,为1表示存在,为为0表示不存在 . 
方案 2:这个问题在《编程珠玑》里有很好的描述,大家可以参考下面的思路,探讨一
下:又因为 2^32 为 40 亿多,所以给定一个数可能在,也可能不在其中;这里我们把 40 亿个数中的每一个用 32 位的二进制来表示假设这 40 亿个数开始放在一个文件中 . 然后将这 40 亿个数分成两类:1.最高位为 0 2.最高位为 1 并将这两类分别写入到两个文件中,其中一个文件中数的个数<=20 亿,而另一个>=20 亿(这相当于折半了);与要查找的数的最高位比较并接着进入相应的文件再查找,再然后把这个文件为又分成两类:1.次最高位为 0 2.次最高位为 1并将这两类分别写入到两个文件中,其中一个文件中数的个数<=10 亿,而另一个>=10 亿(这相当于折半了); 与要查找的数的次最高位比较并接着进入相应的文件再查找 .  ....... 以此类推,就可以找到了,而且时间复杂度为 O(logn),方案 2 完 . 
附:这里,再简单介绍下,位图方法:使用位图法判断整形数组是否存在重复判断集合中存在重复
是常见编程任务之一,当集合中数据量比较大时我们通常希望少进行几次扫描,这时双重循环法就不可取
了 . 
位图法比较适合于这种情况,它的做法是按照集合中最大元素max创建一个长度为max+1的新数组,
然后再次扫描原数组,遇到几就给新数组的第几位置上1,如遇到 5 就给新数组的第六个元素置 1,这样下
次再遇到 5 想置位时发现新数组的第六个元素已经是 1 了,这说明这次的数据肯定和以前的数据存在着重
复 . 这种给新数组初始化时置零其后置一的做法类似于位图的处理方法故称位图法 . 它的运算次数最坏的
情况为 2N . 如果已知数组的最大值即能事先给新数组定长的话效率还能提高一倍 . 

日志分布在各个业务系统中,我们需要对当天的日志进行实时汇总统计,同时又能离线查询历史的汇总数据(PV UV IP)
解答:
1 通过flume将不同系统的日志收集到kafka中
2 通过storm实时的处理PV UV IP
3 通过kafka的consumer将日志生产到hbase中 . 
4 通过离线的mapreduce或者hive,处理hbase中的数据
 
Hive语言实现word count
解答:
1.建表
2.分组(group by)统计wordcount
select word,count(1) from table1 group by word;

实时数据统计会用到哪些技术,他们各自的应用场景及区别是什么?
解答:
flume:日志收集系统,主要用于系统日志的收集
kafka:消息队列,进行消息的缓存和系统的解耦
storm:实时计算框架,进行流式的计算 . 
 
有两个文本文件,文件中的数据按行存放,请编写MapReduce程序,找到两个文件中彼此不相同的行(写出思路即可)
解答:
写个mapreduce链 ,用依赖关系,一共三个mapreduce,第一个处理第一个文件,第二个处理第二个文件,第三个处理前两个的输出结果,第一个mapreduce将文件去重,第二个mapreduce也将文件去重,第三个做wordcount,wordcount为1的结果就是不同的

如果要存储海量的小文件(大小都是几百K-几M)请简述自己的设计方案
解答:
1.将小文件打成har文件存储
2.将小文件序列化到hdfs中

涉及Java基础部分
ArrayList Vector LinkedList的区别及其优缺点?HashMap HashTable的区别及优缺点?
解答:
ArrayList 和Vector是采用数组方式存储数据的,是根据索引来访问元素的,都可以根据需要自动扩展内部数据长度,以便增加和插入元素,都允许直接序号索引元素,但是插入数据要涉及到数组元素移动等内存操作,所以索引数据快插入数据慢,他们最大的区别就是synchronized同步的使用 . 
LinkedList使用双向链表实现存储,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入数度较快!
如果只是查找特定位置的元素或只在集合的末端增加 移除元素,那么使用Vector或ArrayList都可以 . 如果是对其它指定位置的插入 删除操作,最好选择LinkedList

HashMap HashTable的区别及其优缺点:
HashTable 中的方法是同步的 HashMap的方法在缺省情况下是非同步的 因此在多线程环境下需要做额外的同步机制 . 
HashTable不允许有null值 key和value都不允许,而HashMap允许有null值 key和value都允许 因此HashMap 使用containKey()来判断是否存在某个键 . 
HashTable 使用Enumeration ,而HashMap使用iterator . 
Hashtable是Dictionary的子类,HashMap是Map接口的一个实现类 . 

你们的数据是用什么导入到数据库的?导入到什么数据库?
处理之前的导入:通过hadoop命令导入到hdfs文件系统
处理完成之后的导出:利用hive处理完成之后的数据,通过sqoop导出到mysql数据库中,以供报表层使用 . 

你们业务数据量多大?有多少行数据?
开发时使用的是部分数据,不是全量数据,有将近一亿行 . 

你们处理数据是直接读数据库的数据还是读文本数据?
将日志数据导入到hdfs之后进行处理

你们写hive的hql语句,大概有多少条?
不清楚,我自己写的时候也没有做过统计

你们提交的job任务大概有多少个?这些job执行完大概用多少时间?(面试了三家,都问这个问题)
没统计过,加上测试的,会有很多

你在项目中主要的工作任务是?
利用hive分析数据
如何检查namenode是否正常运行?重启namenode的命令是什么?
通过命令和浏览器查看,通过脚本监控
[root@CentOSA ~]# hdfs haadmin -getServiceState nn1
active
[root@CentOSA ~]# hdfs haadmin -getServiceState nn2
standby
hadoop-daemon.sh start namenode
hdfs-daemon.sh start namenode
 

猜你喜欢

转载自blog.csdn.net/qq_34387470/article/details/114587810