中科软Java银行外包【一面】
前戏
您能介绍一下您的基本情况和工作经历吗?
解答:略
您目前是否在职?如果面试通过,多久能到岗?
解答:略
您对中科软的了解如何?
解答:略
您能详细介绍一下目前负责的项目和职责吗?
解答:略
您提到的项目涉及到十几张表,在设计这些数据结构时是如何考虑的?
解答:略
课程和老师的关联是如何设计的?
解答:略
如果老师将课程下架,学生那边的课程信息是如何处理的?
解答:略
你们的系统是否有考试功能?考试如何实现的?
解答:略
您能详细讲一下课表管理和学习记录的设计和实现吗?
解答:略
正题
你们系统中如何处理消息丢失、消息重复消费和消息积压的问题?
消息丢失
生产者丢失:
消息持久化:在生产者发送消息时,确保消息持久化到MQ(消息队列)服务端,以保证消息不会因MQ服务重启或故障而丢失
生产者确认机制:开启生产者确认机制,生产者发送消息后,会等待MQ服务端的确认,如果未收到确认,生产者会重试发送,确保消息成功进入队列
失败消息处理:如果生产者多次重试发送消息失败,我们会将失败消息记录到数据库中,并通过定时任务或人工处理,确保所有消息最终都会被处理
消费者丢失:
手动确认机制:关闭消费者的自动确认机制,改为手动确认,当消费者成功处理完消息后,再发送确认信息给MQ服务端,只有在收到确认后,MQ服务端才会将消息从队列中删除,如果消费者处理消息失败,则不会发送确认信息,MQ服务端会重新投递该消息
重试机制:配置消费者在处理消息失败时进行重试,并记录失败次数,如果超过预设的重试次数,将消息记录到数据库或发送告警,在进行人工去处理
消息重复消费
防止消息重复消费的方法主要通过幂等性设计来实现:
唯一业务标识:在处理消息时,设计唯一的业务标识,例如用户ID和课程ID的组合。在处理每条消息前,先检查是否已经处理过这条消息(即是否存在该唯一标识的记录),如果存在则跳过处理。
幂等性校验:每次处理消息前,进行幂等性校验,确保同一消息不会被重复处理。例如,课程报名时,通过检查用户和课程的关联关系是否已存在,来决定是否需要处理该消息。
你们使用的集群是什么类型?是服务集群还是镜像集群?
服务集群
服务集群通常用于应用服务的部署和管理。
镜像集群
镜像集群主要用于数据存储和分布式文件系统。
参考回答:
Kafka:
消息镜像:Kafka的MirrorMaker功能用于跨数据中心复制消息,确保数据的高可用性和灾难恢复
分区和副本:Kafka通过分区和副本机制,确保消息在集群中的冗余存储和高可用性
Elasticsearch:
数据分片和副本:Elasticsearch通过数据分片和副本机制,确保数据的高可用性和快速查询
跨集群复制:Elasticsearch的跨集群复制功能,用于在多个集群之间复制数据,提高系统的容错能力
如果消息积压了,您会如何处理?
参考回答
最简单的方式就是水平扩展机器数量,增加内存和存储
您了解Kafka吗?它与MQ有什么区别?Kafka适用于哪些场景?
纯八股文,参考下面的回答
Kafka 是一个分布式的流式处理平台和消息队列系统,与传统的消息队列(MQ)系统在设计和应用场景上有一些显著的区别。
Kafka 与传统消息队列的区别
数据持久性:
Kafka 是设计为高度持久的消息系统,它将消息持久化到磁盘,支持消息的持久存储和回放。
传统的消息队列(如 RabbitMQ、ActiveMQ)通常也支持持久化,但在设计上不同,更多专注于点对点的消息传递和队列管理。
发布订阅模型:
Kafka 基于发布订阅模型,消息由生产者发布到主题(topic),消费者订阅主题并实时获取消息。
传统消息队列通常以点对点模式为主,即消息从一个发送者直接传递到一个接收者。
处理能力:
Kafka 在处理大规模数据流时表现优异,支持高吞吐量和低延迟,适合处理大量实时数据流。
传统消息队列也能处理大量消息,但通常更关注传输的可靠性和消息队列的管理特性。
分布式架构:
Kafka 是为分布式环境设计的,可以水平扩展,支持多个 broker 构成的集群。
传统消息队列系统也可以进行集群化部署,但架构和扩展性可能不如 Kafka 灵活。
Kafka 的适用场景:
实时数据管道:用于构建实时数据管道,将大量实时数据从多个数据源汇聚到数据湖或数据仓库中。
日志聚合和监控:适合用作日志聚合和分析,支持快速的日志数据收集和处理。
事件驱动架构:作为事件驱动架构的核心组件,支持事件发布和订阅,实现高效的事件驱动通信。
流处理应用:结合 Kafka Streams 或类似的流处理框架,可以实现复杂的流处理和实时分析。
Kafka 适合需要高度可扩展、高吞吐量和低延迟的实时数据处理和消息传递场景,特别是在大数据领域和微服务架构中被广泛应用。传统消息队列则更适合于点对点的消息传递和简单的队列管理需求。
详细可以看这篇文章:kafka和rabbitmq之间的区别以及适用场景
网关的作用是什么?
RPC:首先是RPC的端口转发,充当连接不同网络的桥梁,实现跨网络的数据交换和转发
协议转换:网关可以进行不同协议之间的转换,使得使用不同通信协议的网络能够进行互操作,例如,将局域网(LAN)中的数据包转换为互联网(Internet)上使用的数据格式
安全控制:作为网络的入口点,网关可以实施安全措施,如访问控制、防火墙、数据加密等,保护内部网络免受外部威胁的侵害
流量控制:网关可以监控和管理数据流量,优化网络资源的使用,确保网络的高效运行和资源分配
路由选择:根据网络的拓扑结构和目标地址,网关能够选择最佳的路径进行数据传输,以提高传输效率和降低延迟
代理服务:某些网关还提供代理服务,代表客户端请求外部资源,隐藏客户端的真实网络标识,增强网络安全性和隐私保护
拦截器和过滤器的区别是什么?
拦截器(Interceptor)
拦截器是一种设计模式,用于在执行过程中拦截并处理请求或调用,并能够在目标方法执行前后、异常发生时进行拦截处理,常见于面向切面编程(AOP)的实现中,例如在Spring框架中,拦截器可以用来实现日志记录、权限验证、性能监控等功能
过滤器(Filter)
过滤器也是一种设计模式,它用于对数据流进行处理和转换,可以在数据流进入目标之前或离开之后进行处理,通常用于数据的预处理和后处理,例如在Web开发中,过滤器可以用来处理HTTP请求和响应,进行字符编码转换、身份验证、请求参数过滤等操作
主要区别:
作用对象不同:拦截器主要针对方法调用或请求处理过程,而过滤器则主要针对数据流的输入输出进行处理。
实现方式不同:拦截器通常通过面向切面编程(AOP)的方式实现,而过滤器则通常通过设计模式中的责任链模式来实现。
使用场景不同:拦截器更多用于在业务方法执行前后进行扩展或处理,而过滤器更多用于对数据流进行过滤和转换,例如对请求和响应进行预处理和后处理。
是先执行拦截器,还是先执行过滤器?
首先,请求到达Servlet容器,触发过滤器(Filter)
然后,请求被DispatcherServlet捕获,触发拦截器(Interceptor)
接着,如果定义了AOP切面,它们会在相应的时机(如方法执行前或后)被触发
最后,请求到达控制器(Controller),执行相应的业务逻辑
在Spring中,通过什么接口实现请求的拦截?
HandlerInterceptor:这个接口允许开发者在请求处理之前(preHandle)、请求处理之后(postHandle)、视图渲染之后(afterCompletion)等时机对请求进行拦截和处理
反射是什么?一般在什么场景使用反射?
略
Spring Boot常用的一些注解有哪些?
略
什么是雪花算法?如何解决雪花算法重复生成的问题?
雪花算法是一种分布式唯一 ID 生成算法,最初由Twitter开发并开源,用于生成全局唯一的 ID。它的核心思想是在分布式系统中生成唯一的、有序的、趋势递增的 ID,以便于在分布式环境中进行数据的唯一标识和排序。
雪花算法的结构
雪花算法生成的 ID 通常由以下部分组成:
时间戳:占用 41 位,表示生成 ID 的时间戳。可以精确到毫秒级别,可以使用当前时间减去一个起始时间来获得时间戳的值。
机器标识:占用 10 位,表示机器的标识符。通常是机器的 ID,可以配置。
序列号:占用 12 位,表示同一毫秒内生成的序列号。序列号达到上限时会进行自旋等待,直到下一毫秒再生成新的 ID。
解决重复生成问题
参考回答:
雪花算法在分布式系统中生成的 ID 具有全局唯一性,但是在极端情况下,可能会因为系统时间回拨或者某些错误导致生成重复的 ID。为了解决这个问题,可以采取以下几种方法:
时钟回拨检测:在生成 ID 之前,可以检测系统时间是否回拨。如果检测到时间回拨,可以选择等待或者使用备用的时钟源,避免生成重复的 ID。
使用高性能时钟:一些系统可能会使用高性能的时钟源(如机器的 CPU 周期计数器)来代替系统时钟,减少时间回拨的可能性。
添加机器标识:每个机器分配一个唯一的标识符,将机器标识作为 ID 的一部分,确保同一时刻不同机器生成的 ID 不会重复。
序列号重置策略:在同一毫秒内序列号达到上限时,可以采取适当的策略,如自旋等待、使用备用序列号生成策略等,确保生成的 ID 不重复。
这些方法结合起来可以有效地减少雪花算法生成重复 ID 的可能性,保证在分布式系统中生成的 ID 唯一性和稳定性。
MySQL中的自增ID是如何实现的?
在 MySQL 中,自增 ID 主要通过 AUTO_INCREMENT
属性来实现。这种属性可以应用于整数类型的列(通常是主键列),用于自动为插入的新记录生成唯一的递增 ID。
id
列被定义为 AUTO_INCREMENT
,每次插入一条新记录时,MySQL 会自动为 id
列分配一个递增的唯一值,这样就保证了每条记录有一个独一无二的标识符
如何生成有一定顺序且不重复的订单号?
具体方式有很多,这里列举几个我当时回答的:
UUID
雪花+时间
Redis+雪花
是否了解线程池?自定义线程池吗?
略
线程池的工作原理是什么?如何回收?
工作原理:
线程池初始化:
在应用程序启动时,线程池会初始化一定数量的线程,这些线程处于等待就绪状态,可以立即执行任务。
任务提交:
当有任务到达时,线程池会从池中的空闲线程中选择一个线程来执行任务,而不是每次都创建新线程。这种方式减少了线程创建和销毁的开销。
任务执行:
选定的线程会执行提交的任务。如果所有线程都在忙碌,则任务会进入任务队列等待执行。
任务队列:
线程池通常会有一个任务队列(也称作工作队列),用于存储等待执行的任务。当线程池中的线程空闲时,会从队列中取出任务执行。
线程复用:
执行完一个任务后,线程并不会被销毁,而是可以被重用来执行下一个任务,从而节省了线程创建和销毁的开销。
回收机制:
空闲线程回收:
如果线程池中的某些线程在一段时间内没有执行任务,线程池会根据一定的策略进行回收。例如,可以根据线程空闲时间超过一定阈值来回收线程。
动态调整:
线程池一般会根据当前任务的数量和系统负载动态调整线程数量。如果任务数量增加,线程池可以增加线程数以处理更多任务;如果任务减少,可以减少线程数以节省资源。
线程池关闭:
当应用程序关闭或者不再需要线程池时,线程池应当正确地关闭。这包括停止接受新任务,等待现有任务执行完毕,然后释放线程资源。
如何优化SQL?有没有遇到过SQL优化的问题?
是否了解执行计划?如何查看执行计划?
- 感谢你赐予我前进的力量