repeater系列学习笔记进入第二部分,原理说明篇。
本篇章会结合录制回放的流程进行源码的导读,并且附上我的学习解析,可能有讲得不对、不够好的地方,欢迎大家留言指正~
jvm-sandbox-repeater 学习笔记系列的文章建议按照顺序阅读~附上前序篇章:入门使用篇的传送门。
如下图,描述了用户触发请求,当sandbox感知到调用事件到录制结果保存的过程。
在整个录制过程中,repeater进行录制的处理流程是 DefaultEventListener
类中实现。
接下来我们将以这个类作为入口去了解录制过程的处理逻辑。
DefaultEventListener
实现了sandbox的EventListener接口,是用来处理触发事件的类。
在repeater中,不同的插件可以自定义自己的EventListener来进行各自特殊的事件处理。而在当前的代码中,除了http插件,其他插件都使用的是默认的 DefaultEventListener
。
在 DefaultEventListener
中,承接的是所有事件的处理,也就是说无论是录制操作,还是回放操作,都是集中在这个类中实现的,只是根据不同的条件来区分是录制流量还是回放流量,从而判断该执行录制还是该执行回放。
在上面的流程图中,repeater中的流程执行,实际上是 DefaultEventListener
的 onEvent
的流程图。接下来我们一个一个流程去解析录制过程的实现。
在整个事件处理过程中,总共经历了两个阶段,四个事件过滤。
过滤顺序 | 过滤说明 | 实现方法 |
---|---|---|
1 | 针对单个listener,只处理top的事件 不同的插件之间的listener相互隔离,所以即使是录制http的请求,java子调用插件的事件也能通过过滤。 |
DefaultEventListener.isTopEvent |
2 | 进行基础过滤,主要根据系统熔断、降级进行判断。该过滤条件与repeaterConfig中的degrade字段、exceptionThreshold字段有关。 | DefaultEventListener.access |
3 | 执行采样计算(只有entrance插件负责计算采样,子调用插件不计算),该过滤条件与repeaterConfig中的sample字段有关。 | DefaultEventListener.sample |
4 | 判断是否是插件调用处理器设置为忽略的事件。每个插件处理不同。 | processor != null && processor.ignoreEvent((InvokeEvent)event) |
当事件通过第一个过滤时,就会进行跟踪器初始化。
/** * 初始化上下文; * 只有entrance插件负责初始化和清理上下文 * 子调用无需关心traceContext信息(多线程情况下由ttl负责copy和restore,单线程由entrance负责管理) * * @param event 事件 */ protected void initContext(Event event) { if (entrance && isEntranceBegin(event)) { Tracer.start(); } }
跟踪器相关的内容在com.alibaba.jvm.sandbox.repeater.plugin.core.trace包中。
其中我们提到的traceId实际上是这个跟踪器的独立标识。所以无论是录制和回放都会有其独立的traceId。
对应的方法是 DefaultEventListener.doBefore
。
判断当前流量是否为回放流量,若为回放流量则调用 processor.doMock
方法执行Mock,不执行后续操作。
若当前流量非回放流量,则基于当前获取到的信息拼接 Invocation
实例。其中会调用插件调用处理器的assembleRequest、assembleResponse、assembleThrowable、assembleIdentity方法进行请求参数、返回结果、抛出异常、调用标识的拼接。
根据插件调用处理器的设定,判断是否需要进行 Invocation
中的request、response、throwable参数的序列化。
将当前事件的Invocation信息存放到录制缓存中。
return事件与throw事件的处理逻辑基本一致。
判断当前流量是否为回放流量,若为回放流量则不执行后续操作。
从录制缓存中获取对应的 Invocation
实例,如果获取失败则打印失败日志,不执行后续操作
Invocation
实例获取成功后,调用插件调用处理器的assembleResponse或者assembleThrowable方法将reponse或者throwable信息设置到 Invocation
实例中。并设定 Invocation
的结束时间。
回调调用监听器 InvocationListener
的 onInvocation
方法,判断Invocation是否是一个入口调用,如果是则调用消息投递器的broadcastRecord将录制记录序列化后上传给repeater-console。如果不是则当做子调用保存到录制缓存中。
*PS:消息投递器当前支持两种模式,在standalone模式下,保存到本地文件;在非standalone模式下上传到repeater-console。
↙↙↙阅读原文可查看相关链接,并与作者交流