部分面试笔记

1.数据一致性问题

1.1redis一致性(容灾)

原面试题:redis集群数据一致性如何保证,如果挂了一台机会怎样?可以从故障检测和从节点选举说起。

故障检测

集群中每个节点都会定期的向集群中的其他节点发送PING信息。

如果在一定时间内,发送ping的节点A没有收到某节点B的pong回应,那么A将B标识为pfail。

A在后续发送ping时,会带上B的pfail信息,通知给其他节点。

如果B被标记为pfail的个数大于集群主节点个数的一半(N/2 + 1)时,B会被标记为fail,A向整个集群广播,该节点已经下线。 其他节点收到广播,标记B为fail。(又是过半原则)

从节点选举

每个从节点,根据自己对master复制数据的offset(偏移量),来设置一个选举时间,offset越大的从节点,选举时间越靠前,

优先进行选举。

所有的Master开始slave选举投票,给要进行选举的slave进行投票,如果大部分master node(N/2 +1)都投票给了某个从节点,那么选举通过,那个从节点可以切换成master。 RedisCluster失效的判定: 1、集群中半数以上的主节点都宕机(无法投票) 2、宕机的主节点的从节点也宕机了(slot槽分配不连续)

当slave 收到过半的master 同意时,会成为新的master。此时会以最新的Epoch 通过PONG 消息广播 自己成为master,让Cluster 的其他节点尽快的更新拓扑结构(node.conf)。

1.2mysql数据一致性

‘mysql主从复制,并不能保证数据的实时一致性,你可以通过修改my.conf文件,启用mysql主从复制中的半同步复制和异步复制,来减少数据的延迟。

可以通过shardingjdbc或者shardingproxy来实现数据一致性(或者减少延迟),shardingjdbc的特性如下:

1.提供一主多从的读写分离配置。仅支持单主库,可以支持独立使用,也可以配合分库分表使

2.独立使用读写分离,支持SQL透传。不需要SQL改写流程
3.同一线程且同一数据库连接内,能保证数据一致性。如果有写入操作,后续的读操作均从主
库读取。
4.基于Hint的强制主库路由。可以强制路由走主库查询实时数据,避免主从同步数据延迟。

2.jvm gc

gc流程回顾

1.首先,eden区满时触发第一次GC,把还活着的对象拷贝到S0区,当eden去再次触发GC的时候会扫描eden区和S0区,对这两个区域进行垃圾回收,经过这次回收后还存活的对象,则直接复制到S1区,

同时把这些对象的年龄+1(如果有对象的年龄达到了老年的标准,默认15次垃圾回收,这个对象进入老年区)

2.新生代占1/3,Eden区占新生代的8/10空间,s0和s1分别占用1/10。

3.然后,清空eden区和s0的对象,也就是复制之后有交换,谁空谁是s1

4.最后,s1和s0互换,原s1成为下一次GC的s0区。

标记清除算法

不会浪费空间,但是会产生内存碎片。

CMS收集器

CMS(Concurrent Mark Sweep)收集器是⼀种以获取最短回收停顿时间为⽬标的收集器。它非常符合
在注重⽤户体验的应⽤上使⽤。
CMS(Concurrent Mark Sweep)收集器是HotSpot虚拟机第⼀款真正意义上的并发收集器,它第⼀次实
现了让垃圾收集线程与⽤户线程(基本上)同时⼯作。

cms采用了标记清除算法,仍然会产生内存碎片

cms 4个步骤

初始标记,并发标记,重新标记,并发清除。

G1收集器

G1 (Garbage-First)是⼀款⾯向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器.
以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征.

与CMS的“标记–清理”算法不同,G1从整体来看是基于“标记整理”算法实现的收集器;

从局部上来看是基于“复制”算法实现的。

G1不会产生内存碎片。

G1主要是改变新生代和老年代,变成了一个个大小一样的region

每个region从1m到32m不等。

G1的核心思想是将整个堆内存分成大小相同的子区域(最多可以分2048个region)

G1 4个步骤

初始标记,并发标记,最终标记,筛选回收

垃圾回收器种类

串行,并行,并发,G1

2.1聊聊full gc

  1. java内存模型分为新生代和老年代,元空间(永久代)
  2. 新生代分为Eden区和2个Survivor区。
  3. Eden区最大,当快要满时,执行young gc(minor gc),将存活对象放入Survivor A区。
  4. Eden区继续向外提供服务,当再次满时,对Eden区和Survivor A区执行垃圾回收,
    使用复制清除算法将存活对象存入Survivor B区
  5. 当Survivor区被填满,某些对象在经历过15次垃圾回收后,还存活的话,将这部分对象存入老年代。
  6. 老年代内存填满时,执行full gc对老年代进行垃圾回收。

3.mysql篇

3.1mysql存储引擎

myisam引擎

myisam引擎不支持事务,不支持外键,索引和数据文件分开,这样子内存中可以缓存更多的索引,对查询性能会更好。
适用于经典的报表系统,现在基本不用这种了。

innodb引擎

支持事务,聚簇索引,myisam所有的索引都指向数据,innodb的索引都指向主键,如果innodb表中没有主键,mysql会自动为该表生成。
建议innodb的主键或者索引值为连续的或者递增的。

3.2聊聊B+树

  • 一个节点存储多个索引值,存储效率高
  • 树高度低
  • 一页存储更多的数据,减少磁盘io。
  • 减少磁盘定位(读写数据,磁盘先定位,再磁盘移动读写,减少定位次数)

3.3mvcc

通过undo log实现记录快照存储。RC级别每次都获取最新快照读,RR后续读取使用的是第一次的快照读。

3.4深度分页问题

在查询记录时,如果查询记录量相同,偏移量超过100后就开始随着偏移量增大,查询时间
急剧的增加。(这种分页查询机制,每次都会从数据库第一条记录开始扫描,越往后查询越慢,而
且查询的数据越多,也会拖慢总查询速度。)

简单理解:mysql的limit,并不是跳过数据库的n条记录,而是每次查询都是从第一条开始扫描。

注意:es同样有深度分页问题,这个一般是使用scoll api来解决。

注意:redis在遍历大key时,同样也有类似的问题,老师在课件上补了一个游标的查询方案,scan api。

分页优化方案
第一步:利用覆盖索引优化

select * from user limit 10000,100;
select id from user limit 10000,100;

第二步:利用子查询优化

select * from user limit 10000,100;
select * from user where id>= (select id from user limit 10000,1) limit 100;

原因:使用了id做主键比较(id>=),并且子查询使用了覆盖索引进行优化

4.架构篇,如何设计一个秒杀系统

关键点:消息队列,分布式锁,mysql乐观锁,限流思路

4.1关于架构选型,为什么要使用消息队列

应用解耦,流量削峰,数据分发
应用系统如果遇到系统请求流量的瞬间猛增,有可能会将系统压垮。有了消息队列可以将大量请求
缓存起来,分散到很长一段时间处理,这样可以大大提到系统的稳定性和用户体验。
举例:业务系统正常时段的QPS如果是1000,流量最高峰是10000,为了应对流量高峰配置高性能
的服务器显然不划算,这时可以使用消息队列对峰值流量削峰

4.2各种消息队列对比

主要对比rocketmq和kafka。
1.rocketmq使用nameserver实现broker发现,而kafka则需要依赖zookeeper
2.rocketmq支持推拉模式,推模式采用长轮训实现,而kafka支持拉取。
3.rocketmq单机吞吐量大,kafka适用于与大数据结合,比如elk。

4.3如何实现分布式锁

1.使用redis的watch命令实现,也是会出现"少卖"的现象(不确定)
2.使用redis的互斥命令setnx实现,解锁时要使用lua脚本解锁。
3.直接使用redisson实现。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EULBZaSu-1629426421088)(https://oscimg.oschina.net/oscnet/up-a28e18079ececef1dd4246b6db051825b71.png)]
加锁机制
如果该客户端面对的是一个redis cluster集群,他首先会根据hash节点选择一台机器。
自动延时机制
只要客户端1一旦加锁成功,就会启动一个watch dog看门狗,他是一个后台线程,会每隔10秒检查一
下,如果客户端1还持有锁key,那么就会不断的延长锁key的生存时间。
可重入锁机制
使用incr命令实现。

4.4mysql乐观锁实现

mysql的乐观锁,一般是使用+版本号字段来实现,在秒杀场景下,会出现"少卖"的现象

4.5限流思路

参考https://www.cnblogs.com/aspirant/p/9093437.html

4.6你们使用了消息队列,那么是怎么考虑消息幂等性问题

1.获取到消息时,判断消息是否被处理过,可以在数据库加上状态字段以及唯一标识。
2.使用redis的set集合。
3.如果对重复数据考虑的不严谨,可以使用bloomfilter

4.7订单号如何生成(雪花id算法)

雪花算法是Twitter推出的一个用于生成分布式id的策略。

  1. 符号位:固定为0,二进制表示最高位是符号位,0代表正数,1代表负数。
  2. 时间戳:41个二进制用来记录时间戳,表示某一个毫秒。
  3. 机器id:代表当前算法运行机器的id。
  4. 序列号:12位,用于记录某个机器同一个毫秒内产生的不同序列号,代表同一个机器同一个毫秒可以产生的id序列号。

5.redis篇

5.1redis持久化

RDB是redis默认的存储方式,是通过快照完成的。这一刻的数据,不关注过程。触发快照的方式如下:

1.符合自定义配置的快照规则。

2.执行save或者bgsave命令,执行flushall命令

3.执行主从复制操作(第一次)

save 300 10 # 表示5分钟(300秒)内至少10个键被更改则进行快照。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gai9EggK-1629426421091)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S6mJLhUR-1629426421092)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)]

RDB优缺点

优点

RDB是二进制压缩文件,占用空间小,便于传输。

主进程fork子进程,可以最大化redis性能。主线程不能太大,复制过程中主进程阻塞。

缺点

不保证数据完整性,会丢失最后一次快照以后更改的数据。

RDB原理

这个记得住就讲。

AOF持久化

REDIS默认情况不开启,开启AOF持久化后REDIS将所有写入的命令以及参数记录到AOF文件,AOF会记录过程,RDB只管结果

AOF保存模式

Redis 目前支持三种 AOF 保存模式,它们分别是:

AOF_FSYNC_NO :不保存。
AOF_FSYNC_EVERYSEC :每一秒钟保存一次。(默认)

AOF_FSYNC_ALWAYS :每执行一个命令保存一次。(不推荐)

Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生 停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到 新 AOF 文件,并开始对新 AOF 文件进行追加操作。(copy on write思想,重点)

图片
img

5.2redis数据类型

string,list,set,hash,sortedset有序集合,bitmap

string能代表3种值:字符串、整形、浮点数

5.3缓存穿透

一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如 DB)。

缓存穿透是指在高并发下查询key不存在的数据,会穿过缓存查询数据库。导致数据库压力过大而宕机

解决方案:

使用布隆过滤器。在缓存之前在加一层布隆过滤器(最常用回答)

布隆过滤器的原理是,当一个元素被加入集合时,通过K个Hash函数将这个元素映射成一个数组中的K 个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如 果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。这就是布隆过滤器的 基本思想。 把字符串------>位 省空间 (1或0) 不用循环------>比较位置 省时间

参考: https://my.oschina.net/u/4033707/blog/4479561

5.4缓存雪崩

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如 DB)带来很大压力。 突然间大量的key失效了或redis重启,大量访问数据库,数据库崩溃

解决方案:

1、 key的失效期分散开 不同的key设置不同的有效期

2、设置二级缓存(数据不一定一致)

5.5单线程的redis为什么这么快

相关问题还有redis为什么是单线程的。

答题思路:

redis在内存中操作,持久化只是数据的备份,正常情况下内存和硬盘不会频繁swap

多机主从,集群数据扩展 maxmemory的设置+淘汰策略

数据结构简单,有压缩处理,是专门设计的

单线程没有锁,没有多线程的切换和调度,不会死锁,没有性能消耗

使用I/O多路复用模型,非阻塞IO;

构建了多种通信模式,进一步提升性能

进行持久化的时候会以子进程的方式执行,主进程不阻塞

5.6 IO多路复用

select,poll,epoll、kqueue都是IO多路复用的机制。 I/O多路复用就是通过一种机制,一个进程可以监视多个描述符(socket),一旦某个描述符就绪(一 般是读就绪或者写就绪),能够通知程序进行相应的读写操作。

5.7 redis哨兵

https://my.oschina.net/u/4033707/blog/447877

6.spring篇

6.1spring mvc流程

  1. 用户发送请求到DispatcherServlet。
  2. DispatcherServlet收到请求后调用HandlerMapping处理器映射器。
  3. 处理器根据url找到具体的handler(后端控制器),生成处理器对象以及处理器拦截器。
  4. DispatcherServlet调用HandlerAdapter适配器去调用Handler
  5. 适配器执行Handler。
  6. Handler执行完成后返回ModelAndView。(一般答到这步就差不多了)
  7. 前端控制器请求视图解析器进行视图解析。
  8. 返回view,之后进行视图渲染。

6.2ribbon源码解读

原面试题:讲一下spring cloud的负载均衡机制

使用@LoadBalanced注解后,可以将普通的RestTemplate对象使用LoadBalanceClient去处理。

老规矩,先找spring.factories,可以发现Ribbon的自动装配类为:

LoadBalancerClient类(实现类RibbonLoadBalancerClient,待用)

org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration

1)研究LoadBalancerAutoConfiguration

第一步:注入RestTemplate对象到集合待用。

第二步:注入RestTemplate定制器(RestTemplateCustomizer)

第三步:使用RestTemplateCustomizer为每一个RestTemplate对象添加拦截器

整理的不够好,待补充。

6.3hystrix断路器

这个一般会问,先记录

关闭的条件

  • 当满足一定的阈值的时候(默认10秒内超过20次请求)
  • 当失败率到达一定的时候,默认10秒内超过50%的请求失败
  • 到达以上阈值时,断路器将会开启
  • 当开启的时候,所有的请求都不会进行转发
  • 一段时间之后,默认5秒,这个时候断路器是半开状态,会让其中一些请求进行转发

断路器状态

  • Closed:关闭状态,所有请求都正常访问。
  • Open:打开状态,所有请求都会被降级。Hystix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全打开。默认失败比例的阈值是50%,请求次数最少不低于20次。
  • Half Open:半开状态,open状态不是永久的,打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放部分请求通过,若这些请求都是健康的,则会完全关闭断路器,否则继续保持打开,再次进行休眠计时

6.4nacos原理

面试原题:服务发现原理

关键点:

org.springframework.cloud.client.serviceregistry.ServiceRegistry :定义了服务注册接口

com.alibaba.cloud.nacos.registry.NacosServiceRegistry:nacos实现

引入nacos相关pom时,spring.factories文件会起作用,会去加载

org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration

这个配置类。

nacos服务器(nacos-server.jar)启动时,会通过InstanceController 提供一些rest api。

NacosServiceRegistry在注册实例或者发送心跳信息时,会远程调用InstanceController

7.seata篇

面试原题

既然你学过微服务,就聊聊分布式事务吧。目前我只学了seata。

seata是什么

Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。 它提供了AT(常用)、saga(长事务解决方案)等多种事务模式。

seata术语

Seata分为三个模块,分别是TM、RM和TC(简写)。
TC(transaction Coordinator),代表seata服务器,seata是一个spring boot的jar包。
TM(transaction Manager)事务管理器。
RM(Resource Manager) 代表每个数据库。
Seata还用了一个XID,代表了一个分布式事务,相当于dubbo中的Request ID。

seata流程

  1. TM向TC注册全局事务,并生成全局唯一的XID。
  2. RM向TC注册分支事务,并将其纳入该XID对应的全局事务范围。
  3. RM向TC汇报资源的准备状态。
  4. TC汇总所有事务参与者的执行状态,决定分布式事务是全部提交还是全部回滚。
  5. TC通知所有RM提交/回滚事务。

seata流程相亲版

  1. 卢学霸(TM)跟导师(TC)提议,为卢学霸安排对象,卢学霸生成了一个相亲id。
  2. 女神(RM)向tc注册了资料,卢学霸在他的相亲id中接收到了推送。
  3. 女神向卢学霸汇报自己的资料。
  4. TC汇总所有女神的资料,让卢学霸决定是否去参加相亲。
  5. TC向卢学霸汇报相亲结果。

seata例子

下载 https://seata.io/zh-cn/blog/download.html
官方例子 https://seata.io/zh-cn/docs/user/quickstart.html

seata工作流程

https://seata.io/zh-cn/docs/overview/what-is-seata.html

Seata使用了增强型二阶段提交实现。

  1. 假如你有一个数据库,里面有一张订单表,要实现分布式事务。
    那么要满足2个条件,订单表必须要有id主键字段,主键是为了给Seata加本地锁。
    第二个条件,你的数据库中,要建一张undo_log表,记录回滚日志。 建表语句如下:
   CREATE TABLE `undo_log` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `branch_id` bigint(20) NOT NULL,
      `xid` varchar(100) NOT NULL,
      `context` varchar(128) NOT NULL,
      `rollback_info` longblob NOT NULL,
      `log_status` int(11) NOT NULL,
      `log_created` datetime NOT NULL,
      `log_modified` datetime NOT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  1. 一阶段:业务数据和回滚记录在同一个本地事务中提交,释放本地锁和连接资源。
  2. 二阶段:异步提交,回滚通过一阶段的回滚日志进行反向补偿。

一阶段

从上文中,我们得知seata使用了一个增强型2阶段提交,我们现在开始分析一阶段:

  1. 前文中,我们提到要给订单表实现分布式事务。
  2. 在订单微服务引入了seata之后,seata会拦截每条订单表的sql,
    例如update语句,为订单表生成before image。
  3. 执行业务sql更新之后,其保存为after image,并生成行锁。
  4. 以上操作全部在订单数据库内的一个事务完成,保证了一阶段操作的原子性。

二阶段之提交

因为业务sql在一阶段已经提交至数据库,所以seata框架只需要将一阶段的快照和行锁删除即可。

二阶段之回滚

  1. 前面提到了XID全局事务id,seata要根据XID和branch id找到相应的undo log日志。
  2. 数据校验:拿undo_log中的after image镜像数据与当前业务表中的数据进行比较,
    如果不同,说明数据被当前事务之外的动作做了修改,那么事务不会回滚。
  3. 如果比较通过,则根据undo_log中的before image镜像数据和业务sql的相关信息
    生成回滚语句并执行。

seata工作流程之恋爱篇

  1. 卢学霸和女神谈恋爱了。
  2. 卢学霸预料到自己可能和女神吵架,所以将目前好的状态备份为before image。
  3. 卢学霸某天和女神吵架了。
  4. 卢学霸找到前几天备份的镜像,看看当前状态和after image是否一致,如果一致,说明不会发生蝴蝶效应。
  5. 卢学霸回到过去改变世界。

8.es篇

8.1ES集群核心概念

  • 集群 一个ES集群由多个节点组成,每个集群都有一个共同的集群名称作为标识。

  • 节点(Node) 一个ES实例即一个Node,一台机器可以有多个实例,正常使用下每个实例都应该部署在不同的机器上。 ES的配置文件可以通过node.master、node.data来设置节点类型。

  • node.master:表示节点是否具有成为主节点的资格。

  • node.data: 表示节点是否存储数据。

  • node节点组合

    • 主节点+数据节点默认

    节点既有成为主节点的资格,又存储数据

    • 数据节点(data) 节点没有成为主节点的资格,不参与选举,只会存储数据
  • 客户端节点(client) 不会成为主节点,也不会存储数据,主要是针对海量请求的时候可以进行负载均衡

  • 分片

    1.每个索引有1个或多个分片,每个分片存储不同的数据。分片可分为主分片和复制分片,

    复制分片是主分片的拷贝。默认每个主分片有一个复制分片,

    每个索引的复制分片的数量可以动态地调整,复制分片从不与它的主分片在同一个节点上

    2.假如一个索引有5个主分片,那么这5个主分片合起来才是1份完整的数据。

  • 副本 这里指主分片的副本分片(主分片的拷贝) 分片和副本,同学们可以回顾下monogodb的内容,基本和那里相同。

8.2ES数据一致性如何保证

面试题问到了,这里先讲。

一致性

consistency,one(primary shard),all(all shard),quorum(default)
我们在发送任何一个增删改操作的时候,比如 PUT /index/type/id ,都可以带上一个consistency参 数,指明我们想要的写一致性是什么?
PUT /index/type/id?consistency=quorum
one:要求我们这个写操作,只要有一个primary shard是active状态,就可以执行。
all:要求我们这个写操作,必须所有的primary shard和replica shard都是活跃的,才可以执行这个写操作。
quorum:默认值,要求所有的shard中,必须是大部分的shard都是活跃的,可用的,才可以执行这个写操作。

这里和kafka基本相同,同学们可以回顾下。

quorum机制

写之前必须确保大多数shard可用,公式如下:

int((primary shard + number_of_replicas) / 2) + 1
当number_of_replicas > 1时才生效。




万物离不开过半原则,这里又是过半写入。 quorum不齐全时,会wait(等待)1分钟

es存储的基本单元是shard,es中一个index可能分为多个shard,事实上每个shard都是一个lucene的index,
并且每个lucene index有多个segment(段)组成,每个segenet事实上是一些倒排索引的集合,
每次创建一个Document,都会归属于一个新的segment,而不会去修改原来的segment;
因此每次文档的删除操作,会仅仅标记segment中该文档为删除状态,而不会真正立马的物理删除。

8.3索引文档写入原理

es存储的基本单元是shard,es中一个index可能分为多个shard,事实上每个shard都是一个lucene的index, 并且每个lucene index有多个segment(段)组成,每个segenet事实上是一些倒排索引的集合, 每次创建一个Document,都会归属于一个新的segment,而不会去修改原来的segment; 因此每次文档的删除操作,会仅仅标记segment中该文档为删除状态,而不会真正立马的物理删除。

translog

新文档被索引意味着文档会被首先写入内存buffer和translog文件。每个shard都对应一个translog文件。

translog 提供所有还没有被刷到磁盘的操作的一个持久化纪录。当 Elasticsearch 启动的时候, 它会从 磁盘中使用最后一个提交点去恢复已知的段,并且会重放 translog 中所有在最后一次提交后发生的变 更操作。

translog 的目的是保证操作不会丢失。这引出了这个问题: Translog 有多安全? 在文件被 fsync 到磁盘前,被写入的文件在重启之后就会丢失。默认 translog 是每 5 秒被 fsync 刷新到硬盘, 或者在每次写请求完成之后执行。这个过 程在主分片和复制分片都会发生。最终, 基本上,这意味着在整个请求被 fsync 到主分片和复 制分片的 translog 之后,你的客户端才会得到一个 200 OK 响应。

translog这里,同学们可以参考前面mysql的redo log和kafka章节内容。

refresh

在 Elasticsearch 中, _refresh 操作默认每秒执行一次, 意味着将内存 buffer 的数据写入到一个新 的 Segment 中,这个时候索引变成了可被检索的。

flush

这个执行一个提交并且截断 translog 的行为在 Elasticsearch 被称作一次 flush 。 分片每 30 分钟被自动刷新(flush),或者在 translog 太大的时候也会刷新。

8.4es的乐观锁

面试可能会问,先记录,这里同学们可以回顾之前的mvcc。 Elasticsearch的后台都是多线程异步的,多个请求之间是乱序的,可能后修改的先到,先修改的后到。 Elasticsearch的多线程异步并发修改是基于自己的_version版本号进行乐观锁并发控制的。 在后修改的先到时,修改完毕后,当先修改的后到时,会比较一下_version版本号,如果不相等就直接 扔掉,不需要了。这样结果会就会保存为一个正确状态。

8.5Elasticsearch分布式架构

特性

  • 高扩展性:体现在Elasticsearch添加节点非常简单,新节点无需做复杂的配置,只要配置好集群信 息将会被集群自动发现。
  • 高可用性:因为Elasticsearch是分布式的,每个节点都会有备份,所以宕机一两个节点也不会出现 问题,集群会通过备份进行自动复盘。
  • 实时性:使用倒排索引来建立存储结构,搜索时常在百毫秒内就可完成。

节点对等

每个节点都能接受请求,每个节点接受到请求后都能把该请求路由到有相关数据的其它节点上,接受原 始请求的节点负责采集数据并返回给客户端。

这里简单理解,每个es节点都是一个单独的nginx。

集群发现机制

  • Discovery 是Elasticsearch自动发现节点的机制的模块,Zen Discovery和 EC2 discovery。 Zen Discovery作用就相当于solrcloud中的zookeeper。zen Discovery 从功能上可以分为两部分,第一部分是集群刚启动时的选主,或者是新加入集群的节点发现当前集群的Master。第二部分是选主完成后,Master 和 Folower 的相互探活。

  • 集群发现机制(cluster discovery):在当前启动了一个Elasticsearch进程,在启动第二个 Elasticsearch进程时,这个进程将作为一个node自动就发现了集群,并自动加入,前提是这些 node都必须配置一套集群信息。

  • Shard负载均衡:例如现在由10个 shard (分片),集群中由三个节点,Elasticsearch会进行均 衡的分配,以保持每个节点均衡的负载请求。

8.6文档增删改机制原理

1.对于客户端首先会选择一个节点node发送请求过去,这个节点node就是协调节点coordinating node  
2.协调节点coordinating node会对docuemnt数据进行路由,默认是根据id求余路由,将请求转发给对应的node(含有primary shard)  
3.实际上node的primary shard会处理请求,然后将数据同步到对应的含有replica shard的node  
4.协调节点coordinating node如果发现含有primary shard的node和所有的含有replica shard的 node都搞定之后,就会返回响应结果给客户端

简单总结:ES在索引文档时,首先随意选一台机子作为协调节点。协调节点会根据文档id(如果没有id,

es内部会生成),使用下面的公式。

shard = hash(document_id) % (num_of_primary_shards)

计算出这个文档要存储到哪个分片。

8.7es脑裂问题

面试可能会问,记录下。
6.x和之前版本 尽量避免脑裂,需要添加最小数量的主节点配置: discovery.zen.minimum_master_nodes: (有master资格节点数/2) + 1 这个参数控制的是,选举主节点时需要看到最少多少个具有master资格的活节点,才能进行选举。官方 的推荐值是(N/2)+1,其中N是具有master资格的节点的数量。
在新版7.X的ES中,对es的集群发现系统做了调整,不再有discovery.zen.minimum_master_nodes这 个控制集群脑裂的配置,转而由集群自主控制,并且新版在启动一个新的集群的时候需要有 cluster.initial_master_nodes初始化集群列表。
这里又可以参考过半原则了,我感觉同学们可以回顾下zookeeper。

8.8elasticsearch调优环节

写调优(重点回答这个)
1.副本设置0,用于集群首次写入数据。
2.调整索引的刷新间隔(重点,可以联想到文档写入原理)
3.自动生成doc id
4.合理设置mapping(mysql也有类似章节)
将不需要建立索引的字段index设置为no
5.批处理bulk api
读调优
1.filter代替query,filter不需要返回评分字段。
2.id字段定义为keyword,相当于不分词,keyword内部会被es优化。

8.9query文档搜索机制

query then fetch(es默认的搜索方式)
第一步, 先向所有的 shard 发出请求, 各分片只返回文档 id和排名相关的信息(也就是文档对应的分值),
然后按照各分片返回的文档的分数进行重新排序和排名, 取前size 个文档。
第二步, 根据文档 id 去相关的 shard 取 document。
这个地方,可以联想到mysql的聚簇索引:
mysql innodb的非主键索引,总是先找到id,再去查找对应的数据(相当于es shard中的数据)

8.10 Elasticsearch零停机索引重建

基于scroll+bulk+索引别名方案

es课件讲的很详细,同学们自行查阅。

Reindex API方案
Elasticsearch v6.3.1已经支持Reindex API,它对scroll、bulk做了一层封装,能够 对文档重建索引而不
需要任何插件或外部工具。

POST _reindex
{
 "source": {
  "index": "book"
},
 "dest": {
  "index": "book_new"
}
}

知识点扩充:如果需要对一个数据量很大的表,进行查询,然后重建索引,请直接使用mybatis RowHandler这个类,这个类的作用并不直接把数据查询封装成一个List集合(如果把百万级别的数据,查询出来放到list里面去,你的程序会崩),而是把数据封装成一个游标(相当于手动while resultset.next),这样查询效率更高。

9.其他技术问题

9.1一致性hash

首先有一条直线,开头和结尾定位1和2的32次方-1,相当于一个地址。
把这条线,弯过来构成一个圆环形成闭环,这样的一个圆环成为hash环。
我们将服务器IP或者主机名求hash值然后落到这个hash环上。
那么针对客户端用户(或者数据),也根据它的ip进行求值,
如何确定一个客户端路由到哪个服务器处理呢,按照顺时针找最近的服务器节点。
但是,一致性哈希算法在服务器节点太少时,容易因为节点分布不均与而造成数据倾斜问题。
假如系统只有两台服务器,节点2只能负责非常小的一段请求,
大量的客户端请求落在了节点1上,这就是数据(请求)倾斜问题
为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,对每一个服务节点计算多个哈希,
每个计算结果位置都放置一个此服务节点,成为虚拟节点。(虚拟节点指向的是真实节点)

9.2sleep和wait的区别

  • 两者最主要的区别在于:sleep方法没有释放锁,而wait方法释放了锁。
  • 两者都可以暂停线程的执⾏。
  • Wait 通常被⽤于线程间交互/通信,sleep 通常被⽤于暂停执⾏。

9.3多线程状态转换

新建:new Thread();

运行:run();

就绪:start();

阻塞:wait();

死亡:interrupt();

一般不调用interrupt方法中断线程,而是使用volatile变量控制,如以下例子:

 new Thread(new Runnable() {
            volatile boolean flag;
            @Override
            public void run() {
                while (flag) {
                    // do something
                }
            }
            //提供一个停止的方法,让外部停掉这个线程
            public void stop() {
                this.flag = false;
            }
        }).start();
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,下面是一些 Spring Boot 面试时可能会涉及的重要知识点和面试建议: 1. 什么是 Spring Boot? Spring Boot 是 Spring 框架的一个子项目,它基于 Spring 框架,简化了 Spring 应用的配置和开发过程,使得开发者可以更加便捷地创建独立、生产级别的 Spring 应用。Spring Boot 提供了自动化配置、开箱即用的组件和快速启动的能力,使得开发者可以更加专注于业务逻辑的实现。 2. Spring Boot 有哪些优点? - 简化了 Spring 应用的配置和开发过程。 - 集成了众多常用的第三方库,可以快速地搭建项目。 - 提供了自动化配置和开箱即用的组件,使得开发者可以更加专注于业务逻辑的实现。 - 与 Spring Framework 完美集成,可以很方便地使用 Spring 的各种功能。 - 支持多种开发方式,包括传统的 WAR 包部署、嵌入式服务器部署、Docker 容器化部署等。 3. Spring Boot 的核心注解有哪些? - @SpringBootApplication:用于标记 Spring Boot 应用的主类,它包含了 @Configuration、@EnableAutoConfiguration 和 @ComponentScan 三个注解,可以简化应用的配置和启动过程。 - @Controller、@Service、@Repository、@Component:用于标记 Spring Bean,可以自动扫描并注册到 Spring 容器中。 - @Autowired、@Resource、@Inject:用于依赖注入,可以自动装配 Spring Bean。 4. Spring Boot 的配置文件有哪些? Spring Boot 支持多种配置文件格式,包括 properties、yml、json 等。其中,application.properties 或 application.yml 是 Spring Boot 默认的配置文件,它可以放在项目的 classpath 下,也可以通过指定 spring.config.location 属性来指定配置文件的路径。 5. Spring Boot 的自动配置原理是什么? Spring Boot 的自动配置基于条件注解和条件判断,它会根据应用的上下文环境和 classpath 中的依赖库来自动配置 Spring Bean。例如,当 classpath 中存在 HikariCP 库时,Spring Boot 会自动配置一个 HikariCP 数据源,而不需要手动配置。 6. Spring Boot 如何处理异常? Spring Boot 提供了统一的异常处理机制,可以通过 @ControllerAdvice 和 @ExceptionHandler 注解来处理应用中的异常。在异常处理类中,可以通过 @ExceptionHandler 注解和方法参数来定义需要处理的异常类型和异常处理逻辑。 7. Spring Boot 如何实现 AOP? Spring Boot 集成了 Spring Framework 的 AOP 功能,可以通过 @Aspect 和 @Around 注解来实现切面编程。在切面类中,可以定义需要拦截的方法和拦截逻辑,以实现日志记录、权限控制等功能。 8. Spring Boot 如何实现事务管理? Spring Boot 集成了 Spring Framework 的事务管理功能,可以通过 @Transactional 注解来实现事务控制。在需要进行事务控制的方法上添加 @Transactional 注解,即可开启事务。 9. Spring Boot 如何集成数据库? Spring Boot 支持多种数据库,包括 MySQL、Oracle、MongoDB 等,可以通过在 pom.xml 中添加相应的依赖库来实现数据库的集成。同时,Spring Boot 也提供了多种数据库访问方式,包括 JDBC、JPA、MyBatis 等,可以根据实际需求选择合适的方式。 10. Spring Boot 如何实现缓存? Spring Boot 集成了多种缓存框架,包括 Ehcache、Redis、Caffeine 等,可以通过在 pom.xml 中添加相应的依赖库来实现缓存功能。同时,Spring Boot 也提供了多种缓存注解,包括 @Cacheable、@CachePut、@CacheEvict 等,可以方便地实现缓存功能。 面试建议: - 对于 Spring Boot 的基本原理和使用方法要有深入了解,并能够熟练使用 Spring Boot 搭建项目。 - 对于 Spring Boot 中常用的注解和配置文件要熟练掌握。 - 对于 Spring Boot 中的高级功能(如自动配置、AOP、事务管理、缓存等)要有一定的了解,并能够根据实际需求进行应用。 - 在面试中要注意表达清楚自己的观点和思路,可以通过实际项目经验来证明自己的能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时小浅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值