面试总结-622

前言

为了能很好地迎接今日的面试,我将 Guide 哥面试宝典 里 Java、数据库、常用框架花了两天一口气看完了。

内容太多了消化不了,就在我根本没有把握的状态下,开始了面试。

以下,我仅记录面试中我感觉到自己仍有不足的面试题。

这次的面试,我以及努力不让自己说话变磕巴了,但是有些时候还是会……

还是要多和人说话,否则连说话都不会了……

面试题

1. Kafka相比其他消息队列中间件,有什么优点?如何进行Kafka的顺序消费?怎么解决Kafka多消息重复消费问题?

性能吞吐量很大,可水平扩展,这是他的优点。

如何顺序消费?如何解决消息丢失问题?如何解决重复消费问题? 这是使用Kafka时经常会碰到的问题。

有些业务中,两个操作是一种‘原子性’操作,而这操作都通过消息队列发送,由相同或者不同实例去处理。如何处理顺序不同,可能会影响某些业务中关于数值方面的计算。

而如何顺序消费呢?

Kafka发送消息时,可以指定 topic, partition,key,data, 如果指定了partition,那么消息都会被发送到指定partition,并且同一个key消息可以保证只发送到同一个partition,

  1. 1个topic对应一个partition
  2. 发送消息时指定 key/partition分区(生产者方的策略),让同一个业务可以指定同一个分区,可以顺序消费

而如何解决消息丢失问题呢?

消息丢失分为两种情况:生产者丢失、消费者丢失。

生产者丢失,可能是由于网络问题等发送失败。可以在发送的回调中判断发送是否成功,即时进行重试。

而消费者丢失,可能是在消费者获取到消息,发送自动提交消息时,出现问题并没有实际消费。可以关闭自动提交,在消费完后,手动提交。

如何解决重复消费问题?

可以借助MySQL主键、唯一索引等的唯一性,来解决重复消费问题。

2. 我有一个表A和另一个表B,我想把表A中的a、b两列数据插入到表B,如何用一条SQL办到?

这种SQL的方式我甚至都没有听说过,还能在Insert语句中查询的。毕竟网上搜索SQL教程,Insert语句,都是直接数据的。

至于具体怎么办,如下

1
2
insert into db_a (col_a,col_b)
select col_a, col_b from db_b;

除此之外,还有 如果有数据就更新,没数据就插入,一条sql 的语句。

1
insert into db_a(a_id, col_a, col_b) value (v1,v2,v3) on duplicate key update col_a=v2,col_b=v3;

除此之外,还有 将两个人的姓名对调,一条sql

1
2
3
4
5
6
7
update db_a
set user_name = case
when id = 1 then (select user_name from db_a where id = 2)
when id = 2 then (select user_name from db_a where id = 1)
else name
end
where id = 1 or id = 2;

3. 简述一下冒泡排序的算法步骤

好久没有看排序算法,我竟然把冒泡算法和选择排序混为一谈了。

正好,让我们回顾一下常见的排序算法:

  • 选择排序
  • 冒泡排序
  • 快速排序
  • 希尔排序
  • 堆排序

选择排序,是每一步都选择当前行中最大的数值,放在最后,在经过 O((N^2)) 的复杂度之后,会将结果呈现出来。

而冒泡排序,则是修改了选择排序中每一步里的小步骤,冒泡排序是顺序比对,如果左边比右边大,则交换一下顺序,来达到最后一个获取到最大的值。

快速排序采用的是分治递归算法,首先通常取一个点作为中间点,小于这个点的放左边,大于的放右边,以此分成两部分,然后再分别对两部分做同样的操作。

堆排序使用到了一种叫 大顶堆 或者 小顶堆 的数据结构,主要用到了该数据结构的性质,可以进行排序。

希尔排序的基本思路是,一开始采取一定步长,位于一定步长内的两个元素进行选择排序,随后逐步将步长缩小,最后缩小到1,就完成了排序。

几种常见的算法相关性能对比如下:

排序性能比较

文章参考: 冒泡排序

文章参考: 快速排序

文章参考: 希尔排序

文章参考: 堆排序

4. 如何优化MySQL中大数据量的表?

存储优化

  • 表分区
  • 分表
  • 分库
  • 冷热归档

查询优化

  • 添加索引
  • 分库分表
  • 引入其他搜索快速的数据库,比如ElasticSearch

5. 你们项目里有了JWT,你们是怎么使用JWT的?怎么解决JWT可能存在的泄漏问题?

  1. 使用绑定IP、设备ID的形式验证请求是否属于JWT的目标签发人
  2. 使用短期失效的JWT,提供刷新JWT的方式,若JWT失效只能重新登录或者使用刷新令牌进行刷新

6. Nginx 怎么做负载均衡?

为避免单台服务器负载过重,可以使用nginx提供 upstream 模块来实现负载均衡。

1
2
3
4
5
6
upstream dyn_zuoyu {
server localhost:8081; #tomcat7.0
server localhost:8082; #tomcat8.0
server localhost:8083; #tomcat8.5
server localhost:8084; #tomcat9.0
}

配置完 upstream 后,配置到服务列表。

1
2
3
4
location ~ .*$ {
index index.jsp index.html;
proxy_pass http://dyn_zuoyu;
}

最基本的负载均衡如上所示。这种负载均衡成为 轮询 。请求会按时间顺序逐一分配到不同的后端服务器。

Nginx 支持的负载均衡策略有6种,如下。


名称 说明
轮询 默认方式,按时间顺序逐一分配
weight 权重方式分配
ip_hash 根据ip分配
least_conn 最少连接方式
fair(第三方) 根据响应时间分配
url_hash 根据URL分配

权重方式的配置,示例如下:

1
2
3
4
5
6
upstream dyn_zuoyu {
server localhost:8081 weight=2; #tomcat7.0
server localhost:8082; #tomcat8.0
server localhost:8083 backup; #tomcat8.5
server localhost:8084 max_fails=3 fail_timout=20s; #tomcat9.0
}

ip_hash 方式的配置,示例如下:

1
2
3
4
5
6
7
upstream dyn_zuoyu {
ip_hash;
server localhost:8081 weight=2; #tomcat7.0
server localhost:8082; #tomcat8.0
server localhost:8083 backup; #tomcat8.5
server localhost:8084 max_fails=3 fail_timout=20s; #tomcat9.0
}

least_conn 最少连接方式配置,示例如下:

1
2
3
4
5
6
7
upstream dyn_zuoyu {
least_conn;
server localhost:8081 weight=2; #tomcat7.0
server localhost:8082; #tomcat8.0
server localhost:8083 backup; #tomcat8.5
server localhost:8084 max_fails=3 fail_timout=20s; #tomcat9.0
}

第三方从策略包括 fairurl_hash,配置如下:

1
2
3
4
5
6
7
8
upstream dyn_zuoyu {
server localhost:8081; #tomcat7.0
server localhost:8082; #tomcat8.0
server localhost:8083; #tomcat8.5
server localhost:8084; #tomcat9.0
fair;
}

1
2
3
4
5
6
7
upstream dyn_zuoyu {
hash $request_uri;
server localhost:8081; #tomcat7.0
server localhost:8082; #tomcat8.0
server localhost:8083; #tomcat8.5
server localhost:8084; #tomcat9.0
}

参考文章: nginx负载均衡

写在后面

Guide 哥的面试宝典还没有看完,抓紧时间看完,然后把一些最佳实践最好实践一下。

这次的面试虽然大多数问题我都能回答一点,SQL那个问题我是真的头一次遇到,排序问题也是很久没看了。

希望面试能过吧,不过最简单的两个问题(SQL、排序)我都没有回答成功,估计这次也悬了。

总感觉,销售在远方朝着我挥手……


面试总结-622
https://natsufumij.cn/2024/06/22/interview-622/
作者
阿尔伯特
发布于
2024年6月22日
许可协议