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。