2023-10-8讯飞大模型部署2024秋招后端一面(附详解)

1 mybatis的mapper是什么东西

在MyBatis中,mapper是一个核心概念,它起到了桥梁的作用,连接Java对象和数据库之间的数据。具体来说,mapper可以分为以下两个部分:

  1. Mapper XML文件

    • 这是一个XML文件,其中定义了SQL语句和映射规则。每个SQL语句都有一个唯一的ID,这样Java代码可以引用它。
    • 在这个文件中,你可以定义CRUD操作(如操作来获取一个用户,然后在UserMapper接口中定义一个相应的方法。当你调用这个方法时,MyBatis会执行XML文件中的SQL语句,并将结果映射到User对象。

      总的来说,MyBatis的mapper提供了一个高级、面向对象的方式来操作数据库,它隐藏了底层的SQL细节,使得数据库操作更加简洁和直观。

      2 mysql

      2.1 mysql的索引数据结构,为什么用这个

      3 redis

      3.1 redis能做哪些事情

      Redis是一个高性能的键值对存储系统,它支持的数据结构非常丰富,包括字符串(String)、哈希(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set)等。因此,Redis可以用于以下场景:

      • 缓存:减少数据库的访问压力,提高应用的响应速度。
      • 会话存储:例如Web应用中的用户会话。
      • 消息队列:使用List数据结构实现。
      • 发布/订阅系统:支持消息的发布和订阅。
      • 计数器:例如网站访问计数。
      • 实时分析:例如实时统计用户的行为。
      • 排行榜/计分板:使用Sorted Set数据结构。
      • 地理空间索引:例如查找附近的地点。
      • **分布式锁:**redission分布式锁基于redis实现,预防缓存穿透

      3.2 你手写一个分布式锁是怎么实现的

      3.3 redis分布式锁实现的时候,具体用到了什么命令

      答:实现Redis分布式锁主要用到以下命令:

      • SETNX key value:只有在键不存在时才设置值。
      • EXPIRE key seconds:为键设置一个过期时间,以防止死锁。
      • DEL key:释放锁,删除键。

      在新版本的Redis中,可以使用SET key value NX EX seconds命令结合SETNXEXPIRE的功能。

      3.4 缓存击穿的问题,除了使用分布式锁,还有别的方案呢?

      答:

      我的答案:设置两级缓存,两级缓存中的同一个键值对设置的过期时间是不一样的

      使用两级缓存是一个很好的方法来防止缓存击穿。两级缓存通常包括一个本地缓存和一个分布式缓存。本地缓存通常使用LRU(最近最少使用)策略,而分布式缓存可能是基于Redis或Memcached的。

      对于同一个键值对设置不同的过期时间,这是一个有效的策略。例如,你可以在本地缓存中设置一个较短的过期时间,而在分布式缓存中设置一个较长的过期时间。当本地缓存中的值过期时,应用可以从分布式缓存中获取值,而不是直接查询数据库。这样,即使分布式缓存中的值也过期,只有一个线程会去数据库中查询,其他线程会等待并从缓存中获取更新后的值。

      这种策略可以有效地减少对数据库的访问,特别是在高并发的情况下。但需要注意的是,两级缓存会增加系统的复杂性,需要确保两个缓存之间的同步和一致性。

      4 spring

      4.1 用过异步编程吗

      答:用过CompletableFuture

      4.2 哪些场景下用过CompletableFuture

      答:

      • 并行数据加载:例如,当需要从多个数据源并行加载数据时。
      • 异步API调用:例如,调用多个远程服务并在所有服务响应后进行数据聚合。
      • 异步计算:对于计算密集型任务,可以使用CompletableFuture并行执行。

      4.3 你用spring+mybatis构建web应用的时候,发现某一些请求特别慢,你怎么排查呢

      排查慢请求:

      如果有一些请求非常慢,以下是一些排查的步骤:

      1. 日志分析

        • 记录每个请求的响应时间。许多现代的web框架和服务器都允许你在日志中记录请求的响应时间。
        • 使用日志分析工具或脚本来识别响应时间超过预期阈值的请求。
      2. 性能监控工具

        • 使用如New Relic、Dynatrace、Datadog等性能监控工具,它们可以提供实时的应用性能指标,并帮助你识别慢请求。
      3. 分析请求和响应

        • 查看慢请求的输入参数、HTTP头、负载等,以确定是否有特定的模式导致延迟。
        • 分析响应内容,看是否有大量的数据被返回,这可能导致延迟。
      4. 数据库查询优化

        • 如果应用依赖于数据库,使用慢查询日志来识别和优化慢查询。
        • 使用数据库的性能分析工具来查看查询执行计划。
      5. 代码分析

        • 使用代码分析工具,如Java的JProfiler或VisualVM,来查看哪部分代码执行最慢。
      6. 外部服务

        • 如果应用调用外部服务或API,确保这些服务的响应时间是可接受的。
        • 使用工具如tracerouteping来检查网络延迟。

      4.4 内存泄漏的排查:

      内存泄漏是指应用程序在不再需要时,未能释放已分配的内存。以下是可能导致内存泄漏的情况和排查方法:

      1. 常见导致内存泄漏的情况

        • 静态集合类:长时间持有对象引用的静态集合。
        • 监听器和其他回调:没有被正确注销的监听器或回调。
        • 内部类和匿名类:非静态内部类或匿名类持有外部类的引用。
        • 线程池:长时间运行的线程持有对象引用。
        • 类加载器:当类加载器持有类的引用时,这些类不能被垃圾收集。
      2. 排查方法

        • Java堆转储:使用工具如jmap来获取堆转储,并使用MAT(Memory Analyzer Tool)或其他工具来分析。
        • 分析工具:使用如VisualVM、JProfiler等工具来监视应用的内存使用情况。
        • GC日志:开启GC日志并分析,查看是否有大量的Full GC事件。
        • 代码审查:定期审查代码,特别是那些处理资源和对象生命周期的部分。

      通过上述方法,可以有效地识别和解决应用中的慢请求和内存泄漏问题。

      4.5 MAT工具能够分析出这些发生的内存泄露嘛,怎么识别呢

      MAT(Memory Analyzer Tool)是一个强大的Java堆分析工具,它可以帮助开发者识别内存泄露和其他内存问题。以下是如何使用MAT来识别内存泄露的步骤:

      1. 获取堆转储文件:首先,你需要从受影响的Java应用程序获取一个堆转储文件。这通常可以通过JVM的jmap工具或其他相关工具来完成。

      2. 打开堆转储文件:启动MAT并打开你的堆转储文件。

      3. 使用"Leak Suspects"报告:MAT提供了一个名为"Leak Suspects"的报告,它会尝试识别可能的内存泄露。这是一个很好的起点,因为它会列出可能的泄露对象和它们在堆中的大小。

      4. 分析对象的路径:为了确定一个对象为什么还在内存中(即它为什么没有被垃圾回收),你可以查看该对象到GC Roots的路径。这可以帮助你识别哪些对象或引用链导致了内存泄露。

      5. 查看大的对象实例:MAT允许你查看堆中最大的对象实例。这可以帮助你识别那些占用大量内存但可能不需要的对象。

      6. 使用查询和过滤:MAT提供了一个基于OQL(Object Query Language)的查询系统,允许你执行查询来查找特定的对象或模式。

      7. 查看线程和类加载器信息:有时,内存泄露可能与特定的线程或类加载器相关。MAT允许你查看这些信息,这可以帮助你进一步定位问题。

      8. 比较堆转储:如果你有多个堆转储文件(例如,从应用程序运行的不同时间点),你可以使用MAT来比较它们。这可以帮助你识别内存使用的增长趋势和可能的泄露点。

      识别内存泄露通常需要一些经验和对应用程序的深入了解。MAT提供了很多有用的工具和视图来帮助你,但最终,你需要结合这些信息和你对应用程序的知识来确定和修复内存泄露。

      5 多线程

      5.1 使用多线程的时候注意哪些问题

      我的答案:并发安全、硬件资料的消耗问题,在这两方面做一个tradeoff

      使用多线程时,需要注意以下问题以确保线程安全、高效和可维护的代码:

      1. 数据竞争和条件竞争

        • 当多个线程尝试同时访问和修改共享数据时,可能会导致数据不一致。为了避免这种情况,需要使用适当的同步机制,如synchronized关键字、ReentrantLock等。
      2. 死锁

        • 当两个或多个线程永久地等待彼此释放资源时,会发生死锁。为了避免死锁,需要确保按照固定的顺序获取锁,并使用工具如jstack来检测和诊断死锁。
      3. 活锁

        • 当线程不断地尝试执行某个操作,但总是失败并重试时,可能会发生活锁。虽然线程是活跃的,但它们无法向前进展。
      4. 资源耗尽

        • 创建过多的线程可能会导致系统资源耗尽。使用线程池如ExecutorService可以帮助管理和限制线程的数量。
      5. 线程安全性

        • 不是所有的Java类和库都是线程安全的。在多线程环境中使用它们时,需要确保适当的同步。
      6. 线程间通信

        • 线程间需要合适的通信机制,如wait()notify()BlockingQueue等,以确保正确的协作。
      7. 线程优先级和饥饿

        • 设置线程的优先级可能会导致线程饥饿,即低优先级的线程得不到执行。通常,最好避免修改线程的优先级。
      8. 任务划分和粒度

        • 为了获得最佳的并发性能,需要合理地划分任务。太大的任务可能会导致其他线程等待,而太小的任务可能会导致过多的线程切换开销。
      9. 异常处理

        • 在多线程环境中,需要确保适当地处理异常,否则可能会导致线程意外终止。
      10. 可见性问题

        在没有适当同步的情况下,线程对变量的修改可能不会被其他线程看到。使用volatile关键字或其他同步机制可以确保变量的可见性。

      11. 上下文切换开销

        频繁的上下文切换会导致性能下降。尽量减少锁的竞争和线程的数量可以帮助减少上下文切换。

      12. 测试和调试

        多线程代码比单线程代码更难测试和调试。使用工具如Java Concurrency in Practice和专门的并发测试库可以帮助识别问题。

      总之,多线程编程是复杂的,需要深入的理解和经验来确保正确和高效的代码。

      6 消息队列

      6.1 kafka的消息积压问题怎么解决呢?

      Kafka的消息积压问题通常是指消费者不能及时处理生产者发送的消息,导致消息在Kafka中堆积。以下是一些建议的解决方案:

      1. 增加消费者数量

        • 如果消费者处理能力不足,可以增加消费者的数量。在Kafka中,可以通过增加消费者组中的消费者实例来实现。
      2. 优化消费者处理速度

        • 优化消费者的处理逻辑,确保每条消息都能够快速被处理。
        • 如果消费者需要进行复杂的处理,如数据库操作,可以考虑使用缓存或批量操作来提高效率。
      3. 调整Kafka参数

        • 调整fetch.min.bytesfetch.max.wait.ms参数,使消费者能够更频繁地从Kafka中拉取数据。
        • 调整max.poll.records参数,使消费者每次拉取更多的消息。
      4. 监控和告警

        • 使用监控工具,如Prometheus和Grafana,来监控Kafka的积压情况。
        • 设置告警,当积压达到一定阈值时,立即通知相关人员。
      5. 重新分配分区

        • 如果某些分区的消息积压特别严重,可以考虑重新分配分区,使得消费者能够更均匀地处理消息。
      6. 优化生产者速度

        • 如果生产者发送消息的速度过快,导致消费者无法跟上,可以考虑限制生产者的发送速度。
      7. 使用Kafka Streams或KSQL

        • 如果消费者需要进行复杂的流处理,可以考虑使用Kafka Streams或KSQL来分担处理压力。
      8. 数据压缩

        • 使用数据压缩可以减少Kafka中的数据量,从而减轻积压压力。
      9. 清理旧数据

        • 调整Kafka的log.retention.hours参数,定期清理旧的消息,以释放存储空间。
      10. 扩展Kafka集群

      • 如果Kafka集群的资源不足,可以考虑增加更多的broker来分担压力。

      总之,解决Kafka的消息积压问题需要综合考虑生产者、消费者和Kafka集群的各个方面,通过监控、调优和扩展来确保消息能够及时被处理。

      7 其他方面的能力

      7.1 有接触过容器化嘛

      容器化是一种技术,它允许将应用程序及其所有依赖项、运行时、系统工具和系统库打包到一个容器中。这个容器可以在任何环境中一致地运行,无论是开发者的本地机器、测试环境还是生产环境。容器化的主要优势在于它提供了一种隔离机制,确保应用程序在不同的环境中都能以相同的方式运行。

      容器化的主要特点包括:

      1. 一致性:由于应用程序和所有依赖项都打包在同一个容器中,所以无论容器在哪里运行,它都会表现得一样。

      2. 轻量级:与传统的虚拟机相比,容器不需要完整的操作系统,只需要应用程序和其运行时。这使得容器更加轻量级和快速。

      3. 可移植性:容器可以在任何支持容器技术的环境中运行,无论是物理机、虚拟机还是云环境。

      4. 隔离:每个容器都在其自己的命名空间中运行,与其他容器和主机系统隔离。这提供了安全性和隔离性。

      5. 微服务架构:容器化非常适合微服务架构,因为它允许每个服务在其自己的容器中独立运行。

      6. 快速部署和扩展:容器可以快速启动和停止,这使得部署、扩展和回滚变得更加简单和快速。

      Docker是最流行的容器化技术,它提供了一个平台来创建、运行和管理容器。Kubernetes则是一个开源的容器编排工具,用于自动化容器部署、扩展和管理。

      总的来说,容器化是一种使应用程序更加一致、可移植和可扩展的技术,它正在改变软件开发和部署的方式。

      7.2 你还会其他语言吗

      7.3 有接触过ML嘛

      7.4 你一般是怎么学习技术的呢

      7.5 会写博客嘛

      7.6 会读一些开源项目的源码嘛

      答:redis,spring线程池都读过

      7.7 会介意来合肥嘛

      答:

      8 反问

      8.1 做什么业务呢

      答:大模型

      8.2 大模型哪方面的

      答:大模型后台服务的,工程化的去提供一些周边的生态

      8.3 有哪些周边呢

你可能感兴趣的:(2024秋招,后端开发,科大讯飞)