java-rabbitmq、elasticearch相关面试题

RabbitMQ

RabbitMQ的使用场景

rabbitMQ消息队列可以用来

  • 做任务的异步处理,提高程序的相应时间
  • 提高系统稳定性,通过手动确认机制,当消费者出现故障,只要没有确认签收,请求的数据都不会丢失可以再次处理
  • 服务解耦,生产者通过MQ与消费者交互
  • 消除峰值,通过异步处理,消息传到MQ直接返回,接着等待排队处理,避免了线路拥堵

RabbitMQ如何防止消息丢失

首先,RabbitMQ的消息确认机制,默认是自动签收,也就是说消息一旦被消费者接收,就自动签收,消息就从队列里清除了。因此对于重要的消息,不容丢失的数据,我们需要设置在消费完成后手动签收

其次,我们可以将消息持久化,避免消息在消费前MQ宕机,网络问题等造成的消息丢失

RabbitMQ的交换机有哪几种

Fanout:广播,将消息交给所有绑定到交换机的队列

Direct:定向,把消息交给符合指定routing key的队列

Topic:通配符,把消息交给符合routing pattern的队列

消息是如何从发送者到达消费者的(RabbitMQ工作流程)

分为消息发送和消息接收两个步骤

  • 消息发送:生产者和Broker建立TCP连接,创建信道。通过信道将消息发送给Broker,由Exchange将消息进行转发到指定的队列
  • 消息接收:消费者和Broker建立TCP连接 ,创建信道 ,然后监听指定的队列,当有消息到达队列时,Broker默认将消息推送给消费者,消费者就能接收到消息

如何防止消息重复消费

重复消费,一般时由于消费者消费成功后,在给MQ确认签收的时候出现了网络波动,MQ没有接到确认,就会继续给消费者投递之前的消息,造成消费者接收到了两条一样的消息。

我们可以通过实现消息的幂等性来避免这种情况,比如说让生产者给每个消息携带一个唯一的id,消费者获取消息后根据这个id去查询数据库,如果不存在就正常消费,如果存在了就证明该消息被消费过,直接丢弃

RabbitMQ消息投递失败,你们怎么处理

我们可以设置confirm回调和 returned 回调

比如说,可以在发送消息的时候,把消息详情包括交换机名,路由键,都保存到一个表中,状态设置为发送中,如果在confirm方法中ack为false,代表发送到交换机失败 ,就把这个记录状态修改为发送失败

然后我们创建一个定时任务定时扫表,去读取发送失败的数据并重新发送,为了优化性能,我们设置重试次数3次,如果3次都失败了,我们可以采取人工干预

ElasticSearch

Lucene创建索引原理

Lucene是基于倒排索引原理来实现的

  • 首先,将原文档进行分词处理,形成一个个单独的单词,
  • 然后取出标点符号以及停词,形成词元,
  • 再将词元做一些语言相关的处理,比如变成小写,转换时态,单复数形式等等,
  • 将得到的词创建一个字典,按照字母顺序排序,合并相同的词,最终生成一个倒排索引文档

ES的keyword和text区别

keyword:不分词,直接建立索引,支持模糊查询,精确查询,聚合查询

text:分词后建立索引,支持模糊查询,精确查询,不支持聚合查询

keyword通常用于通常用于存储年龄,性别,邮编,邮箱号码等等,直接将完整数据保存的场景

text通常存储全文搜索的数据,例如地址,文章内容的保存

ES的优势

ES是基于Lucene的开源搜索引擎,它解决了原生Lucene使用的不足,优化了Lucene的调用方式

  • 分布式的实时文件存储,每个字段都被索引并可被搜索
  • 支持实时分析搜索
  • 可以扩展到上百台服务器,处理PB级结构化或非结构化数据
  • 通过简单的 RESTful API、可以跟各种语言的客户端甚至命令行进行交互
  • 上手非常容易,只需很少的学习就可以在生产环境中使用

Lucene/ES为什么那么快(ES用到什么数据结构)

传统搜索比如mysql的like关键字查询,它的搜索方式就是全文扫表,查询性能很低

ES是基于Lucene的全文检索引擎,它采用的是倒排索引结构,在存储时先对文档进行分词,再做一些标点符号去除,大小写时态转换等优化处理,最后按照字母顺序去重排序,形成一个倒排索引文档,我们在检索时,就可以通过二分查找的方式找到目标值

ES的分层结构,index下面是什么

Index:索引库,包含有一堆相似结构的文档数据,类比Mysql中的数据库

Type:类型,它是index中的一个逻辑数据分类,类比Mysql中的表

Document:文档:是ES中的最小数据单元,通常用json结构标识,类比Mysql中的一行数据

Field:字段:类比Mysql中的一个列

从ES7.0开始,Type被干掉了,从此库表合一即一个Index中只有一个默认的Type

讲几个ES中的查询对象:比如TermQuery

TermQuery:匹配关键字查询(关键词不分词)

MatchQuery:匹配关键字查询(关键字分词后)

BooleanQuery:按条件查询

matchAllQuery:匹配所有文档查询

rangeQuery:查询指定范围内的数据

你简单描述一下DSL语法

DSL是一种以json形式标识的,由ES提供的一种查询语言,它由两部分组成,DSL查询和DSL过滤。

DSL过滤类似于模糊查询,DSL查询类似于精确查询

你说一下 match和term的区别?

term:不会对搜索词进行分词处理,而是作为一个整体与目标字段进行匹配,若完全匹配,则可查询到

match:会将搜索词分词,再与目标查询字段进行匹配,若分词中的任意一个词与目标字段匹配上,则可查询到

你使用过ES的哪些聚合查询?

指标聚合,比如求和,求最大值,最小值,平均数

数量统计聚合,计算满足条件数据的总条数,相当于sql中的count

去重聚合,它会计算非重复的数据个数,相当于sql中的distinct

桶聚合,它会将某个field的每个唯一值当成一个桶,并计算每个桶内的文档个数,相当于sql中的group by

最高权值聚合,它会匹配每组前n条数据,相当于sql中的group by后取出前n条

ES高亮怎么做的?

使用HighlightBuilder对关键字作高亮处理,由于我们项目使用的是SpringBoot整合ES的jar包,结果没有进行高亮处理,我们使用ElasticsearchTemplate的queryForPage方法来获取结果,再手动进行分页封装返回前台

你们ES和数据库的数据一致性怎么做的

代码控制的,数据库做了写操作,直接更新ES中的数据,我知道可以通过 Logstash 中数据和ES的数据自动同步。

ES分片机制了解吗

ES的索引库由多个分片 shard组成,shard分为primary shard主shad和replica shard 副本,主shard承担写请求,replica副本的数据从primary复制而来,同时分担读请求,primary shard的数量设定了就不能修改,replica数量可以修改。

描述一下ES添加文档的过程

(1) 客户端请求一个协调节点coordinating node

(2) 协调节点根据算法选择一个primary shard: 算法 hash(document_id) % (num_of_primary_shards)

(3) 对应的primary shard 所在节点保存完数据后,将数据同步到replica node。

(4) 协调节点coordinating node 发现 primary node 和所有 replica node 都搞定之后返回结果给客户端

数据节点存储数据详细流程:

(1) 当分片所在的节点接收到来自协调节点的请求后,会将请求写入到Memory Buffer,然后定时(默认是每隔1秒)写入到Filesystem Cache,这个从Momery Buffer到Filesystem   Cache的过程就叫做refresh

(2) 当然在某些情况下,存在Momery Buffer和Filesystem Cache的数据可能会丢失,ES是通过translog的机制来保证数据的可靠性的。其实现机制是接收到请求后,同时也会写入到translog中,当Filesystem cache中的数据写入到磁盘中时,才会清除掉,这个过程叫做flush;

(3)在flush过程中,内存中的缓冲将被清除,内容被写入一个新段,段的fsync将创建一个新的提交点,并将内容刷新到磁盘,旧的translog将被删除并开始一个新的translog。
flush触发的时机是定时触发(默认30分钟)或者translog变得太大(默认为512M)时;

详细描述一下Elasticsearch获取文档的过程

(1) 客户端请求一个协调节点coordinating node

(2) coordinate node 根据算法hash(document_id) % (num_of_primary_shards),将请求转发到对应的 node,此时会使用 round-robin随机轮询算法,在 primary shard 以及其所有 replica 中随机选择一个,让读请求负载均衡

(3) 接收到请求的 node 返回 document 给调节点 coordinate node。

(4) coordinate node 返回 document 给客户端。

搜索被执行成一个两阶段过程,我们称之为 Query Then Fetch;

详细描述一下Elasticsearch搜索过程

(1) 在初始查询阶段时,查询会广播到索引中每一个分片拷贝(主分片或者副本分片)。

(2) 每个分片在本地执行搜索并构建一个匹配文档的大小为 from + size 的优先队列。PS:在搜索的时候是会查询Filesystem Cache的,但是有部分数据还在Memory Buffer,所以搜索是近实时的。

(3) 每个分片返回各自优先队列中所有文档的 ID 和排序值给协调节点,协调节点它合并这些值到自己的优先队列中来产生一个全局排序后的结果列表。

(4) 接下来就是 取回阶段,协调节点辨别出哪些文档需要被取回并向相关的分片提交多个 GET 请求。每个分片加载并 丰富 文档,如果有需要的话,接着返回文档给协调节点。一旦所有的文档都被取回了,协调节点返回结果给客户端。

详细描述一下Elasticsearch更新和删除文档的过程

删除和更新也都是写操作,但是Elasticsearch中的文档是不可变的,因此不能被删除或者改动以展示其变更; 磁盘上的每个段都有一个相应的.del文件。当删除请求发送后,文档并没有真的被删除,而是在.del文件中被标记为删除。该文档依然能匹配查询,但是会在结果中被过滤掉。当段合并时,在.del文件中被标记为删除的文档将不会被写入新段。

在新的文档被创建时,Elasticsearch会为该文档指定一个版本号,当执行更新时,旧版本的文档在.del文件中被标记为删除,新版本的文档被索引到一个新段。旧版本的文档依然能匹配查询,但是会在结果中被过滤掉。

ES有几种节点类型?他们的作用分别是什么

分为主节点,node.master =true , 数据节点node.data =true , 负载均衡节点(node.data =false,node.master=false),

node.master=true,代表该节点有成为主资格 ,主节点的主要职责是和集群操作相关的内容,如创建或删除索引,跟踪哪些节点是群集的一部分,并决定哪些分片分配给相关的节点。一般会把主节点和数据节点分开

node.data=true,数据节点主要是存储索引数据的节点,主要对文档进行增删改查操作,聚合操作等,数据节点对CPU,IO,内存要求较高,优化节点的时候需要做状态监控,资源不够时要做节点扩充

当主节点和数据节点配置都设置为false的时候,该节点只能处理路由请求,处理搜索,分发索引操作等,从本质上来说该客户节点表现为智能负载平衡器。配置:mode.master=false,mode.data=false

ES集群的三种颜色代表什么

绿色,黄色,红色,绿色代表集群健康,所有的主备分片都得到分配,如果有备分片没有node去分配,集群是黄色,黄色和绿色都是可用状态,如果有主分片的节点down机,集群不可写数据,呈现红色,代表集群不健康。

你们项目怎么使用ES

我们使用的是spring-boot-start-data-elasticsearch这个库来操作ES,用在大数据的搜索场景,比如商品的发布,搜索功能。


注:附加

SpringSeucity

说一下security中的的filter

SecurityContextPersistenceFilter:请求开始会从SecurityContextRepository中获取SecurityContext对象并设置给SecurityContextHolder,在请求完处理成后将SecurityContextHolder持有的SecurityContext再保存到配置好的SecurityContextRepository中,同时清除SecurityContextHolder中的SecurityContext

UsernamePasswordAuthenticationFilter:默认拦截“/login”登录请求,将请求中的认证信息包括用户名,密码封装成UsernamePasswordAuthenticationToken,然后调用AuthenticationManager的认证方法进行认证

BasicAuthenticationFilter:处理 HTTP 请求的 BASIC 授权标头,如果身份验证成功,就把生成的Authentication对象放入SecurityContextHolder。如果设置了记住我,下次访问就不会走这里来了

RememberAuthenticationFilter:记住我,调用RememberMeServices的autoLogin方法自动登录

AnonymousAuthenticationFilter:匿名filter,检测SecurityContextHolder有没有Authentication对象,如果没有,就会创建一个AnonymousAuthenticationToken并保存到SecurityContextHolder

ExceptionTranslationFilter:处理filter链中的所有AccessDeniedException和AuthenticationException

FilterSecurityInterceptor:继承自AbstractSecurityInterceptor,通过调用AccessDecisionManager.decide方法进行授权

说一下security的认证原理

首先,请求会经过UsernamePasswordAuthenticationFilter拦截,请求的用户名密码会封装成UsernamePasswordAuthenticationToken,过滤器将token提交给认证管理器AuthenticationManager进行认证

然后,认证管理器调用AuthenticationProvider进行认证,AuthenticationProvider再调用UserDetailsService获取到数据库中存储的用户信息UserDetails,然后调用密码编码器对密码进行比较,认证成功后封装Authentication

再后来,请求回到UsernamePasswordAuthenticationFilter,调用SecurityContextHolder将Authentication对象封装成SecurityContext并保存到SecurityContextHolder中

最后,请求回到SecurityContextPersistenceFilter,它会调用SecurityContextRepository将SecurityContext对象存储起来,再清理掉SecurityContextHolder中的信息

你可能感兴趣的:(java-rabbitmq、elasticearch相关面试题)