面试总结:1、字节一面

132 阅读10分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情

字节面试一面

1、三级缓存怎么实现一致性?

现在的CPU都是多核的,由于L1/L2cache是各个核心独有的,那么会带来多核心的缓存一致性问题,如果不能保证缓存一致性问题就会造成错误的结果。

那缓存一致性的问题具体是怎么发生的呢?以一个含有两个核心的 CPU 作为例子看一看。

假设 A 号核心和 B 号核心同时运行两个线程,都操作共同的变量 i(初始值为 0 )。 image.png

这时如果 A 号核心执行了 i++ 语句的时候,为了考虑性能,使用了前面所说的写回策略,先把值为 1 的执行结果写入到 L1/L2 Cache 中,然后把 L1/L2 Cache 中对应的 Block 标记为脏的,这个时候数据其实没有被同步到内存中的,因为写回策略,只有在 A 号核心中的这个 Cache Block 要被替换的时候,数据才会写入到内存里。

如果这时旁边的 B 号核心尝试从内存读取 i 变量的值,则读到的将会是错误的值,因为刚才 A 号核心更新 i 值还没写入到内存中,内存中的值还依然是 0。这个就是所谓的缓存一致性问题,A 号核心和 B 号核心的缓存,在这个时候是不一致,从而会导致执行结果的错误。

解决问题

要解决这一问题,就需要一种机制,来同步两个不同核心里面的缓存数据。要实现的这个机制的话,要保证做到下面这 2 点:

  • 第一点,某个 CPU 核心里的 Cache 数据更新时,必须要传播到其他核心的 Cache,这个称为写传播(Wreite Propagation
  • 第二点,某个 CPU 核心里对数据的操作顺序,必须在其他核心看起来顺序是一样的,这个称为事务的串形化(Transaction Serialization

总线

写传播的原则就是当某个 CPU 核心更新了 Cache 中的数据,要把该事件广播通知到其他核心。最常⻅实 现的方式是总线嗅探(Bus Snooping)。

MESI协议

MESI 协议其实是4个状态单词的开头字母缩写,分别是:

  • Modified,已修改
  • Exclusive,独占
  • Shared,共享
  • Invalidated,已失效

2、本地缓存修改后,同步到redis的频率?

默认情况下 Redis 没有开启 AOF(append only file)方式的持久化,可以通过 appendonly 参数开启:

appendonly yes

开启 AOF 持久化后每执行一条会更改 Redis 中的数据的命令,Redis 就会将该命令写入到内存缓存 server.aof_buf 中,然后再根据 appendfsync 配置来决定何时将其同步到硬盘中的 AOF 文件。

AOF 文件的保存位置和 RDB 文件的位置相同,都是通过 dir 参数设置的,默认的文件名是 appendonly.aof

在 Redis 的配置文件中存在三种不同的 AOF 持久化方式,它们分别是:

appendfsync always    #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync everysec  #每秒钟同步一次,显式地将多个写命令同步到硬盘
appendfsync no        #让操作系统决定何时进行同步

为了兼顾数据和写入性能,用户可以考虑 appendfsync everysec 选项 ,让 Redis 每秒同步一次 AOF 文件,Redis 性能几乎没受到任何影响。而且这样即使出现系统崩溃,用户最多只会丢失一秒之内产生的数据。当硬盘忙于执行写入操作的时候,Redis 还会优雅的放慢自己的速度以便适应硬盘的最大写入速度。

3、setNX实现分布式锁有什么问题?

blog.csdn.net/stackfuture… 贴一个看到的比较全的文章

4、Select ...... LIMIT 100000, 10有什么问题?

Select ...... limit 100000, 10语句执行较慢,是因为limit 10000,10的语法实际上是mysql查找到前10010条数据,之后丢弃前面的10000行,这个步骤其实是浪费掉的.

优化操作可以通过添加连续索引id,类似于select * from user where id>1000000 limit 100. 这样的效率非常快,因为主键上是有索引的,但是这样有个缺点,就是ID必须是连续的,并且查询不能有where语句,因为where语句会造成过滤数据.

5、Redis的ZSet底层结构。

  • Redis 支持更丰富的数据类型(支持更复杂的应用场景) 。Redis 不仅仅支持简单的 k/v 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。Memcached 只支持最简单的 k/v 数据类型。

  • Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而 Memcached 把数据全部存在内存之中。

  • Redis 有灾难恢复机制。 因为可以把缓存中的数据持久化到磁盘上。

  • Redis 在服务器内存使用完之后,可以将不用的数据放到磁盘上。但是,Memcached 在服务器内存使用完之后,就会直接报异常。

  • Memcached 没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;但是 Redis 目前是原生支持 cluster 模式的。

  • Memcached 是多线程,非阻塞 IO 复用的网络模型;Redis 使用单线程的多路 IO 复用模型。 (Redis 6.0 引入了多线程 IO )

  • Redis 支持发布订阅模型、Lua 脚本、事务等功能,而 Memcached 不支持。并且,Redis 支持更多的编程语言。

  • Memcached 过期数据的删除策略只用了惰性删除,而 Redis 同时使用了惰性删除与定期删除。


image.png

image.png

6、Redis的压缩列表的连锁更新的问题。

7、线程池是怎么存储线程的?

image.png

线程池的饱和策略有哪些?

如果当前同时运行的线程数量达到最大线程数量并且队列也已经被放满了任务时,ThreadPoolTaskExecutor 定义一些策略:

  • ThreadPoolExecutor.AbortPolicy 抛出 RejectedExecutionException来拒绝新任务的处理。
  • ThreadPoolExecutor.CallerRunsPolicy 调用执行自己的线程运行任务,也就是直接在调用execute方法的线程中运行(run)被拒绝的任务,如果执行程序已关闭,则会丢弃该任务。因此这种策略会降低对于新任务提交速度,影响程序的整体性能。如果您的应用程序可以承受此延迟并且你要求任何一个任务请求都要被执行的话,你可以选择这个策略。
  • ThreadPoolExecutor.DiscardPolicy 不处理新任务,直接丢弃掉。
  • ThreadPoolExecutor.DiscardOldestPolicy 此策略将丢弃最早的未处理的任务请求。

著作权归所有 原文链接:javaguide.cn/java/concur…

8、TCP和UDP的区别?

image.png

9、四次挥手

image.png

第一次挥手:

客户端向服务器请求断开连接

seq:我(client)这条数据的序列号是300 FIN:我(client)已经没有数据给你发送了 我要断开连接 当服务器收到客户端终止连接请求的时候需要做出响应即第二次挥手

第二次挥手:

服务器表示已经收到了客户端断开连接的请求

ack: 我(server)已经收到你(client)序列号为300的数据了 ACK:服务器表示你(client)断开连接的请求我(server)这边已经正确收到了 至此客户端到服务器的连接关闭,但服务器还存在部分数据没有发送给客户端的情况 当服务器发送完成数据会向客户端发送断开连接的请求即第三次挥手

第三次挥手:

服务器收到客户端断开连接且已经没有数据需要发送给客户端的时候向客户端请求断开连接

seq:我(server)这条数据的序列号400 FIN:我(server)已经没有数据给你发送了 我要断开连接 当客户端收到服务器终止连接请求的时候需要做出响应即第四次挥手

第四次挥手:

服务器表示已经收到了客户端断开连接的请求

ack: 我(client)已经收到你(server)序列号为400的数据了 ACK:客户端表示你(server)断开连接的请求我(client)这边已经正确收到了

至此服务器到客户端的连接关闭 客户端到服务器的连接也关闭了 四次挥手保证了双端正确的断开连接

10、怎么生成分布式id?

  • UUID
  • 数据库生成ID
  • Redis生成ID
  • 利用zookeeper生成唯一ID
  • snowflake雪花算法生成ID

11、IO多路复用介绍一下。

IO多路复用(IO Multiplexing)一种同步IO模型,单个进程/线程就可以同时处理多个IO请求。一个进程/线程可以监视多个文件句柄;一旦某个文件句柄就绪,就能够通知应用程序进行相应的读写操作;没有文件句柄就绪时会阻塞应用程序,交出cpu。多路是指网络连接,复用指的是同一个进程/线程。 一个进程/线程虽然任一时刻只能处理一个请求,但是处理每个请求的事件时,耗时控制在 1 毫秒以内,这样 1 秒内就可以处理上千个请求,把时间拉长来看,多个请求复用了一个进程/线程,这就是多路复用,这种思想很类似一个 CPU 并发多个进程,所以也叫做时分多路复用。

12、分布式信号量怎么实现?

信号量就是可以被 多个线程同时持有 的 一种同步对象 image.png

13、聚簇索引和非聚簇索引的区别。

聚簇索引即索引结构和数据一起存放的索引,并不是一种单独的索引类型。 InnoDB 中的主键索引就属于聚簇索引。

优点

  • 查询速度非常快 :聚簇索引的查询速度非常的快,因为整个 B+树本身就是一颗多叉平衡树,叶子节点也都是有序的,定位到索引的节点,就相当于定位到了数据。相比于非聚簇索引, 聚簇索引少了一次读取数据的 IO 操作。
  • 对排序查找和范围查找优化 :聚簇索引对于主键的排序查找和范围查找速度非常快。

缺点

  • 依赖于有序的数据 :因为 B+树是多路平衡树,如果索引的数据不是有序的,那么就需要在插入时排序,如果数据是整型还好,否则类似于字符串或 UUID 这种又长又难比较的数据,插入或查找的速度肯定比较慢。
  • 更新代价大 : 如果对索引列的数据被修改时,那么对应的索引也将会被修改,而且聚簇索引的叶子节点还存放着数据,修改代价肯定是较大的,所以对于主键索引来说,主键一般都是不可被修改的。

非聚簇索引即索引结构和数据分开存放的索引,并不是一种单独的索引类型。二级索引(辅助索引)就属于非聚簇索引。 MySQL 的 MyISAM 引擎,不管主键还是非主键,使用的都是非聚簇索引 优点

更新代价比聚簇索引要小 。非聚簇索引的更新代价就没有聚簇索引那么大了,非聚簇索引的叶子节点是不存放数据的

缺点

  • 依赖于有序的数据 :跟聚簇索引一样,非聚簇索引也依赖于有序的数据
  • 可能会二次查询(回表) :这应该是非聚簇索引最大的缺点了。 当查到索引对应的指针或主键后,可能还需要根据指针或主键再到数据文件或表中查询。