77百科网
当前位置: 首页 生活百科

如何查系统日志组件(日志系统开发总结之Guava)

时间:2023-08-15 作者: 小编 阅读量: 1 栏目名: 生活百科

已经连续有10天没有更新头条号了,原因是最近比较忙。即使服务宕机,MQ可以靠其集群特性保证日志不丢失。优点是方案比较成熟,缺点是增加了维护成本。综上考虑,我们最后决定使用eventbus这个组件,暂时也不引入MQ,因为业务量没有那么大。而是创建一个message的表,用以保存日志或者其他消息记录。guava-eventbus为我们提供了同步和异步的事件解决方案,即我们在进程中希望我们这个事件可以同步完成然后返回,或者可以异步完成不影响主线程。

已经连续有10天没有更新头条号了,原因是最近比较忙。最近和同事一起搞日志系统的开发,涉及到基础架构和具体的业务日志记录,难倒不难,但量比较大,而且这期间还有其他需求和BUG需要我们来维护,所以我也就没有了时间去更新头条号,明天我要请一天假有点事处理,今天下午就写写我们这个日志系统怎么做的吧。

有人会问我,你的日志为什么不用AOP来做呢,对一些方法例如save,update方法做方法级别的拦截,在执行完成后像数据库插入一条记录不就可以了。这种方案我们考虑过,也许是我对AOP的理解不到位吧,我们并没有采用这个方案,原因是因为我们要记录的日志并不是固定的、模版式的,而是具有很强的业务属性,要记录每个操作的人、以及具体做了那些操作,操作的对象都是什么属性等,而AOP适合一些公共的,统一的,业务性弱但行为性强的操作。所以我们就没有考虑使用spring的切面。

首先说一下我们这个日志记录的技术要求有哪些:

(1)日志的保存要求在本次事务提交之后的另外一个新事务异步提交;当然也要支持在同一个事务里同步提交。

(2)支持日志的持久化,即若系统宕机后要记录的日志不能丢并保证日志可以在某个时间点统一保存到日志库(表)中。

针对第一个问题,在以前我记录日志的设计中,通常我会在service层(事务层)执行完后成,将日志信息返回到前一层也就是controller(控制层),在控制层中提交日志。优点是可以保证事务已经提交,不过缺点是改造比较大,我需要改造每一个接口,修改返回值等内容,还要在控制层判断业务是否成功。其次,假设日志保存比较慢,日志的保存应当不能影响主线程的进度,所以要开启一个新的线程完成这项工作。

针对第二个问题,我想可以引入MQ,将日志先保存到MQ中,通过监听来读取mq消息,然后逐一保存到日志库中。即使服务宕机,MQ可以靠其集群特性保证日志不丢失。优点是方案比较成熟,缺点是增加了维护成本。

综上考虑,我们最后决定使用eventbus这个组件,暂时也不引入MQ,因为业务量没有那么大。而是创建一个message的表,用以保存日志或者其他消息记录。那首先我们解释下什么是eventbus.

我们在百度搜索eventbus,竟然没有百度百科,很多人都不知道这是什么,如果让我为其总结一个概念我可能也说不好,根据我个人的理解,eventbus汉语意思就是事件服务总线,事件代表着我们系统中各种各样可能被触发的事件、任务。由于服务中的这些事件可能会越来越多,所以我们需要一套机制去管理这些事件,提供订阅、发布等模式,最终形成一整套的事件调度和执行,适应于多系统集成的方案。当然这都是我自己的体会不一定对。简单来说,eventbus的一个比较好的实现就如mq,mq可以作为事件中心,我们将所有的事件全部注册到mq,mq帮助我们来分发消化我们的消息。这里,我们使用的eventbus的实现方案是google的guava的eventbus库。MQ就是传统的事件订阅与发布的模式,eventbus是进程内的模式,下面我们先来看一下具体的术语概念:

那我们如何将日志抽象成事件呢?

(1)当我们保存日志的时候其实就是要注册一个事件,我们可以称之为LogEvent。

(2)而这个事件我们的目的是要保存它,我们肯定会有一个事件监听者我们称之为LogEventListener。

(3)将来我们系统中还会有其他的事件,不同的事件监听器针对不同的事件进行订阅,会走各自的实现类,但接口应该都是一样的,即IEventListener,提供一个listener方法,LogEventListener实现该接口,重写listener方法。将来比如有发短信的事件处理,我们就在定义一个MsgEventListener即可。

(4)IEventListener的listener方法就是统一的事件处理方法

(5)最后我们要做的就是将该事件注册到总线中,让各位监听者可以监听到。

发现讲了很多,可能大家都不会理解,因为文章涉及的内容比较多,我觉得还是应该拆看来讲,我们今天就主要将guava的eventbus库,让大家理解什么是eventbus,如何使用eventbus。

guava-eventbus为我们提供了同步和异步的事件解决方案,即我们在进程中希望我们这个事件可以同步完成然后返回,或者可以异步完成不影响主线程。各自的实现方式如下图:

为了让大家更清晰的了解EventBus所提供的同步和异步机制,下面我们来做一个DEMO,假设我们现在系统内有A事件与B事件分别发送给事件中心EventBus处理,AB事件分别有各自的事件处理者,首先看事件处理接口定义:

实现类如下:

在主线程中,将这些事件处理者在服务启动的时候注册到eventBus中心来管理,如图:

其中eventBus实例为同步实例,而asyncEventBus为异步实例。

假设主线程可以生存5000毫秒,主线程启动后,启动一个新的线程(这个线程1000毫秒就结束了)发送A事件和B事件,在A事件由于业务简单,基本不需要耗时;B事件需要耗时2000毫秒才能执行完成,如果上述场景存在,那结论应该是当我们分别想eventBus提交我们的事件后,A事件会被处理,但B事件不会别处理,因为在同步情况下,B事件所在的子线程1000毫秒已经死亡,B事件由于耗时太长2000毫秒被终止。我们看结论是否正确:

执行main方法,我们看下输出:

1、子线程处理业务开始

2、子线程发送消息给EventBus

3、AEventListener.listener:A事件执行完成

5、子线程终止

6、主线程....

7、主线程结束....

我们发现(4)也就是B事件压根没有输出,也就是说在同步模式下,由于子线程死亡,B事件没有处理成功。

如果同样的问题,我们使用异步的方式结果是什么呢?只需要将eventBus修改为asyncEventBus实例调用post方法即可。

运行main方法,看下输出:

1、子线程处理业务开始

2、子线程发送消息给EventBus

3、AEventListener.listener:A事件执行完成

5、子线程终止

6、主线程....

4、BEventListener.listener:B事件执行完成

7、主线程结束....

结论是(3)(4)事件都会执行了,由于我们使用的是异步方式,即任务已经在其他子线程中执行了,即使其所在的子线程已经死亡,也不会影响任务的执行。

在这里有同学可能会疑问,你是通过什么让AEventListener监听到A任务的?只调用了一个post方法就可以吗? 因为guava已经帮助我们将这个机制给封装了,我们会在之后的续篇讲解其源代码,这里我们可以看一下源代码,当我们调用eventbus.post(T)方法的时候,实际上guava会在底层解析T对象的类型,将其作为key去找map中的value,而这个map是其维护在内部的,key是参数class,而value就是处理类,我们在定义AEventListener的时候它重写listener方法所接受的参数就是AEvent,同理,BEventListener的参数是BEvent,在服务启动时,eventbus中心根据这些类型将listener放在map中,在运行时,根据post的参数类型找到对应的listener。源码如下:

getAnnotatedMethods是找哪些被注解@Subscribe修饰的方法。即如果你想让这个listener监听到你的事件,就要在其方法上加上注解@Subscribe,这样在服务启动时,它就可以以此监听到你的事件了。

其实有了这个机制,不管是做日志还是做其他的什么,只要涉及到异步执行的例如发短信,发邮件等我们都可以基于这个机制来做,如果说性能肯定不如mq,如果从易用性维护性来讲,对于中小型系统足够了。在我们的日志系统中,我们要选择的就是这种异步的处理方式,当主线程的业务处理完成后,构造的日志内容也完成了,此时我们就要将这个日志post到事件中心。而日志的保存就异步执行了,不会阻塞主线程。不过这里还有一个问题我们没有解决就是事务。我们如何保证让主线程的事务提交后,再去post日志数据呢?之前我们说放在controller层,这样显然不好,改动太大,我们要的就是在service层post日志,但需要在service提交事务后做?这里的确可以使用aop做,不过Spring4.3.2给我们提供了更好更简单的方式ApplicationEventPublisher,这个我们将放在下一篇再讲了。

    推荐阅读
  • 睁眼瞎什么意思(词语睁眼瞎)

    我们一起去了解并探讨一下这个问题吧!睁眼瞎什么意思睁眼瞎,比喻没文化的人,不识字的人,缺乏知识的人。睁眼瞎,是个很形象的词,一双好好的眼睛瞪得老大,却什么也看不到。

  • steam最值得买的3a大作(再也玩不到3A大作了)

    近日,其乐的网友清靈語发布帖子,根据对完美steam的代码进行进一步挖掘,发现完美steam在全局设置防沉迷系统,玩家每次开启游戏都会在开头显示五秒的健康游戏公告。国内正版游戏市场逐渐扩大,为了更好的监管,在完美steam上线之后对相关内容的修改不可避免。但是在完美steam正式上线之后,steam国际服难保不会受到一些影响,玩家担心会因为国服上线而导致steam国际服无法正常的使用。

  • 商标tm与r有什么区别(商标上标注TM和)

    “圆圈R”代表的是已获准注册的商标,商标注册人享有该商标的专用权。非注册商标不能标注“圆圈R”,已注册商标有些可能会标注,有一些品牌可能不标注。有些人对“TM”有误解,认为标注了“TM”的代表是正在申请中的商标,但其实不管有没有提交申请,都可以标注“TM”。总的来说,“圆圈R”仅限注册商标使用,受法律保护,而“TM”没有任何法律效力。

  • 围城作者简介(围城作者介绍)

    书评家夏志清先生认为小说《围城》是“中国近代文学中最有趣、最用心经营的小说,可能是最伟大的一部”。钱钟书在文学,国学,比较文学,文化批评等领域的成就,推崇者甚至冠以“钱学”。《围城》是钱钟书唯一的长篇小说,于1944年动笔,1946年完成,1947年由晨光出版公司印行。解放后,一度绝版30年,1980年再次重印,在青年中激起了强烈反响。

  • 荷叶茶的功效与作用都有哪些 荷叶茶的功效与作用是什么

    荷叶茶的功效与作用都有哪些?荷叶茶里含有大批纤维,能够促使大肠蠕动,有助排便从而能够消除毒素。同时另有极佳的利水功能,久坐少动的上班族、轻易水肿、脾虚、气虚者,就要多喝荷叶茶了,当体内过剩的脂肪和滞留电解液被排挤,人天然就会变瘦了。而喝荷叶茶能弥补人体在肠道耗费的茶瘦素,能进步身材推陈出新,让你酿成易瘦体质。

  • 毛姆读书心得在线阅读(毛姆阅读课明智的读者)

    “明智的读者不会把阅读当成任务,而只是当作消遣。”作为一本来自文学巨匠毛姆亲笔的阅读指南——《毛姆阅读课》,让我受益颇深的莫过于这句话。而迫使我们能够完成这样的壮举,很大一部分原因在于网络作者在情节铺设的时候过于拖沓。《毛姆阅读课》中也有提及到跳读的目的和意义,“想知道羊肉的味道,不必吃下一整只羊,只要一小块羊排就够了。再对吃过的羊排发挥想象力和创造力,就能描绘出爱尔兰炖肉的美味。”

  • 和男生接吻后嗓子不舒服(再次提醒男女亲热)

    送往医院后依旧没能挽回男孩的生命,医生称男孩是因为颈动脉窦反射而引起的心跳、呼吸骤停。主要作用是调节心率、血压,一旦颈动脉窦受到外力刺激,容易导致其承受过大压力。用力亲吻或者是遭受到外力挤压时,颈动脉窦受到压迫,可能会导致人体出现意识丧失、抽搐、甚至死亡。有部分人颈动脉窦特别敏感,只要受到轻微的压迫就容易引起心跳停止,继而导致猝死发生。

  • 安全生产责任制具体内容应包括(安全生产责任制主要内容是)

    安全生产责任制是根据我国的安全生产方针”安全第一,预防为主,综合治理”和安全生产法规建立的各级领导、职能部门、工程技术人员、岗位操作人员在劳动生产过程中对安全生产层层负责的制度。职能管理机构负责人按照本机构的职责,组织有关工作人员做好安全生产责任制的落实,对本机构职责范围内的安全生产工作负责;职能管理机构工作人员在本人职责范围内做好有关安全生产工作。

  • 春菠蛋饼做法窍门(春菠蛋饼做法分享)

    跟着小编一起来看一看吧!春菠蛋饼做法窍门用料:鸡蛋1个、面粉10g、菠菜2颗、盐,胡椒粉适量。将菠菜切碎,鸡蛋搅拌成鸡蛋液。锅预热后加入有烧热,将面糊放入其中。晃动锅使面糊糊满平底锅,将饼煎熟即可。