面试技巧|2021 java面试题目(持续更新...)

  1. 简述分布式锁的几种实现方案
    三种实现方式
    数据库
    通过唯一索引,做排他锁(唯一性约束,这里如果有多个请求同时提交到数据库的话,数据库会保证只有一个操作可以成功)
    缺点:
    锁强依赖数据库,挂掉导致业务系统不可用
    锁不可重入
    锁没有失效
    redis
    redis加锁实现, SET key random_value NX PX 5000
    值得注意的是:
    random_value 是客户端生成的唯一的字符串
    NX 代表只在键不存在时,才对键进行设置操作
    PX 5000 设置键的过期时间为5000毫秒
    缺点:
    集群环境中也会出现,锁失效情况
    zookeeper
    在Zookeeper当中创建一个持久节点lock。当线程A想要获得锁时,需要在lock这个节点下面创建一个临时顺序节点 Lock1
    之后,线程A查找lock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock1是不是顺序最靠前的一个。如果是第一个节点,则成功获得锁
    线程B继续上一个步奏,线程B向排序仅比它靠前的节点Lock1注册Watchers,用于监听Lock1节点是否存在。这意味着Client2抢锁失败,进入了等待状态,一次类推就形成一个后面监听前面的队列
    缺点:
    创建删除节点性能不是很高;
    网络抖动也会出现琐失效
  2. 对外提供的接口如何保证幂等?
    token机制
    服务端提供了发送token的接口。在必须在执行业务前,先去获取token,服务器会把token保存到redis中。(微服务肯定是分布式了,如果单机就适用jvm缓存)。
    把token携带过去,一般放在请求头部。
    服务器判断token是否存在redis中,存在表示第一次请求,这时把redis中的token删除,继续执行业务。
    如果判断token不存在redis中,就表示是重复操作,直接返回重复标记给client,这样就保证了业务代码,不被重复执行。
    数据库去重表
    往去重表里插入数据的时候,利用数据库的唯一索引特性,保证唯一的逻辑
    分布式锁
  3. 简述一下秒杀系统的设计思路
    秒杀的痛点
    并发读(库存,前端静态资源),并发写(减库存),以及系统的高可用
    激增的流量,让他趋于平缓,把流量挡在系统上层,保护系统稳定
    客户端限流(前端提交按钮变灰),
    服务端限流(nginx限流,服务端限流最大请求数),
    降级(确保系统挂后,防止系统雪崩),
    队列削峰(逻辑分布式缓存库存信息,请求异步返回,服务层一步返回)
    https://www.jianshu.com/p/60319f5f4167
  4. JVM堆内存溢出之后,其它线程是否能继续工作? java中什么样的对象能够进入老年代,GC的过程 什么情况下发生fullGC,怎么避免发生fullGc
    能,溢出之前至少要发生一次full gc
    https://www.jb51.net/article/167945.htm
    超过年龄阀值对象(默认15)
    动态年龄判断,当s区的对象大小大于s区的50%,直接进入老年代
    大对象直接进入老年代
    显示调用system.gc()
    老年代空间不足
    方法区空间不足
  5. left join查询时,左右表过滤分别采用什么方式比较合理? Mysql innodb索引为什么不用hash、 二叉、 红黑 数据结构而采用B+Tree
    A Left Join B on (…)on 后面的条件是对B数据的过滤,
    如果要对A的数据或者联合之后的数据集进行过滤,则要把过滤条件放在where子句中
    hash:查找快,但是不适合范围查找
    有序数组:查找和范围查找都很快,但是插入就需要移动之后的所有数据
    二叉树:二分查找法,会有左倾或者右倾的情况,且不适合做范围查询
    平衡二叉树:避免的左倾和右倾,但是数据量大的时候,树高会很高,也就是IO次数会很多
    B-Tree:相比平衡二叉树,树高是降低了,但是还是不适合范围查询,范围查询需要遍历所有数据
    B+Tree:将所有数据都放到叶子节点,且叶子节点形成一个列表(可以做范围查询),非叶子节点只放键值,每个数据叶中的有效数据就多了,可以减少IO次数
    https://blog.csdn.net/weixin_39428938/article/details/77944939
    https://blog.csdn.net/weichi7549/article/details/108179677
  6. 消息队列如何做到消息幂等性?
    去重表
    分布式锁
  7. 简述一下API接口限流的思路
    Nginx前端限流
    按照一定的规则如帐号、IP、系统调用逻辑等在Nginx层面做限流
    常见的限流算法有:
    计数器 qps时间范围内清空
    令牌桶
    漏桶
    https://www.cnblogs.com/exceptioneye/p/4783904.html
  8. 尽可能多的列举出你所知道的Redis使用场景和用到的数据结构
    https://www.jianshu.com/p/40dbc78711c8
    热数据缓存
    限时业务的运用
    计数器
    排行榜
    分布式锁
    延时操作
    队列
    string list hash set sorted set
  9. 如何保证缓存与数据库的双写一致性?
    Cache Aside Pattern
    最经典的缓存+数据库读写的模式,就是 Cache Aside Pattern。读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。更新的时候,先更新数据库,然后再删除缓存
    很多种策略,双写,双删除
    https://www.cnblogs.com/semi-sub/p/13735800.html
  10. 缓存穿透、缓存击穿、缓存雪崩区别和解决方案
    缓存穿透:
    是指缓存和数据库中都没有的数据,而用户不断发起请求,导致数据库压力过大。
    解决方案:
    接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
    从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
缓存击穿:
是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
解决方案:
设置热点数据永远不过期。
互斥锁
缓存雪崩
是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机
解决方案:
缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
设置热点数据永远不过期
  1. 简述一下Spring AOP与AspectJ的不同之处
    静态 AOP 实现:
    AOP 框架在编译阶段对程序源代码进行修改,生成了静态的 AOP 代理类 AspectJ
    动态 AOP 实现:
    AOP 框架在运行阶段对动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP
AspectJ 和 JBoss,除了支持方法切点,它们还支持字段和构造器的连接点。
而 Spring AOP 不能拦截对对象字段的修改,也不支持构造器连接点,我们无法在 Bean 创建时应用通知
https://blog.csdn.net/qq_41981107/article/details/87920537
https://www.jianshu.com/p/872d3dbdc2ca
Spring Aop采用的动态织入,而Aspectj是静态织入。
静态织入:指在编译时期就织入,即:编译出来的class文件,字节码就已经被织入了。
动态织入又分静动两种,静则指织入过程只在第一次调用时执行;动则指根据代码动态运行的中间状态来决定如何操作,每次调用Target的时候都执行
从使用对象不同:
Spring AOP的通知是基于该对象是SpringBean对象才可以,而AspectJ可以在任何Java对象上应用通知
AspectJ可以对类的成员变量,方法进行拦截
  1. 列举一下MyBatis中使用到的设计模式及相关类名
    mybatis流程
    启动通过XmlConfigBuilder,SqlSessionFactoryBuilder(建造者模式)加载的配置文件(mybatis-config.xml,mapper.xml)
    XmlConfigBuilder.parse()构建Configure对象实例,并且SqlSessionFactoryBuilder构建SqlSessionFactory.open(); 创建SQLSession
    通过sqlsession获取到以及configuration获取到mapper代理对象,代理通过Executor执行sql,StatementHandler ,ParameterHandler ResultSetHandler
  2. ElasticSearch中文与拼音的搜索联想如何实现?
    Elasticsearch使用一种叫做倒排索引(inverted index)的结构来做快速的全文搜索。倒排索引由在文档中出现的唯一的单词列表,以及对于每个单词在文档中的位置组成,正序索引是一个索引对应一个文档字段
    使用elasticsearch实现的搜索联想就是通过分词器进行分词 生成tokens,然后通过倒排索引的方式来搜索出所在的文档,然后会显回来
    https://blog.csdn.net/denggouya9281/article/details/101223999
  3. Thread类中start()和run()方法有什么区别? 在并发情况下,Elasticsearch如果保证读写一致? Elasticsearch是如何实现Master选举的?怎么避免脑裂问题?
    start()方法来启动一个线程,JVM通过调用线程类的run()方法来完成实际的业务逻辑,当run()方法结束后,此线程就会终止,所以通过start()方法可以达到多线程(主线程开辟另一个独立线程)的目的,异步调用
    直接调用线程类的run()方法,会被当做一个普通的函数调用,同步调用,完成之后才能调用接着执行其他方法
    读写操作
    https://www.cnblogs.com/duanqibo/articles/12686420.html
    选举和脑裂
    https://blog.csdn.net/u012270682/article/details/106262379
  4. Java如何指定多个线程的执行顺序?
    join方式实现
    使用同步块和wait、notify的方法控制
    三个线程的执行次序为了控制执行的顺序,必须要先持有prev锁(也就前一个线程要释放其自身对象锁),然后当前线程再申请自己对象锁,两者兼备时打印。
    之后首先调用self.notify()唤醒下一个等待线程(注意notify不会立即释放对象锁,只有等到同步块代码执行完毕后才会释放),再调用prev.wait()立即释放prev对象锁,
    当前线程进入休眠,等待其他线程的notify操作再次唤醒
    ReentrantLock
    ReentrantLock搭配的通行方式是Condition
    https://blog.csdn.net/qq_29882585/article/details/108567964
  5. 简述一下Spring的Bean生命周期
    Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
    Bean实例化后对将Bean的引入和值注入到Bean的属性中
    如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
    如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
    如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
    如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
    如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
    如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
    此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
    如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。
  6. 微服务架构中使用统一配置中心有什么优缺点?列举一下你所了解的相关产品
    spring-config
    nacos
    zookeeper
    配置自动发布到应用
    配置支持版本控制
    支持不同环境隔离部署
    问题
    需保证高性能、高可用
  7. SQL优化的一般步骤,(追问SQL索引失效的一些情况)
    通过 show status 命令了解各种sql的执行频率(crud)
    定位执行效率较低的sql语句
    通过explain分析低效sql的执行计划
    通过 show profile 分析sql
    通过trace分析 优化器 如何选择执行计划
    确定问题并采取相应的优化措施
    SQL索引失效的一些情况
    联合索引,没有遵循左前缀原则
    is null 有时候不走索引
    索引字段进行在操作运算
    like以%开头
    索引列隐式转换
    or语句前后没有同时使用索引。当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效
  8. 现有一个需要关联7张表的复杂查询,该如何优化?
    关联键
    可适当设计冗余字段
    切分查询
    可将单条的多表关联查询分解为多条查询,对每一个表进行一次单表查询,然后将结果在应用程序中进行关联
    查询缓存
    或者job视图
  9. 简述一下Spring Boot配置的加载顺序
    优先级按照顺序由高到低,数字越小优先级越高
    1.在命令行中传入的参数。类似于java -jar -Dspring.profiles.active之类。
    2.SPRING_APPLICATION_JSON属性,该属性以JSON形式存储在系统环境变量中。
    3.java:comp/env中JNDI属性。
    4.Java的系统的属性,可通过System.getProperties()获得相关内容。
    5.操作系统中的环境变量。
    6.通过random.*配置的随机属性。
    7.位于当前应用jar包外,针对不同{profile}环境的配置文件内容。
    8.位于当前应用jar包内,针对不同{profile}环境的配置文件内容。
    9.位于当前应用jar包外的application.properties或application.yml配置内容。
    10.位于当前应用jar包内的application.properties或application.yml配置内容。
    11.在@Configuration注解修改的类中,通过@PropertySource注解定义的属性。
    12.应用默认属性,使用SpringApplication.setDefaultProperties定义的属性内容。
  10. 现有Spring Boot 1.X的微服务需要迁移到2.X,需要注意哪些方面的坑?
    一些配置类,有jdk版本
  11. 微服务架构如何保证安全性
    身份验证; 访问授权; 安全的进程间通信
  12. mvn install和mvn package的区别
    区别是maven package只是把包打在自己的项目下。
    maven install会把包打在maven本地仓库下,可以给依赖它的其他项目调用,并自动建立关联
  13. spring boot启动做的事情
https://www.cnblogs.com/theRhyme/p/11057233.html#_label4
  1. spring cloud starter是通过什么机制实现的
    工厂加载机制(Factory Loading Mechanism),自动装配,meta-info spring.factory
27排查线上问题的过程
28技术选型和比较
29ddd和解耦
30常用设计模式,设计模式思想和在项目中的使用
https://blog.csdn.net/qq_38024548/article/details/80480831
31各种中间件原理和核心源代码
32线程安全
33 gc过程及gc算法
gc新生代的氛围eden 区 s1 s2 区,s1 和s2发生from-to交换,就是所谓的minor gc ,
如果年龄对象大于15进入老年代,如果新生代的对象大于to区,直接进入老年代,老年代满了会发生一次full gc
https://www.jianshu.com/p/57c0710c4969
标记清除 碎片
标记压缩 压缩费时间
可达性分析算法 gc roots
引用计数 循环引用
复制算法 空间效率低
34线程池的使用&解决线程安全问题的办法及原理
https://blog.csdn.net/wolf909867753/article/details/77500625/
https://www.cnblogs.com/zincredible/p/10984459.html
常见线程池
①newSingleThreadExecutor 单个线程的线程池,即线程池中每次只有一个线程工作,单线程串行执行任务
②newFixedThreadExecutor(n) 固定数量的线程池,没提交一个任务就是一个线程,直到达到线程池的最大数量,然后后面进入等待队列直到前面的任务完成才继续执行
③newCacheThreadExecutor(推荐使用)可缓存线程池, 当线程池大小超过了处理任务所需的线程,那么就会回收部分空闲(一般是60秒无执行)的线程,当有任务来时,又智能的添加新线程来执行。
④newScheduleThreadExecutor 大小无限制的线程池,支持定时和周期性的执行线程
线程安全问题解决
https://www.cnblogs.com/aspirant/p/8657681.html
决多线程的并发安全问题,java无非就是加锁,具体就是两个方法
(1) Synchronized(java自带的关键字,同步互斥锁)
(2) lock 可重入锁 (可重入锁这个包java.util.concurrent.locks 底下有两个接口,分别对应两个类实现了这个两个接口:
(a)lock接口, 实现的类为:ReentrantLock类 可重入锁;
(b)readwritelock接口,实现类为:ReentrantReadWriteLock 读写锁)
也就是说有三种:
(1)synchronized 是互斥锁;
(2)ReentrantLock 顾名思义 :可重入锁
(3)ReentrantReadWriteLock :读写锁
35 Spring事务的原理,失效场景 Spring事务的原理,失效场景?为什么会失效
事务原理
https://blog.csdn.net/pengdeman/article/details/98507934
配置文件开启注解驱动,在相关的类和方法上通过注解@Transactional标识。spring 在启动的时候会去解析生成相关的bean,这时候会查看拥有相关注解的类和方法
并且为这些类和方法生成代理,代理对象通过拦截器 TransactionInterceptor 来使用拦截在逻辑处理之前添加事务,利用事务管理器AbstractPlatformTransactionManager 操作数据源 DataSource
提交或回滚事务,真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。
失效场景 https://www.cnblogs.com/javastack/p/12160464.html
数据库引擎不支持事务
没有被 Spring 管理
方法不是 public 的
自身调用问题
数据源没有配置事务管理器
异常被吃了
异常类型错误
36 多线程CPU处理方式
37 现场说一个场景,让设计架构和表,如何应对高并发
38 架构规划,为什么这样设计,扩展性,安全性等如何,具体体现在哪里
tcp粘包
https://www.cnblogs.com/kex1n/p/6502002.html
Mysql innodb索引,
mysql数据量超过千万级的操作,
redis分布式锁,数据类型以及各个数据类型的应用场景,
缓存雪崩,缓存穿透,缓存击穿的解决方案,
spring 事务,aop,
bean加载过程,
jvm内存模型,
jvm调优经验。
多线程交替打印ABC,
多线程生产者、消费者。
Spring cloud微服务架构。消息队列等。
tcp粘包:如果TCP接收数据包到缓存的速度大于应用程序从缓存中读取数据包的速度,多个包就会被缓存,应用程序就有可能读取到多个首尾相接粘到一起的包,发送方TCP默认使用Nagle算法接收方:CP接收到数据包缓存
(1)发送方
对于发送方造成的粘包问题,可以通过关闭Nagle算法来解决,使用TCP_NODELAY选项来关闭算法。
(2)接收方
接收方没有办法来处理粘包现象,只能将问题交给应用层来处理。
(2)应用层
应用层的解决办法简单可行,不仅能解决接收方的粘包问题,还可以解决发送方的粘包问题。
mysql的数据结构:
顺序查找: 最基本的查询算法-复杂度O(n),大数据量此算法效率糟糕。二叉树查找(binary tree search): O(log2n),数据本身的组织结构不可能完全满足各种数据结构。hash索引 无法满足范围查找。哈希索引基于哈希表实现,只有精确匹配索引所有列的查询才有效。二叉树、红黑树 [复杂度O(h)]导致树高度非常高(平衡二叉树一个节点只能有左子树和右子树),逻辑上很近的节点(父子)物理上可能很远,无法利用局部性,IO次数多查找慢,效率低。 todo 逻辑上相邻节点没法直接通过顺序指针关联,可能需要迭代回到上层节点重复向下遍历找到对应节点,效率低B-TREE 每个节点都是一个二元数组: [key, data],所有节点都可以存储数据。key为索引key,data为除key之外的数据。 检索原理:首先从根节点进行二分查找,如果找到则返回对应节点的data,否则对相应区间的指针指向的节点递归进行查找,直到找到节点或未找到节点返回null指针。 缺点:1.插入删除新的数据记录会破坏B-Tree的性质,因此在插入删除时,需要对树进行一个分裂、合并、转移等操作以保持B-Tree性质。造成IO操作频繁。 2.区间查找可能需要返回上层节点重复遍历,IO操作繁琐。B+Tree: B-Tree的变种 与B-Tree相比,B+Tree有以下不同点:非叶子节点不存储data,只存储索引key;只有叶子节点才存储data Mysql中B+Tree:在经典B+Tree的基础上进行了优化,增加了顺序访问指针。 在B+Tree的每个叶子节点增加一个指向相邻叶子节点的指针,就形成了带有顺序访问指针的B+Tree。这样就提高了区间访问性能

Redis有哪些数据类型:
redis主要有5种数据类型,包括String,List,Set,Zset,Hash
应用场景:
热数据缓存,
限时业务的运用,
计数器,
排行榜,
分布式锁,
延时操作,
队列
redis持久化:
rdb,
aof
Redis的过期键的删除策略:
定时过期(定时器),
惰性过期(访问判断过期),
定期过期(expires)
Redis的内存淘汰策略:
全局的键空间:
noeviction(写入报错),
allkeys-lru(移除最近最少使用的key),
allkeys-random(随机移除);
过期时间的键空间:
volatile-lru(最少使用),
volatile-random(随机),
volatile-ttl(更早时间移除)
Redis 事务
的本质是通过MULTI、EXEC、WATCH等一组命令的集合,
redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令
multi : 标记一个事务块的开始( queued )
exec : 执行所有事务块的命令 ( 一旦执行exec后,之前加的监控锁都会被取消掉 ) 
discard : 取消事务,放弃事务块中的所有命令
unwatch : 取消watch对所有key的监控
集群方案:
哨兵模式,
Redis Cluster 方案(服务端路由查询),
Redis 主从架构(一主多从,主负责写,并且将数据复制到其它的 slave 节点)
Redis实现分布式锁:
当且仅当 key 不存在,将 key 的值设为 value。
若给定的 key 已经存在,则 SETNX 不做任何动作,
SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。返回值:设置成功,返回 1 。设置失败,返回 0,设置过期时间
SET key random_value NX PX 5000 值得注意的是: random_value 是客户端生成的唯一的字符串 NX 代表只在键不存在时,才对键进行设置操作 PX 5000 设置键的过期时间为5000毫秒

Redis支持的Java客户端都有哪:Redisson、Jedis、lettuce等等,官方推荐使用Redisson
springcloud
常用组件:
Eureka:服务治理组件,包括服务端的注册中心和客户端的服务发现机制,
Zuul(gateway):API网关组件,对请求提供路由及过滤功能,
Ribbon,Feign:客户端的负载均衡,以及回调,IRule实现
Hystrix:服务容错组件,实现了断路器模式,为依赖服务的出错和延迟提供了容错能力;
bus用于传跨多个实例刷新配置的功能
config 用于传跨多个实例刷新配置的功能
微服务之间通讯:
远程过程调用(Remote Procedure Invocation)消息
mysql
自增列作为主键:InnoDB会选择主键作为聚集索引; 数据记录本身被存于主索引(一颗B+Tree)的叶子节点上
B树,每个节点都存储key和data,所有节点组成这棵树,并且叶子节点指针为nul,叶子结点不包含任何关键字信息,
B+树所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接,
所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字
B+比B树更适合实际应用中操作系统的文件索引和数据库索引:
B+的磁盘读写代价更低(具体信息的指针,因此其内部结点相对B树更小),
B±tree的查询效率更加稳定
联合索引:
key index (a,b,c). 可以支持a 、 a,b 、 a,b,c 3种组合进行查找,但不支持 b,c进行查找 .当最左侧字段是常量引用时,索引就十分有效
表分区,
是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成;
分表:
指的是通过一定规则,将一张表分解成多张不同的表。比如将用户订单记录根据时间成多个表。
分表与分区的区别在于:
分区从逻辑上来讲只有一张表,而分表则是将一张表分解成多张表
表分区有什么好处:
存储更多数据; 优化查询,分区表更容易维护,避免某些特殊的瓶颈
MySQL支持的分区类型
RANGE分区; LIST分区; HASH分区; KEY分区
mysql隔离级别:
Read uncommitted (读未提交):最低级别任何情况都无法保证。
Read committed (读已提交):可避免脏读的发生。不可重复读
Repeatable read (可重复读):可避免脏读、不可重复读的发生。mysql默认 幻读
Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
MySQL优化:
开启查询缓存,优化查询;
explain你的select查询;
通过 show status 命令了解各种sql的执行频率,定位执行效率较低的sql语句;
通过explain分析低效sql的执行计划;
通过 show profile 分析sql;
通过trace分析 优化器 如何选择执行计划; 确定问题并采取相应的优化措施
SQL索引失效的一些情况:
联合索引,没有遵循左前缀原则
is null 有时候不走索引
索引字段进行在操作运算
like以%开头
索引列隐式转换
or语句前后没有同时使用索引。当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效
MyISAM 和 InnoDB 的区别:
InnoDB支持事务,MyISAM不支持;
InnoDB支持外键,而MyISAM不支持;
InnoDB是聚集索引;
Innodb不支持全文索引,而MyISAM支持全文索引
mq优点:
解耦
异步
削峰
避免重复消费:
每个消息都会有唯一的消息 id。
业务表添加约束条件; 添加消息表;
redis 或者 zookeeper 的分布式对消息 id 加锁
kafka与zookeeper的关系
kafka用zk做meta信息存储,consumer的消费状态,group的管理以及 offset的值
kafka producer ACK:
1(默认) 数据发送到Kafka后,经过leader成功接收消息的的确认,就算是发送成功了。在这种情况下,如果leader宕机了,则会丢失数据。
0 生产者将数据发送出去就不管了,不去等待任何返回。这种情况下数据传输效率最高,但是数据可靠性确是最低的。
-1 producer需要等待ISR中的所有follower都确认接收到数据后才算一次发送完成,可靠性最高。当ISR中所有Replica都向Leader发送ACK时,leader才commit,这时候producer才能认为一个请求中的消息都commit了。"
Kafka中的ISR、AR又代表什么?ISR的伸缩又指什么:
ISR:In-Sync Replicas 副本同步队列
AR:Assigned Replicas 所有副本
ISR是由leader维护,follower从leader同步数据有一些延迟(包括延迟时间replica.lag.time.max.ms和延迟条数replica.lag.max.messages两个维度,
当前最新的版本0.10.x中只支持replica.lag.time.max.ms这个维度)
任意一个超过阈值都会把follower剔除出ISR, 存入OSR(Outof-Sync Replicas)列表,新加入的follower也会先存放在OSR中。AR=ISR+OSR。
kafka 为什么那么快:
顺序写;零拷貝;批處理,pull
Kafka中的消息是否会丢失和重复消费
针对消息丢失:同步模式下,确认机制设置为-1,即让消息写入Leader和Follower之后再确认消息发送成功;
异步模式下,为防止缓冲区满,可以在配置文件设置不限制阻塞超时时间,当缓冲区满时让生产者一直处于阻塞状态;
针对消息重复:
将消息的唯一标识保存到外部介质中,每次消费时判断是否处理过即可
Kafka中是怎么体现消息顺序性的:
partition中的消息在写入时都是有序; 每个partition只能被每一个group中的一个消费者消费,保证了消费时也是有序的
producer消息生产者:指消息kafka broker发送数据的客户端
consumer消息消费者:向kafka broker 取数据的客户端
topic:主题,可理解为一个队列
cocnsumer group:消费者组,多个消费者共同消费一个topic消息
broker就是一台kafka服务器,一个集群中有多个broker,一个broker有多个topic
partition一个topic可以分为多个partition,每个partition是一个有序队列,partition中的消息都有一个有序的id(offset),
kafka只保证一个partition中的消息的有序性,不能保证一个topic或者多个partition中消息的有序性
offset存储文件按照offset.kafka来命名,用offset命名的好处是方便查找
生产流程:
producer采用推(push)模式将消息发布到broker,每条消息都被追加**(append)到分区(patition)**中,属于顺序写磁盘(顺序写磁盘效率比随机写内存高,零拷贝,kafka分段日志(segment),kafka预读(read ahead),后写(Write behind)保障kafka吞吐率)
消费过程:
consumer链接zookeeper获取kafka集群的相关信息(主要是消费数据的offset值保存在zookeeper,在后期版本之后offset可放在集群中不用放在zookeeper)
消费者pull拉取kafka集群中指定的topic分区的信息消费,分批次取数据(缓冲数据多条数据),一个分区只能一个消费者消费,但是一个消费者可以消费多个分区,
group consumer(消费者组)中包含的多个消费者里面的offset统一管理同组消费者成员消费后期添加消费者消费,集群可做再平衡,
消费者组从新从zookeeper获取集群信息,再平衡在kafka集群中进行
zookeeper= 文件系统+通知机制;
特点
一个leader ,多个follower组成的集群
集群中只要半数以上的节点存活,zookeeper集群就能正常服务
全局数据一致,每个server保存一份相同的数据副本,client无论链接那个server,数据都是一致的
更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行
数据更新原子性,要么成功要么失败
实时性,一定时间范围内,client能读到最新数据
zookeeper文件结构
数据模型的结构与Unix文件系统很相似,整体上可以看作是一个树,每个节点称作一个ZNode,每个ZNode默认能够存储1mb的数据,每个ZNode都可以通过其路径唯一标识
半数机制:
集群中只要半数以上机器存活,集群可用,集群适合奇数台服务器,server启动没有历史数据的情况下,先自投,选举状态一直是looking,
集群相互交换选举信息,所以后加的server票数更多,超过半数以上的投票作为leader ,其他为follower
持久(Persistent)节点 客户端和服务端断开后节点不删除
临时(Ephemeral)节点 客户端和服务端断开后节点自删除
临时有序,持久有序
【面试技巧|2021 java面试题目(持续更新...)】zookeeper监听器原理
创建一个main线程
其中在main线程中创建一个zookeeper的客户端,同时这个客户端拥有两个线程,一个负责网络通信(connection)一个负责监听(listener)
通过connection将注册的监听事件发送给zookeeper
在zookeeper的注册监听器列表将注册的监听事件添加到列表中
zookeeper监听到数据或者路径变化,就会将这个消息告诉给listener线程
listener就会调用相应的process()方法处理

    推荐阅读