Resume

2024 年 9 月 26 日 星期四
7

阅读此文章之前,你可能需要首先阅读以下的文章才能更好的理解上下文。

Resume

简历

基本信息

个人博客

教育背景

本科

  • 专业软件工程

  • 社团经历

  • 成绩绩点

研究生阶段

  • 研究方向ZSL

  • 成绩绩点

项目经历

基于知识图谱的数据智能分析

  • 省级科研项目

  • 作用

    • 上传excel、csv数据自动生成图表
  • 技术栈

    • SpringBoot

      • 快速构建基础的后端羡慕
    • Redis

      • 基于内存的高性能键值对存储

      • 羡慕中负责Session存储、限流

    • RabbitMQ

      • 时效性高,AIGC部分异步化、解耦
  • 技术

    • 基于五个知识图谱、提出基于数据与规则

    • 对原始数据进行校验文件名、大小、内容

      • 校验文件类型、通过检查文件的扩展名,校验后缀必须为xlsx

      • 从MulitpartFile中获取文件大小信息,限制最大10M

      • 防止用户改文件后缀上传非法文件,匹配特定格式文件的开头、结尾来校验格式

      • 使用腾讯云数据万象检验用户上传的内容是否合法

    • Redisson的RateLimiter分布式限流

      • 限流用于控制请求或时间流量,防止系统短时间内接收到过多的请求或时间

      • 项目中使用令牌他,限流算法:

        • 固定窗口技术限流算法

          • 将请求或时间的到达速率限制在固定的窗口内。例如每秒最多处理10个请求
        • 滑动窗口技术限流算法

          • 使用滑动窗口平滑处理请求。窗口内的请求计数按照时间的流逝而衰减,减少窗口边界的尖峰
        • 令牌桶算法

          • 令牌以固定速率添加到桶中,每个请求需要从令牌桶中获取一个令牌才能处理。如无令牌,则请求被延迟或者拒绝
        • 漏桶算法

          • 以恒定的速率漏水,请求到达时,尝试向桶中添加请求。桶满则拒绝请求。可以平滑请求,但不能处理突发请求。
      • Redisson中的RateLimiter

        • 是Redisson基于Redis实现的分布式限流组件,底层使用令牌桶算法,能够控制某个操作或者服务在一定时间内的请求频率。

        • 本项目的请求策略是单个用户每秒内最多执行两次生成图表操作

        • 集中管理限流器:创建一个RedisLimiterManager类,集中管理整个项目中的所有限流器,并提供创建限流器的接口。

        • 创建限流器:向redissonClient传入指定的key来创建限流器,每个用户对应的key不同,对应的限流器也不同,从而实现不同用户的独立限流。

        • 设置先流规则:通过rateLimiter的trySetRate方法制定限流规则,每秒内最多获取两个令牌

        • 请求令牌:用户要执行操作时,会执行对应rateLimiter的tryAcquire方法获取令牌,能获取到则执行,负责抛出异常

    • 自定义SQL分表存储

      • 一种数据库架构设计方法,通过将单一的数据库划分为多个子数据库多个表,将数据分散存储,从而提高查询性能、扩展性和负载均衡

      • 对用户上传的原始表格数据进行分表存储

    • 自定义IO密集型线程池+MQ并发和异步

      • 同步异步

        • 关注消息的通知机制,同步指完成一个任务并得到返回结果,才执行下一个任务; 异步指下一个任务不需要等上一个任务完成和返回结果,等任务完成后通过回调机制通知调用者
      • 阻塞和非阻塞

        • 阻塞指当前执行的任务结果返回之前,该线程会一直等待结果,不能执行其他任务; 非阻塞是指当前任务执行的结果返回之前,线程不用等待返回结果,可以执行其他任务
      • 线程池

        • 一种用于管理和复用线程的机制,允许应用程序中创建一组可用线程,并在需要执行任务时将任务分配给线程。

        • 主要目的是优化线程的创建、销毁和管理

        • 线程池的核心参数

          • ExecutorService executorService = new ThreadPoolExecutor(40, 1000, 10000, TimeUnit.MINUTES, new ArrayBlockingQueue<>(10000));

          • corePoolSize线程池中一直保持活跃的线程数

          • maximumPoolSize线程池中允许存在的最大线程数

          • keepAliveTime线程池中超过核心线程数时,如果在一定时间内没有执行任务,线程会被销毁

          • workQueue存放等待执行任务的阻塞队列

          • threadFacoty创建线程的工厂

          • rejectedExecutionHandler线程池无法接受新的任务时,根据设置的拒绝策略进行处理

    • MQ持久化消息,Direct交换机转发

      • 分布式消息队列

        • 作用是将一个消息从一个发送者传递给一个或多个接收者,从而实现解耦、异步、可靠的通信

        • 应用场景

          • 应用解耦:解耦系统内的不同模块,使其能够独立开发、部署、扩展。一个模块可以将消息发送到队列,而其他模块则可以异步接收并处理消息

          • 异步处理:将耗时的任务放入队列,由单个或多个工作线程来处理

          • 流量雪峰:突发高峰流量时,通过请求排队实现流量的平滑处理

          • 日志和监控:分布式MQ高效收集传输日志数据、监控数据、指标数据

          • 跨语言、平台:支持不同的语言和OS进行通信

          • 分布式事务:有些分布式MQ支持分布式事务,可以确保消息的可靠性传递和处理,保持一致性

        • 为什么使用

          • 分布式存储:消息存储在MQ中,利于系统扩展

          • 任务重试:使用消息的重试机制,未能成功处理,重新推送给消费者

          • 高扩展性、提高系统可靠性

        • 相比于其他MQ

          • Kafka吞吐量极高,适合处理大规模数据

          • RabbitMQ易学易用、时效性很强,可在多种OS中使用

          • rocketMQ使用金融、电商,要求高可靠性

          • activeMQ适用中小型企业

        • 四种交换机

          • Direct Exchange直连交换机:根据消息的路由键,将消息发送到与之完全匹配的队列上,通常用于点对点通信

          • Fanout Exchange广播交换机:将收到的消息发到所有与之绑定的MQ上,忽略路由键,通常用于广播消息给多个消费者

          • TopicExchange主题交换机:根据消息的路由键和绑定队列的通配符模式进行匹配,将消息发送到符合规则的队列上,常用于支持灵活的消息路由,相对复杂的业务场景

          • HeadersExchange头交换机:根据消息头部信息进行匹配,将消息发送到匹配规则的队列上

        • 如何使用

          • 引入spring-boot-starter-amqp

          • 创建初始化队列类,创建direct交换机、队列、以及交换机和队列的绑定

          • 创建生产者类,通过springboot整合的RabbitTemplate类操作MQ,比如调用convertAndSend方法,向指定的交换机发送指定路由键和消息

          • 创建消费者类,通过@RabbitListener注解标识处理消息的方法,并在方法内编写业务逻辑

  • 模型的推理能力不够

    • 选择付费使用OpenAI的key,带来了许多问题

      • 服务器部署的问题

      • 使用不合法的问题

      • 模型效果好的成本高

      • 还得使用第三方库,考虑使用SpringAI

编程考核系统

  • 校级创新项目

  • 后端模块

    • 用户服务

    • 题目服务

    • 判题服务

    • 代码沙箱

    • 公共模块

    • 网关服务

  • 库表设计

    • 用户表

    • 题目表

      • 通过json对象字符串存储判题配置信息,内存限制、时间限制。而不是把每种具体的配置单独做唯一列存储,便于该字段扩展

      • 给userid、questionid添加索引,提高查询性能

    • 题目提交表

      • status采用int存储,节约空间,业务代码定义枚举
  • 判题模块

    • 作用是查询题目提交和题目信息,调用沙箱代码,把代码和输入用例交给代码沙箱去执行,收集结果并执行判题逻辑

    • 定义一个通用的代码沙箱调用接口,选择三种代码沙箱实现类

      • 实例代码沙箱,本地跑通流程

      • 远程代码沙箱:调用自己开发的沙箱接口

      • 第三方沙箱:调用网上的,未采用

    • 为了简化代码沙箱硬编码,将代码沙箱的类型字符串配置化,更改application.yml动态调用

    • 使用代理模式对沙箱进行封装,实现同一日志操作

    • 原生代码沙箱和docker代码沙箱

      • 将用户代码保存成文件

      • 编译代码,得到class文件

      • 执行Java代码

      • 手机整理输出结果

      • 清理文件释放空间

      • 错误处理

      • 区别:Java原生通过Runtime.exec执行命令来执行代码,通过Process对象的流来获取输出结果,不够安全, Docker通过创建隔离的Java容器,通过exec在容器内部执行Java代码获取输出

    • Java安全管理器

      • 控制Java应用程序对系统资源的访问和执行权限。通过定义安全策略文件来管理和限制Java程序的操作,确保程序不会越权访问系统资源

      • 继承SecurityManager类自定义安全管理器,重写checkWrite和checkExce禁止用户写文件和执行文件

      • 修改沙箱代码执行Java的执行,绑定自定义的安全管理器 -DJava.security.,manager=MySecurityManager

    • JVM参数

      • -Xmx设置JVM最大堆的内存

      • Xms初始堆内存

      • Xss每个线程的堆栈大小

      • Xmn设置年轻代的对内存大小

    • Docker沙箱保证程序安全

      • 超时控制。指定超时参数,超时自动中断

      • 资源限制。HostConfig指定最大内存和CPU占用

      • 网络管理。禁用网络

      • 权限管理。限制用户代码的操作

    • 代码沙箱接口的安全性

      • 调用方与服务方约定加密字符串,调用方发送请求时,必须在请求头中携带该字符串,服务提供者会从请求头中取出该字符串进行比对。

      • API签名认证机制。给可信方分配accessKey、secretKey。调用方发送请求,使用sk堆请求参数进行校验;服务方用sk堆请求参数进行签名,然后校验是否一种

  • Redis的分布式Session实现用户登录

    • 用户登录成功后,后端生成唯一SessionId,表示用户的登陆状态

    • 用户信息存储:用户Id昵称等封装到java对象中,存储到Redis中

    • SessionID通常是随机字符串,关联用户和Session信息

    • Session信息存储到Redis中,存储时使用SessionID作为键,将用户序列化为字符串或其他适当的格式作为值,存储的时效性通过由Session的过期时间决定。

    • SessionID分货给前端:通过http的Cookie或者其他方式

    • 后续请求会携带SessionID,后端通过此获取用户信息,校验身份

    • 设置Session的过期时间,释放资源

实习经历

普华

  • ollama框架

    • 详细描述一下配置Ollama框架的过程吗?遇到过哪些挑战,您是如何解决的?

      • 环境准备、安装框架、拉去llama3模型,通过api和sdk,配置api接口

      • 权重文件大,gpu资源不够

  • 爬虫

鼎捷

技术栈

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...