面试

什么是高效的面试

自信

要怎么准备

拉伸知识的广度:了解互联网的主要技术栈,形成知识网络

提升知识的深度:由浅入深,由点到面,对每个技术栈形成梯度,整理梳理。每个梯度都要准备1到2个由代表性的高频面试题。(种子)

并发篇

一、Java如何开启线程?怎么保证线程安全?

线程和进程的区别:进程是操作系统进行资源分配的最小单元。线程是操作系统进行任务分配的最小单元,线程隶属于进程。

如何开启线程?1、继承Thread类,重写run方法。2、实现Runnable接口,实现run方法。3、实现Callable接口,实现call方法。通过FutureTask创建一个线程,获取到线程执行的返回值。4、通过线程池开启线程。

JVM的Synchronized和JDK提供的Lock

// 死锁代码
public class DeadLock {
    static final Object lockA = new Object();
    static final Object lockB = new Object();

    public static void main(String[] args) {
        Thread threadA = new ThreadA();
        threadA.start();
        new Thread(new ThreadB()).start();
    }
    public static class ThreadA extends Thread {
        public void run(){
            synchronized(lockA){
                System.out.println("线程a拿了lockA");
                try {
                    sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized(lockB){
                    System.out.println("线程a拿了lockB");
                }
            }
        }
    }
    public static class ThreadB implements Runnable {
        @Override
        public void run() {
            synchronized (lockB){
                System.out.println("线程b拿了lockB");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized(lockA){
                    System.out.println("线程B拿了lockA");
                }
            }
        }
    }
}

二、volatile和Synchronized?volatile能不能保证线程安全?DCL(Double Check Lock)单例模式为什么要加volatile?

1、Synchronized用来加锁。volatile只能保证变量的线程可见性和有序性。通常用于一个线程写,多个线程读的情况。

2、不能,volatile不保证原子性。

3、volatile防止指令重排序。在DCL中,防止高并发情况下,指令重排造成的线程安全问题。(int i= 1;分三步1,分配内存2,对象初始化3,建立指针关系)

三、java线程锁机制?偏向锁,轻量级锁,重量级锁?如何升级

1、就是在对象头第一个字节后三位中记录一个锁状态。1位是否偏向,2位锁标志

2、java的锁机制就是根据资源竞争的激烈程度不断进行锁升级的过程。

四、AQS(AbstractQueuedSynchronizer)?AQS如何实现可重入锁

1、AQS是一个java线程同步框架,是jdk中很多锁工具的核心实现框架。

2、维护了state信号量和一个线程组成的双向链表队列,这个线程队列用来给线程排队的。

五、CountDownLatch(模拟高并发),CylicBarrier(满足个数才走),Semaphore(给排队的线程一个权重,交错执行)

网络通信篇

一、TCP和UDP

Transfer Control Protocol 面向连接,可靠的传输层协议

close_wait,time_wait 2MSL最长报文段寿命

User Datagram Protocol 无连接,不可靠的传输层协议

Ø 同步:客户端在发送请求之后必须等到服务器回应之后才可以发送下一条请求。串行运行

Ø 异步:客户端请求之后,不必等到服务器回应之后就可以发送下一条请求。并行运行

二、NIO、AIO

同步非阻塞,解决了BIO中线程太多的问题,引入了Selector,不过还是要检查有没有处理完

异步是针对请求,阻塞、非阻塞是针对客户端

AIO:后端有一个异步请求队列,服务端处理完之后放入队列,通过队列把响应推给客户端,解决了服务端一直守着线程的问题

然而异步通知的过程服务是没法做的,需要操作系统的支持,因为服务是不稳定的。

三、NIO的组件

client→Buffer→Channel→Selector→Thread

Channel类似于“流”。每个Channel对应一个Buffer缓冲区。Channel会注册到selector。

Selector会根据Channel上发生的读写事件,将请求交由某个空闲的线程处理。底层是epoll实现,有两个集合,socketchannel集合和就绪事件集合

buffer和channel都是全双工

四、select、poll和epoll(API)

他们是NIO中多路复用的三种实现机制,由LinuxOS提供。

文件描述符 File Descriptor(FD):形式上是个整数,实际上是一个索引值。指向内核中为每个进程维护进程所打开的文件的记录表。当程序打开或创建一个文件时,内核就会向进程返回一个FD。

  1. Select机制:会维护一个FD的数组 fd_set。将fd_set从用户空间复制到内核空间,激活socket。最大为2048
  2. Poll机制:和select机制差不多,把fd_set结构进行优化换成了链表实现,FD集合的大小突破了OS的限制
  3. EPoll(红黑树):Event Poll,epoll不再扫描所有的FD,只将用户关心的FD事件放到内核的一个事件表中。减少用户空间和内核空间之间需要拷贝的数据

五、http和https

  1. https要ca证书,要钱
  2. 传输协议不同,https443端口,而http80端口
  3. http的连接是简单无状态的,https的数据传输时经过证书加密的

JVM篇

一、JVM内存模型

JMM

二、类加载过程,双亲委派,一个对象从加载到JVM,到被GC清除经历了什么过程?

类加载过程:加载→验证→准备→解析→初始化

加载:把Java的字节码数据加载到JVM内存(方法区)中,并映射成JVM认可的数据结构。

验证:检查加载到的字节信息是否符合JVM规范。(比如.class字节码文件开头的CA FE BA BE)

准备:创建类或接口的静态变量,并赋初始值,半初始化状态(在堆中初始化,classpoint指向元空间的class)

解析:把符号引用转为直接引用(在栈里初始化指针,指向堆里面的内存)

初始化:执行类构造器clinit方法,静态变量赋值和静态代码块,如果类构造器方法中触发了对象初始化(init方法),会执行init方法之后回来继续执行clinit方法。

类加载器:AppClassloader→ExtClassloader→BootStrap Classloader(在Java中不是继承关系)

每个类加载器对他加载过的类,都有一个缓存

双亲委派:向上委托查找,向下委托加载

一个对象的一生

  1. 用户创建了一个对象,JVM首先需要到方法区去找对象的类型信息。然后再创建对象。
  2. JVM实例化一个对象,首先要在堆中创建一个对象。→半初始化状态
  3. 对象首先会分配在堆中的Eden,然后经过一次Minor GC,对象如果存活就进入S区。在后续的每次GC中如果对象一直存活,就会在S区来回拷贝,每移动一次年龄加一(4bit)。超过一定年龄后对象转入老年代。
  4. 当方法执行结束后,栈中指针先移除
  5. 堆中的对象,经过Full GC,就会被标记为垃圾被GC线程清除。

什么时候会fullgc

  1. 调用system.gc()
  2. 未指定老年代和新生代大小,堆伸缩时会fullgc,所以要配置-Xmx和-Xms;
  3. 老年代空间不足;
  4. 统计得到的minor gc存活对象超过了老年代剩余空间;
  5. jdk1.7之前的永久代满了

常用工具

jps,jstack,jconsole。jps可以查看Java进程,jstack查看死锁,jconsole还可以查看到对象分配情况。

三、确定垃圾,GC root

引用计数:给堆内存中的每个对象记录一个引用计数。无法解决循环引用

可达性分析:从GC root向下一直找引用,找不到就是垃圾。

GC Root:Stack→JVM Stack,Native Stack,方法区→static,Class类,常量池

四、垃圾回收算法

MarkSweep 标记清除

Copying 复制(新生代是复制算法)

MarkCompact 标记压缩

五、垃圾回收器,STW发生在哪些阶段,三色标记,如何解决错标和漏标?为什么设计这么多垃圾收集器?

Serial 串行:只有一个线程在GC

Parallel 并行:多线程GC,PS+PO是JDK1.8默认的垃圾回收器

Concurrent Mark Sweep:将STW打散, 让一部分GC线程和用户线程并发执行。

CMS

  1. 初始标记:STW,只标记出GC Roots直接引用的对象。
  2. 并发标记:继续标记其他对象,并发执行。
  3. 重新标记:STW,对并发执行阶段的对象进行重新标记。
  4. 并发清除:并发将产生的垃圾清除。

G1 Garbage First 垃圾优先

对堆内存不在分old和eden,而是划分为一个一个小内存块Region。每个Region可以隶属于不同的年代。

  1. 初始标记:STW,标记出GC Roots直接引用的Region。
  2. 标记Region:通过RSet标记出初始标记的Region引用的Old区Region。
  3. 并发标记:跟CMS差不多,只需遍历第二步标记出的Region。
  4. 最终标记:STW,跟CMS差不多。
  5. 筛选回收:跟CMS不同,G1可以采用拷贝算法。这个阶段G1只选择垃圾较多的Region清理。

CMS核心算法就是三色标记。

CMS通过增量标记 increment update 方式来解决漏标问题

G1通过SATB(Snapshot at the Beginning)将所有即将被删除的引用关系的旧引用记录下来。

六、如何JVM调优?JVM参数,怎么查看JAVA进程的JVM参数,谈谈你了解的jvm参数。一个java程序每运行一段时间后都变得非常卡顿,如何优化?

通过定制JVM运行参数来提高JAVA应用程度的运行。

JVM参数大致分为三类:

  1. 标注指令:-开头,所有HotSpot都支持的指令。java -help
  2. 非标准指令:-X开头,跟特定的HotSpot版本对应。java -X
  3. 不稳定指令:-XX开头,变化大。如java -XX:+PrintCommandLineFlags:查看当前命令的不稳定指令。java -XX:+PrintFlagsInitial:查看所有不稳定指令的默认值。java -XX:+PrintFlagsFinal:查看所有不稳定指令最终生效的实际值。

https://arthurjq.com/2021/03/16/java/jvm-tuning/

缓存篇

一、为什么使用缓存

高性能、高并发

二、缓存击穿,缓存雪崩,缓存穿透

并发查同一条数据,同一时间大面积失效,并发查不存在的数据

三、如何保证redis和数据库的一致性

  1. 如果删除了缓存Redis,还没有来得及写库MySQL,另一个线程就来读取,发现缓存为空,则去数据库中读取数据写入缓存,此时缓存中为脏数据。
  2. 如果先写了库,在删除缓存前,写库的线程宕机了,没有删除掉缓存,则也会出现数据不一致情况。

没有什么方案是完美的,先更新数据库,然后删除缓存,删除缓存时,把key放到消息队列,直到删除成功。

四、如何设计一个分布式锁,如何对锁性能优化

数据库利用主键冲突控制一次只有一个线程能获取锁,非阻塞(要自己写阻塞代码)、不可重入(递归不支持,要自己实现AQS)、单点、不支持失效时间(要自己写定时器)

zk通过Znode解决死锁问题,一旦客户端获取锁后突然挂掉,这个临时节点会自动删除,其他客户端自动获取锁。临时顺序节点解决惊群效应。

setNX命令,单线程处理网络请求,不需要考虑并发安全性。

setNX问题:

  1. 早期版本没有超时参数,需要单独设置,存在死锁问题(key不会超时)
  2. 后期版本提供加锁和设置时间原子操作(set(NX,timeout)),但是存在任务超时,锁自动释放,导致并发问题,加锁和释放锁不是同一线程问题(假如T1获得锁要执行15s,锁失效时间为10s,在这5s内T2获得了锁,T1执行完了要把锁释放掉,结果把T2的锁释放了,解决方法可以在value中存上线程的唯一标识或者uuid,删除锁:判断线程唯一标识再删除

可重入性及锁续期没有实现,通过redisson解决(类似AQS实现(count计数),看门狗监听机制(设置一个监听器监听任务,任务没有执行完就延长过期时间))

redlock:以上的机制都只操作单节点,即使Redis通过Sentinel保证高可用,如果这个master节点由于某些发生了主从切换,那么就会出现锁丢失的情况(主从节点间是异步通信,Redis同步设置可能数据丢失)。redlock从多个节点申请锁,当一半以上节点获取成功才算成功,redisson有相应的实现

五、redis如何配置key的过期时间?实现原理

1、EXPIRE 。2、SETEX

实现原理:1、定期删除:每隔一段时间,执行一次删除过期key的操作。2、懒汉式删除:当使用get、getset等指令取获取数据时,判断key是否过期。过期后,就先把key删除,再执行后面的操作。

Redis是将两种方式结合使用。定期删除:平衡执行频率和执行时长。定期删除时会遍历每个database,检查当前库中指定个数的key(默认20)。随机抽查这些key,过期了就删除。程序中有一个全局变量记录扫描到哪个库

expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间的某个键的指针,value是该键的毫秒精度的unix时间戳表示的过期时间,键空间是指向该redis集群中保存的所有键。

六、海量数据快速查询

1、使用布隆过滤器,快速过滤不存在的记录。使用Redis的bitmap结构来实现布隆过滤器

2、再Redis中建立数据存储。将对redis使用场景的理解表达出来

以字符串存储(userId->user.json)。以hash存储一条数据(HMSET user {userId}:name jinquan {userId}:age 24),一个hash最多能支持2^32 - 1(40多亿)个键值对

缓存击穿:对不存在的数据也建立key,这些key都是经过布隆过滤器过滤的,所以一般不会太多

缓存过期:将热点数据设置永不过期,定期重建缓存。使用分布式锁重建缓存

3、查询优化,按槽位分配数据

微服务篇

一、微服务的理解,优点

微服务是一种架构风格,通过将大型的单体应用划分为比较小的服务单元,从而降低整个系统的复杂度。

优点:

  1. 服务部署更灵活:每个应用都可以是一个独立的项目,可以独立部署,不依赖于其他服务,耦合性降低
  2. 技术更新灵活:再大型单体应用中,技术要进行更新,往往是非常困难的。而微服务可以根据业务特点,灵活选择技术栈
  3. 应用的性能得到提高:大型单体应用中,往往启动就是一个难关。而采用微服务后,整个系统的性能能够提高
  4. 更容易组合专门的团队:在单体应用时,团队成员往往需要对系统的各个部分都要深入了解,门槛高。采用微服务后可以给每个微服务建专门的团队
  5. 代码复用:很多底层服务可以以REST API的方式对外提供统一的服务,所有基础服务可以在整个微服务系统中通用

缺点:

  1. 服务调用的复杂性提高:网络问题,容错问题,负载问题,高并发问题等
  2. 分布式事务:尽量不要使用微服务事务
  3. 测试难度提高
  4. 运维难度提高:单体架构只要维护一个环境,而到了微服务是很多个环境,并且维护方式不一样,所以对部署、监控、告警等要求就会变得非常困难。

去中心化,独立数据库

建module→改pom→写yml→主启动→业务类

二、SpringCloud和SpringCloudAlibaba组件?都解决了什么问题

Netflix

Alibaba

SpringCloud提供了构建微服务系统所需要的一组通用开发模式以及一系列

gateway:统一服务对外入口,鉴权,过滤拦截(Gateway Handler Mapping→Gateway Web Handler, http请求断言,发送代理请求前后的Filter链),webflux→Reactor模式的netty

hystrix:熔断:防止异常扩散,降级:断路器打开,调用失败的补救,只是服务水平下降,监控

Ribbon:客户端负载均衡

Feign / OpenFeign:RESTful的http服务客户端,定义一个服务接口添加注解

sleuth-zipkin:每个请求都会形成一条复杂的分布式服务调用链路,链路中任何一环出现高延时或错误都会引起整个请求最后的失败

nacos:集成ribbon,项目初始化时先从配置中心拉取配置

sentinel:@SentinelResourse,熔断,降级(异常比例或异常数),限流(QPS,线程数快速失败,预热,排队等待)组件可以单独独立出来,界面化的细粒度统一配置,信号量隔离

seata:

  1. 事务管理器TM(事务的发起方)向事务协调者TC申请开启事务,全局事务创建成功并生成一个全局唯一XID
  2. XID在多个TM和RM中传播
  3. RM向TC注册分支事务(branch_id),将其纳入XID管辖
  4. TM向TC发起针对XID的全局提交或回滚
  5. TC协调XID下全部事务分支完成提交或回滚

三、分布式事务如何处理?怎么保证事务一致性

分布式事务就是将不同节点上的事务操作,提供操作原子性保证,同时成功或者同时失败。分布式事务的第一个要点就是在原来没有直接关联的事务之间建立联系。

1、HTTP连接:最大努力通知。本质上通过定期校对(事后补偿),实现数据一致性

2、MQ:事务消息机制。

3、Redis:除了下图外,还有很多细节需要处理,分布式事务时长,幂等性问题

Redis实现分布式事务

4、Seata:通过TC在多个事务之间建立联系

2PC:1、准备阶段,协调者向参与者发送pre,询问参与者是否能够提交事务;参与者收到pre后进行本地事务的预处理但不提交。2、提交阶段,如果协调者收到参与者失败就rollback,所有的参与者都返回ready就都发送commit回去。

两阶段

2PC问题:单点故障,事务管理器一旦故障参与者就被阻塞。同步阻塞,需要锁资源,所以XA和AT前提需要连接数据库来保障,数据不一致

3PC:把2PC的准备阶段再次拆分,第一个阶段不锁资源,引入参与者超时机制,解决了协调者故障后参与者阻塞问题。解决了单点故障问题。

3阶段

  1. canCommit:协调者问参与者,是否具备执行事务的条件
  2. preCommit:协调者通知参与者进行事务的预提交
  3. doCommit:协调者根据preCommit参与者反馈结果通知参与者commit or rollback

TCC(业务层次):校验、资源锁定、补偿,对每个操作(Try)都提供确认(Confirm)和取消(cancel)的操作

TCC问题:业务服务需要提供try、confirm、cancel三种方法来支持,业务侵入性强。Confirm / Cancel要做幂等性设计

Sage:与TCC不同的是Saga不需要Try,而是直接进行confirm、cancel操作,适合长流程的业务。不需要锁资源。事件驱动模式,参与者可异步执行,高吞吐,成本低,但是无法保证隔离性

AT:无侵入的分布式事务解决方案,适用于不希望对业务进行改造的场景,几乎0学习成本(sql都由框架托管统一执行,会存在脏写问题)

  1. 保存before image→业务sql→保存after image→生成行锁,业务sql和undo log/redo log在同一个本地事务提交,释放本地锁和连接资源
  2. 提交异步,回滚通过一阶段的回滚日志反向补偿(校验脏写→还原数据),成功或回滚都要删除前后快照和行锁

https://arthurjq.com/2021/03/20/mq/

四、怎么拆分微服务?怎么设计出高内聚低耦合的微服务?DDD领域驱动设计?中台?中台和微服务的关系

拆分微服务时,为了尽量保证微服务的稳定,会有一些基本的准则:1、微服务之间尽量不要有业务交叉。2、微服务之间只能通过接口进行服务调用,不能直接访问对方数据库。3、高内聚低耦合,一种从上而下指导微服务设计的方法。实现工具有 同步的接口调用 和 异步的事件驱动(如MQ)

  1. 基于工作流拆分服务:服务的拆分法则,基于工作流拆分服务,确保该工作流运行在一个实例中。
  2. 服务器即是服务池:所有物理机应该是一个服务池,根据我们的需求,可以将它部署成任何服务。

比如:用户 —> 商品中心(浏览)—> 搜索中心(过滤)—> 用户中心(添加购物车)—> 物流中心 (物流方式) —> 结算中心(支付结算/扣积分)—> 商品中心(扣库存)—> 用户中心 (完成)

Domain-Driven-Design在2004年有Eric Evans提出,面向软件复杂之道

Maritin Fowler 贫血模型,贫血失忆症→充血模型

MVC架构→领域优先的四层架构

充血模型

大泥团:不利于微服务的拆分。大泥团结构拆分出来的微服务依然是泥团结构,当服务业务逐渐复杂,这个妮团又会膨胀成大泥团(比如下单微服务和物流微服务公用一个DB)

所以采用领域拆分:

DDD只是一种方法论,没有一个稳定的技术框架。DDD要求领域跟技术、存储、通信无关。

中台:将各个业务线中可以复用的一些功能抽取出来,剥离个性,提取共性,形成一些可复用的组件。大体上分为三类:业务中台(抽象出来的在各个业务线都能公用的组件,如用户的权限管理,用户支付)、数据中台(对整个系统的数据进行统一的存储建模与计算,为各个系统的分析与利用提供支持,如芝麻信用,大数据杀熟)和技术中台(封装各个系统需要的技术框架,对上层业务开发的门槛降低,提高交互的速度)。

中台和DDD结合:DDD会通过限界上下文将系统拆分成一个一个的领域,而这种限界上下文,天然就成为了中台的逻辑屏障。设计不再凭个人,而是整个团队的力量。DDD在技术与资源调度方面都能够给中台建设提供不错的指导。

DDD分为战略设计和战术设计。上层的战略设计能够很好的指导中台划分,下层的战术设计能够很好的指导微服务搭建。

五、你的项目中是怎么保证微服务敏捷开发的?微服务链路追踪,持续集成,AB发布要怎么做?

敏捷开发:目的是提高团队的交付效率,快速迭代,快速试错。

每个月固定发布新版本,以分支的形式保存到代码仓库中。快速入职。任务面板,站立会议。团队人员灵活流动,同时形成各个专家代表。测试环境-生产环境 →开发测试环境SIT、集成测试环境、压测环境STR、预投产环境、删除环境PRD。文档优先。晨会、周会、需求拆分会。

链路追踪:1、基于日志。形成全局事务ID,落地到日志文件。filebeat→logstash→elasticsearch形成大型报表。2、基于MQ,往往需要架构支持。经过流式计算形成一些可视化的结果。

持续集成:SpringBoot maven pom→build→shell;Jenkins。

AB发布:1、蓝绿发布(基于本地)、红黑发布(基于云计算)。老版本和新版本是同时存在的。2、灰度发布、金丝雀发布。邀请一部分人新版本尝试

Spring底层篇

一、什么是Spring,IOC和AOP

装java bean的容器框架

IOC:

  1. 容器:实际上就是个map存各种对象,在代码需要用到里面对象时,再通过DI注入
  2. 控制反转:解耦,获得依赖对象的过程由主动变为被动
  3. 依赖注入:实现IOC的方法,动态地注入依赖关系

AOP:

将程序中的交叉业务逻辑(比如安全,日志,事务等),封装成一个切面,然后注入到目标对象(具体业务逻辑)中去。AOP可以对某个对象或某些对象的功能进行增强,比如对象中的方法进行增强,可以在执行某个方法之前或之后额外做一些事情。

Spring的特性

ioc,aop,声明式事务的支持,方便测试(以非容器依赖的编程方式进行),方便整合框架,降低JavaEE API的使用难度

二、Spring容器启动流程

  1. 初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中
  2. 将用户配置类的BeanDefinition注册到容器中
  3. 调用refresh方法刷新容器

三、Bean的创建流程

首先是实例化、属性赋值、初始化、销毁这 4 个大阶段;

再是初始化的具体操作,有 Aware 接口的依赖注入、BeanPostProcessor 在初始化前后的处理以及 InitializingBean 和 init-method 的初始化操作;

销毁的具体操作,有注册相关销毁回调接口,最后通过DisposableBean 和 destory-method 进行销毁。

四、Spring中Bean是线程安全的么?如何处理

单例无状态Bean是线程安全的,有状态的Bean通过ThreadLocal解决,因为ThreadLocal每个线程私有

五、Spring如何处理循环依赖

三级缓存(解决循环依赖):

一级:singletonObjects map<beanName,Object> (单例池)

二级:earlySingletonObjects map<beanName,Object> (提前AOP)

三级:singletonFactories (放了个lambda)

earlyProxyReferences ConcurrentHashMap<beanName,bean的原始对象>(循环引用时记录是否提前生成了代理对象)

creatingSet ()

流程:假设Aservice和Bservice互相依赖,当Aservice出现循环依赖的话会提前AOP

  1. creatingSet.add(Aservice)
  2. class→实例化得到Aservice原始对象→singletonFactories map<beanName,lambda(beanName,BeanDefinition,Aservice原始对象)>
  3. 给Bservice属性赋值→从单例池找Bservice→找不到→创建Bservice的bean
    1. class→实例化得到Bservice原始对象
    2. 给Aservice属性赋值→从单例池找Aservice→找不到→creatingSet→Aservice出现循环→earlySingletonObjects→singletonFactories→lambda→AOP→Aservice代理对象→放入二级缓存(调用getEarlyBeanReference()提前生成代理对象)
    3. 给其他属性赋值
    4. 其余AOP
    5. 将对象放入单例池
  4. 给其他属性赋值
  5. 其余事情AOP→Aservice代理对象→postProcessAfterInitialization()(看earlyProxyReferences有没有提前生成代理对象)
  6. earlySingletonObjects.get(Aservice)
  7. creatingSet.remove(Aservice)
  8. 将对象放入单例池

六、Spring如何处理事务

编程式事务:通过编码方式实现事务,使用TransactionTemplate或PlatformTrasactionManager

声明式事务:注解,AOP,本质就是在目标方法执行前后进行拦截

七、SpringMVC中控制器如何保证线程安全

SpringMVC中控制器默认单例,在Controller中使用ThreadLocal变量或scope=”prototype”

最好的方式是将控制器设计成无状态模式,在控制器中不要携带数据,但可以引用无状态的service和dao。

Mysql篇

一、数据存储引擎,区别

show ENGINES

MyISAM:

  1. 不支持事务,但是每次查询都是原子
  2. 支持表级锁
  3. 存储表的总行数
  4. 一个MyISAM表有三个文件:表结构文件,索引文件,数据文件
  5. 采用非聚簇索引,索引文件的数据域存储指向数据文件的指针。辅索引与主索引基本一致,但是辅索引不保证唯一性

InnoDB

  1. 支持ACID事务,支持四种隔离级别
  2. 支持SAVEPOINT部分回滚
  3. 支持行级锁及外键约束,因此可以支持写并发
  4. 不存储总行数,算行数要全表扫描
  5. 一个InnoDB引擎存储在一个文件空间(共享表空间,表大小不受操作系统控制,一个表可能分布在多个文件里),也可能多个(设置为独立表空,表大小受操作系统文件大小限制,一般为2G)
  6. 主键索引采用聚簇索引,辅索引的数据域存储主键的值;最好使用自增主键,防止插入数据时,为维持B+树结构,文件的大调整。

二、脏读,不可重复读,幻读,如何处理

为了防止脏读,每次写入前,数据库都会记住旧值,当前事务尚未提交时,其他事务的读取都会拿到旧值。当前事务提交后,其他事务才能读取到新值。

原子写,for update锁行,CAS

加锁:1、脏读和不可重复读:在修改时加排他锁,直到事务提交才释放。读取时加共享锁。2、幻读:加范围锁。

三、事务的基本特性和隔离级别

https://arthurjq.com/2020/12/25/database/isolation/

四、Mysql的锁有哪些,间隙锁

共享锁:读锁。多个事务可以对同一个数据共享一把锁。持有锁的事务都可以访问数据,但是不能修改。select xxx LOCK IN SHARE MODE

排他锁:写锁。只有一个事务能够获得。InnoDB会对ipdate/delete/insert语句自动添加排他锁。

自增锁:通常时针对mysql的自增字段。如果又事务回滚,数据回回滚,但自增序列不会回滚。

粒度:表锁,行锁(记录锁+间隙锁=临建锁),页锁,全局锁(Flush tables with read lock)

间隙锁(Gap Lock):属于行锁的一种,是在事务加锁后其锁住的是表记录的某一个区间,当表的相邻ID之间出现间隙则会形成一个区间,遵循左开右闭原则。只会出现在重复读的事务级别中。

五、Mysql的索引结构是什么?

B+ Tree

六、Mysql的集群如何搭建,读写分离怎么做

让master来响应事务性操作,让slave来响应select非事务性操作,然后再采用主从复制来把master上的事务性操作同步到slave数据库中。实现简单的负载均衡。

show master status查看binlog文件和Position

show slave status查看Slave_io_State,Master_Host,Master_Log_File,Read_Master_Log_Position等

mysql主从复制

主要由三个线程:master(binlog dump thread)、slave(I / O thread、SQL thread)

  1. 主节点binlog,主从复制的基础是主库记录数据库的所有变更记录到binlog。binlog是数据库服务器启动的那一刻起,保存所有修改数据库结构或内容的一个文件。
  2. 主节点log dump线程,当binlog有变动时,lo g dump线程读取其内容并发送给从节点。
  3. 从节点I /O 线程接受binlog 内容,并将其写入到relay log 文件中。(relay log在从节点)
  4. 从节点的SQL线程读取 relay log 文件内容对数据更新进行重放,最终保证主从数据库一致性。

半同步复制

七、分库分表,多大数据量需要分库分表,分库分表方式和分片策略

1,阿里开发手册建议一个表的数据量超过500w或数据文件超过2G

分库分表最常用组件:Mycat / ShardingSphere(Sharding-JDBC)

垂直分库:指按照业务将表进行分类,分布到不同的数据库上面,专库专用

水平分库:把同一个表的数据按一定规则拆到不同的数据库中,如id%2

垂直分表:将一个表按照字段分成多表,每个表存储其中一部分字段

水平分表:在同一个数据库内,把同一个表的数据按一定规则拆到多个表中,跟水平分库类似

分片策略:地理,id,用户,时间,目标字段前缀,取决于你的应用

搜索引擎篇

一、倒排索引?有什么好处

索引:从ID到内容。倒排索引:从内容到ID。

记录每个词条出现在那些文档,及文档中的位置,快速定位到包含这个词条的文档和出现的位置,控制数据的总量

倒排本质上就是基于term的反向列表,基于FST形成一个有向无环图,FST定位到倒排链后,然后倒排链的合并

为了能够快速查找docid,SkipList本质上是在有序的链表上实现实现二分查找,空间换时间

文章→term→排序term dictionary→term index(维护了字典的前缀和偏移范围)→Posting List→[文章ID,[在文章中出现的偏移量],权重] TFIDF

二、ES?说说你们公司的es集群架构

  1. index:mysql中的table。
  2. document:row。
  3. 字段 field text/keyword/byte :列
  4. 映射 Mapping:Schema
  5. 查询方式 DSL:sql,新版也支持sql
  6. 分片sharding和副本replicas

动态映射,不需要定义Mapping映射

ES 集群架构 3 个节点,索引根据通道不同共 10+索引,根据日期,每日递增 10+,索引:1 分片,replica默认1对1,每日递增3GB数据

默认混合部署,Data Node 和 Transport Node,Node中会持有一个全局的路由表,缺点就是多种类型的请求会相互影响,不能支持集群的热更新

三、如何进行中文分词?用过哪些分词器

ik_smart、ik_max_word

HanLP

四、es写入数据的工作原理?

  1. 客户端通过hash选择一个node发送请求,这个node被称做coordinating node(协调节点)
  2. 协调节点对document进行路由,将请求转发给到对应的primary shard
  3. primary shard 处理请求,将数据同步到所有的replica shard
  4. 此时协调节点,发现primary shard 和所有的replica shard都处理完之后,就反馈给客户端。

五、es查询数据的工作原理

  1. 客户端发送get请求到任意一个node节点,然后这个节点就称为协调节点
  2. 协调节点将查询请求广播到每一个数据节点,每个分片进行数据查询,将符合条件的数据放在一个队列中,并将这些数据的文档ID,节点信息,分片信息都返回给协调节点
  3. 由协调节点将所有的结果进行汇总并排序
  4. 协调节点向包含这些文档ID的分片发送get请求,对应的分片将文档数据返回协调节点,最后协调节点将数据整合返回客户端

六、es部署时如何优化

调整ES的一些重要参数,path.data目录尽量使用SSD。更合理的sharding布局。定制JVM堆内存大小

liunx:不要用root用户,修改虚拟内存大小,普通用户最大线程数

1、根据业务增量需求,采取基于日期模板创建索引,通过 roll over API 滚动索引;

2、使用别名进行索引管理;

3、每天凌晨定时对索引做 force_merge 操作,以释放空间;

4、采取冷热分离机制,热数据存储到 SSD,提高检索效率;冷数据定期进行 shrink

5、采取 curator 进行索引的生命周期管理;

6、仅针对需要分词的字段,合理的设置分词器

7、Mapping 阶段充分结合各个字段的属性,是否需要检索、是否需要存储等。

安全验证篇

一、什么是认证和授权?如何设计一个权限认证框架?

认证:验证您的身份。授权发生在系统成功验证您的身份后,最终会授予您访问资源的完全权限。后台接口访问权限、前台控件的访问权限

RBAC(Role-Based Access Control)模型:主体→角色→资源→访问系统得到行为

用户←多对多→角色←多对多→权限

二、Cookie和Session区别

Session在服务端保存,用来跟踪用户的状态

Cookie客户端保存,用来记录用户的一些信息

三、如果没有Cookie,Session还能进行身份验证么

Cookie中存有SessionID

四、CSRF攻击,如何防止

Cross-site request forgery, 跨站请求伪造

  • 添加并验证 token
  • 添加自定义 http 请求头
  • 敏感操作添加验证码

五、OAuth2.0协议?有几种认证方式?JWT令牌?和普通令牌的区别

向第三方应用颁发令牌

  • 授权码(authorization-code)
  • 隐藏式(implicit)
  • 密码式(password):
  • 客户端凭证(client credentials)

session随着认证用户的增多,服务端的开销会明显增大

JWT:header.payload.signature

头部声明类型,加密算法

载荷就是存放有效信息的地方

签证由HMACSHA256(base64UrlEncode(header) + ‘.’ + base64UrlEncode(payload), ‘secret’)

secret是保存在服务器端的私钥,JWT可以跨语言支持

token需要查库验证token 是否有效,而JWT不用查库或者少查库,直接在服务端进行校验,并且不用查库

self-introduction

面试官角度:最希望知道的是你能否胜任你面试的岗位工作;

所有你可以在介绍的时候,最好是加入你最擅长的专业技能、对哪块知识比较深的理解、你项目中曾经完成了哪个模块功能、项目中让你感觉最有收获的事。

STAR:Situation什么情况下,Task你要干什么,Action你采用了什么样的行动和努力,Result得到什么样的结果

要有细节,要有感情,要有思考,总结得失

项目贡献了多少代码,解决了多少问题,修复了多少bug

范文

您好,我叫吴锦泉,就读于华南理工大学,软件工程专业,22届毕业生,曾经在百度meg部门的YY事业部中的测开部门中的构建组担任过3个月的测试开发实习生,主要负责ci/cd持续集成构建系统的重构和在此基础上的二次开发,实习期间主要负责Android构建功能的开发和负责Shiro权限控制模块的从0到1前后端开发,从无到上线实现公司构建系统的迁移,自动化程度到70%,从刚开始开发只有几个部门负责人使用到后来适配所有渠道开发人员。使用的技术大多是SpringBoot、Mybatis-Plus、Mysql、Shiro、Slf4j等。

一键CI/CD持续集成部署系统,BS系统,先选渠道,然后选择是日常构建还是发布构建,发布构建的话要发布新版本,所以要打tag,然后选择你需要构建的分支,然后进行命名检查和组件之间的版本依赖检查,利用JGit组件从GitLab拉取源代码,分层、分多个子任务的去根据制定的规则触发构建任务,构建结果发送如流通知。保证让开发的产品可以保持高质量的情况下快速迭代,频繁的将测试通过的代码合并到主分支,不断的去尽早的试错,敏捷开发。

最后,我业余时间有写博客的习惯,会定期归纳总结自己的笔记。

在互联网医院项目中用了SpringBoot,nacos服务发现治理配置中心,gateway网关服务负载均衡和服务路由,Netty,kafka,elasticsearch,redis,mysql。移动端线上问诊开药平台,类似于好大夫,核心功能是基于nettyws的im即时通讯服务的在线问诊,此外还有预约挂号,智能导诊和复诊开药功能。

通信流程大概是这样的:上边是客户端,下边为多个WS服务器,服务器要往nacos里边注册。

  1. 客户端携带授权token(jwt请求头加token)向服务集群发起connect请求,请求会被网关转发都具体的某一个ws节点
  2. ws服务针对connect进行鉴权,并且将该连接会话缓存在服务内,返回连接成功
  3. 客户端定时向服务端发送ws心跳,服务端返回ping报文
  4. 客户端需要发送消息时,通过ws发送报文。对应的ws节点收到报文信息后,直接发布到kafka的topic中
  5. 所有ws服务器监听消息队列topic,收到topic信息后根据busiCode类型,toUserId,groupId等寻找对应的用户id。再通过用户id获取到session,通过session进行消息推送
  6. redis负责缓存用户信息和实现分布式锁,作为服务端和mysql数据库的中间件
  7. elk负责持久化kafka信息,提供http get接口进行历史信息模糊查询

我在项目中负责在线问诊和复诊开药流程的开发,elk的搭建和相关需求开发。

gateway:统一服务对外入口,鉴权,过滤拦截(Gateway Handler Mapping→Gateway Web Handler, http请求断言,发送代理请求前后的Filter链),webflux→Reactor模式的netty

Zookeeper(CP)

Znode兼具文件和目录两种特点,具有原子性操作

watch机制实现实时监听znode,不告知事件内容

ZAB:1、消息广播:第一步是广播事务操作,第二步时广播提交操作,其中过半数指的是反馈节点数 >= N/2 + 1

2、崩溃恢复:开启新一轮Leader选举,选举产生的Leader会与过半的Follower进行同步,强一致性

Zxid,事务编号,高32位代表每代Leader的唯一性,低32位代表了每代Leader中事务的唯一性

Redis集群

三主三从,随机需要遍历所有redis服务器,hash取模的话如果服务器变动所有缓存都改变,不易拓展

使用饿汉模式进行管理。只有在读时才缓存加载,其他操作删除相关缓存
缓存时间设置不宜过长,5分钟内为宜(因为现在业务没什么对数据库压力特别大)
考虑缓存穿透问题
不要使用redis事务
先存数据库,再删除缓存
数据粒度要很大时,借助定时任务定期刷新内存
缓存中找不到时,应该去查找数据库中是否存在,记得用一定策略保证击穿问题得到解决
用service屏蔽缓存的直接操作,避免造成缓存管理困难(因为service的操作一定可以反映到数据库上,直接操作缓存不一定能落到数据库)

key定义的规范,这个是用的时候比较容易出错的,重名,和系统关键字冲突,长度等,都需要给出规范来

value上,应该控制数据的长度,比如防止一些大数据类型,redis本来是提速的,不要因为数据长度影响了自身性能,另外就是合理的使用数据类型,节省存储提升性能,比如能整型的就不要字符串型

一致性hash,对2的32方取模,服务器iphash,keyHash后沿环顺时针查找直到遇到服务器,容错性和可拓展性高(只需重定位环空间中的一小部分数据),数据倾斜问题用虚拟节点解决。

主从复制

在主从复制中,有主库(Master)节点和从库(Slave)节点两个角色。从节点服务启动会连接主库,并向主库发送SYNC命令。

主节点收到同步命令,启动持久化工作,工作执行完成后,主节点将传送整个数据库文件到从库,从节点接收到数据库文件数据之后将数据进行加载。此后,主节点继续将所有已经收集到的修改命令,和新的修改命令依次传送给从节点,从节点依次执行,从而达到最终的数据同步。

通过这种方式,可以使写操作作用于主库,而读操作作用于从库,从而达到读写分离。

  1. 从节点执行slaveof masterIp port保存主节点信息
  2. 从节点中的定时任务发现主节点信息,建立和主节点socket连接
  3. 建立连接后,主节点将所有数据发送给从节点
  4. 完成数据同步后,主节点就会持续的把写命令发送给从节点,保证主从数据一致

runId:每个redis节点启动都会生成唯一的uuid

offset:主从节点各自维护自己的偏移量

repl_backlog_size:保存在主节点的一个固定长度的FIFO队列,默认1MB

全量复制

  1. 从节点发送psync命令,psync runid offset(第一次runid为?,offset为-1)
  2. 主节点返回 FULLRESYNC runid offset
  3. 主节点启动bgsave命令fork子进程进行RDB持久化
  4. 主节点将RDB文件发送给从节点,到从节点加载数据完成之前,写命令写入缓存区
  5. 从节点清理本地数据并加载RDB,如果开启AOF会重新AOF

哨兵模式

哨兵模式监控redis集群中Master的工作的状态。在Master主服务器宕机时,从slave中选择新机器当作master,保证系统高可用。

每个哨兵每10秒向主服务器,slave和其他哨兵发送ping。

客户端通过哨兵,由哨兵提供可供服务的redis master节点。

哨兵只需要配master节点,会自动寻找其对应的slave节点。

监控同一master节点的哨兵会自动互联,组成哨兵网络,当任一哨兵发现master连接不上,即开会投票,投票半数以上决定Master下线,并从slave节点中选取master节点。

cluster集群

cluster提出了虚拟槽的概念。

redis cluster默认有16384个槽,在集群搭建的时候,需要给节点分配哈希槽尽可能相同数量虚拟槽。
如果目前redis执行set操作,redis先对这个key经过CRC16 hash运算,并把结果对16384取余,得到槽编号。
根据槽编号,寻找到其对应的redis节点,在节点上执行hash命令。
如果此时执行get操作,节点先验证该key对应的槽编号是不是归本节点管,如果是则保存数据。如果不是,则发送正确节点编号给客户端。

Redis的save命令

save命令是redis手动触发RDB过程的命令。使用该命令后,服务器阻塞,直到RDB过程完成后终止。该过程占用内存较多。

Redis的bgsave命令

bgsave命令不阻塞主进程(严格意义上也不是完全不阻塞,详看下面过程),该命令fork一个子进程用于执行RDB过程。其具体过程为:

判断此时有没有子进程用于RDB,有的话直接返回。
redis进行fork子进程过程,此时父进程处于阻塞状态。
子进程创建RDB文件,完成后返回给父进程

Netty

  1. Netty抽象出两组线程池BossGroup专门负责接收客户端连接,WorkerGroup专门负责网络的读写
  2. BossGroup和WorkerGroup类型都是NioEventLoopGroup
  3. NidEventLoopGroup相当于一个事件循环组,这个组中含有多个事件循环,每一个事件循环是NioEventLoop
  4. NioEventLoop表示一个不断循环的执行处理任务的线程,每个NioEventLoop都有一个selector用于监听绑定在其上的socket的网络通讯
  5. 每个BossEventLoopGroup的NioEventLoop循环执行:
    1. 轮询accept事件
    2. 处理accept事件,与client建立连接,生成NioSocketChannel,并将其注册到某个worker的NioEventLoop上的selector
    3. 处理taskQueue的任务,即 runAllTasks
  6. 每个Worker-NioEventLoop 循环执行:
    1. 轮询 read、write 事件
    2. 处理异步 i / o事件(ChannelFuture接口实现异步),即read,write 事件,在对应的NioSocketChannel处理(每个NioSocketChannel都绑定一个自己的全新的ChannelPipeline)
    3. 处理任务队列的任务,即 runAllTasks
  7. 每个Worker的NioEventLoop 处理业务时,会使用pipeline,pipeline中包含了 channel,即通过pipeline可以获得对应通道,管道中维护了很多 handler。

NioEventLoop内部串行化,消息在多个handler中读取→解码→处理→编码→发送

ChannelInboundHandler / ChannelOutboundHandler 入站(server→client) / 出站io

ChannelPipeline是一个ChannelHandler集合链,负责处理和拦截inbound或者outbound事件和操作

ChannelHandlerContext:上下文对象,含具体的事件管理器ChannelHandler,含pipeline,channel,地址

每添加一个handler都会创建一个关联的Context,调用addLast方法将Context追加到链表

tail是inbound类型的handler,head既是inbound又是outbound类型的handler。

  1. pipeline首先调用ctx的pipeline的静态方法fireXXX(如fireChannelRead),并传入head
  2. 静态方法调用ctx的invoke方法,invoke方法内部调用该ctx所包含的Handler的真正方法,调用结束传递给下一个ctx

https://arthurjq.com/2021/01/21/project/netty-pipeline/

http+json tcp+protobuf

ES

调整堆内存最少2g -Xms2g -Xmx2g

通过ElasticsearchRepository接口自定义基本查询

模糊查询:restHighLevelClient→boolQueryBuilder.filter(queryBuilder.multiMatchQuery(id,fromUserId,toUserId))→boolQueryBuilder.must(queryBuilder.matchQuery(key,content))

查询调优

  1. 禁用 wildcard(支持通配符的模糊检索)
  2. 充分利用倒排索引机制,能 keyword 类型尽量 keyword
  3. es的搜索引擎严重依赖于底层的filesystem cache
  4. 数据预热,每隔一会儿,你自己的后台系统去搜索一下热数据,刷到filesystem cache里去
  5. 冷热分离
  6. 分页性能优化,你翻页的时候,翻的越深,每个shard返回的数据就越多,而且协调节点处理的时间越长。非常坑爹。所以用es做分页的时候,你会发现越翻到后面,就越是慢。
  7. 基于时间敲定索引再检索
  8. 路由优化,可以定好属性再查询

es写入和查询慢

先查看监控、硬件资源以及es中各种线程池的状况

kafka作用

即使WS server因故障停止运行,数据会先被存储下来,从而避免数据丢失

Gradle

Gradle 是新一代的自动化构建工具,主要面向java应用

Gradle是Android里最方便也是最好的用来管理第三方库和打包用的工具。
自动下载多种类型依赖库:本地、库依赖、远程依赖。
最方便的地方是支持自定义打包脚本,为多渠道打包提供了便捷的基础。

面试官对实习经历的关注点:

  • 在实习中做了什么工作?
  • 遇到哪些问题?如何解决?
  • 通过实习,得到了哪些成长?比如 Git 操作、内部工具、团队协作、开发流程/规范等。
  • 实习过程有哪些产出?有没有主动的贡献?比如整理新人手册、发现并解决了某个问题、提升了业务指标等。
  • 对团队的现状和下一步规划,有没有自己的思考?

尖锐的问题

答不出来的问题

不要放弃,让面试官看到你的思考,如果不懂可以追问,但回去要努力补课

对于做过的项目你觉得有什么不足的地方?怎么去弥补?

数据库有些字段可以为null,一开始设计的就不好

加redis,减轻数据库查询压力

你有什么缺点

希望冲,有时为了尽快完成工作任务可能会牺牲一些同事的之间的关系,第一间公司实习的时候我需要另一个实习生的接口才能走完整个流程,他晚上本来想走的想明天再完成,我拉着他加班加点对接完了。

背书不太行,特别是那些没有逻辑关系或者不能理解的段落,理工男,如果有逻辑关系的或者有理解的东西记忆就比较深刻

我的公开演讲能力比较差, 在公共场合讲话的时候我会感到紧张, 不过谈论我熟悉的领域我会比较放松。所以当我需要做公开发言的时候,我必须要准备得很充分。我确实羡慕那些无论什么话题都能够高谈阔论的人。

测开职业规划

我想解决问题,想成为技术专家,成为团队里的核心,学习基础知识,做项目,向大佬学习,跟leader学习,让他帮助我成长

  • 一年内,熟悉整个测试过程及产品业务领域,学习和掌握自动测试工具,学习测试自动化编程技术;开发和执行测试脚本,承担系统测试实施任务
  • 三年内,深入了解测试过程,掌握测试过程设计及改进,参与软件工作产品的同行评审;进一步了解产品业务领域,改进测试自动化编程技术,成为高级测开工程师;
  • 五年内,形成自己的知识体系框架,对业务领域内问题都能提出自己的思路和解决方案,成为测开技术专家

理解:尽早、尽量用最少的测试发现尽可能多的问题,以保证软件产品的质量。
期望 :大致是这样:先做手工或者黑盒测试,慢慢接触自动化测试,希望可以精通一门自动化测试技术,有可能的话会往白盒测试方向发展,希望成为一名专业的测试人才;第二种选择,就是往管理层方向发展;第三种选择,是业务方向,比如技术支持、相关销售等岗位;
职业规划:
半年-1年:重点是快速学习测试相关的知识和基本技能,如测试计划、测试文档、测试执行、结果整理等,并对软件测试行业有一个大致的了解和把握,在此基础上,快速学习公司项目中用到的相关自动化测试工具,并不断提高编程和脚本开发能力。
1年-2年:不断强化自动化测试能力,并形成系统的知识体系;同时不断提高编程能力,力求对公司项目有整体的认识,最好可以作为项目的小负责人,可以带领小团队。
2年之后的发展,可以从测试开发架构师或测试经理等方向发展。

开发职业规划

1年内熟悉公司业务并在此基础上学习分布式和应对高并发流程的知识,实现leader分配下来的各种需求,逐渐向中级技术工程师发展
3年内形成自己的技术框架,应对问题都能提出自己的一番解决思路和简介,成为高级工程师
5年时我希望能成为技术专家,在一个领域内有一定的实力

测试开发

1、尽量测试左移,让测试工程师尽早介入测试提早发现问题解决问题;
2、把控代码研发过程中的质量,编码规范,提交规范,代码逻辑校验;
3、有效的利用自动化测试改变重复测试工作,提升测试效率;
4、测试环境测试把控,第一时间close问题;
5、持续的部署,快速的迭代和测试交付;
6、更加深入理解整个项目质量体系;
7、对于测试有深刻的理解,快速的挖掘出当前测试过程问题并加以改进。

测试开发还是测试,只是用更为全面的技术手段来提高测试效率,同时保障产品质量,提升产品交付效率岗位。

在自己测试的范围内出现了严重的bug,已经马上要上线了,这种情况你会怎么做

(1)首先必须要在缺陷管理平台上提交缺陷报告,缺陷等级为最高优先级,第二抄送邮件给自己的直属领导和相关开发。
(2)找到对应开发确定修复影响范围
(3)尽快开发修复部署环境测试,并报告自己直接领导调派帮手来进行测试
(4)回归完成后记得请开发和帮忙的小伙伴喝奶茶

个人性格总结?三个词概括

打破沙锅,做数学题留下来的习惯吧,不理解想不明白的话会很难受

学习能力比较强

归纳总结

你认为做好测试工作最重要的事情是什么?

最重要:坚持从用户,从需求角度出发。
(1)以业务需求为测试导向,站在用户角度分析问题和设计测试用例及计划
(2)强烈的责任心和一定的项目测试的规划管理能力,能对项目测试工作的进度有一定理解和推进,不断提升测试效率。
(3)技术和业务需求是项目测试工作要求的一体两面,因此要不断的在项目中学习了解和应用项目中使用的技术,既加深对项目的理解,又能提升自己的技术水平。

同事不配合导致工作出错怎么办

(1)找到同事说明当前的情况,向他阐述当前问题的严重性,引起他对该项工作的重视程度。并且询问他是否有自己的想法和意见,我也可以把我之前准备的一些事项跟他分享,通过一起商量找到我们都认可的解决方案,再去共同开展接下来的工作,取得他对工作的配合。
(2)跟同事加班加点,把之前没做好的工作进行返工,尽量减少因此带来的影响。并把最终的结果汇报领导。
(3)做好总结反思,以后再遇到同事不配合,一定要加强沟通、互通有无,协力将工作完成好。

学习中的难点以及如何解决的

不要烦躁,静下心来,想想问题出现的原因以及该怎么去解决,每解决一个问题都是对自己能力的提升。而且每解决一个难以搞定的问题,我相信大部分人都是很高兴的。

1、用到的技术/工具 不熟悉
这类问题的解决方案:如果是公司用到的特有的技术或者工具,建议直接问同事或者leader,他们一般会教你怎么操作,或者会给你一份入手文档。另外就是自己查官网/博客等 技术资料了。

2、开发时,遇到了具体的技术问题
这类问题,是最常见的问题。 解决方案如下:

  1. 自己查阅官网,看官方文档,还有就是自己平时的积累(包括看书、资料、博客等等)
  2. 找度娘、谷爹(这里我推荐用Shadowsocks,一年大概是100RMB,比较稳定,当然了大家可以自己去找免费的翻墙软件)
  3. 去技术论坛求助。这里包括CSDN 、 Stack Overflow 、 博客园、开源中国等等 。很多人对于技术论坛求助比较懵逼,不知道怎么求助。这里分享两个:CSDN:新人提问指南 、 如何优雅的使用Stack Overflow 。 要记住,提出的问题要经过自己的研究,也不要害怕提问。
  4. 找身边朋友、技术群的朋友问问(记住5W 1H原则)
  5. 向公司同事和leader请教,切记,这里放到第五步就是告诉大家,跟同事和朋友请教问题之前,最好自己先有过尝试,查阅过相关资料,这样你才能对问题描述的很清楚。另外如果一个问题你独自用前面四种方案花了2小时还没解决,请立马请教你们公司的技术牛人并上报leader(我们公司要求是1小时)
  6. 如果是特殊问题,比如一些性能问题/ 接口响应缓慢等等 ,这些就需要各位看官自己的积累了,还有就是熟练运用 jdk自带的分析工具,比如jconsole、jstack等等

如果你是leader,你不喜欢什么样的人

1、不主动不积极。等着派活给你,推一步动一下的那种。 2、没头没尾,不懂报备项目进度的。要上司询问跟进的。 3、不懂自我思考。说一做一,不会想着,在这个基础上是否可以有更优方案。 4、玻璃心,不谦虚。面对同事上司的指导,以为是故意找茬。并不会从中学习,增强能力。

反问技术面试官的问题

  • 组内主要的技术栈 / 语言?
  • 部门具体业务 / 面试官的工作内容?
  • 部门业务的挑战 / 难点?
  • 我加入部门后可能负责的工作内容(判断是否感兴趣)
  • 针对新员工有哪些培训(万能问题)

  • 后续是什么流程?还有几轮面试?(推断自己这一面是否通过)
  • 大概多久能够出结果?(避免一直等结果心慌)

我问了如何提升自己跟部门匹配,主管推荐了编译器和计算机体系结构的书,让我入职之前看看

新人培养机制

反问 HR 的问题

  • 针对新员工有哪些培训?

  • 对我有哪些评价或者建议?

  • 大概多久能够出结果(避免一直等结果心慌)

  • 之前的面评(一般 HR 不会透露)

  • 公司福利 / 三餐 / 房补

    注意:HR 面试时,不要直接问户口、薪资等问题,等收到 Offer 后、在沟通薪资时再问。


   转载规则


《面试》 锦泉 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录