光宇游戏一面记录

146 阅读8分钟

光宇游戏一面记录

半小时的hr面后迎来了技术一面,目前二面邀约还没有参加,仅仅作为记录📢
  1. 从基础开始吧,说一下HashMap集合结构吧

    • 首先对于jdk1.7来说,它的结构是数组+链表的形式
    • 对于jdk1.8来说,它引入了红黑树,也就是数组+链表+红黑树的结构
    • 对于红黑树的转换流程:当插入时使得链表长度大于8,数组长度小于64,会触发扩容
    • 如果扩容后没有导致链表长度减小,并且数组长度已经达到了64,会触发链表转换为红黑树
  2. 为什么要进行链表到红黑树的转换

    • 首先对于链表来说,它的时间复杂度是O(N),对于红黑树来说,它的时间复杂度是O(logN)
    • 常规情况下,我们使用hashMap时候很难触发到红黑树的转换规则,数学期望在千万分之6
    • 如果服务器被攻击时,也就是大量经过rehash后的相同的key被存入hashmap才会触发
    • 因此,主要目的还是为了防止由于这样的情况导致hashMap理想O(1)复杂度因链表过长恶化
  3. 对于HashMap的下标是如何计算的

    • 首先就是插入的时期,首先插入是惰性的,数组节点在首次插入时才会初始化
    • 对于下标的计算,在拿到这个key的hashcode之后,和它的高16位进行异或运算
    • 对于异或后的结果,后容量-1做与运算,得到具体的下标,二次hash为了综合高位,结果更散列
    • 对于扩容时的流程中(扩容容量翻倍),只需要判断hash&oldcap==0?保留原位置:旧位置+旧容量
  4. 关于Mysql和Redis这样关系型和非关系型数据库的区别,以及各自的适应场景

    • 性能方面,mysql基于磁盘,redis基于内存,因此redis适合做缓存或者少量热点数据,后者存储上限更高
    • 存储方面,redis是简单k-v存储,mysql基于表,字段,后者更适合做复杂查询
    • 安全方面,mysql具备acid四大原则,支持事务提交回滚,多级锁机制,适用数据安全性更高的场景
  5. 说到redis适合做缓存,那么和在程序内部通过hashmap的方式作为缓存哪里不一样

    • 在本地像使用Caffeine或者自定义的hashmap也可以起到缓存的作用,但是容量受到限制太大
    • 使用redis可以将这个容量大大提高,并且必要下还可以搭建分片集群提高上限,但是由于网络io性能会不及前者
  6. 聊一下垃圾回收算法

    • 常见的垃圾回收算法共三种,分别是标记清楚,标记整理,复制算法,对于老年代和新生代又采用分代回收
    • 标记阶段就是使用可达性分析算法寻找存活对象的过程,为了避免并发标记出现的漏标采用了三色标记算法
    • 清除就是在标记阶段后对死亡的对象在内存不足时候的回收的过程,但是会存在内存碎片出现
    • 整理就是在清除后对内存的紧凑,避免内存碎片的出现,但是影响一定的性能
    • 复制算法采用了两倍的内存空间,将存活对象从一块移动到另外一块,移动过程自然完成了清理的过程
    • 分代回收就是将老年代和新生代分别采用不同算法实现,一般年轻代采用复制算法,老年代采用标记整理算法
    • 但是对于cms垃圾回收器,老年代采用了标记清楚算法,由于内存碎片以及浮动垃圾(并发清理阶段用户线程产生的垃圾)导致有空间但大对象无法存放,会退化成seria old垃圾回收器
  7. 关于TCP和UDP有什么区别

    • TCP面向连接,提供可靠服务,UDP发送数据之前不需要建立连接,不保证可靠交付,只有简单差错检验
    • UDP具备很好的实时性能,工作效率比TCP高,对于高速传输和实时性通信更适用
    • UDP分组开销小,适用于单次传输较小数据的网络应用,TCP面向字节流,UDP每次是完整报文
  8. 现在使用的腾讯会议是采用的TCP还是UDP

    • 从性能上来说,udp的实时性能更好,对于这种实时性要求高的应用,运行偶尔卡顿出现,采用UDP
    • 另外本质特点,对上面区别的补充,TCP是1对1的,UDP支持1对1,1对多,多对多交互
  9. 关于spring的IOC和AOP

    • IOC是一种思想,spring使用容器化的方式给予了它实现,典型的两大容器BeanFactory以及ApplicationContext,一个Bean的创建,生命周期,乃至初始化都由前者的实现类完成。它的核心思想即控制反转,原来由我们程序员创建对象的权利交给了Spring去管理,之前如果需要一个dao层的对象,我们需要用new去创建,现在只需要将它从容器中获取即可
    • 说到IOC不得不提的一个相关概念DI依赖注入,一个对象在创建的过程中如果依赖的其它对象,这时候也不需要手动为它注入,而是spring帮助我们对它进行注入的过程
    • 对于AOP是一种面向切面编程的思想,简单来说就是通过不修改原有代码的前提下,去访问或者增强原有核心业务的非核心功能,比如事务控制,全局异常处理,日志处理等,spring通过动态代理的方式对它做了实现,一种是基于接口的jdk动态代理,一种是基于继承的cglib动态代理
  10. 对于文件上传到阿里云,如果某个时刻我先上传到腾讯云,怎样在不发版的下完成?

    • 采用配置热更新的方式,通过在我们的配置中心,比如nacos中的配置文件进行更改,并且允许这个注入值随着配置文件更改同时变动,当修改后下次读取最新的配置,进行上传
  11. 业务方面看你解决过OOM的问题,可以展开聊聊吗

    • 首先这个问题是由于在做Excel导出时候所产生的事故,这个问题的出现由于熔断机制不足也牵连了其他服务的故障,在对其它服务排查后没有发现到问题所在,于是紧急下线了最近上线的业务
    • 然后对这块的堆内存进行了一个导出分析,发现fullgc的频率十分的高,在正场情况下,fullgc的频率是不会超过一天一次的,这里肯定出现了问题,进一步分析后发现堆内存中存在大量Excel对象,于是定位到了问题所在。之后在测试环境中进行了测试,发现前端可以频繁的点击excel的导出,并且这里的excel使用的是poi,一次性将数据全部导入到内存,本身分配给这个服务的内存空间也比较小,上线后多个人频繁的多次点击必然引发了最终的oom
    • 解决,使用easyExcel对数据进行一个逐行导出,并且前后端做了幂等校验,当下载中的时候,不允许再次点击下载
  12. 你是怎么做的这个幂等校验?

    • 在数据库中增加状态字段,当点击下载后会将这个状态进行修改,再次点击的情况下会先判断状态值,如果正在下载会禁止重复点击,下载完成后更新状态为下载完成
  13. 看到你们有这个热数据实时计算,这个是怎么做的?

    • 这里我们没有引入复杂的逻辑,通过Kafka的stream流做了实时计算处理。当有点赞收藏等行为发生时,先通过Kafka stream的聚合处理,根据key(文章id)聚合,处理结果10秒进行一次发送,发送到消费者端重新按照各权重进行计算分值,当天的权重还要再*3,然后对redis数据做一个替换。reddis替换时先查询redis的缓存文章, 文章如果已经存在就更新分值,文章数量小于30直接加入到缓存,否则替换掉分值比它小且最小的文章,然后重新排序
  14. 你们项目中用到了哪些定时任务,以及频率

    • 我们的文章在康复师后台上架后,会对ap端做一个同步,通过kafka做消息同步,为了避免丢失,通过定时任务做一个补偿,每小时对后台审核成功的文章进行扫描,对没有成功在ap端上架的文章重新上架
    • 对延迟任务采用的redis,每分钟讲数据库的数据同步到zset结构当中去,每秒把zset结构中的数据同步到list结构中去,其中zset同步到list过程采用scan扫描key以及pipline管道传输的方式
    • 对于文章,每天临晨对文章计算分值,重新排序,热点文章存入redis等等