公司要为一些系统做一个记录审计日志的功能。这些日志不是我们开发人员常用的系统日志功能(用来记录我们程序运行情况的,比如用log4j记录下来的日志),而是为了今后对审计部门所使用,具有很强的业务要求的日志功能。架构已经被公司里的其他同事设计好了,虽然我现在只是做些边角料的辅助工作,不过这个命题我很感兴趣,我今天仔细琢磨了一下这样的一个业务需求,觉得还是很有意思,真正把这个做起来是会有一定技术含量。下面就是我的思考,这些思考不全是我自己独立想出来的,也借鉴了些同事的设计。
首先我要设定一个业务场景:我们是为一个重要的商业支付网站做一套审计系统。最重要的技术要求是审计系统不能影响到业务系统的性能以及业务系统的稳定性。
下面是我想到的设计:
- 如果想让审计系统不会影响到业务系统的性能,我个人觉得最后是把审计的系统从业务系统里独立出来,如果资源充足最好有一台专门的服务器独立部署审计系统,如果实在没有新的服务器作为资源,我们可以在装有业务系统的服务器上开辟有限的资源供给审计系统,但是审计系统和业务系统所占该服务器的计算机资源的比率一定要控制好。
- 审计日志往往是包含了很多业务要求,所以用户记录审计的代码一定会和业务操作的代码耦合,特别是如果审计需要很变态可能会导致我们业务系统中每个功能点都会记录审计日志的代码(导致我们每个业务方法的代码都要更改,痛苦啊),这种耦合必然会给系统带来风险那么审计系统和业务系统的交互如何设计最好了?由于我的设计里是把两个系统都独立出来,那么这就表明两个系统是一套异构的系统,异构的系统的信息交互就得通过通讯,通讯的方式有很多:webservice、http方式、消息队列或者是企业内部电文系统。(我对消息队列不太熟悉,前两种我比较熟悉,后面的理解不代表消息队列也会存在同样的缺陷)在我的理解里不管哪个通讯方式都会存在请求和响应的过程,而这个请求和响应过程并不是总是安全的,假如某种原因导致通讯的阻塞使得请求和相应过程不能顺利完成就会使得系统产生错误,为系统的稳定性产生风险,因此嵌入到业务系统代码中的记录审计日志的代码最好不能包含请求和相应功能,让请求相应的功能耦合到业务功能中去。我个人觉得最好是把记录日志的功能独立到一个线程中去,这个线程不能干扰到用户请求的线程,而放在业务方法代码的接口只要传值就行,传值成功如否业务代码完全不用关心。因为我就得在业务系统里嵌入一个线程池,这个线程池里的线程都是用来记录日志功能的。这个线程池在web服务启动时候也会附带运行,业务系统记录日志的信息的方法作为一个线程记录添加到线程里去,业务系统记录日志的方法只要放入值就行,那么在业务系统里记录日志和业务操作被独立开来了,大伙互不干扰,这样就减少了记录审计日志的功能对业务系统的干扰从而降低了日志记录系统对业务系统不安全的影响。对这个线程池里线程就是负责把数据传输到审计系统,只要数据传到了审计系统,审计系统就返回一个success标识,线程不关心审计系统里操作是否成功。
- 对于审计系统里的设计也是值得考量的,我个人是这么想的,我们把从业务系统接收到数据放到一个队列里(queue)。为了提高日志请求的效率我还是为审计系统审计一个线程池,这个线程池所使用到的数据就是我们构建的队列(queue),这么做的好处在哪里:
- 并发操作一定会提高系统运行的效率,这个我想谁都没有异议吧;
- 假如我们把审计系统和业务系统布置到一台服务器上,我们可以通过控制queue的大小以及线程池的大小来限定审计日志系统所消耗的系统资源。
- 或许有人会有疑问我为什么不把数据直接传到线程而是使用队列存储,我的目的有两个:一是数据先进队列,这个操作很简单不容易出错,进入队列后马上给业务系统一个响应回复,这样会减少系统的不稳定因素,一是我们先让数据进队列而不是线程池,那么我们可以为缩减线程池大小做好准备,特别是在审计系统部署到业务系统服务器上时候这个做法很有效的。
以上就是我的初步想法,我的设计里牵涉到的比较难点的技术有:异构系统的通讯方式、线程池技术以及一个高效安全的queue的设计。
我个人感觉到一个难点:我要在业务系统里独立设计一个线程池用来记录日志信息,这个线程池里的线程要独立于用户请求的线程,在我们用java开发的web系统里该如何做才是最好了?不知道哪位童鞋可以给我一点建议。
或许有的童鞋会有这样的疑问:我在业务系统里开辟新线程记录日志不是一样的影响到了业务系统的性能。这个问题其实比较好解决,因为开辟新线程记录日志只是消耗了服务器资源而非消耗到业务系统每个用户请求所负载的系统资源,加入了审计日志记录功能应该是影响了部署业务系统服务器所能承受用户并发量,而不是给每个用户系统带来了负担,至于如何提高并发解决方法就比较简单,提高业务服务器的性能(比如加cpu,内存等)或者加几台服务器就行。
这里面牵涉到的线程池技术我是最感兴趣的,我最近查阅了些线程池技术,发现线程池并不是我想象中那么简单,对于jdk自带的ThreadPool技术就很值得研究。
最后希望博客园里的大牛看到此文能否给我一些建议,看看我的设计到底好不好,合不合理。