字节一面
先简单自我介绍一下吧
- ~ 固定问题,只要是面试就一定会问。现在总结的套路是一共回答以下几个问题:
~ 1)我是谁,哪年毕业的,哪年来北京的,来北京的工作履历;
~ 2)每段工作的工作内容,时间长的着重介绍一下。
Java的HashMap实现结构是什么?
- ~ 数组 + 链表,后转为数组 + 红黑树 / 链表;
是数组吗?还是哈希表?
- ~ 是数组,只不过元素在数组中的下标,是通过元素的hash值和size做摩尔运算获取的,这样可以保证不管差距多大的值都可以均匀的分布在指定容量的数组内,缺点是只要数组容量(HashMap容量发生变化,就会导致元素位置变化,需要reHash);
Java有使用什么框架么?
- ~ 公司使用的是Spring-Boot + Spring-Cloud;
Rpc请求和直接进行Http请求的区别是什么?
InnoDB的索引结构是什么样的?
- ~ B+树,每个节点中包含多个排好序的键值对;
~ 非叶子节点不包含实际的数据,只包含键和指向下一节点的指针。这使得非叶子节点比较小,可以更多地存储在内存中提高访问速度;
~ 叶子节点包含实际的数据,且叶子节点中的键值对通过链表连接在一起,按键值顺序存储,允许范围查找和顺序访问所有叶子节点;
2kw的表,主键是bigint类型的,他的主键索引树高度怎么计算?
- ~ B+树的高度计算公式为
log(表数据量)/log(每个叶子节点的索引数量)
,对于InnoDB来说,每个叶子节点的容量是固定的,为 16k ,同时每个节点又必须存储指向下一个节点的指针,一般为4byte
,所以对于大小是8byte
的bigint来说,每个子节点存储的数据为 16 * 1024 / ((8 + 4) * 8) ≈ 170,差不多为170个索引数据,所以B+树的高度是 log(20000000) / log(170) ≈ 3 约为3;
聚簇索引和非聚簇索引?
- ~ 1)聚簇索引叶子节点存储的是行数据;而非聚簇索引叶子节点存储的是聚簇索引标识;
~ 2)聚簇索引查询效率更高,而非聚簇索引需要进行回表查询,因此性能不如聚簇索引;
~ 3)聚簇索引一般为主键索引,而主键一个表中只能有一个,因此聚簇索引一个表中也只能有一个,而非聚簇索引则没有数量上的限制。
MySQL存时间类型的数据,可以用哪些数据类型?
- ~ timestamp和datetime:
timestamp | datetime | |
---|---|---|
占用空间 | 4byte | 原8byte,后改为5byte |
表示范围 | 1970~2038 | 0000~9999 |
时区分别 | 根据存取时区不同而不同 | 存什么取什么 |
应用场景 | 同一份数据在不同时区的展示内容不同(eg:飞机起飞时间) | 记录时间数据 |
一个页面请求后端接口比较慢,怎么排查?代码排查的话主要关注点是什么?
Redis的数据类型都有哪些?
- ~ string、list、hash、set、zset;
Redis的大Key、热Key的影响?如何解决?
-
~ 大Key:含有较大数据或含有大量成员、列表数的Key称之为大Key;
~ 大Key引发的问题:1)Redis内存不断变大引发OOM,或达到maxmemory引发写阻塞、无辜重要Key被逐出;2)Redis Cluset中的某个node内存远超其余node,但因Redis Cluset的数据迁移最小粒度为Key而无法将node上的内存均衡化;3)
大Key上的读请求使Redis占用服务器全部带宽,自身变慢的同时影响到该服务器上的其它服务;4)删除一个大Key造成主库较长时间的阻塞并引发同步中断或主从切换;
~ 如何发现大Key:包装并使用 redis-rdb-tools
~ 如何处理大Key:1)拆分某个特别大的Key;2)删除;3)集合类型的数据很容易快速增长,需要增添对应的监控; -
~ 热Key:某个Key接收到的访问次数显著高于其它Key;
~ 热Key引发的问题:1)热Key占用大量的Redis CPU时间使其性能变差并影响其它请求;2)Redis Cluset中各node流量不均衡造成Redis Cluster的分布式优势无法被Client利用;3)在抢购、秒杀活动中,由于商品对应库存Key的请求量过大超出Redis处理能力造成超卖;4)热Key的请求压力数量超出Redis的承受能力造成缓存击穿,此时大量请求将直接指向后端存储将其打挂并影响到其它业务;
~ 如何处理热Key:1)多个集群都复制一份热key,保证访问的流量是均衡的;2)读写分离,这样可以不断增加读节点缓解压力;3)缓存预热;4)增加容错机制,防止意料之外的热点数据直接打到数据库;
消息队列RabbitMq发消息一般多大的量?
- ~ 单消息频次不超100,消息积压总量不超2w;
RabbitMq里一个消息是怎么从发送到消费的?
-
~ RabbitMq消息流转大致分为两个大的流程:消息生产 -> 消息消费
-
~ 消息生产:
~ 1)建立连接:生产者连接到 RabbitMQ Broker 建立一个连接Connection
并开启一个信道Channel
;
~ 2)声明交换器:生产者声明一个交换器Exchange
,并设置交换机类型、是否持久化;
~ 3)声明队列:生产者声明一个队列Queue
,并设置是否持久化、是否自动删除、数量等;
~ 4)绑定交换器与队列:生产者通过路由键Routing-key
将交换器和队列绑定起来,并生成绑定Key,两者共同保证消息能正对地到达目标队列;
~ 5)消息发送至Broker:生产者发送消息至 RabbitMQ Broker,消息内容包含路由键、交换器、消息体等信息,如果没有找到对应绑定信息,根据生产者配置的属性选择丢弃还是回退给生产者;
~ 6)查找队列对应的交换器:根据接收到的Rounting-key
查找队列;
~ 7)消息存入队列:则将从生产者发送过来的消息存入相应的队列中;
~ 8)关闭信道; -
~ 消息消费:
~ 1)消费者连接到 RabbitMQ Broker:建立一个连接,开启一个信道(Channel);
~ 2)消费者向 RabbitMQ Broker请求消费相应队列中的消息;
~ 3)等待 RabbitMQ Broker 回应并投递相应队列中的消息;
~ 4)消费者发送确认ack表示正确接收消费了消息;
~ 5)RabbitMQ 从队列中删除相应己经被确认的消息;
注意:
1)并不是每次发送一条消息都会建立一个新的TCP连接;
2)RabbitMq会通过在一个连接里面增加 Channel 来尽可能地复用TCP连接,TCP 连接建立之后,客户端会创建一个 AMQP Channel;
3)每个 Channel 都会被指派唯一标识;
4)Channel 相当于建立在 Connection 上的 Virtual Connection,RabbitMQ 处理的每条 AMQP 指令都是通过 Channel 完成的;
5)当整体的流量因为Connection内的Channel过多而被限制时候, 可以开辟多 Connection ,将这些 Channel 均摊到这些 Connection 中;
多个机器上都有RabbitMq,那怎么确定发到哪个机器上呢?
- ~ 我不会,也没搜到,待补充…
RabbitMq队列消息是怎么存储的?
- ~ RabbitMQ存储层包含两个部分:队列索引、消息存储;其中存储两种类型数据:持久化消息、非持久化消息;
~ 持久化消息:在进入队列时写入磁盘 + 内存备份,当内存不足时,清除备份;
~ 非持久化消息:存于内存中,当内存不足时写入磁盘;
RabbitMq消息消费的可靠性、有序性是怎么保证的?
-
~ 可靠性:
~ 1. 生产者发的消息没有到达Broker:I. 开启RabbitMq事务,但是不建议,会降低吞吐量(没接收到的消息就卡在那了);II. springboot提供了RabbitMq的回调开关,开启后RabbitMq会回调confirm接口通知消息收到了,如果没收到可以做后续的处理;
~ 2. Mq存消息在内存里,还没触发落库,也没消费者消费,这个时候节点Down了,内存的消息没了:I. 设置消息的持久化;II. 合理利用Confirm机制,可以维护一个队列,当消息接受到Confirm之后,再从本地队列中删除;
~ 3. 消费者已经拿到了消息,但是还没开始处理,而且RabbitMq已经删除了队列中的消息:I. 使用手动ACK(默认情况下消费者接收到到消息,RabbitMQ会自动提交ACK,之后这条消息就不会再发送给消费者了,改为手动ACK后,可以视为return true
的时候才会认为消息消费成功,其他的情况消息可以进入失败队列进行重新消费; -
~ 有序性:一般Mq为了保证消费效率,一个队列都会配置多个消费者,有时候可能无法保证消息的有序消费;
~ 一般从消息从消费端进行保证;
讲一个对你来说最复杂的项目,业务背景、使用了什么技术手段?
ES有了解吗?
做一个算法题吧:如何判断一个二叉树B是不是二叉树A的子树?(空树不是任何树的子树)
暂无评论