项目问题

1、项目介绍

将接入采集站的执法记录仪设备中的视频、图片、音频等文件,采集到采集站本地,融合了管理平台功能,提供用户查看编辑视音频等文件,也提供了对当前组织人员设备等信息的管理。同时还有同步服务,定时从上层平台同步相应的组织人员等信息,并上报采集站上的视音频等文件到上层平台。

2、说说工厂模式

由于该项目会接入不同厂商的设备,对不同厂商设备的通讯和处理方式有很大区别,而其中又有一些共同点(例如文件上传逻辑),所以定义了抽象类作为父类,实现共有方法,各种设备对应一个子类实现,并由一个工厂类去根据设备类型新建对应的子类。增加了系统对不同设备的扩展性。

3、有高并发场景吗

对于设备插拔过程,没有高并发场景,但需要严格控制设备插入行为,同一时间只处理一台设备,因为可能出现人为的同时插入两台设备的情况。

有两个版本(动态库单设备通讯和多设备通讯,最新版本是多设备通讯)

①单设备通讯:采用synchronized锁+redis锁(也可以只说redis锁),设备插入后,事件和设备信息会进入队列等待处理,只有获取锁成功的设备才能进行后续处理。

等待队列实现:线程轮询队列是否为空,不为空则队首出队列,进行后续处理。

redis锁:轮询过程会尝试加锁,redis中存放了key为锁名,value为当前时间+存活时间的数据;

当线程尝试加锁时发现该key已存在,则判断该key对应的value是否已到过期时间,未过期则视为线程加锁失败,已过期则删除该key(防止死锁),并由该线程重新写入新的key-value,线程加锁成功。

②多设备通讯:

仅采用synchronized锁,锁住设备插入的识别事件方法,避免识别到设备接入的hub标识与设备不匹配。

(此时大概率会问你synchronized锁原理之类的)

4、如何控制大批量文件的拷贝及大文件拷贝

满载使用时,插入设备22台,假设每台设备1000个文件需采集,则同时需要采集2万多个文件。

每个文件开启一条线程去拷贝,这种方式不实际,会在一瞬间线程数量暴涨。

因此项目中采用一台设备开启一条线程专注于拷贝当前设备的所有文件。每次拷贝文件前会根据文件大小进行分段处理,通过NIO方式分段拷贝,但没有采用一段一线程的方式,因为这样也会导致线程数量暴增(例如由22个文件,每个文件分为5段,那么就会新增110条线程处理文件)。因此,做分段的目的在于:通过测试,大文件整个拷贝耗时会相对于一小段一小段传稍慢些,因此将大文件分段传输。

后来为了充分利用系统IO资源,借鉴信号量机制,实现对同一时间文件上传总数的控制(当由22个文件同时传输时,系统总IO到达顶峰,且单个文件的IO很小,而假设仅有5个文件同时上传,系统总IO也是顶峰,但单个文件的IO会相对更高)。定义一个允许同一时间内文件上传总数限制,假设为5,当当前正在上传文件的线程数量达到5个时(信号量为5),后续即将上传文件的线程只能进入等待状态,直到5个文件中有完成拷贝的线程(此时信号量变为4),则正在等待上传文件的线程进行争抢,哪个文件所在的线程成功修改信号量(修改为5),说明取得上传文件的权利,线程开始上传文件。

5、为什么使用LongAdder

由于需要统计上传进度,且该进度受多个线程影响,线程中会对该值进行修改,各个线程共享唯一一个该变量。

假设使用long类型,由于不是线程安全的类型,当传递给各个线程时,线程会对该变量存储为自己的副本,且需要定义为final类型传递,线程中对该值的修改,对其他线程来说并不可见。

为解决以上问题,使得某个线程对进度的修改对其他线程可见,且保证线程安全,于是采用LongAdder。LongAdder提供api,支持在各自线程中对数值的累加等计算(原理没有很了解,只记得是维护一个数组,累加就是在数组中插入一个值,最后总数就是数组内所有数值的总和)。

Atomiclong对比:也是实现了多线程下对一个数值的读写,也是线程安全,和LongAdder不同的是,Atomiclong通过维护一个volatile变量,通过对volatile变量的值的修改来做到多线程下的可见性。但由于采用的是volatile实现,底层采用CAS实现,于是在大量线程的情况下效率会急剧骤减,大量没有CAS成功的线程会进入自旋等待,不断尝试CAS,消耗CPU。

(这里会问volatile原理,还有CAS)

6、为什么用队列

MD5的计算,对于大文件来说十分耗时,于是通过全局的一个队列来存储准备计算MD5的文件信息,通过线程轮询判断队列是否有文件信息存在,若有,则出队列并计算MD5。

在证据文件同步到平台的过程中,也是采用队列方式,将准备上报平台的证据文件入队列,线程轮询队列进行文件上报。

7、redis在项目中的作用

数据库数据缓存、服务间共享数据的缓存(如系统配置)、同步锁。

8、nginx在项目中的作用

映射静态资源,包括证据文件。

9、JVM调优经历(这个涉及JVM,要深入理解)

现象:面板上设备信息闪烁

问题定位:第一反应是系统线程调度出了问题,查看系统CPU情况,CPU占用100%

问题排查:CPU占用100%极大可能是JVM的GC活动频繁,尤其是full GC。于是打开jdk自带的JVM监控工具jvisualvm,发现新生代每分钟上百次GC,老年代每分钟几十次GC,且新生代每次GC都有大量对象存活,被移动到老年代,而老年代GC时又回收了大量对象。这个现象说明,新生代有大量无用对象在GC时幸存下来。于是要找到该对象,利用抽样器对线程及内存进行抽样,发现有两个线程分配了大量内存且不断增加:一个是文件拷贝线程,一个是视频缩略图截取线程。初步分析:文件拷贝采用的工具类完成任务后,没有被即时回收,导致堆中大量该类存在;在大批量小文件上传的场景下,每个视频都要开一个单独的线程去截取缩略图,这也导致线程大量增长,且该方法较耗时。

问题解决:将文件拷贝工具类定义为bean,单例模式,大大减少了GC频率;优化缩略图截取方法,介绍不必要的处理,并取消线程,串行处理,提高性能。

问题分析:在大批量小文件传输过程中,假设单台设备需处理2000个文件,当设备中途拔出,设备服务类会对所有失败文件进行日志记录,在这个过程中文件拷贝工具类依然被设备服务类所引用,不会被回收。所以当22台这样的设备接入,并全部中途拔出,造成大量无用的文件拷贝工具类存在堆内存中。

(这一块一定要理解JVM内存模型,还有堆的GC原理,包括新生代具体的GC流程)

10、SQL优化

只说了对频繁查询的字段加索引

(这里就要知道索引的原理,最左匹配原则等)

你可能感兴趣的:(项目问题)