大数据面试积累

1 Hadoop面试题

1.1 hadoop文件系统为什么不支持随机写?

1.hadoop设计的初衷是大规模数据的计算和olap分析, 应用场景区别与数据库,所以在HDFS设计时候就侧重在一次写入多次读取

2.假设现在我们在HDFS中加入了随机写.那么为了正确性我们需要保障的东西有哪些?

鉴于hadoop设计之初是想在廉价硬件上执行大规模的数据计算,HDFS是设计的必须支持CAP理论之分区容错性(partition tolerance)来抵消不可靠硬件随时会宕机的风险,那么在修改的时候,我们也是需要去namenode查询重新得到需要改写的文件的HDFS数据块的其他备份来修改以保证数据备份的一致性,中间过程增加了文件io和不同数据块备份间的网络io开销,并且在修改的过程中,还需要考虑修改完一个block之后,然后在修改备份block时候的各种异常回退的操作.
如果上一条的操作效率跟HDFS写入类似的话,那么在修改数据块数据时,如何保证不被其他试图修改同一个块的用户修改而被迫加锁的性能的损耗,将是一个新增的性能消耗点.这没有删除一个数据,然后重新写入的效率高
如果现在数据a在修改过程中(三个备份分别在datanode1,datanode2,datanode3),datanode1上的数据a已经修改成功,datanode2和datanode3还在同步的过程中,如果此时一个读请求由于网络路径比较短选择在datanode3上读取数据a, 此时你是要加锁不让读呢还是提供一个脏读数据呢?如果是第一种情况加速不让读提供强一致性分布式事务,不仅大大降低HDFS性能而且违背hadoop设计的初衷. 如果提供一个脏读数据,为什么不直接删除数据a然后重新插入修改后数据a,让用户有个正确的读取操作呢?
综上,首先hadoop初衷不是为了修改数据而是侧重查询,其次就是确实是可以实现HDFS修改,但是同时也要付出系统复杂性和性能的代价.这是一个trade-off的选择

1.2 入门

1.2.1 常用端口号

  • 3.x 版本
    HDFS-- 9870 (2.x中是50070)
    历史服务器–19888
    MapReduce-- 8088
    客户端-- 9000/8020

1.2.2 HDFS

1)读写流程
2)小文件问题
a.危害
1,占namenode元数据内存(不管文件多小,都要占150字节)
128g内存的namenode能存储多少个文件快
128g * 1024m * 1024kb * 1024字节 /150字节 约等于9亿
2,增加切片,进而影响增加maptask个数(1g),增加计算内存
b.优化手段
har归档;(类似于压缩)
CombineTextInputformat:改变切片
JVM重用
3) HDFS块大小
2.x 3.x 128m (本地模式32m)
1.x 64m
hive中的块大小:256m

1.2.3 MapReduce

1)shuffle及其优化
map方法之后,reduce方法之前
在这里插入图片描述

1.2.4 YARN

1)FIFO 容量调度器 公平调度器
2)默认哪个调度器;
Apache:默认容量调度器
CDH:默认公平调度器
3)FIFO 调度器
支持单队列,先进先出,同一时间只有一个任务执行
并发度非常低,在企业里面不会使用
4)容量调度器
支持多队列,由多个FIFO调度器组成,优先满足,先进入的任务
5)公平调度器
· 支持多队列,每个任务都公平享有资源,并发度最高
6)在企业里面怎么选择
如果电脑服务器性能比较好,对并发度要求比较高,先择公平调度器(上市公司,大厂)
如果电脑服务器性能比较差,对并发度要求不是特别高,选择容量调度器(中小型公司)
9)YARN工作机制
在这里插入图片描述

1.3 HDFS 的优缺点

1.3.1 HDFS优点

  • 高容错性: 数据自动保存多个副本,副本丢失后,会自动恢复。
  • 适合批处理: 移动计算而非数据、数据位置暴露给计算框架。
  • 适合大数据处理: GB、TB、甚至PB级数据、百万规模以上的文件数量,1000以上的节点规模。
  • 流式文件访问: 一次性写入,多次读取;保证数据的一致性。
  • 可构建在廉价的机器上: 通过多副本提高可靠性,提供了容错和恢复机制。

1.3.2 HDFS缺点

  • 不适合低延迟数据访问: 比如毫秒级、低延迟与高吞吐率。
  • 不适合小文件存储: 占用NameNode大量内存,寻址时间超过读取时间。
  • 不适合并发写入、文件随机修改: 一个文件只能有一个写入者,仅支持append。
    (如果发生随机写的过程,则给数据一致性带来挑战,设计到多个block的随机数据同步,随机写,以及数据的偏移量,校验和等信息都得变动,成本变大,性能大大降低,所以就设计成一次写入,多次读取的场景。)

1.4 MapReduce的调优方法

MapReduce优化方法主要从6个方面考虑:数据输入、Map阶段、Reduce阶段、IO传输、数据倾斜、常用的调优参数;

  1. 数据输入:

    (1)合并小文件,在执行MR任务前将小文件进行合并,大量的小文件会产生大量的map任务,增大map任务装载次数,而任务的装载比较耗时,从而导致MR运行缓慢。
    (2)采用combineTextinputformat来作为输入,解决输入端大量小文件的场景。
    附加点:

       默认情况下 TextInputformat 对任务的切片机制是按文件规划切片,不管文件多小,都会是一个单独的切片,都会交给一个 maptask,这样如果有大量小文件,就会产生大量的 maptask, 处理效率极其低下。
       如果已经是大量小文件在 HDFS 中了,可以使用另一种 InputFormat 来做切片(CombineTextInputFormat),它的切片逻辑跟 TextFileInputFormat 不同:它可以将 多个小文件从逻辑上规划到一个切片中,这样,多个小文件就可以交给一个 maptask。优先满足最小切片大小,不超过最大切片大小 。
  1. Map阶段:

    (1)减少溢写次数,通过调整io.sort.mb及sort.spill.percent参数值,增大触发溢写的内存上限,减少溢写次数,从而减少磁盘IO;
    (2)减少合并次数,通过调整io.sort.factor参数,增大merge的文件数目,减少merge的次数,从而缩短MR处理时间;
    (3)在map之后,不影响业务逻辑的前提下,先进行combine处理,减少IO。

  2. Reduce阶段:

    (1)合理设置map和reduce的数量,两个数量都不能太少或者太多;太少会导致task等待时间太长,延长处理时间;太多会导致map和reduce任务之间竞争资源,造成处理超市等错误。
    (2)设置map和reduce共存,调整,show start completedmaps参数,是map运行到一定程度后,reduce也开始运行,从而减少reduce等待时间。
    (3)规避使用reduce,因为reduce在用于连接数据集的时候会产生大量的网络消耗;
    (4)合理设置reduce端的buffer,可以通过设置参数来配置,使得buffer中的一部分数据可以直接输送到reduce,从而减少IO开销;MapReduce.Reduce.input.buffer.percent的默认为0.0,当值大于0时,会保留在指定比例的内存读buffer中的数据直接拿给reduce使用。

  3. IO传输

    (1)采用数据压缩的方式,减少任务的IO时间;
    (2)使用seq二进制文件。

=============================

2 Flume面试题

2.1 你是如何实现Flume数据传输的监控的

使用第三方框架Ganglia实时监控Flume的。

2.2 Flume的Source,Sink,Channel的作用是什么?你们Source是什么类型?

1.作用
(1)Source 组件是专门用来收集数据的,可以处理各种类型,各种格式的日志数据,包括avro,thrift,exec,jms,spooling,directory,netcat,sequence generator,syslog,http,legacy。
(2)Channel 组件是对采集的数据进行缓存,可以存放在Memory或File中。
(3)Sink 组件是用于把数据发送到目的地的组件,目的地包括HDFS,Logger,avro,thrift,ipc,file,Hbase,solr,自定义等。
2.我公司采用的Source类型为:
(1)监控后台日志:exec(测试用 )
(2)监控后台产生日志的端口:netcat

2.3 Flume的Channel Selectors

在这里插入图片描述

channel Selectors,可以让不同的项目日志通过不同的Channel到不同的Sink中去。官网文档上channel Selectors 有两种类型 Replicating Channel Selectors(default) 和Multiplexing channel Selectors。
这两种的区别是replicating会将Source过来的events发往所有的channel,而Multiplexing可以选择该发往哪些channel。

2.4 Flume 参数调优

1.Source
增加Source个数(使用Tair Dir Source时可增加FileGroups个数),可以增大Source的读取数据的能力。例如:当某一个目录产生的文件过多时需要将这个文件目录拆分成多个文件目录,同时配置好多个Source以保证source有足够的能力获取到新产生的数据。
batchSize参数决定Source一次批量运输到channel的event条数,适当调大这个参数可以提高Source搬运event到channel时的性能。
2.Channel
type选择memory时Channel的性能最好,但是如果Flume进程意外挂掉可能会丢失数据,type选择file时channel的容错性更好,但是性能上会比memory channel差。
使用file channel时dataDirs配置多个不同盘下的目录可以提高性能。
Capacity 参数决定Channel可容纳最大的event条数。transactionCapacity 参数决定每次Source王channel里面写的最大event条数和每次Sink从Channel里面读取的最大event条数。transactionCapacity需要大于Source和Sink的batch参数。
3.Sink
增加Sink的个数可以增加sink消费event的能力。Sink也不是越多越好,够用就行,过多的Sink会占用系统资源,造成系统资源不必要的浪费。
batchSize参数决定Sink一次批量从channel读取的event条数,适当调大这个参数可以提高Sink从channel搬出event的性能。

2.5 Flume的事务机制

Flume的事务机制(类似数据库的事务机制);Flume使用两个独立的实物分别负责从Source到channel,以及从channel到sink的时间传递。比如spooling directory source为文件的每一行创建一个事件,一旦事务中所有的事件全部传递到channel且提交成功,那么Source就将改文件标记为完成。同理,实物以类似的方式处理从channel到sink的传递过程,如果因为某种原因使得事件无法记录,那么事务将会回滚,且所有的事件都会保持到channel中,等待重新传递。

2.6 Flume采集数据会丢失吗?

根据Flume的架构原理,Flume是不可能丢失数据的,其内部有完善的事务机制,Source到channel是事务性的,channel到sink是事务性的,因此这两个环节不会出现数据的丢失,唯一可能丢失数据的情况是channel采用memory channel,agent宕机导致数据丢失,或者channel存储数据已满,导致Source不再写入,未写入的数据丢失。
Flume不会丢失数据,但是有可能造成数据的重复,例如数据已经成功由sink发出,但是没有接收到响应,sink会再次发送数据,此时可能会导致数据的重复。

3 Hive面试题

3.1 笔试题

题一

数据:
在这里插入图片描述
图中数据表示的是用户每天的访问次数

要求:
使用SQL统计出每个用户的累积访问次数,如下表所示:

在这里插入图片描述
原始数据:
u01 2017/1/21 5
u02 2017/1/23 6
u03 2017/1/22 8
u04 2017/1/20 3
u01 2017/1/23 6
u01 2017/2/21 8
u02 2017/1/23 6
u01 2017/2/22 4

第一步:建表

create table visitors(userId string,visitDate string,visitCount string) row format delimited fields terminated by ' ';

第二步:向表中插入数据

load data local inpath '/home/hivedemo/visitors' into table visitors;

第三步:分析查询语句
由查询结果可以得知,要查询用户Id,年月,每个月的访问次数,以及按时间排序的总访问次数。原始数据给的是年月日,首先把年月日格式转换成年月格式,
“yyyy/MM/dd” ==> “yyyy-MM”

(1) 先借助hive的日期函数把时间转换成时间戳格式

select unix_timestamp(visitDate,'yyyy/MM/dd') tmptime from visitors;

查询结果:
在这里插入图片描述

(2)再借助日期函数将时间戳格式转换成年月格式

select from_unixtime(unix_timestamp(visitDate,'yyyy/MM/dd'),'yyyy-MM') tmptime from visitors;

查询结果:
在这里插入图片描述

(3)再根据月份求每个月的访问次数

select v.userId,v.month,sum(v.visitCount) totalCount from (
select userId,
from_unixtime(unix_timestamp(visitDate,'yyyy/MM/dd'),'yyyy-MM') month,
visitCount from visitors) v group by v.userId,v.month;

查询结果:
在这里插入图片描述
最后一步:
到此为止,已经查询出来了 userId,month,和每个月的访问次数 totalCount,但是和目标结果还差一列,按月份排序的累计访问次数。
在这里就需要用到开窗函数。
相关的开窗函数解释及说明

命令解释
OVER()指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变而变化。
CURRENT ROW当前行
n PRECEDING往前n行数据
n FOLLOWING往后n行数据
UNBOUNDED起点,
UNBOUNDED PRECEDING表示从前面的起点
UNBOUNDED FOLLOWING表示到后面的终点
LAG(col,n,default_val)往前第n行数据
LEAD(col,n, default_val)往后第n行数据
NTILE(n)把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。
select v1.userId,v1.month,v1.totalCount,
sum(v1.totalCount) over(partition by userId order by month rows between UNBOUNDED PRECEDING and current row) from (
select v.userId,v.month,sum(v.visitCount) totalCount from (
select userId,
from_unixtime(unix_timestamp(visitDate,'yyyy/MM/dd'),'yyyy-MM') month,
visitCount from visitors) v group by v.userId,v.month) v1;

查询结果:
在这里插入图片描述
注意:
如果原始数据的日期格式是2020-10-16格式的,可以直接使用date_format()函数对日期进行格式化,省去了中间由时间戳格式转化的过程
那么查询语句就是:

select v1.userId,v1.month,v1.totalCount,
sum(v1.totalCount) over(partition by userId order by month rows between UNBOUNDED PRECEDING and current row) from (
select v.userId,v.month,sum(v.visitCount) totalCount from (
select userId,date_format(visitDate,'yyyy-MM') month,
visitCount from visitors) v group by v.userId,v.month) v1;

查询结果:

在这里插入图片描述

题二

描述:
每个顾客访客访问任何一个店铺的任何一个商品时都会产生一条访问日志,访问日志存储的表名为Visit,访客的用户id为user_id,被访问的店铺名称为shop,请统计:
1)每个店铺的UV(访客数)
2)每个店铺访问次数top3的访客信息。输出店铺名称、访客id、访问次数
原始数据:
u1 a
u2 b
u1 b
u1 a
u3 c
u4 b
u1 a
u2 c
u5 b
u4 b
u6 c
u2 c
u1 b
u2 a
u2 a
u3 a
u5 a
u5 a
u5 a
建表:

create table visit(userId string,shop string) row format delimited fields terminated by '\t';

从本地加载数据:

load data local inpath '/home/hivedemo/jdvisit' into table visit;

分析第一问:
第一问要问的是每个店铺的访客数(这里要的是访客数,不是访问量),所以应该先对店铺进行分组,在对访客id进行去重查询。

第一种查询方法–distinct去重

select shop,count(distinct userId) visitCount from visit group by shop;

查询结果:
在这里插入图片描述

但是,在Hive中 (distinct:如果表数据量大的话distinct会导致reduce数量过大(hive没有对distinct优化))

所以,第二种查询方法
(1) 先根据店铺和用户id进行分组

select shop,userId from visit group by shop,userId;

查询结果:
在这里插入图片描述

(2) 再根据分组之后的结果统计shop的数量

select shop,count(userId) from (select shop,userId from visit group by shop,userId) s group by shop;

查询结果:
在这里插入图片描述
可以看出,两种查询得到的结果是一样的,在数据量大的时候,第二种分组查询就会显得高效很多。

分析第二问
每个店铺的访问次数top3的访客信息。输出店铺名称,访客id,访问次数
–即店铺访问数量最多的三位的游客信息
1.先获取每家店铺中每位访客的访问次数

select shop,userId,count(userId) visitCount from visit group by shop,userId;

查询结果:
在这里插入图片描述

2.利用窗口函数针对visitCount进行分组排序形成一个新的字段rk–rank

select shop,userId,visitCount,row_number() over(partition by shop order by visitCount) rk from (
select shop,userId,count(userId) visitCount from visit group by shop,userId) tmp;

查询结果:
在这里插入图片描述

3.有了访客访问次数的排名之后,删选出前三名的房客信息

select shop,userId,visitCount from (
select shop,userId,visitCount,row_number() over(partition by shop order by visitCount) rk from (
select shop,userId,count(userId) visitCount from visit group by shop,userId) tmp) tmp2 where tmp2.rk<=3;

查询结果:
在这里插入图片描述

完成

题三

已知一个表orders,有如下字段:orderDate,orderId,userId,amount。请给出sql进行统计:数据样例:2017-01-01,10029028,1000003251,33.57。
(1)查询出 2017年每个月的订单数、用户数、总成交金额。
(2)给出2017年1月的新客数(指在1月才有第一笔订单)。
(3)给出每月的新客数(指每月才有第一笔订单)

原始数据:
2017-01-01,10029028,1000003251,33.57
2017-01-03,10029029,1000003252,42.12
2017-02-07,10029030,1000003253,38.26
2017-03-14,10029031,1000003254,29.17
2017-01-22,10029032,1000003255,35.55

建表

create table orders(orderDate string,orderId string,userId string,amount double) row formatdelimited fields terminated by ',';

加载数据

load data local inpath '/home/hivedemo' into table orders;

(1)分析第一问
先把时间转化成yyyy-MM格式,然后根据时间进行分组查询

select date_format(orderDate,'yyyy-MM') oDate,count(orderId),
count(userId),sum(amount) from orders group by date_format(orderDate,'yyyy-MM');

查询结果:
在这里插入图片描述

(2)分析第二问
先查询出1月份的客户,然后在根据userId分组,那么得到的就是这个月的新用户

select count(o.userId) from (select userId from orders 
where date_format(orderDate,'yyyy-MM')='2017-01' group by userId) o;

查询结果
在这里插入图片描述
说明一月份的新客户是3个

(3)分析第三问
这一问和第二问有点类似,不同点就是求每个月的新客数
先根据日期和userId进行分区查询,日期分组是为了求出每个月的总客户
userId分组是为了对userId进行去重,防止重复计算

select o.oDate,count(o.userId) from 
(select date_format(orderDate,'yyyy-MM') oDate,
userId from orders group by date_format(orderDate,'yyyy-MM'),userId) o
group by o.oDate;

查询结果
在这里插入图片描述
结束!

题四

有一个5000万的用户文件(userId,name,age),一个2亿记录的用户看电影的记录文件(userId,url),根据年龄段查询观看电影的次数并进行排序?
原始数据users
1 Tom 22
2 Jack 25
3 Alice 23
4 Bob 19
5 Andy 33
6 Bruth 28
7 Davie 16
8 Nike 27
9 Mike 40
10 ooe 27
11 Grace 30
12 Peter 25
13 Candy 36
14 Joo 29
15 Evie 32

原始数据movies
1 影片1
2 影片2
3 影片3
4 影片1
5 影片4
6 影片5
7 影片6
8 影片7
9 影片4
10 影片8
11 影片9
12 影片13
13 影片8
14 影片10
15 影片12
1 影片3
2 影片4
4 影片6
8 影片9

建表users

create table users(userId int,name string,age int) row format delimited fields terminated by ' ';

建表movies

create table movies(userId int,url string) row format delimited fields terminated by ' ';

加载数据

load data local inpath '/home/hivedemo/users' into table users;
load data local inpath '/home/hivedemo/movies' into table movies;

或者使用

insert into table forth_user values();

分析
(1)先根据用户id统计出每个用户的观影次数

select userId,count(url) con from movies group by userId;

查询结果
在这里插入图片描述

(2)在通过联合查询 得到一个新表

select u.userId userId,age,con from users u join (select userId,count(url) con from movies group by userId) m on u.userId = m.userId;

查询结果
在这里插入图片描述

(3)针对新表对年龄进行分段

select case when 0<age and age<20 then '0~20' 
when 20<=age and age<40 then '20~40' 
when 40<=age and age<=60 then '40~60' 
else 'others' end as age_group,con from (select u.userId,age,m.con from users u join (select userId,count(url) con from movies group by userId) m on u.userId = m.userId) m1;

查询结果
在这里插入图片描述

(4)年龄分段之后再对年龄段进行分组

select age_group,sum(con) Scon from (
select case when 0<age and age<20 then '0~20' 
when 20<=age and age<40 then '20~40' 
when 40<=age and age<=60 then '40~60' 
else 'others' end as age_group,con from (
select u.userId,age,m.con from users u join (select userId,count(url) con from movies group by userId) m on u.userId = m.userId) m1) m2 group by m2.age_group;

查询结果
在这里插入图片描述

(5)分组之后在针对观影次数进行排序,由于在hive中,order by 的列必须要是order by 中的列,在这里,group by 的列是age_group,而order by的列是Scon,所以不能在group by 后面跟order by;

select age_group,Scon from (
select age_group,sum(con) Scon from (
select case when 0<age and age<20 then '0~20' 
when 20<=age and age<40 then '20~40' 
when 40<=age and age<=60 then '40~60' 
else 'others' end as age_group,con from (select u.userId,age,m.con from users u join (select userId,count(url) con from movies group by userId) m on u.userId = m.userId) m1) m2 group by m2.age_group) m3 order by Scon desc;

查询结果
在这里插入图片描述
结束!

* 行列转换

*.1 行转列

原始数据:
上海 上海梅岭路
上海 上海大学
上海 徐家汇
上海 陆家嘴
上海 古北
北京 东四环
北京 朝阳区

建表:

create table cityinfo(cityname string,regionname string)
row format delimited fields terminated by '\t';

加载数据:

load data local inpath '/home/cityinfo' into table cityinfo;

分析:
利用concat_ws()(或者是concat())=>二者用法有一点区别。和collect_set(或者是collect_list)=>一个表示去重,一个不去重

select cityname,concat_ws(',',collect_set(regionname)) from cityinfo group by cityname;

查询结果:
在这里插入图片描述

*.2 列转行

将一列数据进行炸裂成多行
原始数据

上海 上海梅岭路,上海大学,徐家汇,陆家嘴,古北
北京 东四环,朝阳区
建表

create table city(cityname string,region array<string>) row format delimited fields terminated by '\t' collection items terminated by ',';

加载数据

load data local inpath '/home/city' into table city;

分析:

select cityname,r from city lateral view explode(region) tmp as r;

查询结果:
在这里插入图片描述
另外注意的是:
如果建表时的语句是

create table city(cityname string,region string) row format delimited fields terminated by '\t';

这里面的region是一个string格式的字符串,并非数组,所以不需要加,这两种的不同就是region这一列的格式不一样而已。

collection item terminated by '.';

但是在查询的时候,

select cityname,r from city lateral view explode(split(region,',')) tmp as r;

这里在执行explode()函数的时候,里面用了split()函数分割字符串形式region列
查询结果同上!!!

4 Zookeeper面试题

4.1 Zookeeper是什么?

Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache的项目。
从设计模式角度分析:Zookeeper是一个基于观察者模式设计的分布式服务管理库框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper就将负责同志已经在Zookeeper上注册的那些观察者做出响应的反应。
作用:
统一命名服务:
统一配置管理:
统一集群管理:
服务器节点动态上下线:
软负载均衡:

4.2 监听器原理(面试重点)

1.监听的原理

  • 1)首先要有一个main()线程
  • 2)在main线程中创建Zookeeper客户端,这时就会创建两个线程,一个负责网络连接通信(connet),一个负责监听(listener)。
  • 3)通过connect线程将注册的监听事件发送给Zookeeper。
  • 4)在Zookeeper的注册监听器列表中将注册的监听事件添加到列表中。
  • 5)Zookeeper监听到有数据或路径变化,就会将这个消息发送给listener线程。
  • 6)listener线程内部调用了process()方法。

2、常见的监听

  • 1)监听节点数据的变化
    get path [watch]
  • 2)监听子节点增减的变化
    ls path [watch]
    在这里插入图片描述

4.3 选举机制(面试重点)

1)半数机制:集群中半数以上机器存活,集群可用。所以 Zookeeper 适合安装奇数台
服务器。
2)Zookeeper 虽然在配置文件中并没有指定 Master 和 Slave。但是,Zookeeper 工作时,
是有一个节点为 Leader,其他则为 Follower,Leader 是通过内部的选举机制临时产生的。
3)以一个简单的例子来说明整个选举的过程。
假设有五台服务器组成的 Zookeeper 集群,它们的 id 从 1-5,同时它们都是最新启动的,
也就是没有历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依序启动,来
看看会发生什么,如图所示。
在这里插入图片描述
(1)服务器 1 启动,发起一次选举。服务器 1 投自己一票。此时服务器 1 票数一票,
不够半数以上(3 票),选举无法完成,服务器 1 状态保持为 LOOKING; (2)服务器 2 启动,再发起一次选举。服务器 1 和 2 分别投自己一票并交换选票信息:
此时服务器 1 发现服务器 2 的 ID 比自己目前投票推举的(服务器 1)大,更改选票为推举
服务器 2。此时服务器 1 票数 0 票,服务器 2 票数 2 票,没有半数以上结果,选举无法完成,
服务器 1,2 状态保持 LOOKING
(3)服务器 3 启动,发起一次选举。此时服务器 1 和 2 都会更改选票为服务器 3。此
次投票结果:服务器 1 为 0 票,服务器 2 为 0 票,服务器 3 为 3 票。此时服务器 3 的票数已
经超过半数,服务器 3 当选 Leader。服务器 1,2 更改状态为 FOLLOWING,服务器 3 更改
状态为 LEADING; (4)服务器 4 启动,发起一次选举。此时服务器 1,2,3 已经不是 LOOKING 状态,
不会更改选票信息。交换选票信息结果:服务器 3 为 3 票,服务器 4 为 1 票。此时服务器 4
服从多数,更改选票信息为服务器 3,并更改状态为 FOLLOWING; (5)服务器 5 启动,同 4 一样当小弟。

5 Kafka面试

5.1 *Kafka和传统消息队列有什么区别?

1.首先kafka会将接收到的消息分区(partition),每个主题(topic)的消息有不同的分区,这样一方面消息的存储就不会受到单一服务器存储空间大小的限制,另一方面消息的处理也可以在多个服务器上并行。

2.其次为了保证高可用,每个分区都会有一定数量的副本(replica)。这样如果有部分服务器不可用,副本所在的服务器就会接替上来,保证应用的持续性。

3.然后保证分区内部消息的消费有序性。

4.Kafka还具有consumer group的概念,每个分区只能被同一个group的一个consumer消费,但可以被多个group消费。
特点:分区、副本机制–可用性、分区内消费的顺序性、高吞吐量、集群负载均衡。

5.2 kafka的应用场景

5.3 *在高并发的情况下,如何避免消息丢失和消息重复

5.3.1 消息丢失解决方案

(1)对Kafka进行限速。
(2)启用重试机制,重试间隔时间设置长一些。
(3)kafka设置acks=all,即需要相应的所有处于ISR的分区都确认收到该消息之后,才算发送成功。

5.3.2 消息重复解决方案

(1)消息可以使用唯一id标识。
(2)生产者(ack=all 代表至少成功发送一次)。
(3)消费者(offset手动提交,业务逻辑成功处理后,提交offset)。
(4)落表(逐渐或者唯一索引的方式,避免重复数据)。
业务逻辑处理(选择唯一逐渐存储到Redis或者mongdb中,先查询是否存在,若存在则不处理,若不存在,先插入Redis或mongdb,在进行业务逻辑处理)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值