面试相关内容04

面试相关内容04 杂项

Posted by ZBX on July 12, 2020

一致性hash

解决的问题

  • 动态节点增减:在分布式系统中,当增加或删除节点时,传统的取模哈希算法会导致大量数据迁移,增加网络通信压力。一致性哈希算法限制了数据迁移仅在两个节点之间,避免全局的网络问题。
  • 雪崩效应:传统哈希算法在节点数量变化时,可能导致数据倾斜,某些节点负载过重,而其他节点负载较轻。一致性哈希算法通过虚拟节点机制,均匀分布节点,减轻了这种问题,防止雪崩效应的发生。
  • 高效资源定位:一致性哈希算法通过路由表提高资源定位效率,使得查询次数与节点数不再成线性关系,适用于大规模分布式系统。

原理

  • 环形哈希环。首先,将所有节点映射到一个环形空间上,通常使用哈希值作为环的坐标。这个环被抽象为一个圆环,节点的哈希值映射到环上。
  • 虚拟节点。为了均匀分布数据,每个节点会对应多个虚拟节点。
  • 数据映射:当需要存储数据时,先对数据进行哈希计算,然后顺时针查找环上的第一个虚拟节点,该节点即为数据的目标节点。
  • 节点添加:只会影响新增节点与前一个虚拟节点之间的数据映射,只会影响删除节点与前一个虚拟节点之间的数据映射。
  • 总之,一致性哈希算法通过环形哈希环、虚拟节点和权重设置,实现了高效的数据分布和节点变化时的平滑迁移。

JVM内存区域

image-20240401194231693

  • 为什么要将永久代 (PermGen) 替换为元空间 (MetaSpace) : 整个永久代有一个JVM本身设置的固定大小上限,无法进行调整,而元空间使用的是本地内存,受本机可用内存的限制,虽然元空间仍旧可能溢出,但比原来出现的几率会更小。
  • 总的来说,JVM常量池中存储的是符号引用或字面量值,而不是对象本身。在运行时,这些引用会被解析为实际的对象或方法引用,同时JVM会确保合法性和一致性,以防止越权访问。
  • 主要是因为永久代(方法区实现)的 GC 回收效率太低,只有在整堆收集 (Full GC)的时候才会被执行 GC。

类的生命周期

  • 加载
    • 通过全类名获取定义此类的二进制字节流
    • 将字节流所代表的静态存储结构转换为方法区的运行时数据结构
    • 在内存中生成一个代表该类的Class对象,作为方法区这些数据的访问入口。
  • 链接
    • 验证
      • 文件格式验证、元数据验证、字节码验证、符号引用验证
    • 准备
      • 为类变更分配内存并设置类变更初始值的阶段
    • 解析
      • 虚拟机将常量池内的符号引用替换为直接引用的过程。
  • 初始化
    • 执行初始化<clinit>()方法的过程,是类加载的最后一步,这一步JVM才开始真正执行类中的定义的Java程序代码。
  • 使用
  • 卸载

事务的一致性,和分布式的一致性

  • 事务一致性是指在数据库中,事务的执行不会破坏数据的完整性和约束条件。当一个事务执行成功后,数据库的状态应该是从一个一致的状态转变为另一个一致的状态,
  • 分布式系统中的一致性是指在多个节点之间保持数据的一致性,即使在面对网络故障、节点故障或并发操作时也能保持数据的正确性。

MySQL解决幻影读

  • 间隙锁 (Gap Locking)。对查询范围内的间隙进行锁定,从而防止其他的事务在这个范围内插入新的数据。在事务中使用SELECT … FOR UPDATE语句,它会在读取数据的同时对查询的范围内的间隙进行锁定。
  • 一致性非锁定读。你可以使用SELECT … LOCK IN SHARE MODE语句或者SELECT … READ UNCOMMITTED语句来进行一致性非锁定读。这样一来,事务可以在读取数据的同时,其他事务仍然可以对相同的数据进行插入或修改操作,但是读取到的数据仍然是一致的

模板方法的钩子

钩子方法是一种特殊的方法,它被生命在抽象类中,但通常只有空的或者默认的方法实现。钩子方法的存在,可以让子类有能力对算法的的不同点进行挂钩。要不要挂钩由子类自行决定。

在抽象类中定义一个模板方法,这个模板方法中包含了一个算法的骨架,而算法的某些步骤则被设计为抽象方法和钩子方法。

Full GC线程数

Full GC的线程数量取决于垃圾回收器的类型和配置。例如,对于并行垃圾回收器(Parallel GC),Full GC的线程数量通常等于可用的CPU核心数。然而,对于串行垃圾回收器(Serial GC),Full GC只会使用一个线程。

横向越权和纵向越权解决思路

横向越权指的是攻击者尝试访问与他拥有相同(级别或角色)权限的用户的资源。

纵向越权指的是一个低级别(低权限)攻击者尝试访问高级别(高权限)用户的资源

横向越权(水平越权)

  • 建立用户和可操作资源的绑定关系,用户对任何资源进行操作时,通过该绑定关系确保该资源是属于该用户所有的。
  • 对请求中的关键参数进行间接映射,避免使用原始关键参数名,比如使用索引1代替id值123等。

纵向越权

  • 使用基于角色访问控制机制来防止纵向越权攻击,即预先定义不同的权限角色,为每个角色分配不同的权限,每个用户都属于特定的角色,即拥有固定的权限,当用户执行某个动作或产生某种行为时,通过用户所在的角色判定该动作或者行为是否允许。

spring AOP失效的场景

  1. 私有方法调用:AOP无法增强私有方法。
  2. 静态方法调用:AOP无法增强静态方法。
  3. final方法调用:AOP无法增强final方法。
  4. 类内部自调用:如果在同一个类中的一个方法调用另一个方法,那么被调用的方法上的AOP可能会失效。这是因为这种内部调用实际上是在目标对象上进行的,而不是在AOP代理对象上进行的。
  5. 内部类方法调用:AOP无法增强内部类的方法。

Mysql的最左匹配原则

MySQL的最左匹配原则是指在使用联合索引进行查询时,MySQL会从联合索引的最左边开始匹配

这个原则可以从联合索引的结构来解释。在InnoDB中,联合索引只有先确定了前一个(左侧的值)后,才能确定下一个值。如果有范围查询的话,那么联合索引中使用范围查询的字段后的索引在该条SQL中都不会起作用

在创建联合索引时,MySQL会首先对最左边的字段进行排序,然后在保证第一个字段有序的情况下,再对第二个字段进行排序,以此类推。

因此,当我们进行查询时,MySQL可以通过最左边的字段快速定位到具有相同 a 值的数据,然后在这些数据中,再通过 b 字段快速定位到具有相同 b 值的数据,最后再通过 c 字段找到最终的结果。

I/O多路复用

  • 非阻塞IO是一种调用方式,每次发起系统调用,只能检查一个文件描述符是否就绪,当文件描述符很多时,系统调用成本较高。
  • IO多路复用一种机制,允许一个线程同时处理多个IO请求。通过一个系统调用,可以检查多个fd的状态,避免了频繁的用户态和内核态的切换,减少了系统调用的开销。

消费之Rebalance机制

rebalance机制的目的

  • 当一个消费组在消费一个Topic时,kafka为了保证消息不被重复消费或遗漏,将每个分区唯一地分配给消费者。
  • 但是,如果某个消费者宕机或者有新的消费者加入,分区分配可能变得不公平,导致某些消费者负载过重,而其他消费者则没有负载。

Kafka会触发Rebalance机制时机:

  • 消费组成员发生变更,例如有新的消费者加入或有消费者宕机。
  • 消费者无法在指定的时间内完成消息的消费。
  • 订阅的Topic发生变化。
  • 订阅的Topic的分区发生变化。

ES写入的原理

image-20240304001621335

  1. 客户端发写请求的时,可以发往任意节点。这个节点就会变成coordinating node协调节点。
  2. 计算的点文档要写入的分片;计算时就采用hash取模的方式来计算。
  3. 协调节点就会进行路由,将请求转发给对应的primary sharding所在的datanode。
  4. datanode节点上的primary sharding处理请求,写入数据到索引库,并将数据同步到对应的replica sharing。
  5. 等primary sharding和replica sharding都保存好了文档之后,返回客户端相应,

ES查询数据的工作原理

  1. 客户端发请求给任意节点,这个节点就成为协调节点
  2. 协调节点将查询请求广播到每一个数据节点,这些数据节点的分片就会处理查询请求。
  3. 每个分片进行查询,将符合条件的数据放到一个队列中,并将数据的文档ID、节点信息、分片信息都返回给协调节点。
  4. 由协调节点将所有的结果进行汇总,并排序。
  5. 协调节点向包含这些文档ID的分片发送get请求,对应的分片将文档数据返回给协调节点,最后协调节点数据整合返回给客户端。

image-20240304001640291

全连接队列满了会影响半连接队列吗

  • SYN queue 队列长度由 /proc/sys/net/ipv4/tcp_max_syn_backlog 指定,默认为2048。
  • Accept queue 队列长度由 /proc/sys/net/core/somaxconn 和使用listen函数时传入的参数,二者取最小值。默认为128。 TCP三次握手第一步的时候如果全连接队列满了会影响第一步drop 半连接的发生。大概流程的如下:

     tcp_v4_do_rcv->tcp_rcv_state_process->tcp_v4_conn_request
     //如果accept backlog队列已满,且未超时的request socket的数量大于1,则丢弃当前请求  
       if(sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_yong(sk)>1)
           goto drop;
    

一个进程用kill 杀不死

ps -aux 看看STAT一栏,如果是Z,那就是zombie状态的僵尸进程

ps -ef grep 僵尸进程id , 可以找到父进程id,然后kill父进程即可

一个子进程的进程描述符在子进程退出时不会释放,只有当父进程通过wait() 和waitpid()获取子进程信息后才会释放,如果子进程退出,而父进程并没有调用wait()或waitpid(),那么子进程的进程描述符仍然保存在系统中,这种进程称为僵尸进程。

磁盘满了

df - h 查看磁盘使用的情况,查看对应的日志,按天切割,crontab定时,定期删除7天以前的日志。

是否有很多大于100M的大文件 : find / -size +100M xargs ls -lh

或者有很多文件,du -h > fs_du.log ,看看各个目录占用的磁盘空间带下

线上CPU100%,怎么排查问题

  1. top -c, 就可以显示进程列表,然后输入P,按照cpu使用率排序
  2. top -Hp 43987,就是输入那个进程id就好了,然后输入P,按照cpu使用率排序
  3. 定位哪段代码导致的cpu过高,将线程pid转成16进制,
    1. jstack 43987 grep ‘0x41e8’ -C5 –color

ConcurrentHashMap中TreeBin与TreeNode的区别

ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成。

Segment 实现了 ReentrantLock,所以 Segment 是一种可重入锁,扮演锁的角色。HashEntry 用于存储键值对数据。

static class Segment<K,V> extends ReentrantLock implements Serializable {
}

ConcurrentHashMap 取消了 Segment 分段锁,采用 CAS 和 synchronized 来保证并发安全。数据结构跟 HashMap1.8 的结构类似,数组+链表/红黑二叉树。

在Java1.8的实现中,TreeBin并不是红黑树的存储节点,TreeBin通过root属性维护红黑树的根结点,因为红黑树在旋转的时候,根结点可能会被它原来的子节点替换掉,在这个时间点,如果有其他线程要写这棵红黑树就会发生线程不安全问题,所以在ConcurrentHashMap中TreeBin通过waiter属性维护当前使用这棵红黑树的线程,来防止其他线程的进入。

所以在Java8中TreeBin并没有指向下一节点的引用,而是使用TreeNode来存储红黑树节点

static final class TreeBin<K,V> extends Node<K,V> {
        TreeNode<K,V> root;
        volatile TreeNode<K,V> first;
        volatile Thread waiter;
        volatile int lockState;
        // values for lockState
        static final int WRITER = 1; // set while holding write lock
        static final int WAITER = 2; // set when waiting for write lock
        static final int READER = 4; // increment value for setting read lock
...
}

Spring AOP 中 JDK 和 CGLib 动态代理哪个更快?

1、JDK动态代理具体实现原理:

  • 通过实现InvocationHandler接口创建自己的调用处理器;
  • 通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理;
  • 通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型;
  • 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数参入;

2、CGLib是一个强大、高性能的Code生产类库,可以实现运行期动态扩展java类,Spring在运行期间通过 CGlib继承要被动态代理的类,重写父类的方法,实现AOP面向切面编程呢。

3、性能对比

  • CGLib所创建的动态代理对象在实际运行时候的性能要比JDK动态代理高不少;

  • 但是CGLib在创建对象的时候所花费的时间却比JDK动态代理要多很多;

  • 因此,对于Singleton的代理对象或者具有实例池的代理,因为无需频繁的创建代理对象,所以比较适合采用CGLib动态代理,反正,则比较适用JDK动态代理。

#{}和${}的区别是什么?

  • #{}是sql的参数占位符,Mybatis把其替换成?,#{itme.name}的取值方式为使用反射从参数对象中获取item对象的name属性值。

  • ${}是properties文件中的变量占位符,属于静态文本替换。

HashMap负载因子为什么是0.75?

Ideally, under random hashCodes, the frequency of
* nodes in bins follows a Poisson distribution
* (http://en.wikipedia.org/wiki/Poisson_distribution) with a
* parameter of about 0.5 on average for the default resizing
* threshold of 0.75, although with a large variance because of
* resizing granularity. Ignoring variance, the expected
* occurrences of list size k are (exp(-0.5) * pow(0.5, k) /
* factorial(k)). The first values are:
*
* 0:    0.60653066
* 1:    0.30326533
* 2:    0.07581633
* 3:    0.01263606
* 4:    0.00157952
* 5:    0.00015795
* 6:    0.00001316
* 7:    0.00000094
* 8:    0.00000006
* more: less than 1 in ten million

在理想情况下,使用随机哈希吗,节点出现的频率在hash桶中遵循泊松分布,同时给出了桶中元素的个数和概率的对照表。 从上表可以看出当桶中元素到达8个的时候,概率已经变得非常小,也就是说用0.75作为负载因子,每个碰撞位置的链表长度超过8个是几乎不可能的。hash容器指定初始容量尽量为2的幂次方。HashMap负载因子为0.75是空间和时间成本的一种折中。

count(*) 和 count(1)和count(列名)区别

  • count(*)包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL
  • count(1)包括了忽略所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL
  • count(列名)只包括列名那一列,在统计结果的时候,会忽略列值为空(这里的空不是只空字符串或者0,而是表示null)的计数,即某个字段值为NULL时,不统计。

redis和zk分布式的对比

  1. redis分布式锁,其实需要自己不断去尝试获取锁,比较消耗性能

  2. zk分布式锁,获取不到锁,注册个监听器即可,不需要不断主动尝试获取锁,性能开销较小

  3. 另外一点就是,如果是redis获取锁的那个客户端bug了或者挂了,那么只能等待超时时间之后才能释放锁;而zk的话,因为创建的是临时znode,只要客户端挂了,znode就没了,此时就自动释放锁

  4. redis分布式锁比较麻烦,遍历上锁,计算时间等等,zk的分布式锁语义清晰实现简单

ThreadLocal

  • 每个Thread维护着一个ThreadLocalMap的引用
  • ThreadLocalMap是ThreadLocal的内部类,用Entry来进行存储
  • ThreadLocal创建的副本是存储在自己的threadLocals中的,也就是自己的ThreadLocalMap。
  • ThreadLocalMap的键值为ThreadLocal对象,而且可以有多个threadLocal变量,因此保存在map中
  • 在进行get之前,必须先set,否则会报空指针异常,当然也可以初始化一个,但是必须重写initialValue()方法。
  • ThreadLocal本身并不存储值,它只是作为一个key来让线程从ThreadLocalMap获取value。

死锁怎么检测

必要条件:不可剥夺、互斥、请求保持和循环等待。

防止:破坏必要条件

避免:银行家算法

死锁检测算法:

  1. 首先针对每种资源类型只有一个实例的情况。
    1. 构建资源分配图,采用深度优先遍历算法确定是否存在环路
  2. 第二种情况是每种资源类型还有多个实例的情况
    1. 构建向量矩阵,利用向量矩阵算法模拟资源分配。

美团一面

  1. 类的三大特性

  2. 继承和接口的区别

  3. Kafka的结构,高可用模型

  4. kafka的partition选举算法

    image-20240303204129966

  5. 怎么保证顺序消费

  6. volatile原理

    image-20240303204800137

  7. 怎么保证a++的线程安全性,有多少种方案 (synchronized、 ReentrantLock、AtomicInteger )

  8. synchronize原理

  9. ApplicationContext的内部结构

image-20240303205117345

  1. 如何解决循环依赖,(setter注入,而不是构造方法注入)

  2. Spring用到哪些设计模式

  3. 数据库存储引擎,Myisam 和InnoDB的区别

  4. 索引,索引失效

  5. 线程池怎么创建、线程池的执行过程、参数、拒绝策略

  6. 事务的特性(ACID),C是怎么保证的

快手一面

  1. kafka优点,为什么用kafka
  2. kafka为什么吞吐量高
  3. kafka怎么保证数据不丢失
  4. 限流算法,固定窗口,url+userId
  5. 接口归一化设计
  6. Java的基础数据类型,
  7. int几个字节,int数据范围,为什么,float的底层表示,0.2的表示
  8. 非受检异常和受检异常
  9. LinkedHashMap结构
  10. HashMap的put操作,原先的头插法的有什么问题,
  11. key的hashcode的扰动,低16位和高16位进行异或
  12. 头插法为什么换成尾插法
  13. 什么时候转成红黑树,什么是红黑树
  14. ConcurrentHashMap,put的过程,resize的过程
  15. Redis的数据对象
  16. SDS的优点
  17. zset = ziplist + skiplist ,Set的底层结构,整数集合,什么时候用压缩列表
  18. 跳表查询
  19. 归并排序是什么,链表的归并排序

快手二面

  1. 线程池,线程池为什么要有最大线程池和工作队列,为什么要两者,怎么考虑设计
  2. 抛硬币的先手赢的概率,1/2
  3. Trie
  4. BST

腾讯一面

  1. 为什么是16384

  2. 半连接队列,全连接队列

  3. redis rdb aof

  4. IO模型

  5. 那么全连接队列满了会影响半连接队列吗?

猿辅导二面

线程创建过程,